In [12]:
import altair as alt
from bs4 import BeautifulSoup
from vega_datasets import data
import gpdvega
import geopandas
import json
import shapely
import re
from matplotlib import pyplot as plt
%matplotlib inline
In [85]:
portraitRaw = open('../portrait.xml').read()
portraitSoup = BeautifulSoup(portraitRaw)
geos = portraitSoup.find_all('geo')
In [86]:
geotext = [item.text for item in geos]
In [87]:
lineNos = [int(item.parent.parent.find_previous('lb').attrs['n']) for item in geos]
In [88]:
points = [shapely.geometry.point.Point([float(x) for x in pt.strip().split()[-1::-1]]) for pt in geotext]
In [89]:
def clean(text):
return re.sub('\s+', ' ', text.strip().replace('\n', ' '))
In [90]:
names = [clean(item.parent.parent.find('placename').text.strip()) for item in geos]
In [91]:
gdf = geopandas.GeoDataFrame({'name': names, 'lineNo': lineNos, 'geometry': points})
In [92]:
gdf.head()
Out[92]:
From: https://www.naturalearthdata.com/downloads/50m-physical-vectors/50m-land/
In [21]:
gdf2 = geopandas.read_file('mapData/ne_50m_land.shp')
In [22]:
gdf.head()
Out[22]:
In [23]:
gdf2.head()
Out[23]:
In [24]:
gdf.crs = {'init': 'epsg:4326'}
# gdf.crs = {'init': 'epsg:27700'}
# gdf2.crs = {'init': 'epsg:27700'}
In [25]:
gdf.crs
Out[25]:
In [26]:
mercator, britain, americas, web = (4326, 27700, 2163, 3857)
#gdf = gdf.to_crs(epsg=web)
In [27]:
gdf.crs, gdf2.crs
Out[27]:
In [28]:
def lineToPercent(lineNo):
""" Convert the line number to a percentage in the narrative time of the novel,
i.e., 0% is the beginning of the novel, 100% is the end. """
maxLines = {1: 1848, 2: 1458, 3: 1584, 4: 922, 5: 2794}
totalLines = sum(maxLines.values())
chap = int(str(lineNo)[0])
linesIntoChap = lineNo - (chap * 10000)
preceedingLines = sum([maxLines[i] for i in range(1, chap)])
return (preceedingLines + linesIntoChap) / totalLines
In [29]:
gdf['percentNarrative'] = gdf['lineNo'].apply(lineToPercent)
In [30]:
gdf.head()
Out[30]:
In [93]:
# Slice so that it's only showing the British Isles
gdf = gdf.cx[-11:1,50:58]
gdf2 = gdf2.cx[-11:1,50:58]
# Reproject
gdf = gdf.to_crs(epsg=web)
gdf2 = gdf2.to_crs(epsg=web)
In [32]:
# Setting the figsize width here (20) seems to take effect,
# but not setting the figsize height (40)
fig, ax = plt.subplots(figsize=(20,20))
gdf2.plot(ax=ax, color='white', edgecolor='black')
gdf.plot(ax=ax, marker='o', c=(gdf.percentNarrative * 256), cmap='Reds', markersize=70, alpha=0.7)
plt.ylim([6400000, 7650000])
plt.xticks([])
plt.yticks([])
plt.savefig('/home/jon/Code/article-jjq/images/portrait-map.svg')
plt.show()
In [33]:
# Setting the figsize width here (20) seems to take effect,
# but not setting the figsize height (40)
fig, ax = plt.subplots(figsize=(20,20))
gdf2.plot(ax=ax, color='white', edgecolor='black')
gdf.plot(ax=ax, marker='o', c=(gdf.percentNarrative * 256), cmap='Greys', markersize=70, alpha=0.7)
plt.ylim([6400000, 7650000])
plt.xticks([])
plt.yticks([])
plt.savefig('/home/jon/Code/article-jjq/images/portrait-map-bw.svg')
plt.show()