Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for sophisticated y-axis information. #39

Merged
merged 1 commit into from
Mar 18, 2022
Merged

Conversation

jsoules
Copy link
Collaborator

@jsoules jsoules commented Mar 11, 2022

This PR implements support for a dynamic y-axis display mechanism. This satisfies SortingView issue #184 (labeling the extrema of the vertical axis in timeseries panels), and lays groundwork for SortingView issue #181 (allowing user-specified y-scale for TimeSeriesView-based visualizations).

It also addresses SpikeSortingView issue #38 (regarding illegible rasterplotview unit IDs) and does a few other housekeeping things (though not enough to satisfy #28 or #32, which will come later).

Features

The y-axis tick marks implement the following features:

  1. Can be turned on or off at the per-view level
  2. Display min/max values of range
  3. Dynamically scale the step size to keep grid line distances to an acceptable pixel distance
  4. Dynamically choose major ticks (defined as those with a 0 in the step size)
  5. Tick labels are displayed in scientific notation when the step size's order of magnitude is greater than 3 or less than -3.
  6. Steps align consistently to the axis zero point, and do not depend on the observed minimum
  7. Labeled ticks can be set to suppress invariant high-order digits from the range, to ensure that heavily zoomed views remain legible

Consider a plot drawn with a vertical span of 250 pixels. Grid lines should be spaced between 26 and 60 pixels apart, so we need an integer number of grid lines in the range [5, 9]. Assume the data values run from 91.117656 to 91.125787; the total range displayed in this plot is .008131 units.

We will scale this range to an integer, then compute step sizes of 1, 2, or 5 units at several scales until we find the first step size that creates grids with appropriate spacing. So, 8131/1, 8131/2, 8131/5, 8131/10, [...20, 50, ...] all yield too many grid lines; eventually we find that a step size of 1000 fits in the appropriate range. Resetting the scale, we should span the range from 91.117656 to 91.125787 with eight steps of size 0.001, resulting in grid lines drawn at 91.118, 91.119, 91.120, ... 91.125. The tick at 91.120 is major (as it has a 0 in the thousandths place); the other lines are minor ticks. The resulting graph will label the extrema exactly, but ticks will be labeled while suppressing the repeated higher-order digits, i.e. as 0.118, 0.119, ... 0.125, to highlight the moving scale. (This last feature may potentially be controversial; it can be toggled off easily in code, or we can later implement a user control if it would be useful in limited circumstances.)

Example:
https://www.figurl.org/f?v=http://localhost:3000&d=7086880aeb347d2b2a1f71e2638f7560b67e678e&channel=flatiron1&label=Jaq_03_12_visualization_data2
image
(Example for 0-based linear position and speed.)

https://www.figurl.org/f?v=http://localhost:3000&d=79f878acca63c2527d2e5d99189852047b5af2c2&channel=flatiron1&label=despereaux20191125_.nwb_02_r1_13_franklab_default_hippocampus
image
(An individual plot, whose range spans the axis 0.)

image
(The same example, dynamically rescaled just by removing unit 7, which has an outlier).

Additionally, I have added code to suppress display of the unit labels for the raster plot when there is not sufficient room to write them legibly (currently defined as having 7.2 pixels of space or more).

Implementation

Main changes:

  • src/views/common/TimeScrollView/YAxisTicks.tsx is new; it defines a hook and several functions for computing the axes, and should probably be reviewed first.
  • src/views/RasterPlot/TimeScrollView/paint.ts has been updated with a significant function for painting the y-axes, modeled on the one that does the time axis. (Open question: these are quite similar; can we come up with an efficient way to reduce the duplicate code between them?)
  • Same file also had some tweaks to the unit label logic. Just to say it explicitly, we're always assuming that labels will be drawn in a TimeSeriesView if they are set--they just generally aren't, except for the RasterPlotView.
  • Same file, rewrote the unit highlight code in a more functional style.

Smaller changes:

  • Modified the SpikeAmplitudesView and PositionPlotView component code so that they take advantage of the y-axis logic and can actually display. (It'd be nice to generalize this so it isn't needed for each component--a revision should probably get passed a function that describes how to get the data range from the component's data and lets the base TimeSeriesView handle axis computation from that point, rather than having the calling classes use a bunch of logic to set the range externally.
  • Hook for setting margins, originally located in the PositionPlotView file, was moved to the TimeSeriesView class and given an optional parameter which allows the user to override defaults for any of the four margins.
  • Had to change the signatures and imports of basically every visualization built off of the TimeSeriesView component to accommodate for having moved the margin-handling hook.
  • TSVAxesLayer.tsx has been modified to accept the y-tick data.
  • TimeSeriesView modified to add some hooks for using transformation matrices to compute the correct position of y-axis labels.

Outstanding:

  • There's a couple testing changes left in this code that should be reverted (just forcing use of the y-axis display, which would otherwise need to be set in the figURL generation like other time series display options).
  • Need to implement data-range-passing in more of the TimeSeriesView-derived components, so that they can use the new feature.
  • Spike Amplitudes display zoom winds up changing the actual displayed range. The grid lines zoom appropriately, but they should actually be redrawn to correctly describe the new range. (Leaving this for now since it looks like it might actually have bigger problems that should be addressed in a separate ticket.)

@magland
Copy link
Owner

magland commented Mar 18, 2022

@jsoules
This looks excellent! I like how you handled all the weird/difficult cases.
I've tested it locally and everything seems good to go.

One small item: I think it's distracting to display the min/max of the range ... I can see the value, but you really never see that in scientific plots. Also sometimes the labels overlap with the tick labels -- like the -450/-454 in the example above. But we can leave that for now.

Merging.

@magland magland merged commit ec7ad2b into main Mar 18, 2022
@jsoules
Copy link
Collaborator Author

jsoules commented Mar 18, 2022

Thanks! Glad you like it.

The range min/max was a specific feature request--SortingView issue #184. I'm also annoyed by the tick label overlap; maybe a solution (if we keep the extrema) would be to suppress tick label display if the tick is less than maybe half a grid span from the range end point? (There's definitely further refinement to be done here)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants