Vector 2: Interactive plots#

UW Geospatial Data Analysis
CEE467/CEWA567
David Shean

Part 5: Interactive plots#

GeoPandas explore#

#Example for WA GLAS points
#glas_gdf_aea_wa.explore()

Create an interactive map for your states geodataframe with explore defaults#

#Student Exercise

Create an interactive map for your states geodataframe with colors representing GLAS point count#

#Student Exercise

Explore some more!#

  • Below is a helper function that creates a plot for an input geodatframe and the specified column

  • Try for the larger CONUS dataset

  • See how the stride values impact performance

  • Can pass in different xyz tiles as an argument

def plotcol(gdf, col='glas_z', stride=10, tiles=xyz.Esri.WorldImagery):
    #Set colorbar limits to 2-98 percentile
    clim = gdf[col].quantile((0.02, 0.98)).values
    #Create interactive folium plot using GeoPandas explore function
    m = gdf[::stride].explore(tiles=tiles, column=col, cmap='inferno', vmin=clim[0], vmax=clim[1])
    #Return plot, required to display when calling this function
    return m
#plotcol(glas_gdf_aea, col='decyear', stride=100)

Explore at least two other available tiled basemaps#

#List available tiles
#xyz
#Student Exercise
#Student Exercise

ipyleaflet#

ipyleaflet is similar to folium, with some nice interactive “widget” support (useful if you need to update the map or retrieve user input from the map, like clicked points):

Note that leaflet uses tiled basemaps: https://en.wikipedia.org/wiki/Tiled_web_map

Default projection for these tiled basemaps is almost always Web Mercator (EPSG:3857): https://en.wikipedia.org/wiki/Web_Mercator_projection. This works well for lower latitudes, but not the polar regions. QGIS and contextily can reproject tiled basemaps on the fly, but looks like leaflet requires some workarounds (https://kartena.github.io/Proj4Leaflet/)

hvplot#

  • See: https://hvplot.holoviz.org/user_guide/Introduction.html

  • Based on bokeh backend, a nice alternative to matplotlib that is better suited for interactive visualization

  • https://hvplot.holoviz.org/

  • Plugs in with datashader which is designed to render large point datasets efficiently

  • Still relatively new, with multiple parallel efforts holoviews, geoviews, datashader and some bugs, outdated or limited documentation, etc.

# Use the pandas hvplot interface
import hvplot.pandas
#Using `hvplot` instead of `plot` call on our GeoDataFrame
stride=10
#glas_gdf_aea[::stride].hvplot(aspect='equal')

Explore the above plot and tools. Try some interactive zooming, hover over points, etc.#

Add some map tiles#

  • geoviews has some nice tile support

from geoviews import tile_sources as gvts
#map_tiles = gvts.StamenTerrain
map_tiles = gvts.EsriImagery
kw = {'width':500, 'height':400, 'hover':False, 'data_aspect':1, 'alpha':1.0}
kw['colorbar'] = True
kw['cmap'] = 'inferno'

Overlay points on map tiles (subset of points)#

  • To combine layers in a single plot using holoviews, you use the asterisk (*) to overlay the two objects

    • You can use the plus sign (+) to build a layout with two separate subplots

  • Currently need to use the geo=True option and revert back to the glas_gdf GeoDataFrame with lat/lon geometry, not our reprojected points in glas_gdf_aea.

    • In principle, hvplot/geoviews should work with our projected points, but there are some residual issues, and it appears that some underlying code somewhere in the stack is assuming lat/lon

#map_tiles * glas_gdf[::stride].hvplot(geo=True, c='glas_z', title='GLAS Elevation', **kw)

Using DataShader to efficiently render points on the fly#

  • There are still some limitations and bugs in the current datashader support for GeoDataFrame objects, so we will revert to glas_df and specify x and y columns here

  • Zoom in and see how points are re-rendered for each view

#glas_df.hvplot.scatter(x='lon', y='lat', datashade=True, c='glas_z', title='GLAS Elevation', **kw)

folium#

  • We haven’t discussed as a class yet, but this is a simple, effective interactive visualization package (alternative to matplotlib)

  • See the example here: https://python-visualization.github.io/folium/quickstart.html

  • For your plot:

    • Isolate points to WA state for now, convert to EPSG:4326

    • Compute the centroid of the WA state polygon (remember GeoPandas unary_union) in EPSG:4326

    • Create a map object centered on this centroid

      • Use the ‘Stamen Terrain’ basemap layer

      • Experiment with zoom_start level to find a good extent

    • Export your WSG84 GeoDataFrame using to_json(), then load all features using folium.features.GeoJson

    • Add the points to the map

  • Take a moment to explore this interactive map interface.

#Compute WA state centroid in WGS84
#wa_center_wgs84 = list(wa_gdf.to_crs('EPSG:4326').centroid.iloc[0].coords)[0][::-1]
wgs_c = wa_gdf.to_crs('EPSG:4326').unary_union.centroid
wa_center_wgs84 = (wgs_c.y, wgs_c.x)
wa_center_wgs84
#Reproject to WGS84
glas_gdf_wa = glas_gdf_aea_wa.to_crs('EPSG:4326')
#Note: some students reported issues using folium on Chrome browser with many points (n=5265)
#This is one workaround: https://github.com/python-visualization/folium/issues/812#issuecomment-437483792
#Alternatively, reduce number of points, using only every 10th point
#stride=10
stride=1
#import folium
#m = folium.Map(location=wa_center_wgs84, zoom_start=7, tiles='Stamen Terrain')
#folium.features.GeoJson(glas_gdf_wa[::stride].to_json()).add_to(m)
#m

OK, but performance isn’t great with so many points#

from folium.plugins import MarkerCluster
#m = folium.Map(location=wa_center_wgs84, tiles='Stamen Terrain', zoom_start=7)
#Create clustered map with popups
#locations, popups = [], []
#for idx,row in glas_gdf_wa.iterrows():
#    locations.append([row['geometry'].y, row['geometry'].x])
#    popups.append(idx)
#t = folium.FeatureGroup(name='GLAS')
#t.add_child(MarkerCluster(locations=locations, popups=popups))

#m.add_child(t)
#m