I had a quick play with the latest updates to the folium python package today, generating a few choropleth maps around some of today’s Gov.UK data releases.
The problem I had was that folium generates an interactive Leaflet map as an HTML5 document (eg something like an interactive Google map), but I wanted a static image of it – a png file. So here’s a quick recipe showing how I did that, using a python function to automatically capture a screengrab of the map…
First up, a simple function to get a rough centre for the extent of some boundaries in a geoJSON boundaryfile containing the boundaries for LSOAs in the Isle of Wight:
#GeoJSON from https://github.com/martinjc/UK-GeoJson import json import fiona fi=fiona.open(GEO_JSON) fi.bounds centre_lon, centre_lat=((bounds[0]+bounds[2])/2,(bounds[1]+bounds[3])/2)
Now we can get some data – I’m going to use the average travel time to a GP from today’s Journey times to key services by lower super output area data release and limit it to the Isle of Wight data.
import pandas as pd gp='https://www.gov.uk/government/uploads/system/uploads/attachment_data/file/485260/jts0505.xls' xl=pd.ExcelFile(gp) #xl.sheet_names tname='JTS0505' dbd=xl.parse(tname,skiprows=6) iw=dbd[dbd['LA_Code']=='E06000046']
The next thing to do is generate the map – folium makes this quite easy to do: all I need to do is point to the geoJSON file (geo_path), declare where to find the labels I’m using to identify each shape in that file (key_on), include my pandas dataframe (data), and state which columns include the shape/area identifiers and the values I want to visualise (columns=[ID_COL, VAL_COL]).
import folium m = folium.Map([centre_lat,centre_lon], zoom_start=11) m.choropleth( geo_path='../IWgeodata/lsoa_by_lad/E06000046.json', data=iw, columns=['LSOA_code', 'GPPTt'], key_on='feature.properties.LSOA11CD', fill_color='PuBuGn', fill_opacity=1.0 ) m
The map object is included in the variable m. If I save the map file, I can then use the selenium testing package to open a browser window that displays the map, generate a screen grab of it and save the image, and then close the browser. Note that I found I had to add in a slight delay because the map tiles occasionally took some time to load.
#!pip install selenium import os import time from selenium import webdriver delay=5 #Save the map as an HTML file fn='testmap.html' tmpurl='file://{path}/{mapfile}'.format(path=os.getcwd(),mapfile=fn) m.save(fn) #Open a browser window... browser = webdriver.Firefox() #..that displays the map... browser.get(tmpurl) #Give the map tiles some time to load time.sleep(delay) #Grab the screenshot browser.save_screenshot('map.png') #Close the browser browser.quit()
Here’s the image of the map that was captured:
I can now upload the image to WordPress and include it in an automatically produced blog post:-)
PS before I hit on the Selenium route, I dabbled with a less useful, but perhaps still handy library for taking screenshots: pyscreenshot.
#!pip install pyscreenshot import pyscreenshot as ImageGrab im=ImageGrab.grab(bbox=(157,200,1154,800)) # X1,Y1,X2,Y2 #To grab the whole screen, omit the bbox parameter #im.show() im.save('screenAreGrab.png',format='png')
The downside was I had to find the co-ordinates of the area of the screen I wanted to grab by hand, which I couldn’t find a way of automating… Still, could be handy…