I am currently trying to project a dataset (Berlin public transport spots) on to map tiles with the help of datashader and bokeh. To certain extents it worked nicely, while three problems remain:
- when zooming into the data, the pixels remain rather large and are not rearranged - how to do this?
- how to get the projected data semi-transparent to still see the map below?
- the "save"-function of the bokeh toolbar disappeared, as the map tiles were merged. How to get it back?
Thanks for any input!
the (far from perfect) code written:
import numpy as np
import pandas as pd
import geopandas as gp
import datashader as ds
import datashader.transfer_functions as tf
from datashader.utils import export_image
from datashader.utils import lnglat_to_meters as webm
from datashader.colors import Hot
import dask.dataframe as dd
import multiprocessing as mp
from functools import partial
from IPython.core.display import HTML, display
import matplotlib.pyplot as plt
import holoviews as hv
from holoviews.operation.datashader import datashade, dynspread
hv.extension("bokeh", "matplotlib")
from bokeh.io import output_file, output_notebook, show
from bokeh.plotting import figure, show
from holoviews import dim, opts
import geoviews as gv
from colorcet import palette, fire
#get official data of bus/subway stops in Berlin
# -> https://www.vbb.de/media/download/2035
#read data
df = pd.read_csv('UMBW.CSV', engine= 'python', sep=';', usecols=['Y-Koordinate', 'X-Koordinate'])
##some formatting
##replace comma by point
df = df.apply(lambda x: x.str.replace(',','.'))
#delete rows witn NaN -> pandas.DataFrame.dropna
df = df.dropna()
#entries were objects - need to convert to floats
df['X-Koordinate']=pd.to_numeric(df['X-Koordinate'])
df['Y-Koordinate']=pd.to_numeric(df['Y-Koordinate'])
# Project longitude and latitude onto web mercator plane.
df.loc[:, 'easting'], df.loc[:, 'northing'] = webm(df['X-Koordinate'],df['Y-Koordinate'])
# Getting range/box of latitude and longitude for plotting later.
# drop the points lying on the border
y_range_min = df['Y-Koordinate'].quantile(0.01)
y_range_max = df['Y-Koordinate'].quantile(0.99)
x_range_min = df['X-Koordinate'].quantile(0.01)
x_range_max = df['X-Koordinate'].quantile(0.99)
#cornerspots for canvas
sw = webm(x_range_min,y_range_min)#southwest
ne = webm(x_range_max,y_range_max)#northeast
SF = zip(sw, ne)
dask_df = dd.from_pandas(df, npartitions=mp.cpu_count())
dask_df = dask_df.compute()
display(HTML("<style>.container { width:100% !important; }</style>"))
plot_width = int(3600)
plot_height = int(3600)
cvs = ds.Canvas(plot_width, plot_height, *SF)
agg = cvs.points(dask_df, 'easting', 'northing')
#dynamic map tiles -> https://wiki.openstreetmap.org/wiki/Tile_servers
#url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}.png"
url="https://a.tile.openstreetmap.org/{Z}/{X}/{Y}.png"
geomap = gv.WMTS(url)
#manipulate pixelsize for zoom
dynspread.max_px=1
dynspread.threshold=0.1
points = hv.Points(gv.Dataset(dask_df, kdims=['easting', 'northing']))
bvg_stops = dynspread(datashade(points, cmap=Hot).opts(height=640,width=640))
fig = geomap * bvg_stops
hv.save(fig, 'berlin.html', backend='bokeh')
An example output of the initial bokeh plot and a zoomed in version (around the city of Cottbus).