Compare commits

...

11 Commits

Author SHA1 Message Date
wendtalexander
ffc4f9995d [docstring] 2025-10-21 11:56:13 +02:00
wendtalexander
ea9dd555d8 [docstring] 2025-10-21 11:56:07 +02:00
wendtalexander
cd7cd43313 [docstring] 2025-10-21 11:56:01 +02:00
wendtalexander
af98fdc2cb [main] renaming main to convert, adding plot and timeline 2025-10-21 11:55:52 +02:00
wendtalexander
6dd148656b [doc] adding calc lag 2025-10-21 11:55:30 +02:00
wendtalexander
ce1fe10050 [doc] adding sam 2025-10-21 11:55:15 +02:00
wendtalexander
1c93c7aa95 [doc/index] fixing typo 2025-10-21 11:55:10 +02:00
wendtalexander
efcae6339e [formatting] 2025-10-21 11:54:46 +02:00
wendtalexander
9ed6d44c4e [docs] adding delays overview 2025-10-21 11:54:23 +02:00
wendtalexander
3da1a323c2 [formatting] 2025-10-21 11:54:11 +02:00
wendtalexander
335a83414b [doc/quarto] adding new contens 2025-10-21 11:53:53 +02:00
11 changed files with 582 additions and 57 deletions

View File

@@ -39,15 +39,20 @@ website:
- text: "Sample Rates"
href: "samplerates.qmd"
- section: "Delays"
href: 'delays.qmd'
contents:
- "baseline.qmd"
- "calibration.qmd"
- "fi_curve.qmd"
- "filestimulus.qmd"
- "sam.qmd"
- section: "API"
href: "api/index.qmd"
contents:
- "api/index.qmd"
- "api/main.qmd"
- "api/metadata.qmd"
- "api/stimulus_recreation.qmd"
- "api/tonix.qmd"
quartodoc:
@@ -62,6 +67,12 @@ quartodoc:
desc: Terminal client
contents:
- main
- title: helper
desc: Helper Function
contents:
- metadata
- stimulus_recreation
- tonix
execute:
freeze: auto

View File

@@ -20,22 +20,22 @@ Lets look at the calibration and the first trial of the recording.
import pathlib
import rlxnix as rlx
import plotly.graph_objects as go
import numpy as np
import plotly.graph_objects as go
import rlxnix as rlx
import scipy.signal as signal
from plotly.subplots import make_subplots
from util import trial_plot, plot_line_comparision
from util import plot_line_comparision, trial_plot
dataset_path = pathlib.Path("../oephys2nix/test/Test1/2025-10-08-aa-invivo-2-recording.nix")
relacs_path = pathlib.Path("../oephys2nix/test/Test1/2025-10-08-aa-invivo-2_relacs/2025-10-08-aa-invivo-2.nix")
relacs_path = pathlib.Path(
"../oephys2nix/test/Test1/2025-10-08-aa-invivo-2_relacs/2025-10-08-aa-invivo-2.nix"
)
dataset = rlx.Dataset(str(dataset_path))
relacs = rlx.Dataset(str(relacs_path))
#INFO: Select the first stimulus of the calibration repro
# INFO: Select the first stimulus of the calibration repro
repro_d = dataset.repro_runs("CalibEfield_1")[0].stimuli[2]
repro_r = relacs.repro_runs("CalibEfield_1")[0].stimuli[2]
@@ -57,7 +57,7 @@ ttl, t = repro_d.trace_data("ttl-line")
If you zoom in you can see a little delay between the different recording systems. It seems that open-ephys is before the relacs recording.
```{python}
#| echo: False
# | echo: False
fig = trial_plot(repro_d, repro_r)
fig.show()
```
@@ -68,11 +68,10 @@ print(f"Duration of the dataset {repro_d.duration}")
print(f"Duration of the relacs {repro_r.duration}")
# Resample the open-ephys data
sinus_resampled = signal.resample(sinus, len(sinus_r))
```
```{python}
#| echo: False
# | echo: False
fig = plot_line_comparision(t_r, t, sinus_r, sinus, ["sinus-relacs", "sinus-oephys"])
fig.show()
```
@@ -83,19 +82,27 @@ oephys_lanes = [sinus, local_eod_oe, global_eod_oe, stimulus_oe]
relacs_lanes = [sinus_r, local_eod_re, global_eod_re, stimulus_re]
names_lanes = ["sinus", "local-eod", "global-eod", "stimulus"]
lags_lanes = []
for oephys_lane, relacs_lane, names_lane in zip(oephys_lanes, relacs_lanes, names_lanes, strict=True):
print(oephys_lane.shape)
print(relacs_lane.shape)
oephys_lane_resampled = signal.resample(oephys_lane, len(relacs_lane))
correlation = signal.correlate(oephys_lane_resampled, relacs_lane, mode="full")
lags = signal.correlation_lags(oephys_lane_resampled.size, relacs_lane.size, mode="full")
lag = lags[np.argmax(correlation)]
lags_lanes.append(lag)
print(f"{names_lane} has a lag of {lag}")
for oephys_lane, relacs_lane, names_lane in zip(
oephys_lanes, relacs_lanes, names_lanes, strict=True
):
print(oephys_lane.shape)
print(relacs_lane.shape)
oephys_lane_resampled = signal.resample(oephys_lane, len(relacs_lane))
correlation = signal.correlate(oephys_lane_resampled, relacs_lane, mode="full")
lags = signal.correlation_lags(oephys_lane_resampled.size, relacs_lane.size, mode="full")
lag = lags[np.argmax(correlation)]
lags_lanes.append(lag)
print(f"{names_lane} has a lag of {lag}")
```
```{python}
#| echo: False
fig = plot_line_comparision(t_r, t_r, np.roll(sinus_r, lags_lanes[0]),sinus_resampled, ["sinus-relacs", "sinus-resampled-openepyhs"])
# | echo: False
fig = plot_line_comparision(
t_r,
t_r,
np.roll(sinus_r, lags_lanes[0]),
sinus_resampled,
["sinus-relacs", "sinus-resampled-openepyhs"],
)
fig.show()
```

147
doc/delays.qmd Normal file
View File

@@ -0,0 +1,147 @@
---
title: Delays anaylsis
format:
html:
toc: true
toc-title: Contents
code-block-bg: true
code-block-border-left: "#31BAE9"
code-line-numbers: true
highlight-style: atom-one
link-external-icon: true
link-external-newwindow: true
eqn-number: true
---
### 1. Delays
We noticed a delay in the recodings if you were to plot a comparision between
the base relacs recording and the new generated open-ephys.
```{python}
# | echo: False
import pathlib
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import rlxnix as rlx
import scipy.signal as signal
from plotly.subplots import make_subplots
from rich.progress import track
from rich.table import Table
from util import calc_lag, plot_line_comparision, trial_plot
dataset_path = pathlib.Path("../oephys2nix/test/Test1/2025-10-08-aa-invivo-2-recording.nix")
relacs_path = pathlib.Path(
"../oephys2nix/test/Test1/2025-10-08-aa-invivo-2_relacs/2025-10-08-aa-invivo-2.nix"
)
dataset = rlx.Dataset(str(dataset_path))
relacs = rlx.Dataset(str(relacs_path))
# INFO: Select the first stimulus of the calibration repro
repro_d = dataset.repro_runs("FileStimulus_1")[0].stimuli[2]
repro_r = relacs.repro_runs("FileStimulus_1")[0].stimuli[2]
sinus, t = repro_d.trace_data("sinus")
sinus_r, t_r = repro_r.trace_data("V-1")
stimulus_oe, t = repro_d.trace_data("stimulus")
stimulus_re, t_r = repro_r.trace_data("GlobalEFieldStimulus")
local_eod_oe, t = repro_d.trace_data("local-eod")
local_eod_re, t_r = repro_r.trace_data("LocalEOD-1")
global_eod_oe, t = repro_d.trace_data("global-eod")
global_eod_re, t_r = repro_r.trace_data("EOD")
ttl, t = repro_d.trace_data("ttl-line")
fig = plot_line_comparision(
t_r,
t,
stimulus_re,
stimulus_oe - np.mean(stimulus_oe),
["stimulus-relacs", "stimulus-open-ephys"],
)
fig.show()
```
### 2. Look at differnt RePros
Currently implemented repros are:
- [x] [Baseline](baseline.qmd)
- [x] [Calibration](calibration.qmd)
- [x] [FI Curve](fi_curve.qmd)
- [x] [File Stimulus](filestimulus.qmd)
- [ ] Sams
- [ ] Chrips
- [ ] Beats
### 3. General Delay in detail
```{python}
rich_tabel = Table("Repro Run", "Signal", "Lag (samples)")
names_lanes = ["sinus", "local-eod", "global-eod", "stimulus"]
dataframe = []
for repro_idx, (repro_d, repro_r) in enumerate(
zip(dataset.repro_runs(), relacs.repro_runs(), strict=True)
):
if not repro_d.stimuli:
lags = calc_lag(repro_d, repro_r)
for lag, names_lane in zip(lags, names_lanes, strict=True):
rich_tabel.add_row(f"{repro_d.name}", f"{names_lane}", f"{lag}")
dataframe.append(
{"ReproName": repro_d.name, "Line": names_lane, "Lag": lag, "Trial": 0}
)
else:
lags_lanes = {f"{key}": [] for key in names_lanes}
for trial, (stim_oe, stim_re) in enumerate(
zip(repro_d.stimuli, repro_r.stimuli, strict=True)
):
lags = calc_lag(stim_oe, stim_re)
for lag, names_lane in zip(lags, names_lanes):
lags_lanes[names_lane].append(lag)
dataframe.append(
{"ReproName": repro_d.name, "Line": names_lane, "Lag": lag, "Trial": trial}
)
for lane in lags_lanes:
mean_lag = np.mean(lags_lanes[lane])
std_lag = np.std(lags_lanes[lane])
rich_tabel.add_row(f"{repro_d.name}", f"{lane}", f"{mean_lag:.2f}\u00b1{std_lag:.2f}")
rich_tabel
```
```{python}
repros = dataset.repro_runs("Baseline")
print(repros)
exclude = []
for rep in repros:
exclude.append(rep.name)
df = pd.DataFrame(dataframe)
df = df[~df["ReproName"].isin(exclude)]
fig = px.box(
df,
x="Line",
y="Lag",
color="Line",
title="Lag Distribution Across Different Signals",
labels={"Line": "Signal", "Lag": "Lag (samples)"},
)
fig.update_layout(template="plotly_dark")
fig.show()
fig = px.box(
df,
x="Line",
y="Lag",
color="ReproName",
title="Lag Distribution by Signal and Repro Run",
labels={"Line": "Signal", "Lag": "Lag (samples)"},
)
fig.update_layout(template="plotly_dark")
fig.show()
```

View File

@@ -69,9 +69,7 @@ fig.show()
print(f"Duration of the dataset {repro_d.duration}")
print(f"Duration of the relacs {repro_r.duration}")
# Resample the open-ephys data
sinus_resampled = signal.resample(sinus, len(sinus_r))
```
```{python}
@@ -99,6 +97,8 @@ for oephys_lane, relacs_lane, names_lane in zip(oephys_lanes, relacs_lanes, name
```{python}
#| echo: False
fig = plot_line_comparision(t_r, t_r, np.roll(sinus_r, lags_lanes[0]), sinus_resampled, ["rolled sinus-relacs", "sinus-resampled-open-ephys"])
fig = plot_line_comparision(t_r, t, np.roll(stimulus_re, lags_lanes[-1]), stimulus_oe-np.mean(stimulus_oe), ["rolled sinus-relacs", "sinus-resampled-open-ephys"])
fig.show()
print(f"The lag of the whitenoise is {lags_lanes[-1] * (1/20_000) * 1000} milli seconds")
```

View File

@@ -38,7 +38,7 @@ Please follow the installation instructions for quarto, and install the extra
dependencies.
```bash
pip install "[.doc]"
pip install "[.docs]"
cd doc
quartodoc build
quarto preview

111
doc/sam.qmd Normal file
View File

@@ -0,0 +1,111 @@
---
title: SAM
format:
html:
toc: true
toc-title: Contents
code-block-bg: true
code-block-border-left: "#31BAE9"
code-line-numbers: true
highlight-style: atom-one
link-external-icon: true
link-external-newwindow: true
eqn-number: true
---
### SAM
```{python}
import pathlib
import numpy as np
import plotly.graph_objects as go
import rlxnix as rlx
import scipy.signal as signal
from plotly.subplots import make_subplots
from util import plot_line_comparision, trial_plot
dataset_path = pathlib.Path("../oephys2nix/test/AllStimuli/2025-10-20-aa-invivo-2-recording.nix")
relacs_path = pathlib.Path(
"../oephys2nix/test/AllStimuli/2025-10-20-aa-invivo-2_relacs/2025-10-20-aa-invivo-2_relacs.nix"
)
dataset = rlx.Dataset(str(dataset_path))
relacs = rlx.Dataset(str(relacs_path))
# INFO: Select the first stimulus of the calibration repro
repro_d = dataset.repro_runs("SAM")[0].stimuli[2]
repro_r = relacs.repro_runs("SAM")[0].stimuli[2]
sinus, t = repro_d.trace_data("sinus")
sinus_r, t_r = repro_r.trace_data("V-1")
stimulus_oe, t = repro_d.trace_data("stimulus")
stimulus_re, t_r = repro_r.trace_data("GlobalEFieldStimulus")
local_eod_oe, t = repro_d.trace_data("local-eod")
local_eod_re, t_r = repro_r.trace_data("LocalEOD-1")
global_eod_oe, t = repro_d.trace_data("global-eod")
global_eod_re, t_r = repro_r.trace_data("EOD")
ttl, t = repro_d.trace_data("ttl-line")
```
### Plotting the First trial
If you zoom in you can see a little delay between the different recording systems. It seems that open-ephys is before the relacs recording.
```{python}
# | echo: False
fig = trial_plot(repro_d, repro_r, 0.2)
fig.update_xaxes(range=[0, 0.2])
fig.show()
```
### Correlation between the Signals
```{python}
print(f"Duration of the dataset {repro_d.duration}")
print(f"Duration of the relacs {repro_r.duration}")
# Resample the open-ephys data
sinus_resampled = signal.resample(sinus, len(sinus_r))
```
```{python}
# | echo: False
fig = plot_line_comparision(
t_r, t_r, sinus_r, sinus_resampled, ["sinus-relacs", "sinus-resampled-open-ephys"]
)
fig.show()
```
We need to scale the two signals
```{python}
oephys_lanes = [sinus, local_eod_oe, global_eod_oe, stimulus_oe]
relacs_lanes = [sinus_r, local_eod_re, global_eod_re, stimulus_re]
names_lanes = ["sinus", "local-eod", "global-eod", "stimulus"]
lags_lanes = []
for oephys_lane, relacs_lane, names_lane in zip(
oephys_lanes, relacs_lanes, names_lanes, strict=True
):
print(oephys_lane.shape)
print(relacs_lane.shape)
oephys_lane_resampled = signal.resample(oephys_lane, len(relacs_lane))
correlation = signal.correlate(oephys_lane_resampled, relacs_lane, mode="full")
lags = signal.correlation_lags(oephys_lane_resampled.size, relacs_lane.size, mode="full")
lag = lags[np.argmax(correlation)]
lags_lanes.append(lag)
print(f"{names_lane} has a lag of {lag}")
```
```{python}
# | echo: False
fig = plot_line_comparision(
t_r,
t,
np.roll(stimulus_re, lags_lanes[-1]),
stimulus_oe - np.mean(stimulus_oe),
["rolled sinus-relacs", "sinus-resampled-open-ephys"],
)
fig.show()
print(f"The lag of the whitenoise is {lags_lanes[-1] * (1 / 20_000) * 1000} milli seconds")
```

View File

@@ -1,5 +1,6 @@
import numpy as np
import plotly.graph_objects as go
import scipy.signal as signal
from plotly.subplots import make_subplots
@@ -122,7 +123,7 @@ def trial_plot(repro_d, repro_r, x_lim: int = 1.0):
)
# Add a label to the shared x-axis (targeting the last subplot)
fig.update_xaxes(title_text="Time (s)", row=4, col=1)
fig.update_xaxes(range=[0, 0.5])
fig.update_xaxes(range=[0, x_lim])
return fig
@@ -178,5 +179,31 @@ def plot_line_comparision(
x=0.72,
),
)
fig.update_xaxes(range=[0, 0.01])
fig.update_xaxes(title_text="Time (s)", range=[0, 0.01])
return fig
def calc_lag(repro_d, repro_r):
sinus, t = repro_d.trace_data("sinus")
sinus_r, t_r = repro_r.trace_data("V-1")
stimulus_oe, t = repro_d.trace_data("stimulus")
stimulus_re, t_r = repro_r.trace_data("GlobalEFieldStimulus")
local_eod_oe, t = repro_d.trace_data("local-eod")
local_eod_re, t_r = repro_r.trace_data("LocalEOD-1")
global_eod_oe, t = repro_d.trace_data("global-eod")
global_eod_re, t_r = repro_r.trace_data("EOD")
oephys_lanes = [sinus, local_eod_oe, global_eod_oe, stimulus_oe]
relacs_lanes = [sinus_r, local_eod_re, global_eod_re, stimulus_re]
lags_lanes = []
for oephys_lane, relacs_lane in zip(oephys_lanes, relacs_lanes, strict=True):
oephys_lane_resampled = signal.resample(oephys_lane, len(relacs_lane))
correlation = signal.correlate(oephys_lane_resampled, relacs_lane, mode="full")
lags = signal.correlation_lags(oephys_lane_resampled.size, relacs_lane.size, mode="full")
lag = lags[np.argmax(correlation)]
lags_lanes.append(lag)
return lags_lanes

View File

@@ -18,7 +18,7 @@ console = Console()
@app.command()
def main(
def convert(
data_path: Path = typer.Argument(
...,
help="The source directory containing the Open Ephys data.",
@@ -92,32 +92,68 @@ def main(
stim = StimulusToNix(open_ephys, str(relacs), str(nix_path))
stim.create_repros_automatically()
stim.print_table()
# stim.checks()
# if debug:
# stim.plot_stimulus()
@app.command()
def timeline(
data_path: Path = typer.Argument(
...,
help="The source directory containing the Open Ephys data.",
help="The source directory containing a dataset.",
exists=True,
file_okay=False,
dir_okay=True,
readable=True,
resolve_path=True,
),
):
) -> None:
"""Plot the timeline for a given dataset."""
dataset = list(Path(data_path).rglob("*.nix"))
if not dataset:
log.error("Did not find any dataset")
raise typer.Exit()
if len(dataset) > 1:
log.info(f"Found multiple datasets {len(dataset)} taking the first one")
dataset = rlx.Dataset(str(dataset[0]))
dataset.plot_timeline()
dataset.close()
@app.command()
def plot(
data_path: Path = typer.Argument(
...,
help="The source directory containing the open-ephys and relacs data.",
exists=True,
file_okay=False,
dir_okay=True,
readable=True,
resolve_path=True,
),
) -> None:
"""Plot the stimulus, TTL and the relacs stimulus.
You can run this if you converted already the nix-file.
"""
relacs_data_paths = list(Path(data_path).rglob("*relacs/*.nix"))
if not relacs_data_paths:
log.error("Did not find any relacs data")
raise typer.Exit()
dataset = rlx.Dataset(str(relacs_data_paths[0]))
dataset.plot_timeline()
dataset.close()
open_ephys_data_paths = list(Path(data_path).rglob("*open-ephys"))
if not open_ephys_data_paths:
log.error("Did not find any open-ephys data")
raise typer.Exit()
nix_file_name = relacs_data_paths[0].parent.name.split("_")[0] + "-recording.nix"
nix_path = relacs_data_paths[0].parent.parent / nix_file_name
if not nix_path.is_file:
log.error("Did not find any converted nix file")
raise typer.Exit()
stim = StimulusToNix(open_ephys_data_paths[0], str(relacs_data_paths[0]), str(nix_path))
stim.plot_stimulus()
stim.close()
if __name__ == "__main__":

View File

@@ -2,6 +2,15 @@ import nixio
def create_metadata_from_dict(d: dict, section: nixio.Section) -> None:
"""Creating nix section from dictionary.
Parameters
----------
d : dict
Dictionary that needs to be saved to section
section : nixio.Section
Target section in Nix file
"""
for key, value in d.items():
if isinstance(value, dict):
new_sec = section.create_section(key, f"{type(key)}")
@@ -18,6 +27,18 @@ def create_metadata_from_dict(d: dict, section: nixio.Section) -> None:
def create_dict_from_section(section: nixio.Section) -> dict:
"""Creating dictionary from Nix section
Parameters
----------
section : nixio.Section
Source nix section that will be exported to the dictionary
Returns
-------
dict: dict
Nix section in a dictionary
"""
d = {}
for key, value in section.items():
if isinstance(value, nixio.Section):

View File

@@ -1,7 +1,6 @@
import logging
import pathlib
import sys
import tomllib
import matplotlib.pyplot as plt
import nixio
@@ -22,6 +21,47 @@ console = Console()
class StimulusToNix:
"""Processing the stimulus recreation from the relax dataset and the open-ephys data.
Parameters
----------
open_ephys_path: pathlib.Path
Path to open-ephys recording
relacs_nix_path : str
Path to relacs nix file
nix_file : str
Path to new nix file
Attributes
----------
relacs_nix_path : str
Path to relacs nix file
nix_file_path : str
Path to new nix file
dataset : rlx.Dataset
Dataset from the relacs file
relacs_nix_file : nixio.File
Relacs nix file
relacs_block : nixio.Block
Relacs nix block
relacs_sections :nixio.Section
Relacs nix Section
neo_data : neo.OpenEphysBinaryIO
Open-ephys data
fs : float
Sample rate of the open-ephys recording
nix_file : nixio.File
New nix file
block : nixio.Block
New nix block
threshold : float
Threshold for TTL line
new_start_jiggle : float
For finding the new start, ensuring finding next TTL pulse
"""
def __init__(self, open_ephys_path: pathlib.Path, relacs_nix_path: str, nix_file: str):
self.relacs_nix_path = relacs_nix_path
self.nix_file_path = nix_file
@@ -43,7 +83,8 @@ class StimulusToNix:
self.threshold = 2
self.new_start_jiggle = 0.1
def _append_relacs_tag_mtags(self):
def _append_relacs_tag_mtags(self) -> None:
"""Append relacs tags and multi tags to new nix file."""
for t in self.relacs_block.tags:
log.debug(f"Appending relacs tags {t.name}")
tag = self.block.create_tag(f"relacs_{t.name}", t.type, position=t.position)
@@ -80,7 +121,31 @@ class StimulusToNix:
pass
mtag.metadata = self.nix_file.sections[sec.name]
def _find_peak_ttl(self, time_ttl, peaks_ttl, lower, upper):
def _find_next_ttl(
self, time_ttl: np.ndarray, peaks_ttl: np.ndarray, lower: float, upper: float
) -> np.ndarray:
"""Find the next TTL pulse within a specific duration constrained by lower and upper.
Parameters
----------
time_ttl : np.ndarray
Time array of the TTL line
peaks_ttl : np.ndarray
Detected peaks indeces on the TTL line
lower : float
lower bound for searching the TTL pulse
upper : float
upper bound for searching the TTL pulse
Returns
-------
np.ndarray
time point of the new TTL pulse
"""
peak = time_ttl[peaks_ttl[(time_ttl[peaks_ttl] > lower) & (time_ttl[peaks_ttl] < upper)]]
if not peak.size > 0:
@@ -92,7 +157,28 @@ class StimulusToNix:
peak = np.mean(peak)
return peak
def _find_peak_ttl_index(self, time_ttl, peaks_ttl, current_position):
def _find_peak_ttl_index(
self, time_ttl: np.ndarray, peaks_ttl: np.ndarray, current_position: np.ndarray
) -> np.ndarray:
"""Find the next TTL pulse from the indeces of the detected TTL pulses.
Parameters
----------
time_ttl : np.ndarray
Time array of the TTL line
peaks_ttl : np.ndarray
Detected peaks indeces on the TTL line
current_position : np.ndarray
Current time of the TTL pulse
Returns
-------
np.ndarray
Next time of TTL pulse
"""
new_repro_start_index = peaks_ttl[
(time_ttl[peaks_ttl] > current_position - self.new_start_jiggle)
& (time_ttl[peaks_ttl] < current_position + self.new_start_jiggle)
@@ -112,13 +198,34 @@ class StimulusToNix:
@property
def _reference_groups(self) -> list[nixio.Group]:
"""Holds the reference groups.
Returns
-------
list[nixio.Group]
"""
return [
self.block.groups["neuronal-data"],
self.block.groups["efish"],
self.block.groups["relacs"],
]
def _append_mtag(self, repro, positions, extents):
def _append_mtag(self, repro: rlx.Dataset, positions: np.ndarray, extents: np.ndarray) -> None:
"""Apped multi tags of the current repro to the nix file.
Parameters
----------
repro : rlx.Dataset
Current Repro
positions : np.ndarray
postions of the multi tags
extents : np.ndarray
extents of the multi tags
"""
try:
nix_mtag = self.block.create_multi_tag(
f"{repro.name}",
@@ -159,7 +266,20 @@ class StimulusToNix:
nix_group = self.nix_file.blocks[0].groups[repro.name]
nix_group.multi_tags.append(nix_mtag)
def _append_tag(self, repro, position, extent):
def _append_tag(self, repro: rlx.Dataset, position: np.ndarray, extent: np.ndarray) -> None:
"""Append tag of the current repro.
Parameters
----------
repro : rlx.Dataset
Current Repro
position : np.ndarray
positions of the multi tags
extent : np.ndarray
extents of the multi tags
"""
try:
nix_tag = self.block.create_tag(
f"{repro.name}",
@@ -201,7 +321,8 @@ class StimulusToNix:
nix_group = self.nix_file.blocks[0].groups[repro.name]
nix_group.tags.append(nix_tag)
def create_repros_automatically(self):
def create_repros_automatically(self) -> None:
"""Create the repros form relacs with the TTL pulses."""
ttl_oeph = self.block.data_arrays["ttl-line"][:]
time_ttl = np.arange(len(ttl_oeph)) / self.fs
time_index = np.arange(len(ttl_oeph))
@@ -214,7 +335,7 @@ class StimulusToNix:
if close_peaks.size > 0:
peaks_ttl = np.delete(peaks_ttl, close_peaks)
first_peak = self._find_peak_ttl(
first_peak = self._find_next_ttl(
time_ttl,
peaks_ttl,
time_ttl[peaks_ttl[0]] - self.new_start_jiggle,
@@ -229,6 +350,8 @@ class StimulusToNix:
log.warning(f"Skipping repro {repro.name} because it is two short")
continue
embed()
exit()
if repro.stimuli:
log.debug("Processing MultiTag")
repetition = len(repro.stimuli)
@@ -244,7 +367,9 @@ class StimulusToNix:
time_ttl, peaks_ttl, current_position
)
# current_position = position_mtags[-1]
if "FICurve" in repro.name:
position_mtags += 0.2
self._append_mtag(repro, position_mtags, extents_mtag)
extent = position_mtags[-1] + extents_mtag[-1] - position_mtags[0]
self._append_tag(repro, position_mtags[0], extent)
@@ -282,9 +407,11 @@ class StimulusToNix:
last_repro_position.reshape(-1, 1),
(current_position - last_repro_position).reshape(-1, 1),
)
# self.close()
def create_repros_from_config_file(self):
def create_repros_from_config_file(self) -> None:
"""Creates repros form a config file.
NOT MAINTAINED.
"""
ttl_oeph = self.block.data_arrays["ttl-line"][:]
peaks_ttl = signal.find_peaks(
ttl_oeph.flatten(),
@@ -429,7 +556,8 @@ class StimulusToNix:
]
nix_group.multi_tags.append(nix_mtag)
def print_table(self):
def print_table(self) -> None:
"""Print the converted times in a rich table."""
nix_data_set = rlx.Dataset(self.nix_file_path)
table = Table("Repro Name", "start", "stop", "duration")
for repro_r, repro_n in zip(self.dataset.repro_runs(), nix_data_set.repro_runs()):
@@ -443,7 +571,8 @@ class StimulusToNix:
console.print(table)
nix_data_set.close()
def checks(self):
def checks(self) -> None:
"""Just for debugging currently."""
important_repros = ["FileStimulus", "SAM", "FICurve"]
nix_data_set = rlx.Dataset(self.nix_file_path)
@@ -508,7 +637,8 @@ class StimulusToNix:
v_eod, t_eod = repro_n.trace_data("global-eod")
v_eodr, t_eodr = repro_n.trace_data("EOD")
def plot_stimulus(self):
def plot_stimulus(self) -> None:
"""Plot the relacs stimulus, open-epyhs and TTL line."""
ttl_oeph = self.block.data_arrays["ttl-line"][:]
time_index = np.arange(len(ttl_oeph))

View File

@@ -14,6 +14,36 @@ log = logging.getLogger(__name__)
class RawToNix:
"""Appending all raw data from relacs and open-ephsy to a new nix file.
Parameters
----------
open_ephys_path: pathlib.Path
Path to open-ephys recording
relacs_nix_path : str
Path to relacs nix file
nix_file : str
Path to new nix file
Attributes
----------
relacs_nix_file : nixio.File
Relacs nix file
dataset : rlx.Dataset
Dataset of the relacs file
relacs_block : nixio.Block
Relacs block
relacs_sections : nixio.Section
Relacs section
neo_data : neo.OpenEphysBinaryIO
Open Ephys data
nix_file : nixio.File
New nix file
block : nixio.Block
New nix file block
"""
def __init__(self, open_ephys_path: pathlib.Path, relacs_nix_path: str, nix_file: str):
self.relacs_nix_file = nixio.File.open(relacs_nix_path, nixio.FileMode.ReadOnly)
self.dataset = rlx.Dataset(relacs_nix_path)
@@ -25,7 +55,8 @@ class RawToNix:
self.nix_file.create_block("open-ephys.data", "open-ephys.sampled")
self.block = self.nix_file.blocks[0]
def append_section(self):
def append_section(self) -> None:
"""Append sections from relacs."""
sec = self.nix_file.create_section(
self.relacs_sections[0].name, self.relacs_sections[0].type
)
@@ -33,7 +64,8 @@ class RawToNix:
create_metadata_from_dict(d, sec)
self.block.metadata = sec
def append_fish_lines(self):
def append_fish_lines(self) -> None:
"""Append fish lines from open-ephys."""
efishs = ["ttl-line", "global-eod", "stimulus", "local-eod", "sinus"]
efish_types = [
@@ -63,7 +95,8 @@ class RawToNix:
)
efish_group.data_arrays.append(data_array)
def append_relacs_lines(self):
def append_relacs_lines(self) -> None:
"""Append relacs lines."""
relacs = [
"V-1",
"EOD",
@@ -111,7 +144,8 @@ class RawToNix:
efish_group.data_arrays.append(data_array)
def append_raw_data(self):
def append_raw_data(self) -> None:
"""Append Open-Ephys Raw data."""
gr = self.block.create_group("neuronal-data", "open-epyhs.sampled")
raw_neo_data = self.neo_data[0].segments[0].analogsignals[0].load()
@@ -128,6 +162,7 @@ class RawToNix:
)
gr.data_arrays.append(nix_data_array)
def close(self):
def close(self) -> None:
"""Close all nix files."""
self.nix_file.close()
self.relacs_nix_file.close()