Compare commits

..

30 Commits

Author SHA1 Message Date
32487e09a9 [sorting] fixing cleanup 2026-05-07 11:55:37 +02:00
wendtalexander
d9aed0551f [sorting] need more fixing 2026-05-06 16:58:56 +02:00
wendtalexander
11d76b205a [pyproject] adding spikeinterface 2026-05-06 16:30:40 +02:00
wendtalexander
56e6d1c589 [soritng] adding sorign and small fixes 2026-05-06 16:30:24 +02:00
wendtalexander
616dd721f5 [features] fixing duplicate name 2026-04-29 14:00:16 +02:00
wendtalexander
2c39f26a06 [pyproject] adding pyqt for matplotlib 2026-04-29 13:26:31 +02:00
wendtalexander
f8dc845625 [features] adding features 2026-04-29 13:26:20 +02:00
wendtalexander
3b849c0c23 [pyproject] adding ipython 2026-04-22 10:17:41 +02:00
wendtalexander
f068ba3c42 [pyproject] adding shorthandle 2025-10-24 13:32:25 +02:00
wendtalexander
9f4facc7bc [doc] adding samplerates back again 2025-10-24 13:32:13 +02:00
wendtalexander
88250f8f85 [readme] 2025-10-21 16:21:34 +02:00
wendtalexander
d6c5cfdac0 [readme] 2025-10-21 16:20:38 +02:00
wendtalexander
396ebe0c52 [pyproject] updating to new version 2025-10-21 15:07:06 +02:00
wendtalexander
58b88b7e73 [stim] remove embed 2025-10-21 15:06:53 +02:00
wendtalexander
a8778f3596 [doc] adding doc for different comands 2025-10-21 15:06:40 +02:00
wendtalexander
d5499eb3e8 [formatting] 2025-10-21 15:06:19 +02:00
wendtalexander
307709834b [doc] adding algorithm 2025-10-21 15:06:01 +02:00
wendtalexander
a32a1f8cb4 [doc/quarto] adding algorithm 2025-10-21 15:05:50 +02:00
wendtalexander
56a430df26 [doc/assets] adding algorithm png 2025-10-21 15:05:34 +02:00
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
20 changed files with 1218 additions and 159 deletions

View File

@@ -0,0 +1,34 @@
## 1. Motivation
`oephys2nix` is a comand-line-interface (cli), which helps converting
[relacs](https://github.com/relacs/relacs) data and
[open-ephys](https://open-ephys.org/gui) data to a single nix file. For making
life easier to work with behavior and neuronal data.
## 2. Installation and Documentation
Here my general workflow for installing the package.
```bash
git clone https://whale.am28.uni-tuebingen.de/git/awendt/oephys2nix
cd oephys2nix
python -m venv .venv
source .venv/bin/activate
pip install -e .
```
To see the documentation you need to install [quarto](https://quarto.org).
Please follow the installation instructions for quarto, and install the extra
dependencies.
```bash
pip install "[.docs]"
cd doc
quartodoc build
quarto preview
```
which should open the documentation at localhost.
## 3.To-Dos
- [x] Analyzed the delay in the two recoding systems
- [x] Analyzed the difference in sample rate
- [ ] Get offset and gain from open-ephys recorded lines.

View File

@@ -5,11 +5,9 @@ project:
format:
html:
# code-fold: true
# code-summary: "Show the code"
theme:
light: flatly
dark: darkly
light: flatly
css:
- api/_styles-quartodoc.css
- styles.css
@@ -38,16 +36,23 @@ website:
href: "usage.qmd"
- text: "Sample Rates"
href: "samplerates.qmd"
- text: "Algorithm"
href: "algorithm.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

7
doc/algorithm.qmd Normal file
View File

@@ -0,0 +1,7 @@
---
title: Algorithm
---
### 1. Algorithm for automatic detection of repros with TTL pulses
![Algorithm](assets/algorithm.png)

BIN
doc/assets/algorithm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

View File

@@ -19,23 +19,22 @@ Lets look at the calibration and the first trial of the recording.
```{python}
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/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")
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
# INFO: Select the first stimulus of the calibration repro
repro_d = dataset.repro_runs("BaselineActivity")[0]
repro_r = relacs.repro_runs("BaselineActivity")[0]
@@ -57,7 +56,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
# 2. Add traces to the FIRST subplot (row=1, col=1)
# Note: Plotly rows and columns are 1-indexed
fig = trial_plot(repro_d, repro_r, 1.0)
@@ -70,12 +69,13 @@ 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"])
# | 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
@@ -85,23 +85,26 @@ 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"]
samples_20kHz = t[-1] * 20_000
print(samples_20kHz)
print(f"Total duration {t[-1]}")
print(repro_d.duration)
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, int(samples_20kHz))
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
):
oephys_lane_resampled = signal.resample(oephys_lane, int(samples_20kHz))
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, ["rolled sinus-relacs", "sinus-resampled-open-ephys"])
# | 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.show()
```

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,8 +57,8 @@ 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
fig = trial_plot(repro_d, repro_r)
# | echo: False
fig = trial_plot(repro_d, repro_r, 0.41)
fig.show()
```
### Correlation between the Signals
@@ -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,25 @@ 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
):
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

@@ -19,23 +19,22 @@ Lets look at the calibration and the first trial of the recording.
```{python}
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("FICurve_1")[0].stimuli[2]
repro_r = relacs.repro_runs("FICurve_1")[0].stimuli[2]
@@ -57,10 +56,8 @@ 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
# 2. Add traces to the FIRST subplot (row=1, col=1)
# Note: Plotly rows and columns are 1-indexed
fig = trial_plot(repro_d, repro_r)
# | echo: False
fig = trial_plot(repro_d, repro_r, 0.41)
fig.show()
```
### Correlation between the Signals
@@ -70,12 +67,13 @@ 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"])
# | 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
@@ -85,19 +83,25 @@ 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
):
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, ["rolled sinus-relacs", "sinus-resampled-open-ephys"])
# | 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.show()
```

View File

@@ -18,23 +18,22 @@ format:
```{python}
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("FileStimulus_1")[0].stimuli[2]
repro_r = relacs.repro_runs("FileStimulus_1")[0].stimuli[2]
@@ -56,10 +55,10 @@ 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
# 2. Add traces to the FIRST subplot (row=1, col=1)
# Note: Plotly rows and columns are 1-indexed
fig = trial_plot(repro_d, repro_r)
fig = trial_plot(repro_d, repro_r,1.01)
fig.show()
```
@@ -69,14 +68,14 @@ 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}
#| echo: False
fig= plot_line_comparision(t_r, t_r, sinus_r, sinus_resampled, ["sinus-relacs", "sinus-resampled-open-ephys"])
# | 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
@@ -86,19 +85,29 @@ 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, ["rolled sinus-relacs", "sinus-resampled-open-ephys"])
# | 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

@@ -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

109
doc/sam.qmd Normal file
View File

@@ -0,0 +1,109 @@
---
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
):
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

@@ -2,10 +2,38 @@
title: How to use it
---
### 1.Usage
If you have a folder or multiple folders with each containing two recordings one from `relacs` and one from `open-ephys` you can simply run the CLI like this:
```{python}
# leave out the ! at the beginning if you running this in your shell
!oephys2nix ../oephys2nix/test/Test1/
!oephys2nix convert ../oephys2nix/test/Test1/
```
which provides you with information about the transition of the stimuli into the new file.
### 1.2 Timeline plot
```sh
oephys2nix timeline ../oephys2nix/test/Test1/
```
```{python}
# | echo: False
from oephys2nix.main import timeline
path = "../oephys2nix/test/Test1/"
timeline(path)
```
### 1.3 plot
```sh
oephys2nix plot ../oephys2nix/test/Test1/
```
```{python}
# | echo: False
from oephys2nix.main import plot
path = "../oephys2nix/test/Test1/"
plot(path)
```

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

@@ -1,4 +1,6 @@
import logging
import sys
from os import path
from pathlib import Path
from typing import Annotated
@@ -9,6 +11,7 @@ from IPython import embed
from rich.console import Console
from oephys2nix.logging import setup_logging
from oephys2nix.sorting import AppendSorting
from oephys2nix.stimulus_recreation import StimulusToNix
from oephys2nix.tonix import RawToNix
@@ -18,7 +21,43 @@ console = Console()
@app.command()
def main(
def append_sorting(
sorter_name: str = typer.Argument(
"sorting_analyzser",
help="The sorter name that should be appended to the generated nix file",
),
data_path: Path | None = typer.Argument(
None,
help="The source directory containing the generated recording.",
exists=True,
file_okay=False,
dir_okay=True,
readable=True,
resolve_path=True,
),
overwrite: bool = typer.Option(default=True, help="Overwrites the sorter"),
verbose: Annotated[int, typer.Option("--verbose", "-v", count=True)] = 0,
) -> None:
"""Combines open ephys data with relacs data from data_path to a new nix file."""
setup_logging(logging.getLogger("oephys2nix"), verbosity=verbose)
if data_path is None:
data_path = Path.cwd()
log.info(f"Selected path is {data_path}")
rec_data_paths = list(Path(data_path).rglob("*recording.nix"))
log.debug(rec_data_paths)
for recording in rec_data_paths:
parent = recording.parent
sorter_path = parent / sorter_name
if not (sorter_path).is_dir:
log.error(f"Could not find the sorter that was specifided in {parent}")
sys.exit(1)
sorter_cls = AppendSorting(sorter_path, recording)
@app.command()
def convert(
data_path: Path = typer.Argument(
...,
help="The source directory containing the Open Ephys data.",
@@ -92,32 +131,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):

96
oephys2nix/sorting.py Normal file
View File

@@ -0,0 +1,96 @@
import logging
import pathlib
import nixio
import numpy as np
import spikeinterface.core as si
from nixio.exceptions import DuplicateName
from rich.console import Console
log = logging.getLogger(__name__)
console = Console()
class AppendSorting:
"""Append the sorting analyzser or a sortign form spikeinterface to the created nix file.
Parameters
----------
sorter_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
"""
def __init__(self, sorter_path: pathlib.Path, recording_path: pathlib.Path):
self.sorter_path = sorter_path
self.recording_path = recording_path
self.sorting = si.load_sorting_analyzer(self.sorter_path)
self.nixfile = nixio.File.open(str(self.recording_path), nixio.FileMode.ReadWrite)
self.block = self.nixfile.blocks[0]
self.das = self.block.data_arrays
self.channel_ids = si.get_template_extremum_channel(
self.sorting, mode="extremum", peak_sign="neg", outputs="index"
)
self.data = self.block.data_arrays["data"]
self._clean()
self.append_sorting_to_recording()
def append_sorting_to_recording(self):
try:
gr = self.block.create_group("units", "sorting.group")
except DuplicateName:
del self.block.groups["units"]
gr = self.block.create_group("units", "sorting.group")
for unit in self.sorting.unit_ids:
spike_times = self.sorting.sorting.get_unit_spike_train_in_seconds(
unit, segment_index=0
)
unit_channel = self.channel_ids[unit]
channel_tag = np.repeat(unit_channel, spike_times.shape[0])
multi_tag_positions = np.column_stack((spike_times, channel_tag))
try:
positions = self.block.create_data_array(
f"unit-{unit}", "sorting.spike_index", data=spike_times
)
positions.append_range_dimension_using_self()
except DuplicateName:
del self.das[f"unit-{unit}"]
positions = self.block.create_data_array(
f"unit-{unit}", "sorting.spike_index", data=spike_times
)
positions.append_range_dimension_using_self()
gr.data_arrays.append(positions)
try:
multi_tag = self.block.create_multi_tag(
f"unit-{unit}", "sorting.spike_index", multi_tag_positions
)
multi_tag.references.append(self.data)
except DuplicateName:
del self.block.multi_tags[f"unit-{unit}"]
del self.das[f"unit-{unit}-positions"]
multi_tag = self.block.create_multi_tag(
f"unit-{unit}", "sorting.spike_index", multi_tag_positions
)
multi_tag.references.append(self.data)
gr.mulit_tags.append(positions)
def _clean(self):
try:
gr = self.block.groups["units"]
except IndexError:
return
for das in gr.data_arrays:
del self.das[das.name]
for mtag in gr.multi_tags:
del self.block.mulit_tags[mtag.name]
del self.das[mtag.name + "-positions"]
def close(self):
self.nixfile.close()

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,22 @@ 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):
self._append_features(repro, nix_mtag)
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 +323,48 @@ class StimulusToNix:
nix_group = self.nix_file.blocks[0].groups[repro.name]
nix_group.tags.append(nix_tag)
def create_repros_automatically(self):
def _append_features(self, repro, mtag):
s = repro.stimuli[0]
if not s.features:
log.debug(f"Repro {repro.name} does not have a feature in multitags")
return
das_names = [f[1] for f in s.features]
for das in das_names:
arr = self.relacs_block.data_arrays[das]
if arr.data.dtype == object:
data = arr.data[:].astype(np.dtypes.StringDType)
else:
data = arr.data[:]
try:
f = self.block.create_data_array(
arr.name,
arr.type,
data=data,
unit=arr.unit,
label=arr.label,
)
except DuplicateName:
f = self.block.data_arrays[arr.name]
for d in arr.dimensions:
if d.dimension_type == nixio.DimensionType.Set:
f.append_set_dimension(labels=d.labels)
elif d.dimension_type == nixio.DimensionType.Range:
f.append_range_dimension(
np.sort(d.ticks),
labels=d.labels,
)
else:
f.append_sampled_dimension(
d.sampling_interval,
labels=d.labels,
)
mtag.create_feature(f, nixio.LinkType.Indexed)
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 +377,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,
@@ -228,7 +391,6 @@ class StimulusToNix:
if repro.duration < 0.05:
log.warning(f"Skipping repro {repro.name} because it is two short")
continue
if repro.stimuli:
log.debug("Processing MultiTag")
repetition = len(repro.stimuli)
@@ -244,7 +406,10 @@ class StimulusToNix:
time_ttl, peaks_ttl, current_position
)
# current_position = position_mtags[-1]
if "FICurve_" in repro.name:
delay = repro.stimuli[0].feature_data(1).item()
extents_mtag += delay
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 +447,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 +596,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 +611,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 +677,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

@@ -1,5 +1,6 @@
import logging
import pathlib
import sys
import nixio
import numpy as np
@@ -14,6 +15,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 +56,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 +65,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 = [
@@ -46,7 +79,7 @@ class RawToNix:
efish_group = self.block.create_group("efish", "open-ephys.sampled")
efish_neo_data = self.neo_data[0].segments[0].analogsignals[2].load()
efish_neo_data = self._load_neo_object(["Data_ADC", "acquisition_board_ADC"])
for i in np.arange(len(efishs)):
log.debug(f"Appending efish traces {efishs[i]}")
@@ -63,7 +96,16 @@ class RawToNix:
)
efish_group.data_arrays.append(data_array)
def append_relacs_lines(self):
def _load_neo_object(self, names: list[str]):
for sig in self.neo_data[0].segments[0].analogsignals:
if any([sig.name.endswith(n) for n in names]):
return sig.load()
log.error(f"No {names} found in open ephys data")
sys.exit(1)
def append_relacs_lines(self) -> None:
"""Append relacs lines."""
relacs = [
"V-1",
"EOD",
@@ -96,24 +138,31 @@ class RawToNix:
label=efish_relacs_data_array.label,
unit=efish_relacs_data_array.unit,
)
if efish_relacs_data_array.dimensions[0].dimension_type == nixio.DimensionType.Sample:
data_array.append_sampled_dimension(
efish_relacs_data_array.dimensions[0].sampling_interval,
label="time",
unit="s",
)
elif efish_relacs_data_array.dimensions[0].dimension_type == nixio.DimensionType.Range:
data_array.append_range_dimension(
np.sort(efish_relacs_data_array.dimensions[0].ticks),
label="time",
unit="s",
)
for d in efish_relacs_data_array.dimensions:
if d.dimension_type == nixio.DimensionType.Sample:
data_array.append_sampled_dimension(
efish_relacs_data_array.dimensions[0].sampling_interval,
label="time",
unit="s",
)
elif d.dimension_type == nixio.DimensionType.Range:
data_array.append_range_dimension(
np.sort(efish_relacs_data_array.dimensions[0].ticks),
label="time",
unit="s",
)
else:
data_array.append_set_dimension(
label="time",
unit="s",
)
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()
raw_neo_data = self._load_neo_object(["Data", "acquisition_board"])
log.debug("Appending raw data")
nix_data_array = self.block.create_data_array(
@@ -126,8 +175,10 @@ class RawToNix:
nix_data_array.append_sampled_dimension(
1 / raw_neo_data.sampling_rate.magnitude, label="time", unit="s"
)
nix_data_array.append_sampled_dimension(1, label="channel")
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()

View File

@@ -1,20 +1,25 @@
[project]
name = "oepyhs2nix"
version = "0.1.0"
version = "0.1.1"
description = "Converting ophen-ephys data to nix format"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"ipython>=9.6.0",
"matplotlib>=3.10.6",
"neo>=0.14.2",
"nixio>=1.5.4",
"pyqt6>=6.11.0",
"rich>=14.1.0",
"rlxnix",
"scikit-learn>=1.8.0",
"scipy>=1.16.2",
"spikeinterface>=0.104.3",
"typer>=0.19.2",
]
[project.scripts]
oephys2nix = "oephys2nix.main:app"
oe2n = "oephys2nix.main:app"
[project.optional-dependencies]
docs = [

271
uv.lock generated
View File

@@ -93,6 +93,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419, upload_time = "2023-09-30T22:11:16.072Z" },
]
[[package]]
name = "asciitree"
version = "0.3.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2d/6a/885bc91484e1aa8f618f6f0228d76d0e67000b0fdd6090673b777e311913/asciitree-0.3.3.tar.gz", hash = "sha256:4aa4b9b649f85e3fcb343363d97564aa1fb62e249677f2e18a96765145cc0f6e", size = 3951, upload_time = "2016-09-05T19:10:42.681Z" }
[[package]]
name = "asttokens"
version = "3.0.0"
@@ -403,6 +409,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload_time = "2021-03-08T10:59:24.45Z" },
]
[[package]]
name = "deprecated"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "wrapt" },
]
sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload_time = "2025-10-30T08:19:02.757Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload_time = "2025-10-30T08:19:00.758Z" },
]
[[package]]
name = "executing"
version = "2.2.1"
@@ -412,6 +430,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload_time = "2025-09-01T09:48:08.5Z" },
]
[[package]]
name = "fasteners"
version = "0.20"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2d/18/7881a99ba5244bfc82f06017316ffe93217dbbbcfa52b887caa1d4f2a6d3/fasteners-0.20.tar.gz", hash = "sha256:55dce8792a41b56f727ba6e123fcaee77fd87e638a6863cec00007bfea84c8d8", size = 25087, upload_time = "2025-08-11T10:19:37.785Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl", hash = "sha256:9422c40d1e350e4259f509fb2e608d6bc43c0136f79a00db1b49046029d0b3b7", size = 18702, upload_time = "2025-08-11T10:19:35.716Z" },
]
[[package]]
name = "fastjsonschema"
version = "2.21.2"
@@ -667,6 +694,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload_time = "2025-03-05T20:05:00.369Z" },
]
[[package]]
name = "joblib"
version = "1.5.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload_time = "2025-12-15T08:41:46.427Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload_time = "2025-12-15T08:41:44.973Z" },
]
[[package]]
name = "json5"
version = "0.12.1"
@@ -1208,16 +1244,16 @@ wheels = [
[[package]]
name = "neo"
version = "0.14.2"
version = "0.14.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
{ name = "packaging" },
{ name = "quantities" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0e/47/ebc266619ea7f1e8025ba057ab446c14423b1265ec9c6810fa3a3fb02de4/neo-0.14.2.tar.gz", hash = "sha256:76517503e114fffcc38aa3600c04dd8be48b1ee5e2c8162bc0db8fb92476811f", size = 5067423, upload_time = "2025-07-08T13:12:54.508Z" }
sdist = { url = "https://files.pythonhosted.org/packages/7f/b1/e9228d616c817098b673ab990e82acb431856559f4e0235a687854df1ef4/neo-0.14.4.tar.gz", hash = "sha256:cbe24031c514543005ec698d8fe024b95a0839e9efd469bf6f8290dc3d86b3b5", size = 5085927, upload_time = "2026-03-12T09:59:56.893Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/e1/16f4f07a65bb952eb99897a4ad6fedbec9e3d8a394e5baa2bc3a97713e0e/neo-0.14.2-py3-none-any.whl", hash = "sha256:ca4e605ffdba944e53cd035e43c0dbeff45efbb1ed00ae0c61c0d49f08ef2b94", size = 679538, upload_time = "2025-07-08T13:12:52.062Z" },
{ url = "https://files.pythonhosted.org/packages/ac/66/93359047a9c7ede7c6319f58b2cee3be19552f57ef5380fe95cb812272fb/neo-0.14.4-py3-none-any.whl", hash = "sha256:0cd863424e35dddd768d713cfcc48cb06ab127fe1b5b132a0793c82975de5be4", size = 697727, upload_time = "2026-03-12T09:59:54.609Z" },
]
[[package]]
@@ -1268,6 +1304,22 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload_time = "2024-02-14T23:35:16.286Z" },
]
[[package]]
name = "numcodecs"
version = "0.15.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "deprecated" },
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/63/fc/bb532969eb8236984ba65e4f0079a7da885b8ac0ce1f0835decbb3938a62/numcodecs-0.15.1.tar.gz", hash = "sha256:eeed77e4d6636641a2cc605fbc6078c7a8f2cc40f3dfa2b3f61e52e6091b04ff", size = 6267275, upload_time = "2025-02-10T10:23:33.254Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/78/57/acbc54b3419e5be65015e47177c76c0a73e037fd3ae2cde5808169194d4d/numcodecs-0.15.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3d82b70500cf61e8d115faa0d0a76be6ecdc24a16477ee3279d711699ad85f3", size = 1688220, upload_time = "2025-02-10T10:23:23.79Z" },
{ url = "https://files.pythonhosted.org/packages/b6/56/9863fa6dc679f40a31bea5e9713ee5507a31dcd3ee82ea4b1a9268ce52e8/numcodecs-0.15.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1d471a1829ce52d3f365053a2bd1379e32e369517557c4027ddf5ac0d99c591e", size = 1180294, upload_time = "2025-02-10T10:23:25.533Z" },
{ url = "https://files.pythonhosted.org/packages/fa/91/d96999b41e3146b6c0ce6bddc5ad85803cb4d743c95394562c2a4bb8cded/numcodecs-0.15.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dfdea4a67108205edfce99c1cb6cd621343bc7abb7e16a041c966776920e7de", size = 8834323, upload_time = "2025-02-10T10:23:27.46Z" },
{ url = "https://files.pythonhosted.org/packages/c3/32/233e5ede6568bdb044e6f99aaa9fa39827ff3109c6487fc137315f733586/numcodecs-0.15.1-cp313-cp313-win_amd64.whl", hash = "sha256:a4f7bdb26f1b34423cb56d48e75821223be38040907c9b5954eeb7463e7eb03c", size = 831955, upload_time = "2025-02-10T10:23:30.601Z" },
]
[[package]]
name = "numpy"
version = "2.3.3"
@@ -1322,15 +1374,19 @@ wheels = [
[[package]]
name = "oepyhs2nix"
version = "0.1.0"
version = "0.1.1"
source = { virtual = "." }
dependencies = [
{ name = "ipython" },
{ name = "matplotlib" },
{ name = "neo" },
{ name = "nixio" },
{ name = "pyqt6" },
{ name = "rich" },
{ name = "rlxnix" },
{ name = "scikit-learn" },
{ name = "scipy" },
{ name = "spikeinterface" },
{ name = "typer" },
]
@@ -1345,17 +1401,21 @@ docs = [
[package.metadata]
requires-dist = [
{ name = "ipython", specifier = ">=9.6.0" },
{ name = "jupyter", marker = "extra == 'docs'", specifier = ">=1.1.1" },
{ name = "jupyterlab", marker = "extra == 'docs'", specifier = ">=4.4.9" },
{ name = "matplotlib", specifier = ">=3.10.6" },
{ name = "neo", specifier = ">=0.14.2" },
{ name = "nixio", specifier = ">=1.5.4" },
{ name = "plotly", marker = "extra == 'docs'", specifier = ">=6.3.1" },
{ name = "pyqt6", specifier = ">=6.11.0" },
{ name = "quartodoc", marker = "extra == 'docs'", specifier = ">=0.11.1" },
{ name = "rich", specifier = ">=14.1.0" },
{ name = "rlxnix", git = "https://github.com/wendtalexander/relacsed_nix.git?branch=open-ephys" },
{ name = "scikit-learn", specifier = ">=1.8.0" },
{ name = "scipy", specifier = ">=1.16.2" },
{ name = "scipy", marker = "extra == 'docs'", specifier = ">=1.16.2" },
{ name = "spikeinterface", specifier = ">=0.104.3" },
{ name = "typer", specifier = ">=0.19.2" },
]
provides-extras = ["docs"]
@@ -1539,6 +1599,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/2b/31/21609a9be48e877bc33b089a7f495c853215def5aeb9564a31c210d9d769/plum_dispatch-2.5.7-py3-none-any.whl", hash = "sha256:06471782eea0b3798c1e79dca2af2165bafcfa5eb595540b514ddd81053b1ede", size = 42612, upload_time = "2025-01-17T20:07:26.461Z" },
]
[[package]]
name = "probeinterface"
version = "0.3.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
{ name = "packaging" },
{ name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ad/b6/149976dac9228c39a80fd1dee1743b3ba8e878b8c425df4304a7ac395aa1/probeinterface-0.3.2.tar.gz", hash = "sha256:8cf02afb1f344be027e1f29e7a2c54fd35b38573ad77890fc5076f957ddf3db5", size = 6681139, upload_time = "2026-03-20T16:06:09.401Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c9/c9/7cd477fa3cc6e31b643c1ca8d13a7b398fa8c2b6a9c5926cab916729cf43/probeinterface-0.3.2-py3-none-any.whl", hash = "sha256:f288d013697a73836384a9ee8db6bc979764814b981b6730d463d3bd04d5f317", size = 68822, upload_time = "2026-03-20T16:06:08.059Z" },
]
[[package]]
name = "prometheus-client"
version = "0.23.1"
@@ -1664,6 +1738,54 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload_time = "2025-09-21T04:11:04.117Z" },
]
[[package]]
name = "pyqt6"
version = "6.11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyqt6-qt6" },
{ name = "pyqt6-sip" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8b/47/b25c13eca5bebc6505394d0223e46d7ebf0c57dcac2ed908d7d19b18ab6b/pyqt6-6.11.0.tar.gz", hash = "sha256:45dd60aa69976de1918b5ced6b4e7b6a25abd2a919ecef5fd5826ecc76718889", size = 1087430, upload_time = "2026-03-30T09:16:13.543Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/33/44/fcd3dd3f64c83c96bf9bce76ec16cca64bd9b91702c3d08fd8e3dafc73d9/pyqt6-6.11.0-cp310-abi3-macosx_10_14_universal2.whl", hash = "sha256:f7100bc7f72b12581ec479a733f4ad11b8002668e6786e8a445ab6f4d1c743d4", size = 12429735, upload_time = "2026-03-30T09:16:03.713Z" },
{ url = "https://files.pythonhosted.org/packages/c3/a0/bd1399740dfa80c0a94d20b02d89962a31458233dcf70eaa09bfbccf3d0f/pyqt6-6.11.0-cp310-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8555277989fa7d114cb3c3443fd261d566909f7268ceedd41d93a5f02d37ec05", size = 8334632, upload_time = "2026-03-30T09:16:06.066Z" },
{ url = "https://files.pythonhosted.org/packages/d3/db/425b184ac2430ba1978bb507ffd285ec007a872644e2ae5df13332dbcb05/pyqt6-6.11.0-cp310-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:0734959955adde095af9a074213a7f73386d1bbbddfc27346b4c0621641a692e", size = 8321484, upload_time = "2026-03-30T09:16:08.135Z" },
{ url = "https://files.pythonhosted.org/packages/6f/85/dd9f03d78d87460e109e0121cd6201c5802bdd655656bf2780e964870fea/pyqt6-6.11.0-cp310-abi3-win_amd64.whl", hash = "sha256:bd11b459c54dca068e988a42cf838303334f0d441b9d16d92ae6719fcb5ac6ba", size = 6844358, upload_time = "2026-03-30T09:16:09.766Z" },
{ url = "https://files.pythonhosted.org/packages/cd/75/970b041bde4372cc6739c5ef9db1de83a6b36e788e4992e598baa35b2255/pyqt6-6.11.0-cp310-abi3-win_arm64.whl", hash = "sha256:b6324e3501b19b4292c7a55b1f22e82d3e80e519e383ce4fe79b4a754c6f0288", size = 5933984, upload_time = "2026-03-30T09:16:11.817Z" },
]
[[package]]
name = "pyqt6-qt6"
version = "6.11.0"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/eb/5e/9e65b87ba746bb3a2ee81d6f3b2a8a7a4dfc33335c0a6afa15e8621e5fe9/pyqt6_qt6-6.11.0-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:447b04baf9bfd800410dc6a3b6faf24a2b754bd6e1c5d0dc609e6935362828f3", size = 70238920, upload_time = "2026-03-24T15:01:22.753Z" },
{ url = "https://files.pythonhosted.org/packages/eb/b2/a15f88a0d9f550b9581592f79fb64b827ab3d3343cbb2af05912e6c77d26/pyqt6_qt6-6.11.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b510d0cb8f4d3f4306b6ff33a63234139c9c87c160909d3853e4deb1094782c2", size = 64036460, upload_time = "2026-03-24T15:01:42.951Z" },
{ url = "https://files.pythonhosted.org/packages/b5/f9/99696e6b2325ae54868111f581c59a8a6283b8f21bc931837f49093bc582/pyqt6_qt6-6.11.0-py3-none-manylinux_2_34_x86_64.whl", hash = "sha256:c2c3a14714536256a9fd761a8ac8e030dfed7b991200a220ca79d399fcc3d265", size = 85757517, upload_time = "2026-03-24T15:02:11.86Z" },
{ url = "https://files.pythonhosted.org/packages/9d/3c/a420d08723d4ab1998afead3e6f643333e93a9eadfde3486bdec25acfff0/pyqt6_qt6-6.11.0-py3-none-manylinux_2_39_aarch64.whl", hash = "sha256:acc5b78d7f718a5642f14b37928e074b048751cc86edb4c539e4425bfbd26827", size = 84854032, upload_time = "2026-03-24T15:03:26.991Z" },
{ url = "https://files.pythonhosted.org/packages/36/cd/da0147d331b44587a7214c7f59719ac4f8e9433b268016962b02067007d1/pyqt6_qt6-6.11.0-py3-none-win_amd64.whl", hash = "sha256:b0e42629cef2575f2178aaeb32b0e539291df869f91f4df48983da3ccaad05af", size = 78309473, upload_time = "2026-03-24T15:03:53.396Z" },
{ url = "https://files.pythonhosted.org/packages/72/9a/8d09ca47a61c2504b49e16c97ccde99b120ceec323d97f7ca776f8331213/pyqt6_qt6-6.11.0-py3-none-win_arm64.whl", hash = "sha256:bcfa594171408319935c25afc7f82a3ae3ba90678ea194631bbca1c6f68daa6d", size = 59848654, upload_time = "2026-03-24T15:04:18.117Z" },
]
[[package]]
name = "pyqt6-sip"
version = "13.11.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/90/24/a753e1af94b9ae5b2da63d4598457308da3cdbf0838c959381db086ccc86/pyqt6_sip-13.11.1.tar.gz", hash = "sha256:869c5b48afe38e55b1ee0dd72182b0886e968cc509b98023ff50010b013ce1be", size = 92574, upload_time = "2026-03-09T13:01:35.418Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ee/0b/dc76c463c203e630b2c6417d4d5e337e919a265ac1c10127ef413551f5de/pyqt6_sip-13.11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0c6d097aae7df312519e2b36e001bd796f6a2ce060ab8b9ed793daa8f407fe2e", size = 112552, upload_time = "2026-03-09T13:01:21.493Z" },
{ url = "https://files.pythonhosted.org/packages/d4/e3/65b605759859d38231ce7544065d4c61f891eb7766c351318e2a0b08a473/pyqt6_sip-13.11.1-cp313-cp313-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a72f4ebdab16a8a484019ff593de90d8013d3286b678c6ba1c0bdb117f4fcb13", size = 299932, upload_time = "2026-03-09T13:01:24.912Z" },
{ url = "https://files.pythonhosted.org/packages/60/f7/c10d2dd5bf503a1de83bd163467bd323f12af016866c2814743b5b1efe1c/pyqt6_sip-13.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b68e442efc4275651bf63f2c43713e242924fd948909e31cf8f20d783ca505e9", size = 321497, upload_time = "2026-03-09T13:01:22.724Z" },
{ url = "https://files.pythonhosted.org/packages/e1/1f/e7e5ad77a76c00db5c8c1b9960f2b0672ec1978b971bb3509858cd7a9458/pyqt6_sip-13.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca24bfd4d5d8274e338433df9ac41930650088c00018d3313c6bd8de21772a02", size = 53371, upload_time = "2026-03-09T13:01:26.286Z" },
{ url = "https://files.pythonhosted.org/packages/36/ef/a7acaf44980aed6fe26f1320e265db528fecb6a47ac67829c7cd011e9821/pyqt6_sip-13.11.1-cp313-cp313-win_arm64.whl", hash = "sha256:f532144c43f2fddcccf2e25df50cdb4a744edb4ce4ba5ed2d0f2cef825197f2f", size = 48745, upload_time = "2026-03-09T13:01:27.212Z" },
{ url = "https://files.pythonhosted.org/packages/20/1d/62c633faedef5bb3b8c7486a72e8a6466adaa2a14efcfccf85bb23426748/pyqt6_sip-13.11.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:cb931c1af45294bbe8039c5cfda184e3023f5dc766fc884964010eedd8fd85db", size = 112678, upload_time = "2026-03-09T13:01:28.15Z" },
{ url = "https://files.pythonhosted.org/packages/03/72/5a3d9ffef0caa7e1bc7a35d6300f6099bfccd1d8a485b4320ba20013a2d9/pyqt6_sip-13.11.1-cp314-cp314-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:353d613129316e9f7eda6bbe821deb7b7ffa14483499189171fd8a246873f9ac", size = 299560, upload_time = "2026-03-09T13:01:32.134Z" },
{ url = "https://files.pythonhosted.org/packages/98/f4/886f901f1e04da717a11e180ba19a9c7fc62da170966d57206006f173bda/pyqt6_sip-13.11.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcadd68e09ee24cdda8f8bfcba52e59c9b297055d2c450f0eb89afa61a8dc31a", size = 321846, upload_time = "2026-03-09T13:01:29.817Z" },
{ url = "https://files.pythonhosted.org/packages/96/f2/b68fd566f7f86dbb53d933489e70487cabaea0e0161690e4899653bbc7fb/pyqt6_sip-13.11.1-cp314-cp314-win_amd64.whl", hash = "sha256:581e287bf42587593b88b30d9db06ed0fccbf40f345a5bd3ec3f00a5692e2430", size = 55055, upload_time = "2026-03-09T13:01:33.467Z" },
{ url = "https://files.pythonhosted.org/packages/8d/42/efb7ced69f7d1d31eb8f19b2d778aeb182be7e070569d02b9057ac478e3e/pyqt6_sip-13.11.1-cp314-cp314-win_arm64.whl", hash = "sha256:42b62530a9b6a9c6e29c2941b8ab78258652da0aeae4eb1fc9a0631d19a7a7b2", size = 49597, upload_time = "2026-03-09T13:01:34.49Z" },
]
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"
@@ -1809,14 +1931,14 @@ wheels = [
[[package]]
name = "quantities"
version = "0.16.2"
version = "0.16.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/40/b4/a14dbeebf8ab08600152f157344fd88db961a3afdfd0eddc25958c5182a1/quantities-0.16.2.tar.gz", hash = "sha256:1f7c24f10d9ff57ddf751a358ea2fdfa9914516722f06a788ef4a2924c77d21c", size = 101862, upload_time = "2025-04-11T14:16:12.154Z" }
sdist = { url = "https://files.pythonhosted.org/packages/aa/50/19194d2cf428239ecbda876d81bbfddb76697a248c5a7478ae83d0b98fee/quantities-0.16.4.tar.gz", hash = "sha256:f5b6deb74f6ed814ec56b204dcf7b5d3c526456157de48e5a78681064f98bf36", size = 100726, upload_time = "2026-01-16T10:43:48.858Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/17/0c/b4ee3f929bbe564101f110080dcdd33d1181a6f8a041cc9e21d992509b52/quantities-0.16.2-py3-none-any.whl", hash = "sha256:bd5b1ed422770b7cd8952ccfccaf67a89024ae0ecb31b1eacbc7ff966899ab34", size = 103021, upload_time = "2025-04-11T14:16:10.524Z" },
{ url = "https://files.pythonhosted.org/packages/cd/1f/9751abbc14422092754423d41c89b0884dba3abc236125adc427d108216a/quantities-0.16.4-py3-none-any.whl", hash = "sha256:cd8e82339eb553d8bee0bda0e41a80b91e21795e1174e7d8a82db8e6de2663f6", size = 104009, upload_time = "2026-01-16T10:43:47.252Z" },
]
[[package]]
@@ -1997,6 +2119,44 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload_time = "2025-08-27T12:15:03.961Z" },
]
[[package]]
name = "scikit-learn"
version = "1.8.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "joblib" },
{ name = "numpy" },
{ name = "scipy" },
{ name = "threadpoolctl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload_time = "2025-12-10T07:08:53.618Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/03/aa/e22e0768512ce9255eba34775be2e85c2048da73da1193e841707f8f039c/scikit_learn-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d6ae97234d5d7079dc0040990a6f7aeb97cb7fa7e8945f1999a429b23569e0a", size = 8513770, upload_time = "2025-12-10T07:08:03.251Z" },
{ url = "https://files.pythonhosted.org/packages/58/37/31b83b2594105f61a381fc74ca19e8780ee923be2d496fcd8d2e1147bd99/scikit_learn-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:edec98c5e7c128328124a029bceb09eda2d526997780fef8d65e9a69eead963e", size = 8044458, upload_time = "2025-12-10T07:08:05.336Z" },
{ url = "https://files.pythonhosted.org/packages/2d/5a/3f1caed8765f33eabb723596666da4ebbf43d11e96550fb18bdec42b467b/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74b66d8689d52ed04c271e1329f0c61635bcaf5b926db9b12d58914cdc01fe57", size = 8610341, upload_time = "2025-12-10T07:08:07.732Z" },
{ url = "https://files.pythonhosted.org/packages/38/cf/06896db3f71c75902a8e9943b444a56e727418f6b4b4a90c98c934f51ed4/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8fdf95767f989b0cfedb85f7ed8ca215d4be728031f56ff5a519ee1e3276dc2e", size = 8900022, upload_time = "2025-12-10T07:08:09.862Z" },
{ url = "https://files.pythonhosted.org/packages/1c/f9/9b7563caf3ec8873e17a31401858efab6b39a882daf6c1bfa88879c0aa11/scikit_learn-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:2de443b9373b3b615aec1bb57f9baa6bb3a9bd093f1269ba95c17d870422b271", size = 7989409, upload_time = "2025-12-10T07:08:12.028Z" },
{ url = "https://files.pythonhosted.org/packages/49/bd/1f4001503650e72c4f6009ac0c4413cb17d2d601cef6f71c0453da2732fc/scikit_learn-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:eddde82a035681427cbedded4e6eff5e57fa59216c2e3e90b10b19ab1d0a65c3", size = 7619760, upload_time = "2025-12-10T07:08:13.688Z" },
{ url = "https://files.pythonhosted.org/packages/d2/7d/a630359fc9dcc95496588c8d8e3245cc8fd81980251079bc09c70d41d951/scikit_learn-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7cc267b6108f0a1499a734167282c00c4ebf61328566b55ef262d48e9849c735", size = 8826045, upload_time = "2025-12-10T07:08:15.215Z" },
{ url = "https://files.pythonhosted.org/packages/cc/56/a0c86f6930cfcd1c7054a2bc417e26960bb88d32444fe7f71d5c2cfae891/scikit_learn-1.8.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:fe1c011a640a9f0791146011dfd3c7d9669785f9fed2b2a5f9e207536cf5c2fd", size = 8420324, upload_time = "2025-12-10T07:08:17.561Z" },
{ url = "https://files.pythonhosted.org/packages/46/1e/05962ea1cebc1cf3876667ecb14c283ef755bf409993c5946ade3b77e303/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72358cce49465d140cc4e7792015bb1f0296a9742d5622c67e31399b75468b9e", size = 8680651, upload_time = "2025-12-10T07:08:19.952Z" },
{ url = "https://files.pythonhosted.org/packages/fe/56/a85473cd75f200c9759e3a5f0bcab2d116c92a8a02ee08ccd73b870f8bb4/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80832434a6cc114f5219211eec13dcbc16c2bac0e31ef64c6d346cde3cf054cb", size = 8925045, upload_time = "2025-12-10T07:08:22.11Z" },
{ url = "https://files.pythonhosted.org/packages/cc/b7/64d8cfa896c64435ae57f4917a548d7ac7a44762ff9802f75a79b77cb633/scikit_learn-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ee787491dbfe082d9c3013f01f5991658b0f38aa8177e4cd4bf434c58f551702", size = 8507994, upload_time = "2025-12-10T07:08:23.943Z" },
{ url = "https://files.pythonhosted.org/packages/5e/37/e192ea709551799379958b4c4771ec507347027bb7c942662c7fbeba31cb/scikit_learn-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf97c10a3f5a7543f9b88cbf488d33d175e9146115a451ae34568597ba33dcde", size = 7869518, upload_time = "2025-12-10T07:08:25.71Z" },
{ url = "https://files.pythonhosted.org/packages/24/05/1af2c186174cc92dcab2233f327336058c077d38f6fe2aceb08e6ab4d509/scikit_learn-1.8.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c22a2da7a198c28dd1a6e1136f19c830beab7fdca5b3e5c8bba8394f8a5c45b3", size = 8528667, upload_time = "2025-12-10T07:08:27.541Z" },
{ url = "https://files.pythonhosted.org/packages/a8/25/01c0af38fe969473fb292bba9dc2b8f9b451f3112ff242c647fee3d0dfe7/scikit_learn-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:6b595b07a03069a2b1740dc08c2299993850ea81cce4fe19b2421e0c970de6b7", size = 8066524, upload_time = "2025-12-10T07:08:29.822Z" },
{ url = "https://files.pythonhosted.org/packages/be/ce/a0623350aa0b68647333940ee46fe45086c6060ec604874e38e9ab7d8e6c/scikit_learn-1.8.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:29ffc74089f3d5e87dfca4c2c8450f88bdc61b0fc6ed5d267f3988f19a1309f6", size = 8657133, upload_time = "2025-12-10T07:08:31.865Z" },
{ url = "https://files.pythonhosted.org/packages/b8/cb/861b41341d6f1245e6ca80b1c1a8c4dfce43255b03df034429089ca2a2c5/scikit_learn-1.8.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb65db5d7531bccf3a4f6bec3462223bea71384e2cda41da0f10b7c292b9e7c4", size = 8923223, upload_time = "2025-12-10T07:08:34.166Z" },
{ url = "https://files.pythonhosted.org/packages/76/18/a8def8f91b18cd1ba6e05dbe02540168cb24d47e8dcf69e8d00b7da42a08/scikit_learn-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:56079a99c20d230e873ea40753102102734c5953366972a71d5cb39a32bc40c6", size = 8096518, upload_time = "2025-12-10T07:08:36.339Z" },
{ url = "https://files.pythonhosted.org/packages/d1/77/482076a678458307f0deb44e29891d6022617b2a64c840c725495bee343f/scikit_learn-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:3bad7565bc9cf37ce19a7c0d107742b320c1285df7aab1a6e2d28780df167242", size = 7754546, upload_time = "2025-12-10T07:08:38.128Z" },
{ url = "https://files.pythonhosted.org/packages/2d/d1/ef294ca754826daa043b2a104e59960abfab4cf653891037d19dd5b6f3cf/scikit_learn-1.8.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:4511be56637e46c25721e83d1a9cea9614e7badc7040c4d573d75fbe257d6fd7", size = 8848305, upload_time = "2025-12-10T07:08:41.013Z" },
{ url = "https://files.pythonhosted.org/packages/5b/e2/b1f8b05138ee813b8e1a4149f2f0d289547e60851fd1bb268886915adbda/scikit_learn-1.8.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:a69525355a641bf8ef136a7fa447672fb54fe8d60cab5538d9eb7c6438543fb9", size = 8432257, upload_time = "2025-12-10T07:08:42.873Z" },
{ url = "https://files.pythonhosted.org/packages/26/11/c32b2138a85dcb0c99f6afd13a70a951bfdff8a6ab42d8160522542fb647/scikit_learn-1.8.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2656924ec73e5939c76ac4c8b026fc203b83d8900362eb2599d8aee80e4880f", size = 8678673, upload_time = "2025-12-10T07:08:45.362Z" },
{ url = "https://files.pythonhosted.org/packages/c7/57/51f2384575bdec454f4fe4e7a919d696c9ebce914590abf3e52d47607ab8/scikit_learn-1.8.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15fc3b5d19cc2be65404786857f2e13c70c83dd4782676dd6814e3b89dc8f5b9", size = 8922467, upload_time = "2025-12-10T07:08:47.408Z" },
{ url = "https://files.pythonhosted.org/packages/35/4d/748c9e2872637a57981a04adc038dacaa16ba8ca887b23e34953f0b3f742/scikit_learn-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:00d6f1d66fbcf4eba6e356e1420d33cc06c70a45bb1363cd6f6a8e4ebbbdece2", size = 8774395, upload_time = "2025-12-10T07:08:49.337Z" },
{ url = "https://files.pythonhosted.org/packages/60/22/d7b2ebe4704a5e50790ba089d5c2ae308ab6bb852719e6c3bd4f04c3a363/scikit_learn-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f28dd15c6bb0b66ba09728cf09fd8736c304be29409bd8445a080c1280619e8c", size = 8002647, upload_time = "2025-12-10T07:08:51.601Z" },
]
[[package]]
name = "scipy"
version = "1.16.2"
@@ -2116,6 +2276,26 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/63/f9/f48a8f489c8ae8930f12c558b4dd26da96791837747fca87e9da2643f12d/sphobjinv-2.3.1.3-py3-none-any.whl", hash = "sha256:41fc39f6f740a707cfe5b24c1a3a4a6e4ddbdd6429a59bf21f0b5ef1fddf932a", size = 50812, upload_time = "2025-05-26T15:18:10.636Z" },
]
[[package]]
name = "spikeinterface"
version = "0.104.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "neo" },
{ name = "numcodecs" },
{ name = "numpy" },
{ name = "packaging" },
{ name = "probeinterface" },
{ name = "pydantic" },
{ name = "threadpoolctl" },
{ name = "tqdm" },
{ name = "zarr" },
]
sdist = { url = "https://files.pythonhosted.org/packages/49/9e/29b474f64dccd4c9c65a33d60bceff22f830b2f64bb5902824721d36af41/spikeinterface-0.104.3.tar.gz", hash = "sha256:ee2f689701e8bdbf3c9f110ab8f686cbfa04736a2698bfec7327e2f21ac888b5", size = 907345, upload_time = "2026-04-22T14:54:59.085Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/52/32/89f7372b4221c18506005e8261648d29cebd816e6655882dbf9083214057/spikeinterface-0.104.3-py3-none-any.whl", hash = "sha256:58b3f3599cedc03dfa836737fdc61e1cd5dfcb6361607fe842d1ead5768f5b41", size = 1129081, upload_time = "2026-04-22T14:54:57.488Z" },
]
[[package]]
name = "stack-data"
version = "0.6.3"
@@ -2153,6 +2333,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload_time = "2024-03-12T14:34:36.569Z" },
]
[[package]]
name = "threadpoolctl"
version = "3.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload_time = "2025-03-13T13:49:23.031Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload_time = "2025-03-13T13:49:21.846Z" },
]
[[package]]
name = "tinycss2"
version = "1.4.0"
@@ -2343,6 +2532,74 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575", size = 2196503, upload_time = "2025-04-10T13:01:23.086Z" },
]
[[package]]
name = "wrapt"
version = "2.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload_time = "2026-03-06T02:53:25.134Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4c/7a/d936840735c828b38d26a854e85d5338894cda544cb7a85a9d5b8b9c4df7/wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b", size = 61259, upload_time = "2026-03-06T02:53:41.922Z" },
{ url = "https://files.pythonhosted.org/packages/5e/88/9a9b9a90ac8ca11c2fdb6a286cb3a1fc7dd774c00ed70929a6434f6bc634/wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e", size = 61851, upload_time = "2026-03-06T02:52:48.672Z" },
{ url = "https://files.pythonhosted.org/packages/03/a9/5b7d6a16fd6533fed2756900fc8fc923f678179aea62ada6d65c92718c00/wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb", size = 121446, upload_time = "2026-03-06T02:54:14.013Z" },
{ url = "https://files.pythonhosted.org/packages/45/bb/34c443690c847835cfe9f892be78c533d4f32366ad2888972c094a897e39/wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca", size = 123056, upload_time = "2026-03-06T02:54:10.829Z" },
{ url = "https://files.pythonhosted.org/packages/93/b9/ff205f391cb708f67f41ea148545f2b53ff543a7ac293b30d178af4d2271/wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267", size = 117359, upload_time = "2026-03-06T02:53:03.623Z" },
{ url = "https://files.pythonhosted.org/packages/1f/3d/1ea04d7747825119c3c9a5e0874a40b33594ada92e5649347c457d982805/wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f", size = 121479, upload_time = "2026-03-06T02:53:45.844Z" },
{ url = "https://files.pythonhosted.org/packages/78/cc/ee3a011920c7a023b25e8df26f306b2484a531ab84ca5c96260a73de76c0/wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8", size = 116271, upload_time = "2026-03-06T02:54:46.356Z" },
{ url = "https://files.pythonhosted.org/packages/98/fd/e5ff7ded41b76d802cf1191288473e850d24ba2e39a6ec540f21ae3b57cb/wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413", size = 120573, upload_time = "2026-03-06T02:52:50.163Z" },
{ url = "https://files.pythonhosted.org/packages/47/c5/242cae3b5b080cd09bacef0591691ba1879739050cc7c801ff35c8886b66/wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6", size = 58205, upload_time = "2026-03-06T02:53:47.494Z" },
{ url = "https://files.pythonhosted.org/packages/12/69/c358c61e7a50f290958809b3c61ebe8b3838ea3e070d7aac9814f95a0528/wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1", size = 60452, upload_time = "2026-03-06T02:53:30.038Z" },
{ url = "https://files.pythonhosted.org/packages/8e/66/c8a6fcfe321295fd8c0ab1bd685b5a01462a9b3aa2f597254462fc2bc975/wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf", size = 58842, upload_time = "2026-03-06T02:52:52.114Z" },
{ url = "https://files.pythonhosted.org/packages/da/55/9c7052c349106e0b3f17ae8db4b23a691a963c334de7f9dbd60f8f74a831/wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b", size = 63075, upload_time = "2026-03-06T02:53:19.108Z" },
{ url = "https://files.pythonhosted.org/packages/09/a8/ce7b4006f7218248dd71b7b2b732d0710845a0e49213b18faef64811ffef/wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18", size = 63719, upload_time = "2026-03-06T02:54:33.452Z" },
{ url = "https://files.pythonhosted.org/packages/e4/e5/2ca472e80b9e2b7a17f106bb8f9df1db11e62101652ce210f66935c6af67/wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d", size = 152643, upload_time = "2026-03-06T02:52:42.721Z" },
{ url = "https://files.pythonhosted.org/packages/36/42/30f0f2cefca9d9cbf6835f544d825064570203c3e70aa873d8ae12e23791/wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015", size = 158805, upload_time = "2026-03-06T02:54:25.441Z" },
{ url = "https://files.pythonhosted.org/packages/bb/67/d08672f801f604889dcf58f1a0b424fe3808860ede9e03affc1876b295af/wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92", size = 145990, upload_time = "2026-03-06T02:53:57.456Z" },
{ url = "https://files.pythonhosted.org/packages/68/a7/fd371b02e73babec1de6ade596e8cd9691051058cfdadbfd62a5898f3295/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf", size = 155670, upload_time = "2026-03-06T02:54:55.309Z" },
{ url = "https://files.pythonhosted.org/packages/86/2d/9fe0095dfdb621009f40117dcebf41d7396c2c22dca6eac779f4c007b86c/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67", size = 144357, upload_time = "2026-03-06T02:54:24.092Z" },
{ url = "https://files.pythonhosted.org/packages/0e/b6/ec7b4a254abbe4cde9fa15c5d2cca4518f6b07d0f1b77d4ee9655e30280e/wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a", size = 150269, upload_time = "2026-03-06T02:53:31.268Z" },
{ url = "https://files.pythonhosted.org/packages/6e/6b/2fabe8ebf148f4ee3c782aae86a795cc68ffe7d432ef550f234025ce0cfa/wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd", size = 59894, upload_time = "2026-03-06T02:54:15.391Z" },
{ url = "https://files.pythonhosted.org/packages/ca/fb/9ba66fc2dedc936de5f8073c0217b5d4484e966d87723415cc8262c5d9c2/wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f", size = 63197, upload_time = "2026-03-06T02:54:41.943Z" },
{ url = "https://files.pythonhosted.org/packages/c0/1c/012d7423c95d0e337117723eb8ecf73c622ce15a97847e84cf3f8f26cd7e/wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679", size = 60363, upload_time = "2026-03-06T02:54:48.093Z" },
{ url = "https://files.pythonhosted.org/packages/39/25/e7ea0b417db02bb796182a5316398a75792cd9a22528783d868755e1f669/wrapt-2.1.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1370e516598854e5b4366e09ce81e08bfe94d42b0fd569b88ec46cc56d9164a9", size = 61418, upload_time = "2026-03-06T02:53:55.706Z" },
{ url = "https://files.pythonhosted.org/packages/ec/0f/fa539e2f6a770249907757eaeb9a5ff4deb41c026f8466c1c6d799088a9b/wrapt-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6de1a3851c27e0bd6a04ca993ea6f80fc53e6c742ee1601f486c08e9f9b900a9", size = 61914, upload_time = "2026-03-06T02:52:53.37Z" },
{ url = "https://files.pythonhosted.org/packages/53/37/02af1867f5b1441aaeda9c82deed061b7cd1372572ddcd717f6df90b5e93/wrapt-2.1.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:de9f1a2bbc5ac7f6012ec24525bdd444765a2ff64b5985ac6e0692144838542e", size = 120417, upload_time = "2026-03-06T02:54:30.74Z" },
{ url = "https://files.pythonhosted.org/packages/c3/b7/0138a6238c8ba7476c77cf786a807f871672b37f37a422970342308276e7/wrapt-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:970d57ed83fa040d8b20c52fe74a6ae7e3775ae8cff5efd6a81e06b19078484c", size = 122797, upload_time = "2026-03-06T02:54:51.539Z" },
{ url = "https://files.pythonhosted.org/packages/e1/ad/819ae558036d6a15b7ed290d5b14e209ca795dd4da9c58e50c067d5927b0/wrapt-2.1.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3969c56e4563c375861c8df14fa55146e81ac11c8db49ea6fb7f2ba58bc1ff9a", size = 117350, upload_time = "2026-03-06T02:54:37.651Z" },
{ url = "https://files.pythonhosted.org/packages/8b/2d/afc18dc57a4600a6e594f77a9ae09db54f55ba455440a54886694a84c71b/wrapt-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:57d7c0c980abdc5f1d98b11a2aa3bb159790add80258c717fa49a99921456d90", size = 121223, upload_time = "2026-03-06T02:54:35.221Z" },
{ url = "https://files.pythonhosted.org/packages/b9/5b/5ec189b22205697bc56eb3b62aed87a1e0423e9c8285d0781c7a83170d15/wrapt-2.1.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:776867878e83130c7a04237010463372e877c1c994d449ca6aaafeab6aab2586", size = 116287, upload_time = "2026-03-06T02:54:19.654Z" },
{ url = "https://files.pythonhosted.org/packages/f7/2d/f84939a7c9b5e6cdd8a8d0f6a26cabf36a0f7e468b967720e8b0cd2bdf69/wrapt-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fab036efe5464ec3291411fabb80a7a39e2dd80bae9bcbeeca5087fdfa891e19", size = 119593, upload_time = "2026-03-06T02:54:16.697Z" },
{ url = "https://files.pythonhosted.org/packages/0b/fe/ccd22a1263159c4ac811ab9374c061bcb4a702773f6e06e38de5f81a1bdc/wrapt-2.1.2-cp314-cp314-win32.whl", hash = "sha256:e6ed62c82ddf58d001096ae84ce7f833db97ae2263bff31c9b336ba8cfe3f508", size = 58631, upload_time = "2026-03-06T02:53:06.498Z" },
{ url = "https://files.pythonhosted.org/packages/65/0a/6bd83be7bff2e7efaac7b4ac9748da9d75a34634bbbbc8ad077d527146df/wrapt-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:467e7c76315390331c67073073d00662015bb730c566820c9ca9b54e4d67fd04", size = 60875, upload_time = "2026-03-06T02:53:50.252Z" },
{ url = "https://files.pythonhosted.org/packages/6c/c0/0b3056397fe02ff80e5a5d72d627c11eb885d1ca78e71b1a5c1e8c7d45de/wrapt-2.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:da1f00a557c66225d53b095a97eace0fc5349e3bfda28fa34ffae238978ee575", size = 59164, upload_time = "2026-03-06T02:53:59.128Z" },
{ url = "https://files.pythonhosted.org/packages/71/ed/5d89c798741993b2371396eb9d4634f009ff1ad8a6c78d366fe2883ea7a6/wrapt-2.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:62503ffbc2d3a69891cf29beeaccdb4d5e0a126e2b6a851688d4777e01428dbb", size = 63163, upload_time = "2026-03-06T02:52:54.873Z" },
{ url = "https://files.pythonhosted.org/packages/c6/8c/05d277d182bf36b0a13d6bd393ed1dec3468a25b59d01fba2dd70fe4d6ae/wrapt-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c7e6cd120ef837d5b6f860a6ea3745f8763805c418bb2f12eeb1fa6e25f22d22", size = 63723, upload_time = "2026-03-06T02:52:56.374Z" },
{ url = "https://files.pythonhosted.org/packages/f4/27/6c51ec1eff4413c57e72d6106bb8dec6f0c7cdba6503d78f0fa98767bcc9/wrapt-2.1.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3769a77df8e756d65fbc050333f423c01ae012b4f6731aaf70cf2bef61b34596", size = 152652, upload_time = "2026-03-06T02:53:23.79Z" },
{ url = "https://files.pythonhosted.org/packages/db/4c/d7dd662d6963fc7335bfe29d512b02b71cdfa23eeca7ab3ac74a67505deb/wrapt-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a76d61a2e851996150ba0f80582dd92a870643fa481f3b3846f229de88caf044", size = 158807, upload_time = "2026-03-06T02:53:35.742Z" },
{ url = "https://files.pythonhosted.org/packages/b4/4d/1e5eea1a78d539d346765727422976676615814029522c76b87a95f6bcdd/wrapt-2.1.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6f97edc9842cf215312b75fe737ee7c8adda75a89979f8e11558dfff6343cc4b", size = 146061, upload_time = "2026-03-06T02:52:57.574Z" },
{ url = "https://files.pythonhosted.org/packages/89/bc/62cabea7695cd12a288023251eeefdcb8465056ddaab6227cb78a2de005b/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4006c351de6d5007aa33a551f600404ba44228a89e833d2fadc5caa5de8edfbf", size = 155667, upload_time = "2026-03-06T02:53:39.422Z" },
{ url = "https://files.pythonhosted.org/packages/e9/99/6f2888cd68588f24df3a76572c69c2de28287acb9e1972bf0c83ce97dbc1/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a9372fc3639a878c8e7d87e1556fa209091b0a66e912c611e3f833e2c4202be2", size = 144392, upload_time = "2026-03-06T02:54:22.41Z" },
{ url = "https://files.pythonhosted.org/packages/40/51/1dfc783a6c57971614c48e361a82ca3b6da9055879952587bc99fe1a7171/wrapt-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3144b027ff30cbd2fca07c0a87e67011adb717eb5f5bd8496325c17e454257a3", size = 150296, upload_time = "2026-03-06T02:54:07.848Z" },
{ url = "https://files.pythonhosted.org/packages/6c/38/cbb8b933a0201076c1f64fc42883b0023002bdc14a4964219154e6ff3350/wrapt-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:3b8d15e52e195813efe5db8cec156eebe339aaf84222f4f4f051a6c01f237ed7", size = 60539, upload_time = "2026-03-06T02:54:00.594Z" },
{ url = "https://files.pythonhosted.org/packages/82/dd/e5176e4b241c9f528402cebb238a36785a628179d7d8b71091154b3e4c9e/wrapt-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:08ffa54146a7559f5b8df4b289b46d963a8e74ed16ba3687f99896101a3990c5", size = 63969, upload_time = "2026-03-06T02:54:39Z" },
{ url = "https://files.pythonhosted.org/packages/5c/99/79f17046cf67e4a95b9987ea129632ba8bcec0bc81f3fb3d19bdb0bd60cd/wrapt-2.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:72aaa9d0d8e4ed0e2e98019cea47a21f823c9dd4b43c7b77bba6679ffcca6a00", size = 60554, upload_time = "2026-03-06T02:53:14.132Z" },
{ url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload_time = "2026-03-06T02:53:12.905Z" },
]
[[package]]
name = "zarr"
version = "2.18.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asciitree" },
{ name = "fasteners", marker = "sys_platform != 'emscripten'" },
{ name = "numcodecs" },
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/da/1d/01cf9e3ab2d85190278efc3fca9f68563de35ae30ee59e7640e3af98abe3/zarr-2.18.7.tar.gz", hash = "sha256:b2b8f66f14dac4af66b180d2338819981b981f70e196c9a66e6bfaa9e59572f5", size = 3604558, upload_time = "2025-04-09T07:59:28.482Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5e/d8/9ffd8c237b3559945bb52103cf0eed64ea098f7b7f573f8d2962ef27b4b2/zarr-2.18.7-py3-none-any.whl", hash = "sha256:ac3dc4033e9ae4e9d7b5e27c97ea3eaf1003cc0a07f010bd83d5134bf8c4b223", size = 211273, upload_time = "2025-04-09T07:59:27.039Z" },
]
[[package]]
name = "zipp"
version = "3.23.0"