magland / sortingview

Web app for viewing results of ephys spike sorting
Apache License 2.0
25 stars 8 forks source link

mark special intervals in timeseries plots: e.g., ripple times #182

Closed magland closed 2 years ago

magland commented 2 years ago

This dataset provided by Eric has ripple times:

https://github.com/scratchrealm/sortingview-dev/blob/main/examples/load_jaq_03_12_data2.py

jsoules commented 2 years ago

Does this require special functionality that makes it distinct from issue #172?

magland commented 2 years ago

@jsoules - you're right - this is a duplicate. I will close this one and add my comment/link to the other one.

magland commented 2 years ago

Actually I decided to keep this one open and closed the other.

jsoules commented 2 years ago

Have been working on this. Testing some things now.

Testing using sha1://2102690caa2db411bc9cca4178270810e5a74f9a/Jaq_03_12_visualization_data2.npy?manifest=c38d157da18611aed00a092a938447a78d8292df for the jaq data with ripple events.

Loaded as per https://github.com/scratchrealm/sortingview-dev/blob/main/examples/load_jaq_03_12_data2.py and https://github.com/magland/sortingview/blob/main/sortingview/SpikeSortingView/create_spike_raster_plot.py to generate a raster plot with highlighted spans. The overall code is as follows:

import numpy as np
import figurl as fig
import kachery_client as kc
from math import ceil, floor

def create_spike_raster_plot_data(*, times: np.array, labels: np.array, label: str):
    unit_ids = np.sort(np.unique(labels))
    plots = []
    for unit_id in unit_ids:
        inds = np.where(labels == unit_id)[0]
        spike_times_sec = times[inds]
        plots.append({
            'unitId': unit_id,
            'spikeTimesSec': spike_times_sec.astype(np.float32)
        })

    data = {
        'type': 'RasterPlot',
        'startTimeSec': np.min(times),
        'endTimeSec': np.max(times),
        'plots': plots
    }
    return data

data_uri = 'sha1://2102690caa2db411bc9cca4178270810e5a74f9a/Jaq_03_12_visualization_data2.npy?manifest=c38d157da18611aed00a092a938447a78d8292df'
fname = kc.load_file(data_uri)
jaq_data = np.load(fname, allow_pickle=True)

spikes = jaq_data[2]
assert spikes['type'] == 'spikes'
spike_times = spikes['spike_times'].astype(np.float32)
cell_ids = spikes['cell_id'].astype(np.int32)

data = create_spike_raster_plot_data(
    times=spike_times,
    labels=cell_ids,
    label='Spikes'
)

# add ripples to data object
ripples = jaq_data[-1]
assert ripples['type'] == 'ripple_times'
np_starts = ripples['start_times'].to_numpy(dtype=np.float32)
np_ends = ripples['end_times'].to_numpy(dtype=np.float32)
assert len(np_starts) == len(np_ends)
for start, end in zip(np_starts, np_ends):
    assert start <= end

data['highlightIntervals'] = [{
    'intervalStarts': np_starts,
    'intervalEnds': np_ends
}]

figure = fig.Figure(
    view_url='http://localhost:3000/',
    data=data
)
print(figure.url(label='SPANS_TEST', channel='flatiron1'))

This yields https://figurl.org/f?v=http://localhost:3000/&d=3efdf652e24633ba8345fb6a02af9d01fc67e5d1&channel=flatiron1&label=SPANS_TEST as of this writing.

EDIT 2/23/22: Updated to ensure that the 'highlightIntervals' key points to a list, as I'd originally intended, not just an object. Regenerated FigURL.

magland commented 2 years ago

I've already merged the PR, but...

There is something off with the highlighted intervals. The location of the highlights changes relative to the spike events as you zoom in/out.

See: https://www.figurl.org/f?v=gs://figurl/spikesortingview-1&d=a5128490421d100de4f469ac[…]e042e2e&channel=flatiron1&label=Jaq_03_12_visualization_data2

jsoules commented 2 years ago

Looks like more is computed at the TimeScrollView level than I realized! That's where the offset for the toolbar (and in the case of the raster plot, the unit labels) is accounted for. So there was a margin alteration that I wasn't realizing.

Submitting a new PR on the same branch that should correct this issue.

In the process, I also discovered that I was painting the highlight bars too far downward in the composite view. This is also fixed.

jsoules commented 2 years ago

Example: Click on the 40-minute mark in https://www.figurl.org/f?v=gs://figurl/spikesortingview-1&d=a5128490421d100de4f469ac%5B%E2%80%A6%5De042e2e&channel=flatiron1&label=Jaq_03_12_visualization_data2 and zoom in. The first interval to the left of the 40-minute mark will move to the right (opposite of the direction it should move for a proper zoom) and eventually pass the 40-minute mark.

This corresponds to a span that begins at second 16799.615 and ends at 16799.732.

This example is now fixed.

jsoules commented 2 years ago

Closed by SpikeSortingView PRs #33 and #34.