import pandas as pd
import geopandas as gp
from plotnine import (
ggplot,
aes,
geom_map,
geom_text,
labs,
scale_fill_brewer,
scale_x_continuous,
scale_y_continuous,
scale_size_continuous,
coord_cartesian,
element_rect,
theme_void,
theme )
The Political Territories of Westeros
Layering different features on a Map
Read data and select features in Westeros only.
= gp.read_file('data/lands-of-ice-and-fire/continents.shp')
continents = gp.read_file('data/lands-of-ice-and-fire/islands.shp')
islands = gp.read_file('data/lands-of-ice-and-fire/lakes.shp')
lakes = gp.read_file('data/lands-of-ice-and-fire/rivers.shp')
rivers = gp.read_file('data/lands-of-ice-and-fire/political.shp')
political = gp.read_file('data/lands-of-ice-and-fire/wall.shp')
wall = gp.read_file('data/lands-of-ice-and-fire/roads.shp')
roads = gp.read_file('data/lands-of-ice-and-fire/locations.shp')
locations
= continents.query('name=="Westeros"')
westeros = islands.query('continent=="Westeros" and name!="Summer Islands"')
islands = lakes.query('continent=="Westeros"')
lakes = rivers.query('continent=="Westeros"')
rivers = roads.query('continent=="Westeros"')
roads
= westeros.geometry[0]
wg = [wg.contains(g) for g in locations.geometry]
bool_idx = locations[bool_idx]
westeros_locations = westeros_locations[westeros_locations['type'] == 'City'].copy() cities
Create map by placing the features in layers in an order that limits obstraction.
The GeoDataFrame.geometry.centroid
property has the center coordinates of polygons, we use these to place the labels of the political regions.
# colors
= '#a3ccff'
water_color = 'white'
wall_color = 'brown'
road_color
# Create label text by merging the territory name and
# the claimant to the territory
def fmt_labels(names, claimants):
= []
labels for name, claimant in zip(names, claimants):
if name:
'{} ({})'.format(name, claimant))
labels.append(else:
'({})'.format(claimant))
labels.append(return labels
def calculate_center(df):
"""
Calculate the centre of a geometry
This method first converts to a planar crs, gets the centroid
then converts back to the original crs. This gives a more
accurate
"""
= df.crs
original_crs = 'EPSG:3857'
planar_crs return df['geometry'].to_crs(planar_crs).centroid.to_crs(original_crs)
'center'] = calculate_center(political)
political['center'] = calculate_center(cities)
cities[
# Gallery Plot
(ggplot()+ geom_map(westeros, fill=None)
+ geom_map(islands, fill=None)
+ geom_map(political, aes(fill='ClaimedBy'), color=None, show_legend=False)
+ geom_map(wall, color=wall_color, size=2)
+ geom_map(lakes, fill=water_color, color=None)
+ geom_map(rivers, aes(size='size'), color=water_color, show_legend=False)
+ geom_map(roads, aes(size='size'), color=road_color, alpha=0.5, show_legend=False)
+ geom_map(cities, size=1)
+ geom_text(
political,'center.x', 'center.y', label='fmt_labels(name, ClaimedBy)'),
aes(=8,
size='bold'
fontweight
)+ geom_text(
cities,'center.x', 'center.y', label='name'),
aes(=8,
size='left',
ha=.20
nudge_x
)+ labs(title="The Political Territories of Westeros")
+ scale_fill_brewer(type='qual', palette=8)
+ scale_x_continuous(expand=(0, 0, 0, 1))
+ scale_y_continuous(expand=(0, 1, 0, 0))
+ scale_size_continuous(range=(0.4, 1))
+ coord_cartesian()
+ theme_void()
+ theme(figure_size=(8, 12), panel_background=element_rect(fill=water_color))
)
<Figure Size: (800 x 1200)>
Credit: cadaei of the cartographersguild website forum.