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 (typicallyDynamicMaps).
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:
