Description: This notebook was made to demonstrate how to make a gif map by merging 2 datasets. The first being a dataset containing mappable coordinates onto which the second dataset may mapping its information of interest.
This lab is split into two sections.
- The first part of this lab provides help you understand the basics operations.
- The second part of this notebook provides a single python function that handles everything covered in this lab (and more).
Input(s):
- Dataset (points/ bounds) url
- Points/ bounds geometry column(s)
- Points/ bounds crs's
- Points/ bounds mapping color(s)
- New filename
Output: Files, Gif
*please note
- This lab in particular makes heavy use of data that is not publicly accessible. Later labs use functions created here on public data.
- A table of contents is provided in the menu to the left.
- And, that this notebook has been optimized for Google Colabs ran on a Chrome Browser.
- While still fully usable, non-critical section of code (eg. Python Magics and HTML) may break if used in a different enviornment.
%%capture
!pip install geopandas
!pip install VitalSigns
pd.set_option('display.expand_frame_repr', False)
pd.set_option('display.precision', 2)
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
# pd.set_option('display.expand_frame_repr', False)
# pd.set_option('display.precision', 2)
# pd.reset_option('max_colwidth')
pd.set_option('max_colwidth', 20)
# pd.reset_option('max_colwidth')
This next function was created in previous colabs. We are going to recycle it for use in this lab
regexMatchingColumnsToMakeTheGifWith = 'hhchpov'
# BNIA ArcGIS Homepage: https://data-bniajfi.opendata.arcgis.com/
final = intaker.Intake.getData("https://services1.arcgis.com/mVFRs7NF4iFitgbY/ArcGIS/rest/services/"+regexMatchingColumnsToMakeTheGifWith.capitalize()+"/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson")[['CSA2010', 'hhchpov15', 'hhchpov16', 'hhchpov17', 'hhchpov18', 'hhchpov19', 'geometry']]
final.head(1)
final.head(1)
final.plot(column='hhchpov15')
Fantastic!
Your data is all together in a single dataset.
now what?
First lets take the centerpoint of each geometry. This will be where we place text on the each geometry.
final['centroid'] = final['geometry'].representative_point()
pd.set_option('precision', 0)
fileNames = []
labelBounds = True
specialLabelCol = False # Labels on GEOM Centroids
saveGifAs = './test.gif'
label = 'Household Poverty'
annotation = 'Source: Maryland Vital Statistics; Analysis by: Baltimore Neighborhood Indicators Alliance'
fontsize='22'
Data was successfully merged across all years and geometry.
Now we want the tractname, geometry, and the specific column we want to make a gif from.
td = final.copy()
td = td.reindex(sorted(td.columns), axis=1)
# This will ensure numbers are rounded to whole digits when displaying the reults
gifCols = td.filter(regex=regexMatchingColumnsToMakeTheGifWith).columns.values
td[gifCols] = td[gifCols].fillna(-1)
td[gifCols] = td[gifCols].astype('int32')
td.head()
Data exploration is essential! But not covered in this lab.
td.filter(regex=regexMatchingColumnsToMakeTheGifWith).hist()
Everything is almost ready to start making our gifmap!
Lets just get the minimum and maximum values so that our color ramp will have consistent values on each picture.
mins = []
maxs = []
for col in td.filter(regex=regexMatchingColumnsToMakeTheGifWith).columns:
mins.append(td[col].min())
maxs.append(td[col].max())
print(mins, maxs)
# set the min and max range for the choropleth map
vmin, vmax = min(mins), max(maxs)
print('Smallest Value: ', vmin, ', Max Value:', vmax)
merged = td.copy()
for indx, col in enumerate(merged.filter(regex="hhchpov").columns):
print('INDEX', indx)
print('Col: '+str(col) )
image_name = col+'.jpg'
fileNames.append(image_name)
# create map, UDPATE: added plt.Normalize to keep the legend range the same for all maps
fig = merged.plot(column=col, cmap='Blues', figsize=(10,10),
linewidth=0.8, edgecolor='0.8', vmin=vmin, vmax=vmax,
legend=True, norm=plt.Normalize(vmin=vmin, vmax=vmax)
)
# https://stackoverflow.com/questions/38899190/geopandas-label-polygons
if labelBounds:
labelColumn = col
if specialLabelCol: labelColumn = specialLabelCol
merged.apply(lambda x: fig.annotate(s=x[labelColumn], xy=x.geometry.centroid.coords[0], ha='center'),axis=1);
# remove axis off chart and set title
fig.axis('off')
fig.set_title(str(col.replace("hhchpov", "Houshold Childhood Poverty 20")), fontdict={'fontsize': fontsize, 'fontweight' : '3'})
# create an annotation for the data source
fig.annotate(annotation,
xy=(0.1, .08), xycoords='figure fraction',
horizontalalignment='left', verticalalignment='top',
fontsize=10, color='#555555')
# this will save the figure as a high-res png in the output path. you can also save as svg if you prefer.
# filepath = os.path.join(output_path, image_name)
chart = fig.get_figure()
# fig.savefig(“map_export.png”, dpi=300)
chart.savefig(image_name, dpi=300)
plt.close(chart)
images = []
for filename in fileNames:
images.append(imageio.imread(filename))
imageio.mimsave(saveGifAs, images, fps=.5)
# This will print out a picture of each picture in the gifmap.
from PIL import Image
import requests
from io import BytesIO
for filename in fileNames:
img = Image.open(filename)
size = 328, 328
img.thumbnail(size, Image.ANTIALIAS)
img
# Change these values in the cell below using different geographic reference codes will change those parameters
# Group By Crosswalked column. Included automatically in final result
# Do Not Group, Include the Crosswalked Column in the final result
# Create the trav45 Indicator
state = '24'
county = '510'
tract = '*'
# Specify the download parameters the acs download function will receieve here
year = '19'
years = ['17', '16', '15']
tableId = 'B08303'
saveAcs = True
# Crosswalk Table
cwUrl = 'CSA-to-Tract-2010.csv'
cw_left_col = 'tract'
cw_right_col= 'TRACTCE10'
merge_how= 'CSA2010'
saveCrosswalked = True
crosswalkedFileName = False
groupBy = False # 'CSA2010'
aggMethod = 'sum'
columnsToInclude = ['CSA2010']
finalFileName = './trav45_20'+year+'_tracts_26July2019.csv'
# Alternatively - groupBy = False & columnsToInclude = ['CSA2010']
# This lower half is to merge to the geom
from dataplay import merge
# Secondary Table
right_ds = 'https://services1.arcgis.com/mVFRs7NF4iFitgbY/ArcGIS/rest/services/Hhchpov/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&f=pgeojson'
right_col ='CSA2010'
interactive = True
merge_how = 'outer'
saveGifAs = './test.gif'
labelBounds = False # 'CSA2010'
annotation = 'Source: Baltimore Neighborhood Indicators Alliance'
title = 'Indicator Name'
fontsize='22'
td = finaldf.filter(regex="final|CSA2010|tract|geometry")
td = td.reindex(sorted(td.columns), axis=1)