holoviz-topics / neuro

HoloViz+Bokeh for Neuroscience
BSD 3-Clause "New" or "Revised" License
18 stars 5 forks source link

[GOAL] Scale bar #34

Open droumis opened 1 year ago

droumis commented 1 year ago

Summary and Links

scale-bar (lead: @mattpap for Bokeh, @Hoxbro for HoloViews)

Resulting Issues and PRs:

Relevant Workflows

Resources

Requirements

General

Scale Bar Styling

Scale Reference

Interaction with Data

Position

Multiple Subplots and Coordinates

image

https://github.com/holoviz-topics/neuro/assets/6613202/d470ad93-8d81-4e69-8bfe-5f303f51000a

droumis commented 1 year ago

WIP: https://github.com/bokeh/bokeh/pull/13319

jbednar commented 1 year ago

the options should be similar in scope to matplotlib-scalebar.

Agreed. I don't see any support in matplotlib-scalebar for the 2D scale bars needed here (separate scales for x and y axes), so we'd also need those options to be controllable per axis and some options about how the two scale bars interact/intersect.

Control over which data a particular scale bar is linked to when multiple subplots/subcoordinates are on a canvas.

In HoloViews, I think the user experience will be simplest and most powerful overall if the MEG and EEG traces are each an NdOverlay, laid out one above the other as a Layout. That way we could have e.g. an annotation that easily applies only to the MEG traces or only to the EEG traces, and similarly for any of the other convenient HoloViews features. I think items in a HoloViews Layout correspond to separate Bokeh figures (may be misusing terminology here across libraries), so my default preference is for these two groups of curves to be in separate plots, not somehow subsets of the same plot. But see below!

Visibility can be made dynamic in response to interaction. For example, the scale bar might for one group of subplots may disappear when panning beyond their visible range. See video:

Hmm. I'm not sure if this requirement is compatible with my conception above of each group being a separate plot, at least not if we want the behavior in that video. Specifically, panning normally happens either per plot, or (for linked axes), in a concerted manner linking plots to cover the same space. In the video, panning reveals or hides MEG and EEG traces indiscriminately, treating them as the same apart from their different colors and scales. If this mode of interaction is important, then that's an argument for having some sort of hierarchical NdLayout in a single plot, with multiple groups with different options but all on a single pair of axes. On the other hand, this behavior might not even be desirable; it may just be the way it was easy to implement in the original viewer. So we should explicitly decide if we want panning behavior like this.

droumis commented 1 year ago

Below I'm trying to be careful about the word 'subplot', so I distinguish subplots being either on same or separate canvas.

I don't see any support in matplotlib-scalebar for the 2D scale bars needed here (separate scales for x and y axes), so we'd also need those options to be controllable per axis and some options about how the two scale bars interact/intersect.

Good point @jbednar ! I've added relevant parts to the following:

Updates to requirements: ### Scale Reference - [ ] **Size Control**: Ability to specify a reference line size, e.g., "1 um" or "10 uV". And if we need separate scale bars for the x and y axes, they should be independently settable. - [ ] **2D Scale Bars**: Support for separate scale bars for the x and y axes, with the ability to independently configure each axis, including size, unit, precision, and notation. - [ ] **Interaction and Intersection of Scale Bars**: Options to define how the x and y scale bars intersect and interact with each other. For example, users might want them to intersect at a right angle at a specific corner of the plot, or have them without intersection. ### Interaction with Data - [ ] **Zoom Integration**: Scale bar should adjust dynamically based on the zoom level for both x and y axes, maintaining an accurate representation of scale. For example, zooming in on the x-axis might require the x-axis scale bar to adjust, while the y-axis scale bar remains the same.

In HoloViews, I think the user experience will be simplest and most powerful overall if the MEG and EEG traces are each an NdOverlay, laid out one above the other as a Layout. That way we could have e.g. an annotation that easily applies only to the MEG traces or only to the EEG traces, and similarly for any of the other convenient HoloViews features. I think items in a HoloViews Layout correspond to separate Bokeh figures (may be misusing terminology here across libraries), so my default preference is for these two groups of curves to be in separate plots, not somehow subsets of the same plot. But see below!

Yea this is a tricky one. Yesterday I was leaning toward imposing separate plots per data type, but I was just thinking that this will complicate the minimap/rangetool creation and control. We probably don't want one minimap per subplot (separate canvases), right? We'd have to bidirectionally link the x_range of each range tool to each other (maybe not crazy? idk). @Hoxbro do you have any intuition of how feasible it would be for a bidirectional link across two rangetool x_ranges that each have a different target plot?

If, as MNE does (see video below), you have a single minimap for all data types, but you want to have separate subplots (separate canvases) for the different data types.. then I don't see how you could control the y_range of each plot. (A crazy/awkward idea is to allow multiple rangetool overlays on the same minimap with linked x_range but independent y_range while not letting them float into each others vertical minimap area). This is all why I am now leaning towards having all the data types on the same plot but hopefully using some reasonable API approach allowing for differently scaled groups. To be fair, it's not clear to me when something like that will be completed. I'll try to chat with @philippjfr early next week about it.

Video of minimap-panning across data types https://github.com/holoviz-topics/neuro/assets/6613202/3f73a143-4eee-47df-b45e-899472920f65

Hmm. I'm not sure if this requirement is compatible with my conception above of each group being a separate plot, at least not if we want the behavior in that video. Specifically, panning normally happens either per plot, or (for linked axes), in a concerted manner linking plots to cover the same space. In the video, panning reveals or hides MEG and EEG traces indiscriminately, treating them as the same apart from their different colors and scales. If this mode of interaction is important, then that's an argument for having some sort of hierarchical NdLayout in a single plot, with multiple groups with different options but all on a single pair of axes. On the other hand, this behavior might not even be desirable; it may just be the way it was easy to implement in the original viewer. So we should explicitly decide if we want panning behavior like this.

I guess we would not need this dynamic visibility behavior if we had separate subplots (separate canvases) because some of each data type would always be present; the reason to have it disappear is to not have data mismatched scale bar on display. Although having subplots (separate canvases) would solve this, I don't know if it's the right solution given my concerns above.

Sidenote, I think the use/benefits of an NdOverlay container go out the window as soon as we replace our current suboptimal approach (of copying the data and adding an offset value to accommodate the vertical stacking), and instead adopt a better API approach utilizing some form or Bokeh's subplots on the same canvas. Hopefully, the solution will be performant AND and a good API that doesn't involve making a copy of the data in order to plot it.

jbednar commented 1 year ago

We probably don't want one minimap per subplot (separate canvases), right?

Good point; definitely want one minimap. But I'm not sure I follow your concerns about the x_range above; seems like a minimap's selected range can be respected by multiple plots or by a single plot about equally easily. In the other direction, updating the xrange on one of the plots should then update the xrange of the minimap and of the other plot, which again seems doable. But I could easily be missing something.

Also note that the minimap won't always be a heatmap as in these examples; we also want minimaps even when there are just one or a few traces, in which case ideally the minimap will show the traces like in a sparkline, not as a heatmap.

Sidenote, I think the use/benefits of an NdOverlay container go out the window as soon as we replace our current suboptimal approach (of copying the data and adding an offset value to accommodate the vertical stacking), and instead adopt a better API approach utilizing some form or Bokeh's subplots on the same canvas.

I guess I'm getting confused between an NdLayout and an NdOverlay here. It's definitely Nd, but whether it's an overlay or layout is hard to say, because it's both; the traces do overlay each other, but they are offset as in a layout. So I actually don't know what the right abstraction is here.

droumis commented 1 year ago

Continuing the Minimap related converstion here