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

Prototype Behavior Interface #3

Merged
merged 8 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,25 +1,109 @@
"""Primary class for converting experiment-specific behavior."""
from pynwb.file import NWBFile
from pydantic import FilePath
import numpy as np
from h5py import File
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
from hdmf.common.table import DynamicTableRegion
from pynwb.behavior import BehavioralTimeSeries, TimeSeries
from ndx_events import EventTypesTable, EventsTable, Task, TimestampVectorData

from neuroconv.basedatainterface import BaseDataInterface
from neuroconv.utils import DeepDict
from neuroconv.tools import nwb_helpers


class Schneider2024BehaviorInterface(BaseDataInterface):
"""Behavior interface for schneider_2024 conversion"""

keywords = ["behavior"]

def __init__(self):
# This should load the data lazily and prepare variables you need
pass

def __init__(self, file_path: FilePath):
super().__init__(file_path=file_path)

def get_metadata(self) -> DeepDict:
# Automatically retrieve as much metadata as possible from the source files available
metadata = super().get_metadata()
metadata = super().get_metadata()

return metadata

def add_to_nwbfile(self, nwbfile: NWBFile, metadata: dict):
# All the custom code to add the data the nwbfile
# Read Data
file_path = self.source_data["file_path"]
with File(file_path, "r") as file:
behavioral_time_series, name_to_times, name_to_values = [], dict(), dict()
for time_series_dict in metadata["Behavior"]["TimeSeries"]:
name = time_series_dict["name"]
timestamps = np.array(file["continuous"][name]["time"]).squeeze()
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
data = np.array(file["continuous"][name]["value"]).squeeze()
time_series = TimeSeries(
name=name,
timestamps=timestamps,
data=data,
unit="a.u.",
description=time_series_dict["description"],
)
behavioral_time_series.append(time_series)
for event_dict in metadata["Behavior"]["Events"]:
name = event_dict["name"]
times = np.array(file["events"][name]["time"]).squeeze()
name_to_times[name] = times
for event_dict in metadata["Behavior"]["ValuedEvents"]:
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
name = event_dict["name"]
times = np.array(file["events"][name]["time"]).squeeze()
values = np.array(file["events"][name]["value"]).squeeze()
name_to_times[name] = times
name_to_values[name] = values

# Add Data to NWBFile
behavior_module = nwb_helpers.get_module(
nwbfile=nwbfile,
name="behavior",
description="Behavioral data from the experiment.",
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
)

# Add BehavioralTimeSeries
behavioral_time_series = BehavioralTimeSeries(
time_series=behavioral_time_series,
name="behavioral_time_series",
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
)
behavior_module.add(behavioral_time_series)

# Add Events
event_types_table = EventTypesTable(name="event_types", description="Metadata about event types.")
event_type_name_to_row = dict()
i = 0
for event_dict in metadata["Behavior"]["Events"]:
event_type_name_to_row[event_dict["name"]] = i
event_types_table.add_row(
event_name=event_dict["name"],
event_type_description=event_dict["description"],
)
i += 1
for event_dict in metadata["Behavior"]["ValuedEvents"]:
event_type_name_to_row[event_dict["name"]] = i
event_types_table.add_row(
event_name=event_dict["name"],
event_type_description=event_dict["description"],
)
i += 1
events_table = EventsTable(
name="events_table",
description="Metadata about events.",
target_tables={"event_type": event_types_table},
)
events_table.add_column(name="value", description="Value of the event.")
for event_dict in metadata["Behavior"]["Events"]:
event_times = name_to_times[event_dict["name"]]
event_type = event_type_name_to_row[event_dict["name"]]
for event_time in event_times:
events_table.add_row(timestamp=event_time, event_type=event_type, value="")
for event_dict in metadata["Behavior"]["ValuedEvents"]:
event_times = name_to_times[event_dict["name"]]
event_values = name_to_values[event_dict["name"]]
event_type = event_type_name_to_row[event_dict["name"]]
for event_time, event_value in zip(event_times, event_values):
events_table.add_row(timestamp=event_time, event_type=event_type, value=str(event_value))
behavior_module.add(events_table)

raise NotImplementedError()
task = Task(event_types=event_types_table)
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
nwbfile.add_lab_meta_data(task)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def session_to_nwb(data_dir_path: Union[str, Path], output_dir_path: Union[str,
output_dir_path = Path(output_dir_path)
recording_folder_path = data_dir_path / "Raw Ephys" / "m69_2023-10-31_17-24-15_Day1_A1"
sorting_folder_path = data_dir_path / "Processed Ephys" / "m69_2023-10-31_17-24-15_Day1_A1"
behavior_file_path = data_dir_path / "Behavior" / "m69_231031" / "raw_m69_231031_001.mat"
if stub_test:
output_dir_path = output_dir_path / "nwb_stub"
recording_folder_path = recording_folder_path.with_name(recording_folder_path.name + "_stubbed")
Expand All @@ -37,9 +38,9 @@ def session_to_nwb(data_dir_path: Union[str, Path], output_dir_path: Union[str,
source_data.update(dict(Sorting=dict(folder_path=sorting_folder_path)))
conversion_options.update(dict(Sorting=dict()))

# # Add Behavior
# source_data.update(dict(Behavior=dict()))
# conversion_options.update(dict(Behavior=dict()))
# Add Behavior
source_data.update(dict(Behavior=dict(file_path=behavior_file_path)))
conversion_options.update(dict(Behavior=dict()))

converter = Schneider2024NWBConverter(source_data=source_data)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
NWBFile:
keywords:
keywords:
- auditory cortex
- predictive coding
- optogenetics
Expand Down Expand Up @@ -52,4 +52,24 @@ Ecephys:
# - name: ch
# description: The channel label of the best channel, as defined by the user.
# - name: sh
# description: The shank label of the best channel.
# description: The shank label of the best channel.
Behavior:
TimeSeries:
- name: encoder
description: Sampled values for entire duration of experiment for lever pressing/treadmill behavior read from a quadrature encoder.
- name: lick
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
description: Samples values for entire duration of experiment for voltage signal readout from an infrared/capacitive) lickometer sensor.
Events:
- name: target
description: Time at which the target zone is entered during a press.
- name: targetOUT
description: Time at which the target zone is overshot during a press.
- name: toneIN
description: Time at which target entry tone is played.
- name: toneOUT
description: Time at which target exit tone is played.
- name: valve
description: Times at which solenoid valve opens to deliver water after a correct trial.
ValuedEvents:
- name: tuningTones
description: Times at which tuning tones are played to an animal after a behavioral experiment during ephys recording sessions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Notes concerning the schneider_2024 conversion

## Behavior
- opto events is just [0, 1] like empty variables (lick events), and opto_time in 'push' is all NaNs. Where is the actual opto stim times recorded?
- TuningTones has a values field with integers, what does this correspond to?
- 'push' is basically some kind of trials table, but need descriptions for variables ex. ITI_respect?

## Data Requests
- Mice sexes
- Remaining data for Grant's project
- More detailed position info for recording probe
- Subfield of auditory cortex: A1? A2? AAF? etc.
- stereotactic coordinates of the whole probe
-
-
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ class Schneider2024NWBConverter(NWBConverter):
data_interface_classes = dict(
Recording=OpenEphysRecordingInterface,
Sorting=PhySortingInterface,
Behavior=Schneider2024BehaviorInterface,
)
Loading