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

Small formatting changes and cleanups. #16

Merged
merged 6 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
12 changes: 7 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ repos:
rev: 22.8.0
hooks:
- id: black
args: [--line-length=79]
nwatters01 marked this conversation as resolved.
Show resolved Hide resolved
exclude: ^docs/
- repo: https://github.com/pycqa/isort
rev: 5.13.1
hooks:
- id: isort
name: isort (python)
- repo: https://github.com/pycqa/isort
rev: 5.13.1
hooks:
- id: isort
name: isort (python)
args: [--profile=black, --line-length=79]
nwatters01 marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
neuroconv==0.4.7
neuroconv==0.4.6
spikeinterface==0.99.1
nwbwidgets==0.11.3
nwbinspector==0.4.31
Expand Down
23 changes: 18 additions & 5 deletions src/jazayeri_lab_to_nwb/watters/display_interface.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
"""Class for converting data about display frames."""

import itertools
import json
from pathlib import Path
from typing import Optional

import numpy as np
import pandas as pd
from neuroconv.datainterfaces.text.timeintervalsinterface import TimeIntervalsInterface
from neuroconv.datainterfaces.text.timeintervalsinterface import (
TimeIntervalsInterface,
)
from neuroconv.utils import FolderPathType
from pynwb import NWBFile

Expand Down Expand Up @@ -40,7 +43,9 @@ def get_metadata(self) -> dict:
return metadata

def get_timestamps(self) -> np.ndarray:
return super(DisplayInterface, self).get_timestamps(column="start_time")
return super(DisplayInterface, self).get_timestamps(
column="start_time"
)

def set_aligned_starting_time(self, aligned_starting_time: float) -> None:
self.dataframe.start_time += aligned_starting_time
Expand All @@ -49,15 +54,23 @@ def _read_file(self, file_path: FolderPathType):
# Create dataframe with data for each frame
trials = json.load(open(Path(file_path) / "trials.json", "r"))
frames = {
k_mapped: list(itertools.chain(*[d[k] for d in trials])) for k, k_mapped in DisplayInterface.KEY_MAP.items()
k_mapped: list(itertools.chain(*[d[k] for d in trials]))
for k, k_mapped in DisplayInterface.KEY_MAP.items()
}

# Serialize object_positions data for hdf5 conversion to work
frames["object_positions"] = [json.dumps(x) for x in frames["object_positions"]]
frames["object_positions"] = [
json.dumps(x) for x in frames["object_positions"]
]

return pd.DataFrame(frames)

def add_to_nwbfile(self, nwbfile: NWBFile, metadata: Optional[dict] = None, tag: str = "display"):
def add_to_nwbfile(
self,
nwbfile: NWBFile,
metadata: Optional[dict] = None,
tag: str = "display",
):
return super(DisplayInterface, self).add_to_nwbfile(
nwbfile=nwbfile,
metadata=metadata,
Expand Down
23 changes: 17 additions & 6 deletions src/jazayeri_lab_to_nwb/watters/get_session_paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,39 @@ def _get_session_paths_openmind(subject, session):
subject_id = SUBJECT_NAME_TO_ID[subject]

# Path to write output nwb files to
output_path = f"/om/user/nwatters/nwb_data_multi_prediction/staging/sub-{subject}"
output_path = (
f"/om/user/nwatters/nwb_data_multi_prediction/staging/sub-{subject}"
)

# Path to the raw data. This is used for reading raw physiology data.
raw_data_path = f"/om4/group/jazlab/nwatters/multi_prediction/phys_data/{subject}/" f"{session}/raw_data"
raw_data_path = (
f"/om4/group/jazlab/nwatters/multi_prediction/phys_data/{subject}/"
f"{session}/raw_data"
)

# Path to task and behavior data.
task_behavior_data_path = (
"/om4/group/jazlab/nwatters/multi_prediction/datasets/data_nwb_trials/" f"{subject}/{session}"
"/om4/group/jazlab/nwatters/multi_prediction/datasets/data_nwb_trials/"
f"{subject}/{session}"
)

# Path to open-source data. This is used for reading behavior and task data.
data_open_source_path = (
"/om4/group/jazlab/nwatters/multi_prediction/datasets/data_open_source/" f"Subjects/{subject_id}/{session}/001"
"/om4/group/jazlab/nwatters/multi_prediction/datasets/data_open_source/"
f"Subjects/{subject_id}/{session}/001"
)

# Path to sync pulses. This is used for reading timescale transformations
# between physiology and mworks data streams.
sync_pulses_path = "/om4/group/jazlab/nwatters/multi_prediction/data_processed/" f"{subject}/{session}/sync_pulses"
sync_pulses_path = (
"/om4/group/jazlab/nwatters/multi_prediction/data_processed/"
f"{subject}/{session}/sync_pulses"
)

# Path to spike sorting. This is used for reading spike sorted data.
spike_sorting_raw_path = (
f"/om4/group/jazlab/nwatters/multi_prediction/phys_data/{subject}/" f"{session}/spike_sorting"
f"/om4/group/jazlab/nwatters/multi_prediction/phys_data/{subject}/"
f"{session}/spike_sorting"
)

session_paths = SessionPaths(
Expand Down
83 changes: 60 additions & 23 deletions src/jazayeri_lab_to_nwb/watters/main_convert_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
See comments below for descriptions of these variables.
"""

import datetime
import glob
import json
import logging
Expand Down Expand Up @@ -89,25 +88,38 @@ def _add_v_probe_data(

# Raw data
recording_file = _get_single_file(probe_data_dir, suffix=".dat")
metadata_path = str(session_paths.data_open_source / "probes.metadata.json")
metadata_path = str(
session_paths.data_open_source / "probes.metadata.json"
)
raw_source_data[f"RecordingVP{probe_num}"] = dict(
file_path=recording_file,
probe_metadata_file=metadata_path,
probe_key=f"probe{(probe_num + 1):02d}",
probe_name=f"vprobe{probe_num}",
es_key=f"ElectricalSeriesVP{probe_num}",
)
raw_conversion_options[f"RecordingVP{probe_num}"] = dict(stub_test=stub_test)
raw_conversion_options[f"RecordingVP{probe_num}"] = dict(
stub_test=stub_test
)

# Processed data
sorting_path = session_paths.spike_sorting_raw / f"v_probe_{probe_num}" / "ks_3_output_pre_v6_curated"
processed_source_data[f"RecordingVP{probe_num}"] = raw_source_data[f"RecordingVP{probe_num}"]
sorting_path = (
session_paths.spike_sorting_raw
/ f"v_probe_{probe_num}"
/ "ks_3_output_pre_v6_curated"
)
processed_source_data[f"RecordingVP{probe_num}"] = raw_source_data[
f"RecordingVP{probe_num}"
]
processed_source_data[f"SortingVP{probe_num}"] = dict(
folder_path=str(sorting_path),
keep_good_only=False,
folder_path=str(sorting_path), keep_good_only=False
)
processed_conversion_options[f"RecordingVP{probe_num}"] = dict(
stub_test=stub_test, write_electrical_series=False
)
processed_conversion_options[f"SortingVP{probe_num}"] = dict(
stub_test=stub_test, write_as="processing"
)
processed_conversion_options[f"RecordingVP{probe_num}"] = dict(stub_test=stub_test, write_electrical_series=False)
processed_conversion_options[f"SortingVP{probe_num}"] = dict(stub_test=stub_test, write_as="processing")


def _add_spikeglx_data(
Expand All @@ -122,7 +134,11 @@ def _add_spikeglx_data(
logging.info("Adding SpikeGLX data")

# Raw data
spikeglx_dir = [x for x in (session_paths.raw_data / "spikeglx").iterdir() if "settling" not in str(x)]
spikeglx_dir = [
x
for x in (session_paths.raw_data / "spikeglx").iterdir()
if "settling" not in str(x)
]
if len(spikeglx_dir) == 0:
logging.info("Found no SpikeGLX data")
elif len(spikeglx_dir) == 1:
Expand All @@ -146,11 +162,17 @@ def _add_spikeglx_data(
folder_path=str(sorting_path),
keep_good_only=False,
)
processed_conversion_options["SortingNP"] = dict(stub_test=stub_test, write_as="processing")
processed_conversion_options["SortingNP"] = dict(
stub_test=stub_test, write_as="processing"
)


def session_to_nwb(
subject: str, session: str, stub_test: bool = False, overwrite: bool = True, dandiset_id: Union[str, None] = None
subject: str,
session: str,
stub_test: bool = False,
overwrite: bool = True,
dandiset_id: Union[str, None] = None,
):
"""
Convert a single session to an NWB file.
Expand Down Expand Up @@ -190,7 +212,9 @@ def session_to_nwb(
logging.info(f"dandiset_id = {dandiset_id}")

# Get paths
session_paths = get_session_paths.get_session_paths(subject, session, repo=_REPO)
session_paths = get_session_paths.get_session_paths(
subject, session, repo=_REPO
)
logging.info(f"session_paths: {session_paths}")

# Get paths for nwb files to write
Expand All @@ -199,8 +223,13 @@ def session_to_nwb(
session_id = f"{session}-stub"
else:
session_id = f"{session}"
raw_nwb_path = session_paths.output / f"sub-{subject}_ses-{session_id}_ecephys.nwb"
processed_nwb_path = session_paths.output / f"sub-{subject}_ses-{session_id}_behavior+ecephys.nwb"
raw_nwb_path = (
session_paths.output / f"sub-{subject}_ses-{session_id}_ecephys.nwb"
)
processed_nwb_path = (
session_paths.output
/ f"sub-{subject}_ses-{session_id}_behavior+ecephys.nwb"
)
logging.info(f"raw_nwb_path = {raw_nwb_path}")
logging.info(f"processed_nwb_path = {processed_nwb_path}")
logging.info("")
Expand Down Expand Up @@ -247,12 +276,16 @@ def session_to_nwb(

# Add trials data
logging.info("Adding trials data")
processed_source_data["Trials"] = dict(folder_path=str(session_paths.task_behavior_data))
processed_source_data["Trials"] = dict(
folder_path=str(session_paths.task_behavior_data)
)
processed_conversion_options["Trials"] = dict()

# Add display data
logging.info("Adding display data")
processed_source_data["Display"] = dict(folder_path=str(session_paths.task_behavior_data))
processed_source_data["Display"] = dict(
folder_path=str(session_paths.task_behavior_data)
)
processed_conversion_options["Display"] = dict()

# Create processed data converter
Expand All @@ -269,10 +302,14 @@ def session_to_nwb(
metadata["Subject"]["age"] = _SUBJECT_TO_AGE[subject]

# EcePhys
probe_metadata_file = session_paths.data_open_source / "probes.metadata.json"
probe_metadata_file = (
session_paths.data_open_source / "probes.metadata.json"
)
with open(probe_metadata_file, "r") as f:
probe_metadata = json.load(f)
neuropixel_metadata = [x for x in probe_metadata if x["probe_type"] == "Neuropixels"][0]
neuropixel_metadata = [
x for x in probe_metadata if x["probe_type"] == "Neuropixels"
][0]
for entry in metadata["Ecephys"]["ElectrodeGroup"]:
if entry["device"] == "Neuropixel-Imec":
# TODO: uncomment when fixed in pynwb
Expand All @@ -291,10 +328,10 @@ def session_to_nwb(

# Check if session_start_time was found/set
if "session_start_time" not in metadata["NWBFile"]:
raise ValueError("Session start time was not auto-detected. Please provide it " "in `metadata.yaml`")
session_start_time = metadata["NWBFile"]["session_start_time"]
metadata["NWBFile"]["session_start_time"] = session_start_time.replace(
tzinfo=ZoneInfo("US/Eastern"))
raise ValueError(
"Session start time was not auto-detected. Please provide it "
"in `metadata.yaml`"
)

# Run conversion
logging.info("Running processed conversion")
Expand Down
Loading