Closed droumis closed 3 months ago
Couldn't push directly so I pushed to a fork: https://github.com/holoviz-topics/neuro/pull/97
The hover tooltips can be defined like:
hover_tooltips=[
("Channel", "$label"),
("Time", "$x s"),
("Amplitude", "$y µV"),
],
# TODO: add handling for large number of channels - at some threshold it will impact loadable pyramid level
# TODO: profile for latency.. potentially parallel stream rendering?
# TODO: debug why sometimes the plotsize stream doesn't get triggered
X_PADDING = 0.2 # buffer x-range to reduce update latency with pans and zoom-outs
# TODO: use custom hv hovertool when holoviews is released.
def rescale(x_range, y_range, width, scale, height):
# Handle edge case when streams are initialized
if x_range is None:
x_range = time_da.min().item(), time_da.max().item()
if y_range is None:
y_range = 0, num_channels
# define time range slice
x_padding = (x_range[1] - x_range[0]) * X_PADDING
time_slice = slice(x_range[0] - x_padding, x_range[1] + x_padding)
channel_slice = slice(y_range[0], y_range[1])
# calculate the appropriate pyramid level and size
if width is None or height is None:
pyramid_level = num_levels - 1
size = time_da.size
else:
sizes = np.array(
[
_extract_ds(ts_dt, pyramid_level)["time"].sel(time=time_slice).size
for pyramid_level in range(num_levels)
]
)
# pyramid_level = np.argmin(np.where(diffs >= 0, diffs, np.inf)) # nearest higher-resolution level
pyramid_level = np.argmin(
np.abs(np.array(sizes) - width)
) # nearest, regardless of direction
size = sizes[pyramid_level]
title = (
f"[Pyramid Level {pyramid_level} ({x_range[0]:.2f}s - {x_range[1]:.2f}s)] "
f"[Time Samples: {size}] [Plot Size WxH: {width}x{height}]"
)
# extract new data and re-paint the plot
ds = _extract_ds(ts_dt, pyramid_level, channels).sel(time=time_slice).load()
df = ds.to_dataframe()
curves = hv.Overlay(kdims="Channel")
for channel in channels:
curves *= hv.Curve(
df.loc[channel], ["time"], ["data"], label=str(channel)
).opts(
color="black",
line_width=1,
subcoordinate_y=True,
subcoordinate_scale=2,
default_tools=["pan", "reset", "wheel_zoom", "box_zoom", WheelZoomTool()],
hover_tooltips=[
("Channel", "$label"),
("Time", "$x s"),
("Amplitude", "$y µV"),
],
)
curves = curves.opts(
xlabel="Time (s)",
ylabel="Channel",
title=title,
show_legend=False,
padding=0,
aspect=1.5,
responsive=True,
framewise=True,
axiswise=True,
)
return curves
range_stream = hv.streams.RangeXY()
size_stream = hv.streams.PlotSize()
pn.serve(hv.DynamicMap(rescale, streams=[size_stream, range_stream]))
I installed the environment at workflows/multi_channel_timeseries/environment.yml
and ran the notebooks in this folder.
small_multi-chan-ts.ipynb
Got this error:
ValueError: Unexpected option 'hover_tooltips' for Curve type across all extensions. Similar options for current extension ('bokeh') are: ['hover_alpha', 'hover_color', 'hover_line_cap'].
The notebook runs fine when commenting out hover_tooltips
, I guess it just needs a dev release of HoloViews.
medium_multi-chan-ts.ipynb
I got ModuleNotFoundError: No module named 'wget'
, fixed by manually downloading the file and putting it in ./data
.
Also got the hover_tooltips
error. Then got KeyError: 'minmax-lttb'
, got it working replacing with lttb
, but newer version of HoloViews would have worked too.
large_multi-chan-ts.ipynb
Worked first try! Just got this warning when plotting the minimap:
WARNING:param.Image00868: Image dimension Time is not evenly sampled to relative tolerance of 0.001. Please use the QuadMesh element for irregularly sampled data or set a higher tolerance on hv.config.image_rtol or the rtol parameter in the Image constructor.
time_range_annotation.ipynb
Doesn't look like this notebook is meant to be shared, it fails as it has no imports.
Thanks @maximlt !!
Replacing Image with QuadMesh seems to work so I'll just go with that.
merging progress now.. will clean up in another PR
I'll probably abandon the cards on the index page because bugs in Panel