Skip to content

Commit 0dedae5

Browse files
authored
Merge pull request #1800 from AllenInstitute/rc/2.5.0
rc/2.5.0
2 parents 43c4fa2 + 5415b45 commit 0dedae5

File tree

15 files changed

+127
-76
lines changed

15 files changed

+127
-76
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Change Log
22
All notable changes to this project will be documented in this file.
33

4+
## [2.5.0] = 2021-01-29
5+
- Adds unfiltered running speed as new data stream
6+
- run_demixing gracefully ignores any ROIs that are not in the input trace file
7+
48
## [2.4.1] = 2021-01-04
59
- update deprecated call to scipy.spatial.transform.Rotation.as_dcm() to .as_matrix()
610

allensdk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838

3939

40-
__version__ = '2.4.1'
40+
__version__ = '2.5.0'
4141

4242

4343
try:

allensdk/brain_observatory/behavior/behavior_ophys_session.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,11 +516,11 @@ def _get_roi_masks_by_cell_roi_id(self, cell_roi_ids=None):
516516
table.set_index("cell_roi_id", inplace=True)
517517
table = table.loc[cell_roi_ids, :]
518518

519-
full_image_shape = table.iloc[0]["image_mask"].shape
519+
full_image_shape = table.iloc[0]["roi_mask"].shape
520520

521521
output = np.zeros((len(cell_roi_ids), full_image_shape[0], full_image_shape[1]), dtype=np.uint8)
522522
for ii, (_, row) in enumerate(table.iterrows()):
523-
output[ii, :, :] = _translate_roi_mask(row["image_mask"], int(row["y"]), int(row["x"]))
523+
output[ii, :, :] = _translate_roi_mask(row["roi_mask"], int(row["y"]), int(row["x"]))
524524

525525
# Pixel spacing and units of mask image will match either the
526526
# max or avg projection image of 2P movie.

allensdk/brain_observatory/behavior/session_apis/abcs/behavior_base.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,14 @@ def get_rewards(self) -> pd.DataFrame:
4444
raise NotImplementedError()
4545

4646
@abc.abstractmethod
47-
def get_running_data_df(self) -> pd.DataFrame:
47+
def get_running_data_df(self, lowpass=True) -> pd.DataFrame:
4848
"""Get running speed data.
4949
50+
Parameters
51+
----------
52+
lowpass: bool
53+
Whether to return running speed with low pass filter applied or without
54+
5055
Returns
5156
-------
5257
pd.DataFrame

allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ def save(self, session_object):
6161
# Add running data to NWB in-memory object:
6262
unit_dict = {'v_sig': 'V', 'v_in': 'V',
6363
'speed': 'cm/s', 'timestamps': 's', 'dx': 'cm'}
64-
nwb.add_running_data_df_to_nwbfile(nwbfile,
65-
session_object.running_data_df,
66-
unit_dict)
64+
nwb.add_running_data_dfs_to_nwbfile(nwbfile,
65+
session_object.running_data_df,
66+
session_object.raw_running_data_df,
67+
unit_dict)
6768

6869
# Add stimulus template data to NWB in-memory object:
6970
for name, image_data in session_object.stimulus_templates.items():
@@ -148,9 +149,22 @@ def get_ophys_session_id(self) -> int:
148149
def get_eye_tracking(self) -> int:
149150
raise NotImplementedError()
150151

151-
def get_running_data_df(self, **kwargs) -> pd.DataFrame:
152+
def get_running_data_df(self, lowpass=True) -> pd.DataFrame:
153+
"""
154+
Gets the running data df
155+
Parameters
156+
----------
157+
lowpass: bool
158+
Whether to return running speed with or without low pass filter applied
152159
153-
running_speed = self.get_running_speed()
160+
Returns
161+
-------
162+
pd.DataFrame:
163+
Dataframe containing various signals used to compute running
164+
speed, and the filtered or unfiltered speed.
165+
"""
166+
167+
running_speed = self.get_running_speed(lowpass=lowpass)
154168

155169
running_data_df = pd.DataFrame({'speed': running_speed.values},
156170
index=pd.Index(running_speed.timestamps,
@@ -263,6 +277,10 @@ def get_task_parameters(self) -> dict:
263277
def get_cell_specimen_table(self) -> pd.DataFrame:
264278
# NOTE: ROI masks are stored in full frame width and height arrays
265279
df = self.nwbfile.processing['ophys'].data_interfaces['image_segmentation'].plane_segmentations['cell_specimen_table'].to_dataframe()
280+
281+
# Because pynwb stores this field as "image_mask", it is renamed here
282+
df = df.rename(columns={'image_mask': 'roi_mask'})
283+
266284
df.index.rename('cell_roi_id', inplace=True)
267285
df['cell_specimen_id'] = [None if csid == -1 else csid for csid in df['cell_specimen_id'].values]
268286

allensdk/brain_observatory/behavior/session_apis/data_io/ophys_lims_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ def get_raw_cell_specimen_table_dict(self) -> dict:
458458
""".format(ophys_cell_seg_run_id)
459459
initial_cs_table = pd.read_sql(query, self.lims_db.get_connection())
460460
cell_specimen_table = initial_cs_table.rename(
461-
columns={'id': 'cell_roi_id', 'mask_matrix': 'image_mask'})
461+
columns={'id': 'cell_roi_id', 'mask_matrix': 'roi_mask'})
462462
cell_specimen_table.drop(['ophys_experiment_id',
463463
'ophys_cell_segmentation_run_id'],
464464
inplace=True, axis=1)

allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_xforms.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def get_cell_specimen_table(self):
4646
fov_height = self.get_field_of_view_shape()['height']
4747

4848
# Convert cropped ROI masks to uncropped versions
49-
image_mask_list = []
49+
roi_mask_list = []
5050
for cell_roi_id, table_row in cell_specimen_table.iterrows():
5151
# Deserialize roi data into AllenSDK RoiMask object
5252
curr_roi = roi.RoiMask(image_w=fov_width, image_h=fov_height,
@@ -55,10 +55,10 @@ def get_cell_specimen_table(self):
5555
curr_roi.y = table_row['y']
5656
curr_roi.width = table_row['width']
5757
curr_roi.height = table_row['height']
58-
curr_roi.mask = np.array(table_row['image_mask'])
59-
image_mask_list.append(curr_roi.get_mask_plane().astype(np.bool))
58+
curr_roi.mask = np.array(table_row['roi_mask'])
59+
roi_mask_list.append(curr_roi.get_mask_plane().astype(np.bool))
6060

61-
cell_specimen_table['image_mask'] = image_mask_list
61+
cell_specimen_table['roi_mask'] = roi_mask_list
6262
cell_specimen_table = cell_specimen_table[sorted(cell_specimen_table.columns)]
6363

6464
cell_specimen_table.index.rename('cell_roi_id', inplace=True)
@@ -340,7 +340,7 @@ def get_corrected_fluorescence_traces(self):
340340
ophys_timestamps = self.get_ophys_timestamps()
341341

342342
num_trace_timepoints = corrected_fluorescence_traces.shape[1]
343-
assert num_trace_timepoints, ophys_timestamps.shape[0]
343+
assert num_trace_timepoints == ophys_timestamps.shape[0]
344344
df = pd.DataFrame(
345345
{'corrected_fluorescence': list(corrected_fluorescence_traces)},
346346
index=pd.Index(cell_roi_id_list, name='cell_roi_id'))

allensdk/brain_observatory/behavior/write_nwb/_schemas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class CellSpecimenTable(RaisingSchema):
1818
height = Dict(String, Int, required=True)
1919
width = Dict(String, Int, required=True)
2020
mask_image_plane = Dict(String, Int, required=True)
21-
image_mask = Dict(String, List(List(Boolean)), required=True)
21+
roi_mask = Dict(String, List(List(Boolean)), required=True)
2222

2323

2424

allensdk/brain_observatory/nwb/__init__.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -333,37 +333,48 @@ def add_running_speed_to_nwbfile(nwbfile, running_speed, name='speed', unit='cm/
333333
unit=unit
334334
)
335335

336-
running_mod = ProcessingModule('running', 'Running speed processing module')
337-
nwbfile.add_processing_module(running_mod)
336+
if 'running' in nwbfile.processing:
337+
running_mod = nwbfile.processing['running']
338+
else:
339+
running_mod = ProcessingModule('running', 'Running speed processing module')
340+
nwbfile.add_processing_module(running_mod)
338341

339342
running_mod.add_data_interface(running_speed_series)
340343

341344
return nwbfile
342345

343346

344-
def add_running_data_df_to_nwbfile(nwbfile, running_data_df, unit_dict, index_key='timestamps'):
345-
''' Adds running speed data to an NWBFile as timeseries in acquisition and processing
347+
def add_running_data_dfs_to_nwbfile(nwbfile, running_data_df, running_data_df_unfiltered, unit_dict):
348+
"""Adds both unfiltered (raw) and filtered running speed data to an NWBFile as timeseries in acquisition and processing
346349
347350
Parameters
348351
----------
349352
nwbfile : pynwb.NWBFile
350-
File to which runnign speeds will be written
351-
running_speed : pandas.DataFrame
352-
Contains 'speed' and 'times', 'v_in', 'vsig', 'dx'
353-
unit : str, optional
353+
File to which running speeds will be written
354+
running_data_df : pandas.DataFrame
355+
Filtered running data
356+
Contains 'speed', 'v_in', 'vsig', 'dx'
357+
Note that 'v_in', 'vsig', 'dx' are expected to be the same as in running_data_df_unfiltered
358+
running_data_df_unfiltered : pandas.DataFrame
359+
Unfiltered (raw) Running data
360+
Contains 'speed', 'v_in', 'vsig', 'dx'
361+
Note that 'v_in', 'vsig', 'dx' are expected to be the same as in running_data_df
362+
unit_dict : dict, optional
354363
SI units of running speed values
355364
356365
Returns
357366
-------
358367
nwbfile : pynwb.NWBFile
359368
360-
'''
361-
assert running_data_df.index.name == index_key
362-
369+
"""
363370
running_speed = RunningSpeed(timestamps=running_data_df.index.values,
364371
values=running_data_df['speed'].values)
365372

373+
running_speed_unfiltered = RunningSpeed(timestamps=running_data_df_unfiltered.index.values,
374+
values=running_data_df_unfiltered['speed'].values)
375+
366376
add_running_speed_to_nwbfile(nwbfile, running_speed, name='speed', unit=unit_dict['speed'])
377+
add_running_speed_to_nwbfile(nwbfile, running_speed_unfiltered, name='speed_unfiltered', unit=unit_dict['speed'])
367378

368379
running_mod = nwbfile.processing['running']
369380
timestamps_ts = running_mod.get_data_interface('speed').timestamps
@@ -883,9 +894,9 @@ def add_cell_specimen_table(nwbfile: NWBFile,
883894
imaging_plane=imaging_plane)
884895

885896
for col_name in cell_roi_table.columns:
886-
# the columns 'image_mask', 'pixel_mask', and 'voxel_mask' are already defined
897+
# the columns 'roi_mask', 'pixel_mask', and 'voxel_mask' are already defined
887898
# in the nwb.ophys::PlaneSegmentation Object
888-
if col_name not in ['id', 'mask_matrix', 'image_mask', 'pixel_mask', 'voxel_mask']:
899+
if col_name not in ['id', 'mask_matrix', 'roi_mask', 'pixel_mask', 'voxel_mask']:
889900
# This builds the columns with name of column and description of column
890901
# both equal to the column name in the cell_roi_table
891902
plane_segmentation.add_column(col_name,
@@ -895,13 +906,13 @@ def add_cell_specimen_table(nwbfile: NWBFile,
895906
# go through each roi and add it to the plan segmentation object
896907
for cell_roi_id, table_row in cell_roi_table.iterrows():
897908

898-
# NOTE: The 'image_mask' in this cell_roi_table has already been
909+
# NOTE: The 'roi_mask' in this cell_roi_table has already been
899910
# processing by the function from
900911
# allensdk.brain_observatory.behavior.session_apis.data_io.ophys_lims_api
901912
# get_cell_specimen_table() method. As a result, the ROI is stored in
902913
# an array that is the same shape as the FULL field of view of the
903914
# experiment (e.g. 512 x 512).
904-
mask = table_row.pop('image_mask')
915+
mask = table_row.pop('roi_mask')
905916

906917
csid = table_row.pop('cell_specimen_id')
907918
table_row['cell_specimen_id'] = -1 if csid is None else csid

allensdk/brain_observatory/nwb/nwb_api.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,23 @@ def from_path(cls, path, **kwargs):
4545

4646
return cls(path=path, **kwargs)
4747

48-
def get_running_speed(self) -> RunningSpeed:
49-
50-
values = self.nwbfile.modules['running'].get_data_interface('speed').data[:]
51-
timestamps = self.nwbfile.modules['running'].get_data_interface('speed').timestamps[:]
48+
def get_running_speed(self, lowpass=True) -> RunningSpeed:
49+
"""
50+
Gets the running speed
51+
Parameters
52+
----------
53+
lowpass: bool
54+
Whether to return the running speed with lowpass filter applied or without
55+
56+
Returns
57+
-------
58+
RunningSpeed:
59+
The running speed
60+
"""
61+
62+
interface_name = 'speed' if lowpass else 'speed_unfiltered'
63+
values = self.nwbfile.modules['running'].get_data_interface(interface_name).data[:]
64+
timestamps = self.nwbfile.modules['running'].get_data_interface(interface_name).timestamps[:]
5265

5366
return RunningSpeed(
5467
timestamps=timestamps,

0 commit comments

Comments
 (0)