Context
I want to plot a map with points on it, and next to it show a scatter plot of a parameter associated with those same points. Additionally I want the scatter plot x-axis range to scale dynamically based on what points are visible on the map.
Example
In this example I have trajectory data, with associated timestamps t
and velocity v
. My goal is to zoom in on part of the trajectory and show the velocity w.r.t. to time of that trajectory segment only. I have managed to show only the points of the zoomed in part of the trajectory, but I can’t get the x-axis (showing time) to update as well. It should show only the timesegment that is associated with the zoomed in points on the map, but it keeps showing the initial timerange.
Here is my example code:
import holoviews as hv
import numpy as np
import pandas as pd
import panel as pn
from holoviews import opts
from holoviews.element.tiles import OSM
from holoviews.util.transform import lon_lat_to_easting_northing
hv.extension("bokeh")
pn.extension()
# Dummy data
df = pd.DataFrame(dict(lat=np.arange(0, 50), lon=np.arange(0, 50), t=np.arange(0, 50), v=np.arange(0, 50)))
df["x"], df["y"] = lon_lat_to_easting_northing(df.lon, df.lat)
def rangefilter(x_range, y_range):
"""Return data within the provided xy-range, or all data if no range is given"""
if x_range is None:
pts = hv.Points(df, kdims=["t", "v"])
else:
selector = df.x.between(x_range[0], x_range[1]) & df.y.between(y_range[0], y_range[1])
pts = hv.Points(df.loc[(selector)], kdims=["t", "v"])
return pts
maptiles = OSM()
mapoverlay = hv.Points(data=df, kdims=["x", "y"])
points = hv.DynamicMap(callback=rangefilter, streams=[hv.streams.RangeXY(source=mapoverlay)])
layout = maptiles * mapoverlay + points
# Attempt 1: plain
dashboard = layout
d1 = pn.Column(
dashboard,
margin=(0, 10, 0, 10),
sizing_mode="stretch_both",
)
d1.servable()
This results in the following when I zoom into the map using the scroll wheel:
The shown points update, by the x-axis range does not.
I’m using the following versions:
python = 3.10.9
jupyterlab = 3.5.3
holoviews = 1.15.4
panel = 0.14.4
bokeh = 2.4.3
What I’ve tried
Here I list all my attempts so far, these lines overwrite the original line in the code. None of these attempt change the outcome.
# Attempt 2: framewise option applied to points
dashboard = layout.opts(opts.Points(framewise=True, axiswise=False))
# Attempt 3: framewise option applied in general
dashboard = layout.opts(framewise=True)
%%opts Points {+framewise} # Attempt 4: adding opts via cell magic
# Attempt 5: adding framewise to DynamicMap directly
points = hv.DynamicMap(callback=rangefilter, streams=[hv.streams.RangeXY(source=mapoverlay)]).opts(
framewise=True
)
# Attempt 6: Set xlim dynamically
dashboard = layout.apply.opts(opts.Points(xlim=points.range("t"), framewise=True))
# Attempt 7: set xlim option on returned points in the rangefilter function
return pts.opts(xlim=pts.range("t"))