My initial thinking was
points.streams = [...]
But streams is a constant param; so I tried with param.edit_constant()
… but the stream didn’t update.
Then I asked an LLM:
“”"
Yes, you can add HoloViews streams to a plot after the fact, but with limitations. Streams are typically meant to be attached at the time of element or DynamicMap creation. However, if you’re working with a DynamicMap
, you can replace it with a new one that has streams attached.
Here’s a practical workaround:
1. Original plot:
import holoviews as hv
from holoviews import streams
hv.extension('bokeh')
def plot_fn(x=0, y=0):
return hv.Points([(x, y)])
dmap = hv.DynamicMap(plot_fn)
2. Add a stream after the fact:
# Define a stream
pointer = streams.PointerXY(x=1, y=1)
# Create a new DynamicMap that uses the stream
dmap_with_stream = hv.DynamicMap(plot_fn, streams=[pointer])
You can’t mutate dmap
to attach the stream directly, but you can construct a new DynamicMap reusing the same callable and attaching the stream.
Notes:
- Some operations (like overlays or layouts) preserve streams when combining elements.
- If you need the stream to act on an existing composite object (e.g.
Layout
,Overlay
), you’ll need to manually propagate it into the components that support it (typicallyDynamicMap
s).
If you have a specific case in mind (e.g. Points, Curve, overlaid plots, or panel interactivity), I can show a tailored example.
“”"
Not very helpful.
I was thinking backwards (stream → plot), and the solution actually is to set the plot as the source of the stream (plot → stream)
import pandas as pd
import holoviews as hv
from holoviews.operation.datashader import rasterize, dynspread
hv.extension("bokeh")
df = pd.DataFrame({
"a": [1, 2, 3],
"b": [4, 5, 6],
"cat": ["x", "y", "z"]
})
points = hv.Dataset(df, ["a", "b"], "cat").to(hv.Points)
points = rasterize(points).opts(tools=["box_select"])
bounds_xy = hv.streams.BoundsXY()
bounds_xy.source = points
The result: