Skip to content

Commit

Permalink
adding NWB loading support
Browse files Browse the repository at this point in the history
  • Loading branch information
carsen-stringer committed Jul 28, 2023
1 parent f70fcc9 commit ef893ef
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 11 deletions.
16 changes: 9 additions & 7 deletions rastermap/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,15 @@ def dropEvent(self, event):
file = files[0]
file0, ext = os.path.splitext(file)
proc_file = file0 + "_embedding.npy"
if ext == ".npy" or ext == ".mat" or ext==".npz":
if ext == ".npy" or ext == ".mat" or ext==".npz" or ext==".nwb":
if file[-14:] == "_embedding.npy":
io.load_proc(self, name=files[0])
elif os.path.exists(proc_file):
io.load_proc(self, name=proc_file)
else:
io.load_mat(self, name=files[0])
else:
print("ERROR: must drag and drop *.npy, *.npz, or *.mat files")
print("ERROR: must drag and drop *.npy, *.npz, *.nwb or *.mat files")

def plane_window(self):
self.PlaneWindow = views.PlaneWindow(self)
Expand Down Expand Up @@ -598,37 +598,39 @@ def plot_neuron_pos(self, init=False, roi_id=None):
self.update_status_bar("ERROR: please upload neuron position data")

def plot_scatter(self, x, y, roi_id=None, iplane=0):
subsample = 1
subsample = max(1, int(len(x)/5000))
n_pts = len(x) // subsample
marker_size = int(3 * max(1, 800 / n_pts))
if self.all_neurons_checkBox.isChecked() and roi_id is None:
colors = colormaps.gist_ncar[np.linspace(
0, 254, len(x)).astype("int")][self.sorting]
brushes = [pg.mkBrush(color=c) for c in colors[::subsample]]
self.scatter_plots[iplane][0].setData(x[::subsample], y[::subsample],
symbol="o", size=3,
symbol="o", size=marker_size,
brush=brushes,
hoverable=True)
for i in range(1, nclust_max + 1):
self.scatter_plots[iplane][i].setData([], [])
else:
if roi_id is None:
self.scatter_plots[iplane][0].setData(
x, y, symbol="o", size=3,
x, y, symbol="o", size=marker_size,
brush=pg.mkBrush(color=(180, 180, 180)),
hoverable=True)
for roi_id in range(nclust_max):
if roi_id < len(self.cluster_rois):
selected = self.neurons_selected(self.cluster_slices[roi_id])
self.scatter_plots[iplane][roi_id + 1].setData(
x[selected][::subsample], y[selected][::subsample],
symbol="o", size=3,
symbol="o", size=marker_size,
brush=pg.mkBrush(color=self.colors[roi_id][:3]),
hoverable=True)
else:
self.scatter_plots[iplane][roi_id + 1].setData([], [])
else:
selected = self.neurons_selected(self.cluster_slices[roi_id])
self.scatter_plots[iplane][roi_id + 1].setData(
x[selected], y[selected], symbol="o", size=3,
x[selected], y[selected], symbol="o", size=marker_size,
brush=pg.mkBrush(color=self.colors[roi_id][:3]), hoverable=True)


Expand Down
29 changes: 25 additions & 4 deletions rastermap/gui/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
import numpy as np
from qtpy import QtGui, QtCore, QtWidgets
from qtpy.QtWidgets import QFileDialog, QMainWindow, QApplication, QWidget, QScrollBar, QSlider, QComboBox, QGridLayout, QPushButton, QFrame, QCheckBox, QLabel, QProgressBar, QLineEdit, QMessageBox, QGroupBox
from qtpy.QtWidgets import QFileDialog, QInputDialog, QMainWindow, QApplication, QWidget, QScrollBar, QSlider, QComboBox, QGridLayout, QPushButton, QFrame, QCheckBox, QLabel, QProgressBar, QLineEdit, QMessageBox, QGroupBox
import pyqtgraph as pg
from scipy.stats import zscore
import scipy.io as sio
Expand Down Expand Up @@ -64,8 +64,8 @@ def load_mat(parent, name=None):
"""
if name is None:
name = QFileDialog.getOpenFileName(parent, "Open *.npy or *.mat",
filter="*.npy *.npz *.mat")
name = QFileDialog.getOpenFileName(parent, "Open *.npy, *.npz, *.nwb or *.mat",
filter="*.npy *.npz *.mat *.nwb")
parent.fname = name[0]
parent.filebase = name[0]
else:
Expand All @@ -74,7 +74,28 @@ def load_mat(parent, name=None):

X, Usv, Vsv, xy = load_activity(parent.fname)
_load_activity_gui(parent, X, Usv, Vsv, xy)


#def load_dandiset(parent, name=None):
# try:
# import fsspec
# import dandi
# import pynwb
# import aiohttp
# except:
# raise ImportError("fsspec, dandi, pynwb, and/or aiohttp not installed, please 'pip install fsspec dandi pynwb aiohttp'")
# if name is None:
# name, ok = QInputDialog().getText(parent, "QInputDialog().getText()",
# "Dandiset ID:", QLineEdit.Normal)
# if not (name and ok):
# raise ValueError("not input by user")
#
# fs = fsspec.filesystem("http")

#X, Usv, Vsv, xy = load_activity(parent.fname)
#_load_activity_gui(parent, X, Usv, Vsv, xy)



def _load_sp(parent):
if parent.n_samples < 100:
smooth = 1
Expand Down
74 changes: 74 additions & 0 deletions rastermap/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ def load_activity(filename):
dat = np.load(filename, allow_pickle=True)
keys = dat.files
X, Usv, Vsv, xy = _load_dict(dat, keys)
elif ext == ".nwb":
X, xy = _load_nwb(filename)
else:
raise Exception("Invalid file type")

Expand Down Expand Up @@ -147,6 +149,78 @@ def load_activity(filename):

return X, Usv, Vsv, xy


def _cell_center(voxel_mask):
x = np.median(np.array([v[0] for v in voxel_mask]))
y = np.median(np.array([v[1] for v in voxel_mask]))
return np.array([x, y])

def _load_nwb(filename):
try:
from pynwb import NWBHDF5IO, NWBFile, TimeSeries
from pynwb.ophys import (
DfOverF,
Fluorescence ,
RoiResponseSeries
)
except:
raise ImportError("pynwb not installed, please pip install pynwb")
""" load ophys data from nwb"""
with NWBHDF5IO(filename, "r") as io:
read_nwbfile = io.read()

# load neural activity
X = [x for x in read_nwbfile.objects.values() if isinstance(x, Fluorescence)]
names = [x.name for x in read_nwbfile.objects.values() if isinstance(x, Fluorescence)]
if len(X) == 0:
X = [x for x in read_nwbfile.objects.values() if isinstance(x, DfOverF)]
names = [x.name for x in read_nwbfile.objects.values() if isinstance(x, DfOverF)]
if len(X) == 0:
X = [x for x in read_nwbfile.objects.values() if isinstance(x, RoiResponseSeries)]
names = [x.name for x in read_nwbfile.objects.values() if isinstance(x, RoiResponseSeries)]


if len(X) > 0:
if len(X) == 3 and "Deconvolved" in names:
X = X[names.index("Deconvolved")]
elif len(X) > 1:
# todo: allow user to select series
print(f"more than one series to choose from, taking first series {names[0]}")
X = X[0]
elif len(X) == 1:
X = X[0]

planes = list(X.roi_response_series.keys())

spks = np.concatenate(([X[plane].data[:] for plane in planes]),
axis=1).T
spks = spks.astype("float32")
ids = np.concatenate(([X[plane].rois.data[:] for plane in planes]),
axis=0)

if hasattr(X[planes[0]].rois[0], "image_mask"):
roikey = "image_mask"
elif hasattr(X[planes[0]].rois[0], "voxel_mask"):
roikey = "voxel_mask"
else:
roikey = None

if roikey is not None:
xy = np.concatenate([np.array([_cell_center(roi[roikey].values[0])
for roi in X[plane].rois])
for plane in planes])
else:
voxel_masks = np.concatenate([np.array([roi
for roi in X[plane].rois])
for plane in planes])
xy = np.stack([_cell_center(vm[0][0]) for vm in voxel_masks],
axis=0)
else:
raise ValueError("not an ophys NWB file with a Fluorescence or DfOverF roi_response_series")

return spks, xy


def _load_iscell(filename):
basename = os.path.split(filename)[0]
try:
Expand Down

0 comments on commit ef893ef

Please sign in to comment.