import time
from itertools import cycle
import holoviews as hv
import geoviews as gv
import param
import panel as pn
import dask.dataframe as dd
import pandas as pd
from colorcet import cm_n
from holoviews import opts
from holoviews.operation.datashader import dynspread, rasterize, shade
from holoviews.streams import RangeXY
hv.extension('bokeh')
def taxi_trips_stream(source='../../data/nyc_taxi_wide.parq', frequency='H'):
"""Generate dataframes grouped by given frequency"""
def get_group(resampler, key):
try:
df = resampler.get_group(key)
df.reset_index(drop=True)
except KeyError:
df = pd.DataFrame()
return df
df = pd.read_parquet(source,
columns=['tpep_pickup_datetime', 'pickup_x', 'pickup_y', 'tip_amount'])
df = df.set_index('tpep_pickup_datetime', drop=True)
df = df.sort_index()
r = df.resample(frequency)
chunks = [get_group(r, g) for g in sorted(r.groups)]
indices = cycle(range(len(chunks)))
while True:
yield chunks[next(indices)]
trips = taxi_trips_stream()
example = next(trips)
In this example we will be doing something a bit more complex - building a full app with widgets. Below we have already outlined the basic components of this app, including a NYCTaxiStream
class that takes some data
and turns those into datashaded Points
. You should execute that cell before you change anything about it, so that you are sure it works at the start.
Your task will be to add some custom widgets to this plot by adding parameters to the NYCTaxiStream
class to control the NYCTaxiStream output.
1.) Begin by adding a widget that will allow us to select between the different cmaps available from cm_n.values()
.
param.ObjectSelector(default=..., objects=...)
2.) Now add a parameter that filters the data based on one of the columns in the data, e.g. trips with >N passengers or the minimum tip.
param.ObjectSelector(default=..., objects=...)
tile_options = opts.WMTS(width=600,height=400,xaxis=None,yaxis=None,bgcolor='black',show_grid=False)
class NYCTaxiStream(param.Parameterized):
time = param.Number(default=0, bounds=(0, 24))
def __init__(self, **params):
self.pipe = hv.streams.Pipe(example)
super(NYCTaxiStream, self).__init__(**params)
@param.depends('time', watch=True)
def update(self):
self.pipe.send(next(trips))
def points(self, data):
return hv.Points(data, ['pickup_x', 'pickup_y'], label=str(data.index[0]))
def view(self):
points = hv.DynamicMap(self.points, streams=[self.pipe])
raster = rasterize(points, x_sampling=1, y_sampling=1, width=700, height=400)
tiles = gv.tile_sources.Wikipedia.opts(tile_options)
return (tiles * shade(raster)).opts(show_legend=False)
nyc_stream = NYCTaxiStream()
pn.Column(pn.Param(nyc_stream.param, widgets={'time': pn.widgets.Player}), nyc_stream.view())
class NYCTaxi(param.Parameterized):
cmap = param.ObjectSelector(default=cm_n["fire"], objects=cm_n.values())
minimum_tip = param.Number(default=0, bounds=(0, 20))
time = param.Number(default=0, bounds=(0, 24))
def __init__(self, **params):
self.pipe = hv.streams.Pipe(example)
super(NYCTaxi, self).__init__(**params)
@param.depends('time', watch=True)
def update(self, value):
self.pipe.send(next(trips))
@param.depends('minimum_tip')
def points(self, data):
points = hv.Points(data, ['pickup_x', 'pickup_y'])
if self.minimum_tip:
points = points.select(tip_amount=(self.minimum_tip, None))
return points
def view(self):
points = hv.DynamicMap(self.points, streams=[self.pipe])
raster = rasterize(points, x_sampling=1, y_sampling=1, width=700, height=400)
tiles = gv.tile_sources.Wikipedia.opts(tile_options)
return tiles * shade(raster, streams=[hv.streams.Params(self, ['cmap'])])
</code>
Add .servable()
to the panel and deploy it as a standalone app using panel serve notebook.ipynb