Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
9ac237c
Remove find/replace corruption from the class-rename commit
audristroyer Jun 10, 2026
339c8d3
Rebuild cloud sync engine for correctness (C1-C4)
audristroyer Jun 10, 2026
5efd281
Fix cloud API contract drift and add 5xx retry
audristroyer Jun 10, 2026
f27d5e6
Make ndi.neuron constructable so sorted units round-trip (C8b)
audristroyer Jun 10, 2026
6359df2
Port time-conversion branches, rule daqsystem, and VHSB I/O (C5, C7, C8)
audristroyer Jun 10, 2026
3f9c6b5
Port addunderlyingepochs + missing-node retry + dest time filter (C6,…
audristroyer Jun 10, 2026
38f6978
Add session/dataset isIngested, convertLinkedSessionToIngested, stimu…
audristroyer Jun 10, 2026
3703cf3
Merge branch 'fix/time-system' into fix/element-addmultiple
audristroyer Jun 10, 2026
769a16d
Add ndi.element.timeseries.addMultiple — batched bulk element creation
audristroyer Jun 10, 2026
7b9d5d5
DAQ parity: epochprobemap header/arrays (C10), mfdaq analog-event typ…
audristroyer Jun 10, 2026
bfb1cb5
epoch parity: epochgraph (cost,mapping) + matchedepochtable hash (§3.…
audristroyer Jun 10, 2026
9bbf2d9
sync parity: port ndi.time.fun trigger-train/random-trigger alignment…
audristroyer Jun 10, 2026
bbeff97
core docs + ndi_common parity: dependency fallback, dup-file error, 9…
audristroyer Jun 10, 2026
9b19e29
ontology: add Uberon/NCIT/EDAM/IAO/STATO/SchemaOrg providers + extend…
audristroyer Jun 10, 2026
2bd6f3d
security: harden secrets, eval, XML, downloads, packaging + CI (§3.5/…
audristroyer Jun 10, 2026
7c26aae
docs: reconcile bridge contracts + porting-guide/audit hygiene (§5, §…
audristroyer Jun 10, 2026
6be3262
feat(app): implement spike + tuning app compute methods from MATLAB (…
audristroyer Jun 10, 2026
9b550c4
feat(fun/probe): port the Kilosort import pipeline from MATLAB (decis…
audristroyer Jun 10, 2026
aca79e5
feat(app): markgarbage identifyvalidintervals + valid_interval array/…
audristroyer Jun 10, 2026
f145ae9
feat(app): implement stimulus.tuning_response compute methods from MA…
audristroyer Jun 11, 2026
ea27e6b
perf(dataset): O(N) bulk document load (was O(N^2)) — 78k docs 40min …
audristroyer Jun 11, 2026
004adad
fix(database): open MATLAB-written datasets + fix find() (0 failing b…
audristroyer Jun 11, 2026
8e5ae1d
fix(dataset): make MATLAB dataset analysis tests green + import-once …
audristroyer Jun 11, 2026
70fc5ef
Merge branch 'fix/cloud-sync-correctness' into integration/ndi-python…
audristroyer Jun 11, 2026
47e8c32
Merge branch 'fix/cloud-api-contract' into integration/ndi-python-all
audristroyer Jun 11, 2026
a0fc674
Merge branch 'fix/core-docs-ndi-common' into integration/ndi-python-all
audristroyer Jun 11, 2026
d6af206
Merge branch 'fix/ontology-providers' into integration/ndi-python-all
audristroyer Jun 11, 2026
280f725
Merge branch 'fix/app-frameworks' into integration/ndi-python-all
audristroyer Jun 11, 2026
d208369
Merge branch 'fix/daq-epoch-parity' into integration/ndi-python-all
audristroyer Jun 11, 2026
ee5219c
Merge branch 'fix/security-packaging-ci' into integration/ndi-python-all
audristroyer Jun 11, 2026
72235e1
Merge branch 'fix/bridge-docs-hygiene' into integration/ndi-python-all
audristroyer Jun 11, 2026
c99708d
Merge branch 'perf/dataset-bulk-load' into integration/ndi-python-all
audristroyer Jun 11, 2026
d1825a5
Merge branch 'fix/dataset-analysis-parity' into integration/ndi-pytho…
audristroyer Jun 11, 2026
b335cd3
style: black reformat after integration merge
audristroyer Jun 11, 2026
da98fe0
test(carbon-fiber): dataset_session_info is regenerated on load (0, n…
audristroyer Jun 11, 2026
74d4366
perf(dataset)+test(jess-haley): chunk JSON-load add_docs; green the j…
audristroyer Jun 11, 2026
3d228f9
fix(stimulus): read presentation_time.bin with correct MATLAB layout …
audristroyer Jun 12, 2026
c0358aa
fix(spike): real .vsw (vhlspikewaveformfile) format so spike storage …
audristroyer Jun 12, 2026
6e130a4
feat(spikesorter): implement automatic clustering path (spike_sort + …
audristroyer Jun 12, 2026
3a67237
feat(cloud): implement the deferred sync pieces + route syncDataset t…
audristroyer Jun 12, 2026
2d1afda
test(spikesorter): seed clustering RNG in spike_sort integration tests
audristroyer Jun 12, 2026
e23bfa6
refactor(ontology): single-source the prefix map from the canonical o…
audristroyer Jun 12, 2026
f096f47
test(kilosort): validate the importer against a real Kilosort2.5/Phy …
audristroyer Jun 12, 2026
d4976c7
test(symmetry): add time/syncgraph (time_convert) symmetry artifacts
audristroyer Jun 12, 2026
df7a06f
feat(spikesorter): interactive PyQt spike-sorter GUI (graphical_mode=1)
audristroyer Jun 12, 2026
373408d
fix(spikesorter): Escape cancels an active lasso, not the whole dialog
audristroyer Jun 12, 2026
e060338
fix(spikesorter): keep a persistent QApplication reference (prevents …
audristroyer Jun 12, 2026
2779873
fix(spikesorter): consistent, persistent zoom in the waveform panels
audristroyer Jun 12, 2026
9a3ac91
feat(spikesorter): light theme + branded header + crisp mean line
audristroyer Jun 12, 2026
afb7f6c
fix(deps): track vhlab-toolbox-python at @main to match ndr (fixes in…
audristroyer Jun 12, 2026
626c1ac
feat(py313): support Python 3.13 + fix clean-install regressions
audristroyer Jun 12, 2026
99afc12
feat(document): class_name-first superclass dual-accessor (schema-v2)
audriB Jun 17, 2026
125ca70
feat(oridirtuning): finish double-gaussian fit + tuning-curve wiring
audriB Jun 17, 2026
eca37a8
fix(oridirtuning): orient individual responses by direction in calcul…
audriB Jun 17, 2026
bf77bb2
perf(cloud): parallelize chunked document download (~2x faster cold-l…
audriB Jun 21, 2026
55c4cc3
fix(doc_table): faithful epoch() parity — timing + mixture_table + ap…
audriB Jun 21, 2026
6a8e10d
fix(daq/probe): unblock ingested-probe readtimeseries — perf + elemen…
audriB Jun 21, 2026
2d6d85f
fix(daq): read MATLAB-ingested t0_t1 layout in t0_t1_ingested
audriB Jun 21, 2026
28dd412
feat(fun/doc): re-export ontologyTableRowDoc2Table for MATLAB-namespa…
audriB Jun 21, 2026
d7664ae
fix(element): read MATLAB-ingested element_epoch + fetch cloud VHSB
audriB Jun 21, 2026
89361ba
fix(ontology): resolve alphanumeric OLS ids + return synonyms
audriB Jun 21, 2026
9287e9a
feat(database/fun): add readtablechar (G2)
audriB Jun 21, 2026
b0c74a1
fix(spikeextractor): derive sample rate from readtimeseries timebase …
audriB Jun 24, 2026
b63b5a9
fix(apps): MATLAB-parity spike-center rounding, oridir square-matrix …
audriB Jun 24, 2026
c4ecafa
test(schema-v2): pin dual-accessor for V_epsilon multiple-inheritance…
audriB Jun 24, 2026
3a93f1a
fix(tuning_response): correct control_stimulus error — data limitatio…
audriB Jun 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursorrules
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# NDI Cursor Rules

## 1. Project Context
This is the NDI (Neuroscience ndi_gui_Data Interface) Python port. It is a "Lead-Follow" project where the MATLAB codebase is the Source of Truth.
This is the NDI (Neuroscience Data Interface) Python port. It is a "Lead-Follow" project where the MATLAB codebase is the Source of Truth.

## 2. Core Instructions
Before proposing or writing any code, you MUST read and adhere to the following project-specific files:
Expand Down
29 changes: 13 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
cache: pip

- name: Install linting tools
run: |
Expand All @@ -33,15 +34,16 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: ${{ matrix.python-version }}
cache: pip

- name: Install with ndi_install.py
run: |
Expand All @@ -51,21 +53,16 @@ jobs:
- name: Validate installation
run: python -m ndi check

# NOTE: cloud credentials are intentionally NOT injected here. Tests that
# need a live cloud account (and the destructive MATLAB BYOL tests gated
# by NDI_CLOUD_TEST_USER_HAS_MATLAB_LICENSE) skip themselves when the
# variables are unset, and run only in the scheduled test-cloud-api.yml
# workflow. This keeps secrets off every collaborator's per-PR run.
- name: Run tests with coverage
env:
NDI_CLOUD_USERNAME: ${{ secrets.TEST_USER_2_USERNAME }}
NDI_CLOUD_PASSWORD: ${{ secrets.TEST_USER_2_PASSWORD }}
# The CI test account does not have a registered MATLAB
# license, so the destructive BYOL tests (DELETE
# /users/me/matlab-license) are allowed to run; they will
# clean up after themselves. The license guard in
# tests/_matlab_license_guard.py enforces this at module-import
# time and refuses to run if this variable is unset.
NDI_CLOUD_TEST_USER_HAS_MATLAB_LICENSE: "false"
run: |
# Use sys.monitoring (PEP 669) on Python 3.12+ for faster coverage.
# CTracer (sys.settrace) is catastrophically slow on 3.12 when
# importing large packages like openminds (~6 min vs ~2 sec).
COVERAGE_CORE=$(python -c "import sys; print('sysmon' if sys.version_info >= (3,12) else 'ctrace')")
export COVERAGE_CORE
pytest tests/ -v --tb=short --cov=src/ndi --cov-report=term-missing
pytest tests/ -n auto -v --tb=short --cov=src/ndi --cov-report=term-missing
12 changes: 9 additions & 3 deletions .github/workflows/test-cloud-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ jobs:
environment: [prod, dev]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
cache: pip

- name: Install with ndi_install.py
run: |
Expand All @@ -40,5 +41,10 @@ jobs:
NDI_CLOUD_USERNAME: ${{ matrix.user == 1 && secrets.TEST_USER_1_USERNAME || secrets.TEST_USER_2_USERNAME }}
NDI_CLOUD_PASSWORD: ${{ matrix.user == 1 && secrets.TEST_USER_1_PASSWORD || secrets.TEST_USER_2_PASSWORD }}
CLOUD_API_ENVIRONMENT: ${{ matrix.environment }}
# The destructive MATLAB BYOL lifecycle tests run here (the scheduled,
# non-PR workflow) rather than per-PR CI. "false" => the test account
# has no registered license, so they run end-to-end and clean up.
NDI_CLOUD_TEST_USER_HAS_MATLAB_LICENSE: "false"
run: |
pytest tests/test_cloud_live.py -v --tb=short
pytest tests/test_cloud_live.py tests/test_cloud_matlab_license.py \
tests/test_cloud_hello_matlab.py -v --tb=short
16 changes: 8 additions & 8 deletions .github/workflows/test-symmetry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ jobs:
steps:
# ── Checkout both repos ────────────────────────────────────────────
- name: Check out NDI-python
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
path: NDI-python

- name: Check out NDI-matlab (matching branch, fall back to main)
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
repository: VH-Lab/NDI-matlab
# Use the same branch name as NDI-python so paired feature
Expand All @@ -37,7 +37,7 @@ jobs:

- name: Check out NDI-matlab (main fallback)
if: steps.matlab_checkout_branch.outcome == 'failure'
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
repository: VH-Lab/NDI-matlab
ref: main
Expand All @@ -51,7 +51,7 @@ jobs:
echo "DISPLAY=:99" >> $GITHUB_ENV

- name: Set up MATLAB
uses: matlab-actions/setup-matlab@v2
uses: matlab-actions/setup-matlab@aa8bbc7b76daa63c5d456d1430cbd6cb5b626ab4 # v2
with:
release: latest
cache: true
Expand All @@ -61,10 +61,10 @@ jobs:
Signal_Processing_Toolbox

- name: Install MatBox
uses: ehennestad/matbox-actions/install-matbox@v1
uses: ehennestad/matbox-actions/install-matbox@8fe220fbaec9e119ec5081eb917c8e016e275f1e # v1

- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"

Expand All @@ -85,7 +85,7 @@ jobs:
# +ndi/+symmetry folder (which has its own narrow requirements.txt),
# and TestSuite.fromFolder discovers tests in that directory tree.
- name: "Stage 1: MATLAB makeArtifacts"
uses: matlab-actions/run-command@v2
uses: matlab-actions/run-command@37b454c384483087929a3d652be474ba585a9659 # v2
with:
command: |
cd("NDI-matlab");
Expand Down Expand Up @@ -124,7 +124,7 @@ jobs:

# ── Stage 3: MATLAB readArtifacts ──────────────────────────────────
- name: "Stage 3: MATLAB readArtifacts (reads Python artifacts)"
uses: matlab-actions/run-command@v2
uses: matlab-actions/run-command@37b454c384483087929a3d652be474ba585a9659 # v2
with:
command: |
cd("NDI-matlab");
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ wheels/
*.egg-info/
*.egg
.eggs/
# Build artifacts are regenerated by CI; never commit them.
*.tar.gz

# Virtual environments
.venv/
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 1. Role & Mission

You are an AI Developer for the NDI (Neuroscience ndi_gui_Data Interface) project. Your mission is to maintain 1:1 functional and semantic parity between the mature MATLAB (Source of Truth) codebase and the Python port.
You are an AI Developer for the NDI (Neuroscience Data Interface) project. Your mission is to maintain 1:1 functional and semantic parity between the mature MATLAB (Source of Truth) codebase and the Python port.

## 2. The Mandatory Knowledge Base

Expand Down Expand Up @@ -85,5 +85,5 @@ black src/ tests/ && ruff check src/ tests/ && pytest tests/ -x -q

## 6. Directory Mapping Reference

- **MATLAB Source:** `VH-ndi_gui_Lab/NDI-matlab` (GitHub)
- **MATLAB Source:** `VH-Lab/NDI-matlab` (GitHub)
- **Python Target:** `src/ndi/[namespace]/` (Mirrors MATLAB `+namespace/`)
1 change: 0 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
include LICENSE
include README.md
include CHANGELOG.md
include MATLAB_MAPPING.md

recursive-include src/ndi/ndi_common *.json *.txt *.tsv *.tsv.gz *.obo *.md
recursive-include src/ndi/ndi_common/example_binaries *
Expand Down
8 changes: 8 additions & 0 deletions REPO_AUDIT.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# NDI Cloud: MATLAB vs Python Structure Audit

> [!NOTE]
> **SUPERSEDED.** This is a narrow, cloud-module-only structural audit. It has
> been superseded by the ecosystem-wide parity & audit report
> (`ECOSYSTEM_AUDIT_2026-06.md`), which covers the full NDI-python codebase
> (time system, epoch/DAQ, documents, ontology, security, packaging) and the
> rest of the NDI ecosystem. Retained for historical context; consult the
> ecosystem report for the current source of truth.

This document analyzes every structural difference between the MATLAB and Python
implementations of the NDI Cloud module, explains why each difference exists,
and recommends whether to change or keep it.
Expand Down
31 changes: 22 additions & 9 deletions docs/developer_notes/PYTHON_PORTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,23 @@ To port or update a function, agents must follow these steps:
2. **Sync the Interface:** If the function is missing or outdated, update the YAML entry first based on the MATLAB `.m` file.
3. **Record the Sync Hash:** Store the short git hash of the MATLAB `.m` file being ported in the `matlab_last_sync_hash` field. Obtain it with: `git log -1 --format="%h" -- <path-to-matlab-file>`. This allows future comparison to detect upstream MATLAB changes.
4. **Implement:** Write the Python code to satisfy the `input_arguments` and `output_arguments` defined in the YAML.
5. **Log & Notify:** Record the sync date in the YAML's `decision_log` (e.g., `"Synchronized with MATLAB main as of 2026-03-12."`). ndi_document any intentional divergences. Explicitly tell the user what changes were made to the bridge file so they can review the contract.

## 4. Input Validation: Pydantic is Mandatory

To replicate the robustness of the MATLAB `arguments` block, use Pydantic for all public-facing API functions.

- **Decorator:** Use the `@pydantic.validate_call` decorator on all functions.
5. **Log & Notify:** Record the sync date in the YAML's `decision_log` (e.g., `"Synchronized with MATLAB main as of 2026-03-12."`). Document any intentional divergences. Explicitly tell the user what changes were made to the bridge file so they can review the contract.

## 4. Input Validation: Pydantic at Trust Boundaries

To replicate the robustness of the MATLAB `arguments` block, use Pydantic
validation where untrusted input crosses into the library.

- **Where to apply:** Decorate public entry points at **trust boundaries** —
functions that receive user-supplied, file-derived, or cloud-derived input
(the cloud layer, document/query construction from external JSON, CLI/API
surfaces). Do **not** blanket-apply `@pydantic.validate_call` to every
internal method: the hot core paths (document/query/session/element/daq/
syncgraph/navigator) call each other with already-validated, often
numpy-heavy arguments, where per-call validation adds overhead and friction
for no safety gain. Validate once at the edge, then trust internally.
- **Decorator:** Use the `@pydantic.validate_call` decorator on the
boundary-facing functions identified above.
- **Type Mirroring:**
- MATLAB `double`/`numeric` → Python `float | int`
- MATLAB `char`/`string` → Python `str`
Expand All @@ -47,8 +57,11 @@ MATLAB allows multiple return values natively. In Python, these must be returned

All Python code must pass formatting and linting before being committed.

- **Black:** The sole code formatter. Use default line length (88).
- **Ruff:** The primary linter. Run `ruff check --fix` before committing.
- **Black:** The sole code formatter. Line length is **100** (matching
`pyproject.toml`'s `[tool.black] line-length` and `AGENTS.md`). Run
`black src/ tests/` before committing.
- **Ruff:** The primary linter, also configured at line length 100. Run
`ruff check --fix` before committing.

## 7. Error Handling & Documentation

Expand Down
4 changes: 2 additions & 2 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
### Prerequisites

- Python 3.10 or later
- Git (for installing VH-ndi_gui_Lab dependencies)
- Git (for installing VH-Lab dependencies)

### Install from source

```bash
git clone https://github.com/Waltham-ndi_gui_Data-Science/NDI-python.git
git clone https://github.com/Waltham-Data-Science/NDI-python.git
cd NDI-python
python -m venv venv
source venv/bin/activate # Linux/macOS (venv\Scripts\activate on Windows)
Expand Down
12 changes: 6 additions & 6 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# NDI-Python

**Neuroscience ndi_gui_Data Interface** - Python implementation.
**Neuroscience Data Interface** - Python implementation.

NDI provides a unified framework for managing, querying, and analyzing neuroscience experimental data across different acquisition systems.

## Overview

NDI-Python is a complete port of the [MATLAB NDI](https://github.com/VH-ndi_gui_Lab/NDI-matlab) codebase, providing:
NDI-Python is a complete port of the [MATLAB NDI](https://github.com/VH-Lab/NDI-matlab) codebase, providing:

- **ndi_document-based metadata** with JSON schema validation
- **Document-based metadata** with JSON schema validation
- **SQLite database** backend for persistent storage and rich queries
- **Time synchronization** across heterogeneous recording devices
- **DAQ readers** for Intan, Blackrock, CED Spike2, and SpikeGadgets
Expand All @@ -33,12 +33,12 @@ with ndi_session_mock('demo') as session:
## Installation

```bash
git clone https://github.com/Waltham-ndi_gui_Data-Science/NDI-python.git
git clone https://github.com/Waltham-Data-Science/NDI-python.git
cd NDI-python
```

See the [Getting Started guide](getting-started.md) or the [README](https://github.com/Waltham-ndi_gui_Data-Science/NDI-python#readme) for full installation instructions including VH-ndi_gui_Lab dependency setup.
See the [Getting Started guide](getting-started.md) or the [README](https://github.com/Waltham-Data-Science/NDI-python#readme) for full installation instructions including VH-Lab dependency setup.

## MATLAB Migration

If you're migrating from MATLAB NDI, see [MATLAB_MAPPING.md](https://github.com/Waltham-ndi_gui_Data-Science/NDI-python/blob/main/MATLAB_MAPPING.md) for a complete function-by-function reference.
If you're migrating from MATLAB NDI, see [MATLAB_MAPPING.md](https://github.com/Waltham-Data-Science/NDI-python/blob/main/MATLAB_MAPPING.md) for a complete function-by-function reference.
4 changes: 2 additions & 2 deletions docs/matlab-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

This page summarizes key differences when migrating from MATLAB NDI to Python NDI.

For the complete function-by-function mapping, see [MATLAB_MAPPING.md](https://github.com/Waltham-ndi_gui_Data-Science/NDI-python/blob/main/MATLAB_MAPPING.md).
For the complete function-by-function mapping, see [MATLAB_MAPPING.md](https://github.com/Waltham-Data-Science/NDI-python/blob/main/MATLAB_MAPPING.md).

## Key API Differences

### ndi_query Syntax
### Query Syntax

**MATLAB:**
```matlab
Expand Down
Loading