Compare commits
11 Commits
d79fa309bf
...
ffc4f9995d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffc4f9995d | ||
|
|
ea9dd555d8 | ||
|
|
cd7cd43313 | ||
|
|
af98fdc2cb | ||
|
|
6dd148656b | ||
|
|
ce1fe10050 | ||
|
|
1c93c7aa95 | ||
|
|
efcae6339e | ||
|
|
9ed6d44c4e | ||
|
|
3da1a323c2 | ||
|
|
335a83414b |
@@ -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
|
||||
|
||||
@@ -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
147
doc/delays.qmd
Normal 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()
|
||||
```
|
||||
@@ -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")
|
||||
```
|
||||
|
||||
@@ -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
111
doc/sam.qmd
Normal 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")
|
||||
```
|
||||
31
doc/util.py
31
doc/util.py
@@ -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
|
||||
|
||||
@@ -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__":
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user