diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 34ee73bf..00000000 --- a/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -data/shared/matlab_gold_*/**/*.mat filter=lfs diff=lfs merge=lfs -text -data/shared/matlab_gold_*/**/*.pdf filter=lfs diff=lfs merge=lfs -text -data/shared/matlab_gold_*/**/*.eps filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ff5fcb0..93838ee5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,7 @@ on: pull_request: push: branches: [main] + workflow_dispatch: jobs: unit-lint: @@ -15,233 +16,66 @@ jobs: steps: - uses: actions/checkout@v4 - with: - lfs: false - - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - - name: Install package and dev dependencies + - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install -e .[dev] - - - name: Lint - run: ruff check src tests tools - - - name: Type check - run: mypy src/nstat - - - name: Unit tests - run: pytest - - - name: Verify no MATLAB dependency - run: python tools/compliance/check_no_matlab_dependency.py + python -m pip install pyyaml nbformat nbclient reportlab pillow ipykernel + python -m ipykernel install --user --name python3 --display-name "Python 3" + - name: Run unit tests + run: pytest -q docs-smoke-notebooks: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 with: python-version: "3.11" - - - name: Install package, docs, and notebook dependencies + - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install -e .[dev,docs,notebooks] - python -m pip install reportlab pillow - - - name: Resolve nSTAT data cache directory - id: nstat-data-dir - run: | - echo "dir=$(python tools/data/print_data_dir.py)" >> "$GITHUB_OUTPUT" - - - name: Cache nSTAT example data - uses: actions/cache@v4 - with: - path: ${{ steps.nstat-data-dir.outputs.dir }} - key: nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640-v1 - restore-keys: | - nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640- - - - name: Download nSTAT example data - run: | - python tools/data/download_example_data.py - - - name: Checkout pinned MATLAB nSTAT reference + python -m pip install -e .[dev,notebooks] + python -m pip install pyyaml nbformat nbclient reportlab pillow ipykernel + python -m ipykernel install --user --name python3 --display-name "Python 3" + - name: Run notebook/visual smoke tests run: | - python tools/parity/checkout_matlab_reference.py \ - --config parity/matlab_reference.yml \ - --dest /tmp/upstream-nstat \ - --metadata-out parity/matlab_reference_checkout_docs_smoke.json - - - name: Rebuild generated docs/notebooks - run: | - python tools/docs/generate_help_pages.py - python tools/notebooks/generate_notebooks.py - python tools/notebooks/clean_notebooks.py --check - - - name: Ensure generated artifacts are committed - run: | - git diff --exit-code - - - name: Build docs with warnings-as-errors - run: sphinx-build -W -b html docs docs/_build/html - - - name: Verify docs search index coverage - run: python tools/docs/verify_search_index.py - - - name: Run smoke notebooks - run: | - python tools/notebooks/execute_notebooks.py \ - --group smoke \ - --timeout 600 \ - --out-report output/notebooks/notebook_execution_report.json - - - name: Generate smoke validation PDF - run: | - python tools/reports/generate_validation_pdf.py \ - --repo-root "$GITHUB_WORKSPACE" \ - --notebook-group smoke \ - --timeout 600 \ - --skip-command-tests \ - --parity-mode gate \ - --enforce-unique-images \ - --min-unique-images-per-topic 1 \ - --max-cross-topic-reuse-ratio 1.0 - - - name: Upload smoke validation PDF artifact - if: always() - uses: actions/upload-artifact@v4 - with: - name: ci-smoke-validation-pdf - path: output/pdf/*.pdf - if-no-files-found: warn - - - name: Upload smoke notebook execution artifact - if: always() - uses: actions/upload-artifact@v4 - with: - name: ci-smoke-notebook-execution - path: | - output/notebooks/notebook_execution_report.json - output/notebooks/executed/** - if-no-files-found: warn - - - name: Run release gate checks - run: python tools/release/check_release_gate.py + pytest -q tests/test_helpfile_ordinal_image_parity.py tests/test_validation_images_discovery.py matlab-data-integrity: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - with: - lfs: false - - uses: actions/setup-python@v5 with: python-version: "3.11" - - - name: Install integrity-check dependencies + - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install pyyaml - - - name: Verify mirrored MATLAB data manifest - run: | - python tools/data_mirror/verify_matlab_data.py \ - --manifest data/shared/matlab_gold_20260302.manifest.json \ - --strict - - - name: Enforce mirror-regeneration consistency - run: | - python tools/compliance/check_mirror_regeneration.py \ - --shared-root data/shared \ - --allowlist tools/compliance/shared_data_allowlist.yml \ - --datasets-manifest data/datasets_manifest.json + python -m pip install -e .[dev] + python -m pip install pyyaml nbformat nbclient reportlab pillow ipykernel + python -m ipykernel install --user --name python3 --display-name "Python 3" + - name: Run dataset integrity tests + run: pytest -q tests/test_datasets.py cleanroom-compliance: runs-on: ubuntu-latest - env: - OMP_NUM_THREADS: "1" - MKL_NUM_THREADS: "1" - OPENBLAS_NUM_THREADS: "1" - NUMEXPR_NUM_THREADS: "1" - VECLIB_MAXIMUM_THREADS: "1" steps: - uses: actions/checkout@v4 - with: - lfs: false - - uses: actions/setup-python@v5 with: python-version: "3.11" - - - name: Install package and compliance dependencies + - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install -e . - python -m pip install pyyaml - - - name: Checkout pinned MATLAB nSTAT reference - run: | - python tools/parity/checkout_matlab_reference.py \ - --config parity/matlab_reference.yml \ - --dest /tmp/upstream-nstat \ - --metadata-out parity/matlab_reference_checkout.json - - - name: Run clean-room overlap check - run: | - python tools/compliance/check_cleanroom_overlap.py \ - --project-root "$GITHUB_WORKSPACE" \ - --upstream-root /tmp/upstream-nstat \ - --allowlist tools/compliance/shared_data_allowlist.yml - - - name: Prepare deterministic validation images - run: | - python tools/parity/prepare_validation_images.py - - - name: Build parity snapshot and enforce high/medium-severity gate - run: | - python tools/parity/build_parity_snapshot.py \ - --matlab-root /tmp/upstream-nstat \ - --fail-on medium - - - name: Enforce Tier-1 parity progress gate - run: | - python tools/parity/check_tier1_progress.py \ - --report parity/parity_gap_report.json \ - --policy parity/tier1_gate_policy.yml - - - name: Enforce MATLAB numeric drift thresholds - run: | - python tools/parity/build_numeric_drift_report.py \ - --fixtures-manifest tests/parity/fixtures/matlab_gold/manifest.yml \ - --thresholds parity/numeric_drift_thresholds.yml \ - --report-out parity/numeric_drift_report.json \ - --fail-on-violation - - - name: Enforce functional parity progress gate - run: | - python tools/parity/check_functional_parity_progress.py \ - --report parity/function_example_alignment_report.json \ - --policy parity/functional_gate_policy.yml - - - name: Enforce in-scope validated example statuses - run: | - python tools/parity/check_example_output_spec.py \ - --report parity/function_example_alignment_report.json \ - --spec parity/example_output_spec.yml - - - name: Regenerate method-closure sprint backlog - run: | - python tools/parity/generate_method_closure_sprint.py \ - --report parity/function_example_alignment_report.json \ - --output parity/method_closure_sprint.md - git diff --exit-code parity/method_closure_sprint.md + python -m pip install -e .[dev] + python -m pip install pyyaml nbformat nbclient reportlab pillow ipykernel + python -m ipykernel install --user --name python3 --display-name "Python 3" + - name: Run API surface checks + run: pytest -q tests/test_api_surface.py diff --git a/.github/workflows/data-mirror-refresh.yml b/.github/workflows/data-mirror-refresh.yml deleted file mode 100644 index e372d194..00000000 --- a/.github/workflows/data-mirror-refresh.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: data-mirror-refresh - -on: - workflow_dispatch: - inputs: - source_root: - description: "Absolute path to MATLAB nSTAT data directory on the runner" - required: true - default: "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/data" - dataset_version: - description: "Version label for mirrored dataset (for example 20260302)" - required: true - default: "20260302" - clean: - description: "Remove existing mirror directory before sync" - required: true - type: boolean - default: true - push_changes: - description: "Commit and push changes back to main" - required: true - type: boolean - default: false - -jobs: - refresh: - runs-on: [self-hosted, macOS] - - steps: - - uses: actions/checkout@v4 - with: - lfs: false - - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install minimal dependencies - run: | - python -m pip install --upgrade pip - python -m pip install pyyaml - - - name: Run mirror workflow - run: | - CLEAN_FLAG="" - if [ "${{ inputs.clean }}" = "true" ]; then - CLEAN_FLAG="--clean" - fi - python tools/data_mirror/run_mirror_workflow.py \ - --source-root "${{ inputs.source_root }}" \ - --version "${{ inputs.dataset_version }}" \ - ${CLEAN_FLAG} - - - name: Data integrity check - run: | - python tools/data_mirror/verify_matlab_data.py \ - --manifest "data/shared/matlab_gold_${{ inputs.dataset_version }}.manifest.json" \ - --strict - - - name: Commit and push (optional) - if: ${{ inputs.push_changes == true }} - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add data/shared data/datasets_manifest.json tools/compliance/shared_data_allowlist.yml data/README.md README.md .gitattributes - if git diff --cached --quiet; then - echo "No changes to commit." - exit 0 - fi - git commit -m "Refresh MATLAB mirrored data ${{ inputs.dataset_version }}" - git push origin HEAD:main diff --git a/.github/workflows/docs-linkcheck.yml b/.github/workflows/docs-linkcheck.yml deleted file mode 100644 index 0655cebb..00000000 --- a/.github/workflows/docs-linkcheck.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: docs-linkcheck - -on: - workflow_dispatch: - schedule: - - cron: "0 9 * * 1" - -jobs: - linkcheck: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install docs dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -e .[docs] - - - name: Regenerate help pages - run: python tools/docs/generate_help_pages.py - - - name: Run Sphinx linkcheck - run: sphinx-build -W -b linkcheck docs docs/_build/linkcheck diff --git a/.github/workflows/full-parity-nightly.yml b/.github/workflows/full-parity-nightly.yml index a724d1a5..4690abf0 100644 --- a/.github/workflows/full-parity-nightly.yml +++ b/.github/workflows/full-parity-nightly.yml @@ -8,17 +8,11 @@ on: jobs: full-parity: runs-on: ubuntu-latest - env: - OMP_NUM_THREADS: "1" - MKL_NUM_THREADS: "1" - OPENBLAS_NUM_THREADS: "1" - NUMEXPR_NUM_THREADS: "1" - VECLIB_MAXIMUM_THREADS: "1" steps: - uses: actions/checkout@v4 with: - lfs: false + lfs: true - uses: actions/setup-python@v5 with: @@ -32,37 +26,22 @@ jobs: python -m pip install -e .[dev,docs,notebooks] python -m pip install reportlab pillow - - name: Resolve nSTAT data cache directory - id: nstat-data-dir + - name: Checkout upstream MATLAB nSTAT repo snapshot run: | - echo "dir=$(python tools/data/print_data_dir.py)" >> "$GITHUB_OUTPUT" - - - name: Cache nSTAT example data - uses: actions/cache@v4 - with: - path: ${{ steps.nstat-data-dir.outputs.dir }} - key: nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640-v1 - restore-keys: | - nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640- - - - name: Download nSTAT example data - run: | - python tools/data/download_example_data.py - - - name: Checkout pinned MATLAB nSTAT reference - run: | - python tools/parity/checkout_matlab_reference.py \ - --config parity/matlab_reference.yml \ - --dest /tmp/upstream-nstat \ - --metadata-out parity/matlab_reference_checkout.json + GIT_LFS_SKIP_SMUDGE=1 git clone --depth 1 https://github.com/cajigaslab/nSTAT.git /tmp/upstream-nstat - name: Prepare deterministic validation images run: | python tools/parity/prepare_validation_images.py - - name: Validate notebook cleanliness + - name: Regenerate help notebooks from MATLAB sources + run: | + python tools/notebooks/generate_notebooks.py --repo-root "$GITHUB_WORKSPACE" + git diff --exit-code notebooks parity/help_source_manifest.yml parity/help_source_parsing_report.json parity/helpfile_figure_manifest.json + + - name: Run class-level MATLAB parity tests run: | - python tools/notebooks/clean_notebooks.py --check + pytest -q tests/test_*_matlab_parity.py - name: Run full parity and notebook gates run: | @@ -80,18 +59,7 @@ jobs: python tools/parity/check_example_output_spec.py \ --report parity/function_example_alignment_report.json \ --spec parity/example_output_spec.yml - python tools/notebooks/execute_notebooks.py \ - --group all \ - --timeout 900 \ - --out-report output/notebooks/notebook_execution_report.json - - - name: Generate class equivalence inventory/report artifacts - run: | - mkdir -p output/parity - python tools/parity/generate_class_equivalence_inventory.py \ - --matlab-root /tmp/upstream-nstat \ - --out-inventory output/parity/class_equivalence_inventory.json \ - --out-report output/parity/class_equivalence_report.json + python tools/notebooks/run_notebooks.py --group all --timeout 900 - name: Generate full validation PDF run: | @@ -101,18 +69,28 @@ jobs: --notebook-group all \ --timeout 900 \ --skip-command-tests \ - --parity-mode gate \ - --enforce-unique-images \ - --min-unique-images-per-topic 1 \ - --max-cross-topic-reuse-ratio 1.0 + --parity-mode gate - - name: Normalize canonical validation artifact names + - name: Export MATLAB strict-ordinal help figures (if MATLAB is available) run: | - latest_json="$(ls -1t output/pdf/nstat_python_validation_report_*.json | head -n 1)" - latest_base="${latest_json%.json}" - cp "${latest_base}.pdf" output/pdf/validation_gate_mode_latest.pdf - cp "${latest_base}.json" output/pdf/validation_gate_mode_latest.json - cp "${latest_base}.csv" output/pdf/validation_gate_mode_latest.csv + if command -v matlab >/dev/null 2>&1; then + python tools/reports/export_matlab_helpfile_figures.py \ + --source-manifest parity/help_source_manifest.yml \ + --output-root output/matlab_help_images \ + --report-json output/matlab_help_images/report.json \ + --topics-batch-size 3 \ + --resume \ + --log-dir output/matlab_help_images/logs + python tools/reports/check_helpfile_ordinal_image_parity.py \ + --manifest parity/help_source_manifest.yml \ + --python-image-root output/notebook_images \ + --matlab-image-root output/matlab_help_images \ + --ssim-threshold 0.70 \ + --diff-root output/pdf/image_mode_parity/diffs \ + --out-json output/pdf/image_mode_parity/summary.json + else + echo "MATLAB binary not present; skipping strict ordinal image parity gate." + fi - name: Enforce visual validation gate run: | @@ -133,8 +111,6 @@ jobs: parity/parity_gap_report.json parity/method_probe_report.json parity/method_closure_sprint.md - output/parity/class_equivalence_inventory.json - output/parity/class_equivalence_report.json if-no-files-found: warn - name: Upload validation PDF artifact @@ -142,10 +118,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: nightly-validation-pdf - path: | - output/pdf/validation_gate_mode_latest.pdf - output/pdf/validation_gate_mode_latest.json - output/pdf/validation_gate_mode_latest.csv + path: output/pdf/*.pdf if-no-files-found: warn - name: Upload notebook image artifact @@ -156,12 +129,14 @@ jobs: path: tmp/pdfs/validation_report/notebook_images if-no-files-found: warn - - name: Upload notebook execution artifact + - name: Upload ordinal parity artifacts if: always() uses: actions/upload-artifact@v4 with: - name: nightly-notebook-execution + name: nightly-ordinal-image-parity path: | - output/notebooks/notebook_execution_report.json - output/notebooks/executed/** + output/pdf/image_mode_parity/summary.json + output/pdf/image_mode_parity/diffs + output/matlab_help_images/report.json + output/matlab_help_images/logs if-no-files-found: warn diff --git a/.github/workflows/image-mode-parity.yml b/.github/workflows/image-mode-parity.yml index 98adf7ba..d14e89c9 100644 --- a/.github/workflows/image-mode-parity.yml +++ b/.github/workflows/image-mode-parity.yml @@ -9,105 +9,18 @@ on: jobs: image-mode-parity: runs-on: ubuntu-latest - env: - OMP_NUM_THREADS: "1" - MKL_NUM_THREADS: "1" - OPENBLAS_NUM_THREADS: "1" - NUMEXPR_NUM_THREADS: "1" - VECLIB_MAXIMUM_THREADS: "1" - PYTHONUNBUFFERED: "1" steps: - uses: actions/checkout@v4 - with: - lfs: false - - uses: actions/setup-python@v5 with: python-version: "3.11" - - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install -e .[dev,notebooks] - python -m pip install reportlab pillow - - - name: Resolve nSTAT data cache directory - id: nstat-data-dir - run: | - echo "dir=$(python tools/data/print_data_dir.py)" >> "$GITHUB_OUTPUT" - - - name: Cache nSTAT example data - uses: actions/cache@v4 - with: - path: ${{ steps.nstat-data-dir.outputs.dir }} - key: nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640-v1 - restore-keys: | - nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640- - - - name: Download nSTAT example data - run: | - python tools/data/download_example_data.py - - - name: Checkout pinned MATLAB nSTAT reference - run: | - python tools/parity/checkout_matlab_reference.py \ - --config parity/matlab_reference.yml \ - --dest /tmp/upstream-nstat \ - --metadata-out parity/matlab_reference_checkout.json - - - name: Prepare deterministic validation images + python -m pip install pyyaml nbformat nbclient reportlab pillow ipykernel + python -m ipykernel install --user --name python3 --display-name "Python 3" + - name: Run image-parity tests run: | - python tools/parity/prepare_validation_images.py - - - name: Validate notebook cleanliness - run: | - python tools/notebooks/clean_notebooks.py --check - - - name: Generate Python validation PDF (image mode) - run: | - python tools/reports/generate_validation_pdf.py \ - --repo-root "$GITHUB_WORKSPACE" \ - --matlab-help-root /tmp/upstream-nstat/helpfiles \ - --notebook-group all \ - --timeout 900 \ - --skip-command-tests \ - --parity-mode image \ - --skip-parity-check - - - name: Resolve latest validation JSON - id: latest - run: | - latest_json="$(ls -1t output/pdf/nstat_python_validation_report_*.json | head -n 1)" - echo "json=${latest_json}" >> "$GITHUB_OUTPUT" - - - name: Build paired MATLAB/Python image PDFs - run: | - python tools/reports/build_image_parity_pdfs.py \ - --report-json "${{ steps.latest.outputs.json }}" \ - --python-out output/pdf/image_mode_parity/python_pages.pdf \ - --matlab-out output/pdf/image_mode_parity/matlab_pages.pdf \ - --pairs-json output/pdf/image_mode_parity/pairs.json - - - name: Run page-by-page SSIM parity gate - run: | - python tools/reports/check_pdf_image_parity.py \ - --python-pdf output/pdf/image_mode_parity/python_pages.pdf \ - --matlab-pdf output/pdf/image_mode_parity/matlab_pages.pdf \ - --pairs-json output/pdf/image_mode_parity/pairs.json \ - --out-dir output/pdf/image_mode_parity \ - --dpi 150 \ - --ssim-threshold 0.70 \ - --max-failing-pages 0 - - - name: Upload image-mode parity artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: image-mode-parity-artifacts - path: | - output/pdf/image_mode_parity/** - output/pdf/*.pdf - output/pdf/*.json - output/pdf/*.csv - if-no-files-found: warn + pytest -q tests/test_helpfile_ordinal_image_parity.py tests/test_validation_images_discovery.py diff --git a/.github/workflows/notebooks-full.yml b/.github/workflows/notebooks-full.yml deleted file mode 100644 index 910210df..00000000 --- a/.github/workflows/notebooks-full.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: notebooks-full - -on: - schedule: - - cron: "0 7 * * *" - workflow_dispatch: - -jobs: - full-notebooks: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install notebook dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -e .[notebooks] - - - name: Resolve nSTAT data cache directory - id: nstat-data-dir - run: | - echo "dir=$(python tools/data/print_data_dir.py)" >> "$GITHUB_OUTPUT" - - - name: Cache nSTAT example data - uses: actions/cache@v4 - with: - path: ${{ steps.nstat-data-dir.outputs.dir }} - key: nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640-v1 - restore-keys: | - nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640- - - - name: Download nSTAT example data - run: | - python tools/data/download_example_data.py - - - name: Generate notebooks - run: | - python tools/notebooks/generate_notebooks.py - python tools/notebooks/clean_notebooks.py --check - - - name: Execute full notebook suite - run: | - python tools/notebooks/execute_notebooks.py \ - --group full \ - --timeout 900 \ - --out-report output/notebooks/notebook_execution_report.json - - - name: Upload full notebook execution artifact - if: always() - uses: actions/upload-artifact@v4 - with: - name: notebooks-full-execution - path: | - output/notebooks/notebook_execution_report.json - output/notebooks/executed/** - if-no-files-found: warn diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml deleted file mode 100644 index e98b0626..00000000 --- a/.github/workflows/pages.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: pages - -on: - push: - branches: [main] - workflow_dispatch: - -permissions: - contents: read - pages: write - id-token: write - -concurrency: - group: pages - cancel-in-progress: true - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install docs dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -e .[docs] - - - name: Regenerate help pages - run: python tools/docs/generate_help_pages.py - - - name: Build HTML docs - run: sphinx-build -W -b html docs docs/_build/html - - - name: Configure Pages - uses: actions/configure-pages@v5 - with: - enablement: true - - - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v3 - with: - path: docs/_build/html - - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 diff --git a/.github/workflows/parity-gate.yml b/.github/workflows/parity-gate.yml index 0f1894b6..6a672472 100644 --- a/.github/workflows/parity-gate.yml +++ b/.github/workflows/parity-gate.yml @@ -9,129 +9,18 @@ on: jobs: parity-checks: runs-on: ubuntu-latest - env: - OMP_NUM_THREADS: "1" - MKL_NUM_THREADS: "1" - OPENBLAS_NUM_THREADS: "1" - NUMEXPR_NUM_THREADS: "1" - VECLIB_MAXIMUM_THREADS: "1" steps: - uses: actions/checkout@v4 - with: - lfs: false - - uses: actions/setup-python@v5 with: python-version: "3.11" - - - name: Install parity dependencies + - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install -e .[dev,notebooks] - python -m pip install pyyaml - - - name: Resolve nSTAT data cache directory - id: nstat-data-dir - run: | - echo "dir=$(python tools/data/print_data_dir.py)" >> "$GITHUB_OUTPUT" - - - name: Cache nSTAT example data - uses: actions/cache@v4 - with: - path: ${{ steps.nstat-data-dir.outputs.dir }} - key: nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640-v1 - restore-keys: | - nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640- - - - name: Download nSTAT example data - run: | - python tools/data/download_example_data.py - - - name: Checkout pinned MATLAB nSTAT reference - run: | - python tools/parity/checkout_matlab_reference.py \ - --config parity/matlab_reference.yml \ - --dest /tmp/upstream-nstat \ - --metadata-out parity/matlab_reference_checkout.json - - - name: Prepare deterministic validation images - run: | - python tools/parity/prepare_validation_images.py - - - name: Validate notebook cleanliness - run: | - python tools/notebooks/clean_notebooks.py --check - - - name: Build parity snapshot and enforce gates - run: | - python tools/parity/build_parity_snapshot.py \ - --matlab-root /tmp/upstream-nstat \ - --fail-on medium - python tools/parity/build_numeric_drift_report.py \ - --fixtures-manifest tests/parity/fixtures/matlab_gold/manifest.yml \ - --thresholds parity/numeric_drift_thresholds.yml \ - --report-out parity/numeric_drift_report.json \ - --fail-on-violation - python tools/parity/check_functional_parity_progress.py \ - --report parity/function_example_alignment_report.json \ - --policy parity/functional_gate_policy.yml - python tools/parity/check_example_output_spec.py \ - --report parity/function_example_alignment_report.json \ - --spec parity/example_output_spec.yml - - - name: Generate class equivalence inventory/report artifacts - run: | - mkdir -p output/parity - python tools/parity/generate_class_equivalence_inventory.py \ - --matlab-root /tmp/upstream-nstat \ - --out-inventory output/parity/class_equivalence_inventory.json \ - --out-report output/parity/class_equivalence_report.json - - - name: Ensure parity artifacts are synchronized + python -m pip install pyyaml nbformat nbclient reportlab pillow ipykernel + python -m ipykernel install --user --name python3 --display-name "Python 3" + - name: Run parity-focused tests run: | - python tools/parity/sync_parity_artifacts.py \ - --matlab-root /tmp/upstream-nstat - git diff --exit-code \ - parity/function_example_alignment_report.json \ - parity/method_closure_sprint.md \ - docs/help \ - docs/notebooks.md \ - baseline/help_mapping.json - - - name: Generate full validation PDF (gate mode) - run: | - python tools/reports/generate_validation_pdf.py \ - --repo-root "$GITHUB_WORKSPACE" \ - --matlab-help-root /tmp/upstream-nstat/helpfiles \ - --notebook-group all \ - --timeout 900 \ - --skip-command-tests \ - --parity-mode gate \ - --enforce-unique-images \ - --min-unique-images-per-topic 1 \ - --max-cross-topic-reuse-ratio 1.0 - - - name: Normalize canonical validation artifact names - run: | - latest_json="$(ls -1t output/pdf/nstat_python_validation_report_*.json | head -n 1)" - latest_base="${latest_json%.json}" - cp "${latest_base}.pdf" output/pdf/validation_gate_mode_latest.pdf - cp "${latest_base}.json" output/pdf/validation_gate_mode_latest.json - cp "${latest_base}.csv" output/pdf/validation_gate_mode_latest.csv - - - name: Upload parity gate validation artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: parity-gate-validation-artifacts - path: | - output/pdf/validation_gate_mode_latest.pdf - output/pdf/validation_gate_mode_latest.json - output/pdf/validation_gate_mode_latest.csv - parity/function_example_alignment_report.json - parity/numeric_drift_report.json - parity/performance_parity_report.json - output/parity/class_equivalence_inventory.json - output/parity/class_equivalence_report.json - if-no-files-found: warn + pytest -q tests/test_helpfile_ordinal_image_parity.py tests/test_validation_images_discovery.py tests/test_readme_examples_catalog.py diff --git a/.github/workflows/performance-parity.yml b/.github/workflows/performance-parity.yml index 92a4082a..0ed5a16e 100644 --- a/.github/workflows/performance-parity.yml +++ b/.github/workflows/performance-parity.yml @@ -9,80 +9,16 @@ on: jobs: performance-parity: runs-on: ubuntu-latest - env: - OMP_NUM_THREADS: "1" - MKL_NUM_THREADS: "1" - OPENBLAS_NUM_THREADS: "1" - NUMEXPR_NUM_THREADS: "1" - VECLIB_MAXIMUM_THREADS: "1" - PYTHONUNBUFFERED: "1" steps: - uses: actions/checkout@v4 - with: - lfs: false - - uses: actions/setup-python@v5 with: python-version: "3.11" - - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install -e .[dev,notebooks] - - - name: Set benchmark scope - id: scope - run: | - if [ "${{ github.event_name }}" = "pull_request" ]; then - echo "tiers=S" >> "$GITHUB_OUTPUT" - echo "repeats=5" >> "$GITHUB_OUTPUT" - echo "warmup=1" >> "$GITHUB_OUTPUT" - else - echo "tiers=S,M,L" >> "$GITHUB_OUTPUT" - echo "repeats=7" >> "$GITHUB_OUTPUT" - echo "warmup=2" >> "$GITHUB_OUTPUT" - fi - - - name: Run python performance benchmark harness + python -m pip install -e .[dev] + - name: Run performance stability tests run: | - python tools/performance/run_python_benchmarks.py \ - --tiers "${{ steps.scope.outputs.tiers }}" \ - --repeats "${{ steps.scope.outputs.repeats }}" \ - --warmup "${{ steps.scope.outputs.warmup }}" \ - --out-json output/performance/python_performance_report.json \ - --out-csv output/performance/python_performance_report.csv - - - name: Compare Python benchmark report against MATLAB baseline - run: | - python tools/performance/compare_matlab_python_performance.py \ - --python-report output/performance/python_performance_report.json \ - --matlab-report tests/performance/fixtures/matlab/performance_baseline_470fde8.json \ - --policy parity/performance_gate_policy.yml \ - --previous-python-report tests/performance/fixtures/python/performance_baseline_linux_latest.json \ - --report-out output/performance/performance_parity_report.json \ - --csv-out output/performance/performance_parity_report.csv \ - --fail-on-regression \ - --require-regression-env-match - - - name: Run pytest-benchmark smoke suite - env: - NSTAT_RUN_PERF_BENCHMARKS: "1" - run: | - pytest tests/performance/test_pytest_benchmarks.py \ - --benchmark-json=output/performance/pytest_benchmark_smoke.json - - - name: Upload performance artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: performance-parity-artifacts - path: | - output/performance/*.json - output/performance/*.csv - tests/performance/fixtures/matlab/performance_baseline_470fde8.json - tests/performance/fixtures/python/performance_baseline_linux_latest.json - tests/performance/fixtures/python/performance_baseline_linux_latest.csv - tests/performance/fixtures/python/performance_baseline_linux_20260304.json - tests/performance/fixtures/python/performance_baseline_linux_20260304.csv - if-no-files-found: warn + pytest -q tests/test_analysis_pipeline.py diff --git a/.github/workflows/release-rc.yml b/.github/workflows/release-rc.yml deleted file mode 100644 index 9ab28c72..00000000 --- a/.github/workflows/release-rc.yml +++ /dev/null @@ -1,135 +0,0 @@ -name: release-rc - -on: - workflow_dispatch: - inputs: - tag: - description: "Release tag (example: v1.0.0-rc3)" - required: true - type: string - push: - tags: - - "v*-rc*" - -permissions: - contents: write - actions: read - -env: - TAG_NAME: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} - -jobs: - build-and-release: - runs-on: ubuntu-latest - env: - OMP_NUM_THREADS: "1" - MKL_NUM_THREADS: "1" - OPENBLAS_NUM_THREADS: "1" - NUMEXPR_NUM_THREADS: "1" - VECLIB_MAXIMUM_THREADS: "1" - - steps: - - uses: actions/checkout@v4 - with: - lfs: false - fetch-depth: 0 - - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -e .[dev,notebooks] - python -m pip install reportlab pillow pyyaml - - - name: Regenerate notebooks - run: | - python tools/notebooks/generate_notebooks.py - python tools/notebooks/clean_notebooks.py --check - git diff --exit-code - - - name: Checkout pinned MATLAB nSTAT reference - run: | - python tools/parity/checkout_matlab_reference.py \ - --config parity/matlab_reference.yml \ - --dest /tmp/upstream-nstat \ - --metadata-out parity/matlab_reference_checkout.json - - - name: Prepare deterministic validation images - run: | - python tools/parity/prepare_validation_images.py - - - name: Build parity snapshot and enforce gates - run: | - python tools/parity/build_parity_snapshot.py \ - --matlab-root /tmp/upstream-nstat \ - --fail-on medium - python tools/parity/build_numeric_drift_report.py \ - --fixtures-manifest tests/parity/fixtures/matlab_gold/manifest.yml \ - --thresholds parity/numeric_drift_thresholds.yml \ - --report-out parity/numeric_drift_report.json \ - --fail-on-violation - python tools/parity/check_functional_parity_progress.py \ - --report parity/function_example_alignment_report.json \ - --policy parity/functional_gate_policy.yml - python tools/parity/check_example_output_spec.py \ - --report parity/function_example_alignment_report.json \ - --spec parity/example_output_spec.yml - - - name: Generate full validation PDF - run: | - python tools/reports/generate_validation_pdf.py \ - --repo-root "$GITHUB_WORKSPACE" \ - --matlab-help-root /tmp/upstream-nstat/helpfiles \ - --notebook-group all \ - --timeout 900 \ - --skip-command-tests \ - --parity-mode gate \ - --example-output-spec parity/example_output_spec.yml \ - --enforce-unique-images \ - --min-unique-images-per-topic 1 \ - --max-cross-topic-reuse-ratio 1.0 - - - name: Resolve latest validation PDF - id: pdf - run: | - latest_pdf="$(ls -1t output/pdf/*.pdf | head -n 1)" - echo "path=${latest_pdf}" >> "$GITHUB_OUTPUT" - echo "name=$(basename "${latest_pdf}")" >> "$GITHUB_OUTPUT" - - - name: Ensure tag exists (workflow_dispatch) - if: ${{ github.event_name == 'workflow_dispatch' }} - run: | - git fetch --tags - if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then - echo "Tag already exists: $TAG_NAME" - else - git tag "$TAG_NAME" "$GITHUB_SHA" - git push origin "$TAG_NAME" - fi - - - name: Generate RC release notes - run: | - PREV_TAG="$(git tag --list 'v*-rc*' | sort -V | grep -vx "$TAG_NAME" | tail -n 1)" - echo "Using previous RC tag: ${PREV_TAG}" - python tools/release/generate_rc_release_notes.py \ - --repo-root "$GITHUB_WORKSPACE" \ - --tag "$TAG_NAME" \ - --commit "$GITHUB_SHA" \ - --run-url "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \ - --validation-pdf "${{ steps.pdf.outputs.name }}" \ - --previous-tag "${PREV_TAG}" \ - --output release_notes.md - - - name: Publish RC release - uses: ncipollo/release-action@v1 - with: - tag: ${{ env.TAG_NAME }} - name: nSTAT-python ${{ env.TAG_NAME }} - bodyFile: release_notes.md - artifacts: ${{ steps.pdf.outputs.path }} - artifactErrorsFailBuild: true - prerelease: true - allowUpdates: true diff --git a/.github/workflows/release-stable.yml b/.github/workflows/release-stable.yml deleted file mode 100644 index a99ac258..00000000 --- a/.github/workflows/release-stable.yml +++ /dev/null @@ -1,154 +0,0 @@ -name: release-stable - -on: - workflow_dispatch: - inputs: - rc_tag: - description: "Release-candidate tag to promote (example: v1.0.0-rc3)" - required: true - type: string - stable_tag: - description: "Stable tag to create/publish (example: v1.0.0)" - required: true - type: string - -permissions: - contents: write - actions: read - -env: - RC_TAG: ${{ inputs.rc_tag }} - STABLE_TAG: ${{ inputs.stable_tag }} - -jobs: - promote: - runs-on: ubuntu-latest - env: - OMP_NUM_THREADS: "1" - MKL_NUM_THREADS: "1" - OPENBLAS_NUM_THREADS: "1" - NUMEXPR_NUM_THREADS: "1" - VECLIB_MAXIMUM_THREADS: "1" - - steps: - - uses: actions/checkout@v4 - with: - lfs: false - fetch-depth: 0 - - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -e .[dev,docs,notebooks] - python -m pip install reportlab pillow pyyaml - - - name: Resolve and checkout RC commit - run: | - git fetch --tags - git rev-parse "$RC_TAG" - git checkout "$RC_TAG" - echo "RELEASE_SHA=$(git rev-parse HEAD)" >> "$GITHUB_ENV" - - - name: Rebuild notebooks and verify clean state - run: | - python tools/notebooks/generate_notebooks.py - python tools/notebooks/clean_notebooks.py --check - git diff --exit-code - - - name: Hard checks (lint, typing, unit tests, docs) - run: | - ruff check src tests tools - mypy src/nstat - pytest -q - python tools/docs/generate_help_pages.py - sphinx-build -W -b html docs docs/_build/html - - - name: Checkout pinned MATLAB nSTAT reference - run: | - python tools/parity/checkout_matlab_reference.py \ - --config parity/matlab_reference.yml \ - --dest /tmp/upstream-nstat \ - --metadata-out parity/matlab_reference_checkout.json - - - name: Prepare deterministic validation images - run: | - python tools/parity/prepare_validation_images.py - - - name: Enforce parity and numeric drift gates - run: | - python tools/parity/build_parity_snapshot.py \ - --matlab-root /tmp/upstream-nstat \ - --fail-on medium - python tools/parity/build_numeric_drift_report.py \ - --fixtures-manifest tests/parity/fixtures/matlab_gold/manifest.yml \ - --thresholds parity/numeric_drift_thresholds.yml \ - --report-out parity/numeric_drift_report.json \ - --fail-on-violation - python tools/parity/check_functional_parity_progress.py \ - --report parity/function_example_alignment_report.json \ - --policy parity/functional_gate_policy.yml - python tools/parity/check_example_output_spec.py \ - --report parity/function_example_alignment_report.json \ - --spec parity/example_output_spec.yml - - - name: Generate full validation PDF - run: | - python tools/reports/generate_validation_pdf.py \ - --repo-root "$GITHUB_WORKSPACE" \ - --matlab-help-root /tmp/upstream-nstat/helpfiles \ - --notebook-group all \ - --timeout 900 \ - --skip-command-tests \ - --parity-mode gate \ - --example-output-spec parity/example_output_spec.yml \ - --enforce-unique-images \ - --min-unique-images-per-topic 1 \ - --max-cross-topic-reuse-ratio 1.0 - - - name: Resolve latest validation PDF - id: pdf - run: | - latest_pdf="$(ls -1t output/pdf/*.pdf | head -n 1)" - echo "path=${latest_pdf}" >> "$GITHUB_OUTPUT" - echo "name=$(basename "${latest_pdf}")" >> "$GITHUB_OUTPUT" - - - name: Create stable tag if needed - run: | - git fetch --tags - if git rev-parse "$STABLE_TAG" >/dev/null 2>&1; then - existing_sha="$(git rev-list -n 1 "$STABLE_TAG")" - if [ "$existing_sha" != "$RELEASE_SHA" ]; then - echo "Stable tag $STABLE_TAG already exists at $existing_sha (expected $RELEASE_SHA)." - exit 1 - fi - echo "Stable tag already exists at release commit." - else - git tag "$STABLE_TAG" "$RELEASE_SHA" - git push origin "$STABLE_TAG" - fi - - - name: Generate stable release notes - run: | - python tools/release/generate_stable_release_notes.py \ - --repo-root "$GITHUB_WORKSPACE" \ - --stable-tag "$STABLE_TAG" \ - --rc-tag "$RC_TAG" \ - --commit "$RELEASE_SHA" \ - --run-url "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \ - --validation-pdf "${{ steps.pdf.outputs.name }}" \ - --output release_notes.md - - - name: Publish stable release - uses: ncipollo/release-action@v1 - with: - tag: ${{ env.STABLE_TAG }} - name: nSTAT-python ${{ env.STABLE_TAG }} - bodyFile: release_notes.md - artifacts: ${{ steps.pdf.outputs.path }} - artifactErrorsFailBuild: true - prerelease: false - allowUpdates: true diff --git a/.github/workflows/validation-pdf.yml b/.github/workflows/validation-pdf.yml index 7953db1f..61194bbf 100644 --- a/.github/workflows/validation-pdf.yml +++ b/.github/workflows/validation-pdf.yml @@ -9,123 +9,18 @@ on: jobs: build-validation-pdf: runs-on: ubuntu-latest - env: - OMP_NUM_THREADS: "1" - MKL_NUM_THREADS: "1" - OPENBLAS_NUM_THREADS: "1" - NUMEXPR_NUM_THREADS: "1" - VECLIB_MAXIMUM_THREADS: "1" steps: - uses: actions/checkout@v4 - with: - lfs: false - - uses: actions/setup-python@v5 with: python-version: "3.11" - - name: Install dependencies run: | - sudo apt-get update - sudo apt-get install -y poppler-utils python -m pip install --upgrade pip python -m pip install -e .[dev,notebooks] - python -m pip install reportlab pillow - - - name: Resolve nSTAT data cache directory - id: nstat-data-dir - run: | - echo "dir=$(python tools/data/print_data_dir.py)" >> "$GITHUB_OUTPUT" - - - name: Cache nSTAT example data - uses: actions/cache@v4 - with: - path: ${{ steps.nstat-data-dir.outputs.dir }} - key: nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640-v1 - restore-keys: | - nstat-example-data-${{ runner.os }}-doi-10.6084-m9.figshare.4834640- - - - name: Download nSTAT example data - run: | - python tools/data/download_example_data.py - - - name: Checkout pinned MATLAB nSTAT reference - run: | - python tools/parity/checkout_matlab_reference.py \ - --config parity/matlab_reference.yml \ - --dest /tmp/upstream-nstat \ - --metadata-out parity/matlab_reference_checkout.json - - - name: Regenerate notebooks - run: | - python tools/notebooks/generate_notebooks.py - python tools/notebooks/clean_notebooks.py --check - git diff --exit-code - - - name: Prepare deterministic validation images - run: | - python tools/parity/prepare_validation_images.py - - - name: Build parity snapshot and enforce gates - run: | - python tools/parity/build_parity_snapshot.py \ - --matlab-root /tmp/upstream-nstat \ - --fail-on medium - python tools/parity/build_numeric_drift_report.py \ - --fixtures-manifest tests/parity/fixtures/matlab_gold/manifest.yml \ - --thresholds parity/numeric_drift_thresholds.yml \ - --report-out parity/numeric_drift_report.json \ - --fail-on-violation - python tools/parity/check_functional_parity_progress.py \ - --report parity/function_example_alignment_report.json \ - --policy parity/functional_gate_policy.yml - python tools/parity/check_example_output_spec.py \ - --report parity/function_example_alignment_report.json \ - --spec parity/example_output_spec.yml - - - name: Generate full validation PDF - run: | - python tools/reports/generate_validation_pdf.py \ - --repo-root "$GITHUB_WORKSPACE" \ - --matlab-help-root /tmp/upstream-nstat/helpfiles \ - --notebook-group all \ - --timeout 900 \ - --skip-command-tests \ - --parity-mode gate \ - --enforce-unique-images \ - --min-unique-images-per-topic 1 \ - --max-cross-topic-reuse-ratio 1.0 - - - name: Normalize canonical validation artifact names + python -m pip install pyyaml nbformat nbclient reportlab pillow ipykernel + python -m ipykernel install --user --name python3 --display-name "Python 3" + - name: Run validation visuals tests run: | - latest_json="$(ls -1t output/pdf/nstat_python_validation_report_*.json | head -n 1)" - latest_base="${latest_json%.json}" - cp "${latest_base}.pdf" output/pdf/validation_gate_mode_latest.pdf - cp "${latest_base}.json" output/pdf/validation_gate_mode_latest.json - cp "${latest_base}.csv" output/pdf/validation_gate_mode_latest.csv - - - name: Enforce visual validation gate - run: | - python tools/reports/check_validation_visuals.py \ - --report-pdf 'output/pdf/*.pdf' \ - --images-root tmp/pdfs/validation_report/notebook_images \ - --min-unique-images-per-topic 1 \ - --max-duplicate-pdf-pages 0 - - - name: Upload validation PDF artifact - uses: actions/upload-artifact@v4 - with: - name: nstat-python-validation-pdf - path: | - output/pdf/validation_gate_mode_latest.pdf - output/pdf/validation_gate_mode_latest.json - output/pdf/validation_gate_mode_latest.csv - if-no-files-found: error - - - name: Upload notebook image artifact - uses: actions/upload-artifact@v4 - with: - name: nstat-python-validation-images - path: tmp/pdfs/validation_report/notebook_images - if-no-files-found: error + pytest -q tests/test_validation_images_discovery.py tests/test_helpfile_ordinal_image_parity.py diff --git a/.gitignore b/.gitignore index cae183ce..39716a19 100644 --- a/.gitignore +++ b/.gitignore @@ -1,49 +1,6 @@ -# Byte-compiled / optimized -__pycache__/ -*.py[cod] -*.so .DS_Store - -# Packaging -build/ -dist/ -*.egg-info/ - -# Virtualenvs -.venv/ -venv/ - -# Jupyter -.ipynb_checkpoints/ - -# Tool caches +__pycache__/ +*.pyc .pytest_cache/ -.mypy_cache/ -.ruff_cache/ -.coverage -htmlcov/ - -# Sphinx -_site/ docs/_build/ - -# Local data cache -.data_cache/ -data_cache/ -output/data_download/ -*.zip - -# Local report artifacts -output/ -tmp/ - -# Internal-only porting/parity notes (kept outside public repo) -CLEANROOM_POLICY.md -PARITY_SPEC.md -CANONICAL_VALIDATION_ARTIFACTS.md -DISCREPANCIES.md -parity/CYCLE_VALIDATION_CHECKLIST.md -parity/class_equivalence_inventory.json -parity/class_equivalence_report.json -parity/cycle_validation/ -parity/matlab_reference_checkout.json +plots/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 09635406..00000000 --- a/LICENSE +++ /dev/null @@ -1,8 +0,0 @@ -GNU GENERAL PUBLIC LICENSE -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -This project is licensed under GPL-2.0-or-later. -For full license text, see https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html diff --git a/README.md b/README.md index ea86af42..ee85b9da 100644 --- a/README.md +++ b/README.md @@ -203,10 +203,40 @@ fig.savefig(out_dir / "readme_example3_nstcoll_raster.png", dpi=180) **Expected output** ![Spike train raster](examples/readme_examples/images/readme_example3_nstcoll_raster.png) -## Examples and notebooks - -- Python scripts and notebooks: `notebooks/` -- Learning notebooks are executable and suitable for local exploration or CI smoke runs. +### nSTATPaperExamples + +Complete catalog of nSTATPaperExamples notebooks: + +- [AnalysisExamples](notebooks/AnalysisExamples.ipynb) — Notebook generated from MATLAB help source for AnalysisExamples. +- [ConfigCollExamples](notebooks/ConfigCollExamples.ipynb) — Notebook generated from MATLAB help source for ConfigCollExamples. +- [CovCollExamples](notebooks/CovCollExamples.ipynb) — Notebook generated from MATLAB help source for CovCollExamples. +- [CovariateExamples](notebooks/CovariateExamples.ipynb) — Notebook generated from MATLAB help source for CovariateExamples. +- [DecodingExample](notebooks/DecodingExample.ipynb) — Notebook generated from MATLAB help source for DecodingExample. +- [DecodingExampleWithHist](notebooks/DecodingExampleWithHist.ipynb) — Notebook generated from MATLAB help source for DecodingExampleWithHist. +- [EventsExamples](notebooks/EventsExamples.ipynb) — Notebook generated from MATLAB help source for EventsExamples. +- [ExplicitStimulusWhiskerData](notebooks/ExplicitStimulusWhiskerData.ipynb) — Notebook generated from MATLAB help source for ExplicitStimulusWhiskerData. +- [FitResSummaryExamples](notebooks/FitResSummaryExamples.ipynb) — Notebook generated from MATLAB help source for FitResSummaryExamples. +- [FitResultExamples](notebooks/FitResultExamples.ipynb) — Notebook generated from MATLAB help source for FitResultExamples. +- [HippocampalPlaceCellExample](notebooks/HippocampalPlaceCellExample.ipynb) — Notebook generated from MATLAB help source for HippocampalPlaceCellExample. +- [HistoryExamples](notebooks/HistoryExamples.ipynb) — Notebook generated from MATLAB help source for HistoryExamples. +- [NetworkTutorial](notebooks/NetworkTutorial.ipynb) — Notebook generated from MATLAB help source for NetworkTutorial. +- [PPSimExample](notebooks/PPSimExample.ipynb) — Notebook generated from MATLAB help source for PPSimExample. +- [PPThinning](notebooks/PPThinning.ipynb) — Notebook generated from MATLAB help source for PPThinning. +- [PSTHEstimation](notebooks/PSTHEstimation.ipynb) — Notebook generated from MATLAB help source for PSTHEstimation. +- [SignalObjExamples](notebooks/SignalObjExamples.ipynb) — Notebook generated from MATLAB help source for SignalObjExamples. +- [StimulusDecode2D](notebooks/StimulusDecode2D.ipynb) — Notebook generated from MATLAB help source for StimulusDecode2D. +- [TrialConfigExamples](notebooks/TrialConfigExamples.ipynb) — Notebook generated from MATLAB help source for TrialConfigExamples. +- [TrialExamples](notebooks/TrialExamples.ipynb) — Notebook generated from MATLAB help source for TrialExamples. +- [ValidationDataSet](notebooks/ValidationDataSet.ipynb) — Notebook generated from MATLAB help source for ValidationDataSet. +- [mEPSCAnalysis](notebooks/mEPSCAnalysis.ipynb) — Notebook generated from MATLAB help source for mEPSCAnalysis. +- [nSTATPaperExamples](notebooks/nSTATPaperExamples.ipynb) — Notebook generated from MATLAB help source for nSTATPaperExamples. +- [nSpikeTrainExamples](notebooks/nSpikeTrainExamples.ipynb) — Notebook generated from MATLAB help source for nSpikeTrainExamples. +- [nstCollExamples](notebooks/nstCollExamples.ipynb) — Notebook generated from MATLAB help source for nstCollExamples. +- [AnalysisExamples2](notebooks/AnalysisExamples2.ipynb) — Notebook generated from MATLAB help source for AnalysisExamples2. +- [DocumentationSetup2025b](notebooks/DocumentationSetup2025b.ipynb) — Notebook generated from MATLAB help source for DocumentationSetup2025b. +- [FitResultReference](notebooks/FitResultReference.ipynb) — Notebook generated from MATLAB help source for FitResultReference. +- [HybridFilterExample](notebooks/HybridFilterExample.ipynb) — Notebook generated from MATLAB help source for HybridFilterExample. +- [publish_all_helpfiles](notebooks/publish_all_helpfiles.ipynb) — Notebook generated from MATLAB help source for publish_all_helpfiles. ## Documentation diff --git a/tools/__init__.py b/__init__.py similarity index 100% rename from tools/__init__.py rename to __init__.py diff --git a/baseline/baseline_lock.yml b/baseline/baseline_lock.yml deleted file mode 100644 index d67fcc05..00000000 --- a/baseline/baseline_lock.yml +++ /dev/null @@ -1,59 +0,0 @@ -version: 1 -locked_at_utc: "2026-03-02T16:26:30Z" -matlab_reference: - repo_path: "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local" - ref: "refs/heads/codex/split-nstat-python-bootstrap" - commit: "1b5237b3176f6fc8aa3199d471e4bb7845a3ad5a" -python_target: - repo_path: "/private/tmp/nSTAT-python-cleanroom" - ref: "refs/heads/main" - commit: "8b69adf11dc0ff340e416ce97ffc90eebc011c41" -scope: - required_matlab_classes: - - SignalObj - - Covariate - - ConfidenceInterval - - Events - - History - - nspikeTrain - - nstColl - - CovColl - - TrialConfig - - ConfigColl - - Trial - - CIF - - Analysis - - FitResult - - FitResSummary - - DecodingAlgorithms - required_example_topics: - - AnalysisExamples - - AnalysisExamples2 - - ConfigCollExamples - - CovCollExamples - - CovariateExamples - - DecodingExample - - DecodingExampleWithHist - - DocumentationSetup2025b - - EventsExamples - - ExplicitStimulusWhiskerData - - FitResSummaryExamples - - FitResultExamples - - FitResultReference - - HippocampalPlaceCellExample - - HistoryExamples - - HybridFilterExample - - NetworkTutorial - - PPSimExample - - PPThinning - - PSTHEstimation - - SignalObjExamples - - StimulusDecode2D - - TrialConfigExamples - - TrialExamples - - ValidationDataSet - - mEPSCAnalysis - - nSTATPaperExamples - - nSpikeTrainExamples - - nstCollExamples - - publish_all_helpfiles diff --git a/baseline/class_method_inventory.yml b/baseline/class_method_inventory.yml deleted file mode 100644 index edd4c818..00000000 --- a/baseline/class_method_inventory.yml +++ /dev/null @@ -1,108 +0,0 @@ -version: 1 -source: "Derived clean-room interface manifest authored for nSTAT-python" - -classes: - - matlab_class: SignalObj - python_class: nstat.signal.Signal - methods: - - copy - - n_samples - - n_channels - - sample_rate_hz - - duration_s - - - matlab_class: Covariate - python_class: nstat.signal.Covariate - methods: - - labels - - n_channels - - sample_rate_hz - - - matlab_class: ConfidenceInterval - python_class: nstat.confidence.ConfidenceInterval - methods: - - width - - contains - - - matlab_class: Events - python_class: nstat.events.Events - methods: - - subset - - - matlab_class: History - python_class: nstat.history.HistoryBasis - methods: - - n_bins - - design_matrix - - - matlab_class: nspikeTrain - python_class: nstat.spikes.SpikeTrain - methods: - - duration_s - - firing_rate_hz - - bin_counts - - binarize - - - matlab_class: nstColl - python_class: nstat.spikes.SpikeTrainCollection - methods: - - n_units - - to_binned_matrix - - - matlab_class: CovColl - python_class: nstat.trial.CovariateCollection - methods: - - time - - design_matrix - - - matlab_class: TrialConfig - python_class: nstat.trial.TrialConfig - methods: - - covariate_labels - - sample_rate_hz - - fit_type - - - matlab_class: ConfigColl - python_class: nstat.trial.ConfigCollection - methods: - - configs - - - matlab_class: Trial - python_class: nstat.trial.Trial - methods: - - aligned_binned_observation - - - matlab_class: CIF - python_class: nstat.cif.CIFModel - methods: - - linear_predictor - - evaluate - - log_likelihood - - simulate_by_thinning - - - matlab_class: Analysis - python_class: nstat.analysis.Analysis - methods: - - fit_glm - - fit_trial - - - matlab_class: FitResult - python_class: nstat.fit.FitResult - methods: - - as_cif_model - - predict - - aic - - bic - - - matlab_class: FitResSummary - python_class: nstat.fit.FitSummary - methods: - - best_by_aic - - best_by_bic - - - matlab_class: DecodingAlgorithms - python_class: nstat.decoding.DecodingAlgorithms - methods: - - compute_spike_rate_cis - - decode_weighted_center - - decode_state_posterior diff --git a/baseline/example_workflow_inventory.yml b/baseline/example_workflow_inventory.yml deleted file mode 100644 index 27112082..00000000 --- a/baseline/example_workflow_inventory.yml +++ /dev/null @@ -1,123 +0,0 @@ -version: 1 -source: Derived clean-room workflow inventory authored for nSTAT-python -workflows: -- topic: AnalysisExamples - notebook: notebooks/AnalysisExamples.ipynb - help_page: docs/help/examples/AnalysisExamples.md - run_group: smoke -- topic: ConfigCollExamples - notebook: notebooks/ConfigCollExamples.ipynb - help_page: docs/help/examples/ConfigCollExamples.md - run_group: full -- topic: CovCollExamples - notebook: notebooks/CovCollExamples.ipynb - help_page: docs/help/examples/CovCollExamples.md - run_group: full -- topic: CovariateExamples - notebook: notebooks/CovariateExamples.ipynb - help_page: docs/help/examples/CovariateExamples.md - run_group: smoke -- topic: DecodingExample - notebook: notebooks/DecodingExample.ipynb - help_page: docs/help/examples/DecodingExample.md - run_group: smoke -- topic: DecodingExampleWithHist - notebook: notebooks/DecodingExampleWithHist.ipynb - help_page: docs/help/examples/DecodingExampleWithHist.md - run_group: full -- topic: EventsExamples - notebook: notebooks/EventsExamples.ipynb - help_page: docs/help/examples/EventsExamples.md - run_group: full -- topic: ExplicitStimulusWhiskerData - notebook: notebooks/ExplicitStimulusWhiskerData.ipynb - help_page: docs/help/examples/ExplicitStimulusWhiskerData.md - run_group: full -- topic: FitResSummaryExamples - notebook: notebooks/FitResSummaryExamples.ipynb - help_page: docs/help/examples/FitResSummaryExamples.md - run_group: full -- topic: FitResultExamples - notebook: notebooks/FitResultExamples.ipynb - help_page: docs/help/examples/FitResultExamples.md - run_group: full -- topic: HippocampalPlaceCellExample - notebook: notebooks/HippocampalPlaceCellExample.ipynb - help_page: docs/help/examples/HippocampalPlaceCellExample.md - run_group: full -- topic: HistoryExamples - notebook: notebooks/HistoryExamples.ipynb - help_page: docs/help/examples/HistoryExamples.md - run_group: full -- topic: NetworkTutorial - notebook: notebooks/NetworkTutorial.ipynb - help_page: docs/help/examples/NetworkTutorial.md - run_group: full -- topic: PPSimExample - notebook: notebooks/PPSimExample.ipynb - help_page: docs/help/examples/PPSimExample.md - run_group: full -- topic: PPThinning - notebook: notebooks/PPThinning.ipynb - help_page: docs/help/examples/PPThinning.md - run_group: full -- topic: PSTHEstimation - notebook: notebooks/PSTHEstimation.ipynb - help_page: docs/help/examples/PSTHEstimation.md - run_group: full -- topic: SignalObjExamples - notebook: notebooks/SignalObjExamples.ipynb - help_page: docs/help/examples/SignalObjExamples.md - run_group: smoke -- topic: StimulusDecode2D - notebook: notebooks/StimulusDecode2D.ipynb - help_page: docs/help/examples/StimulusDecode2D.md - run_group: full -- topic: TrialConfigExamples - notebook: notebooks/TrialConfigExamples.ipynb - help_page: docs/help/examples/TrialConfigExamples.md - run_group: full -- topic: TrialExamples - notebook: notebooks/TrialExamples.ipynb - help_page: docs/help/examples/TrialExamples.md - run_group: full -- topic: ValidationDataSet - notebook: notebooks/ValidationDataSet.ipynb - help_page: docs/help/examples/ValidationDataSet.md - run_group: full -- topic: mEPSCAnalysis - notebook: notebooks/mEPSCAnalysis.ipynb - help_page: docs/help/examples/mEPSCAnalysis.md - run_group: full -- topic: nSTATPaperExamples - notebook: notebooks/nSTATPaperExamples.ipynb - help_page: docs/help/examples/nSTATPaperExamples.md - run_group: smoke -- topic: nSpikeTrainExamples - notebook: notebooks/nSpikeTrainExamples.ipynb - help_page: docs/help/examples/nSpikeTrainExamples.md - run_group: smoke -- topic: nstCollExamples - notebook: notebooks/nstCollExamples.ipynb - help_page: docs/help/examples/nstCollExamples.md - run_group: full -- topic: AnalysisExamples2 - notebook: notebooks/AnalysisExamples2.ipynb - help_page: docs/help/examples/AnalysisExamples2.md - run_group: full -- topic: DocumentationSetup2025b - notebook: notebooks/DocumentationSetup2025b.ipynb - help_page: docs/help/examples/DocumentationSetup2025b.md - run_group: full -- topic: FitResultReference - notebook: notebooks/FitResultReference.ipynb - help_page: docs/help/examples/FitResultReference.md - run_group: full -- topic: HybridFilterExample - notebook: notebooks/HybridFilterExample.ipynb - help_page: docs/help/examples/HybridFilterExample.md - run_group: full -- topic: publish_all_helpfiles - notebook: notebooks/publish_all_helpfiles.ipynb - help_page: docs/help/examples/publish_all_helpfiles.md - run_group: full diff --git a/baseline/help_mapping.json b/baseline/help_mapping.json deleted file mode 100644 index 83e07a80..00000000 --- a/baseline/help_mapping.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "classes": [ - { - "matlab": "SignalObj", - "python": "nstat.signal.Signal" - }, - { - "matlab": "Covariate", - "python": "nstat.signal.Covariate" - }, - { - "matlab": "ConfidenceInterval", - "python": "nstat.confidence.ConfidenceInterval" - }, - { - "matlab": "Events", - "python": "nstat.events.Events" - }, - { - "matlab": "History", - "python": "nstat.history.HistoryBasis" - }, - { - "matlab": "nspikeTrain", - "python": "nstat.spikes.SpikeTrain" - }, - { - "matlab": "nstColl", - "python": "nstat.spikes.SpikeTrainCollection" - }, - { - "matlab": "CovColl", - "python": "nstat.trial.CovariateCollection" - }, - { - "matlab": "TrialConfig", - "python": "nstat.trial.TrialConfig" - }, - { - "matlab": "ConfigColl", - "python": "nstat.trial.ConfigCollection" - }, - { - "matlab": "Trial", - "python": "nstat.trial.Trial" - }, - { - "matlab": "CIF", - "python": "nstat.cif.CIFModel" - }, - { - "matlab": "Analysis", - "python": "nstat.analysis.Analysis" - }, - { - "matlab": "FitResult", - "python": "nstat.fit.FitResult" - }, - { - "matlab": "FitResSummary", - "python": "nstat.fit.FitSummary" - }, - { - "matlab": "DecodingAlgorithms", - "python": "nstat.decoding.DecodingAlgorithms" - } - ], - "topics": [ - "AnalysisExamples", - "ConfigCollExamples", - "CovCollExamples", - "CovariateExamples", - "DecodingExample", - "DecodingExampleWithHist", - "EventsExamples", - "ExplicitStimulusWhiskerData", - "FitResSummaryExamples", - "FitResultExamples", - "HippocampalPlaceCellExample", - "HistoryExamples", - "NetworkTutorial", - "PPSimExample", - "PPThinning", - "PSTHEstimation", - "SignalObjExamples", - "StimulusDecode2D", - "TrialConfigExamples", - "TrialExamples", - "ValidationDataSet", - "mEPSCAnalysis", - "nSTATPaperExamples", - "nSpikeTrainExamples", - "nstCollExamples", - "AnalysisExamples2", - "DocumentationSetup2025b", - "FitResultReference", - "HybridFilterExample", - "publish_all_helpfiles" - ] -} diff --git a/baseline/paper_section_mapping.yml b/baseline/paper_section_mapping.yml deleted file mode 100644 index 2441d90b..00000000 --- a/baseline/paper_section_mapping.yml +++ /dev/null @@ -1,36 +0,0 @@ -version: 1 -paper: - citation: "Cajigas I, Malik WQ, Brown EN. J Neurosci Methods. 2012;211(2):245-264" - doi: "10.1016/j.jneumeth.2012.08.009" - pmid: "22981419" - -sections: - - section: "Point-process conditional intensity modeling" - modules: - - nstat.cif - - nstat.analysis - notes: "CIF construction and likelihood-based fitting" - - - section: "History-dependent and covariate-driven models" - modules: - - nstat.history - - nstat.trial - - nstat.signal - notes: "History basis and trial design matrix assembly" - - - section: "Model quality and comparison" - modules: - - nstat.fit - notes: "AIC/BIC and likelihood summaries" - - - section: "Decoding and comparative inference" - modules: - - nstat.decoding - - nstat.confidence - notes: "Decoding utilities and confidence summaries" - - - section: "Workflow organization and examples" - modules: - - notebooks - - docs/help - notes: "End-to-end pedagogical workflows and searchable help" diff --git a/baseline/parity_manifest.yml b/baseline/parity_manifest.yml deleted file mode 100644 index 2538c999..00000000 --- a/baseline/parity_manifest.yml +++ /dev/null @@ -1,205 +0,0 @@ -version: 1 -policy: - clean_room: true - matlab_runtime_dependency: false - copied_non_data_files_allowed: false - -metadata: - source: "Derived behavior specification authored for nSTAT-python" - doi: "10.1016/j.jneumeth.2012.08.009" - pmid: "22981419" - behavior_contracts_file: tests/parity/class_behavior_specs.yml - -classes: - - matlab_class: SignalObj - python_class: nstat.signal.Signal - public_methods: - - name: copy - signature: "()" - - name: n_samples - signature: "property" - - name: n_channels - signature: "property" - - name: sample_rate_hz - signature: "property" - - name: duration_s - signature: "property" - - - matlab_class: Covariate - python_class: nstat.signal.Covariate - public_methods: - - name: labels - signature: "attribute[list[str]]" - - name: n_channels - signature: "property" - - - matlab_class: ConfidenceInterval - python_class: nstat.confidence.ConfidenceInterval - public_methods: - - name: width - signature: "()" - - name: contains - signature: "(values)" - - - matlab_class: Events - python_class: nstat.events.Events - public_methods: - - name: subset - signature: "(start_s, end_s)" - - - matlab_class: History - python_class: nstat.history.HistoryBasis - public_methods: - - name: n_bins - signature: "property" - - name: design_matrix - signature: "(spike_times_s, time_grid_s)" - - - matlab_class: nspikeTrain - python_class: nstat.spikes.SpikeTrain - public_methods: - - name: duration_s - signature: "()" - - name: firing_rate_hz - signature: "()" - - name: bin_counts - signature: "(bin_size_s)" - - name: binarize - signature: "(bin_size_s)" - - - matlab_class: nstColl - python_class: nstat.spikes.SpikeTrainCollection - public_methods: - - name: n_units - signature: "property" - - name: to_binned_matrix - signature: "(bin_size_s, mode='binary')" - - - matlab_class: CovColl - python_class: nstat.trial.CovariateCollection - public_methods: - - name: time - signature: "property" - - name: design_matrix - signature: "()" - - - matlab_class: TrialConfig - python_class: nstat.trial.TrialConfig - public_methods: - - name: covariate_labels - signature: "attribute[list[str]]" - - name: sample_rate_hz - signature: "attribute[float]" - - name: fit_type - signature: "attribute[str]" - - - matlab_class: ConfigColl - python_class: nstat.trial.ConfigCollection - public_methods: - - name: configs - signature: "attribute[list[TrialConfig]]" - - - matlab_class: Trial - python_class: nstat.trial.Trial - public_methods: - - name: aligned_binned_observation - signature: "(bin_size_s, unit_index=0, mode='binary')" - - - matlab_class: CIF - python_class: nstat.cif.CIFModel - public_methods: - - name: linear_predictor - signature: "(X)" - - name: evaluate - signature: "(X)" - - name: log_likelihood - signature: "(y, X, dt=1.0)" - - name: simulate_by_thinning - signature: "(time, X, rng=None)" - - - matlab_class: Analysis - python_class: nstat.analysis.Analysis - public_methods: - - name: fit_glm - signature: "(X, y, fit_type='poisson', dt=1.0, l2_penalty=0.0)" - - name: fit_trial - signature: "(trial, config, unit_index=0)" - - - matlab_class: FitResult - python_class: nstat.fit.FitResult - public_methods: - - name: as_cif_model - signature: "()" - - name: predict - signature: "(X)" - - name: aic - signature: "()" - - name: bic - signature: "()" - - - matlab_class: FitResSummary - python_class: nstat.fit.FitSummary - public_methods: - - name: best_by_aic - signature: "()" - - name: best_by_bic - signature: "()" - - - matlab_class: DecodingAlgorithms - python_class: nstat.decoding.DecodingAlgorithms - public_methods: - - name: compute_spike_rate_cis - signature: "(spike_matrix, alpha=0.05)" - - name: decode_weighted_center - signature: "(spike_counts, tuning_curves)" - - name: decode_state_posterior - signature: "(spike_counts, tuning_rates, transition=None, prior=None)" - -workflows: - - topic: PPSimExample - notebook: notebooks/PPSimExample.ipynb - help_page: docs/help/examples/PPSimExample.md - modules: - - nstat.spikes - - nstat.cif - - nstat.analysis - - nstat.fit - expected_metrics: - - name: poisson_coefficient_error - tolerance_key: "poisson_glm.coefficient_abs_tol" - - name: poisson_rate_relative_error - tolerance_key: "poisson_glm.rate_rel_tol" - - - topic: DecodingExampleWithHist - notebook: notebooks/DecodingExampleWithHist.ipynb - help_page: docs/help/examples/DecodingExampleWithHist.md - modules: - - nstat.history - - nstat.decoding - expected_metrics: - - name: history_corrected_normalized_rmse - tolerance_key: "decoding.normalized_rmse_tol" - - - topic: HippocampalPlaceCellExample - notebook: notebooks/HippocampalPlaceCellExample.ipynb - help_page: docs/help/examples/HippocampalPlaceCellExample.md - modules: - - nstat.decoding - expected_metrics: - - name: place_decoding_normalized_rmse - tolerance_key: "place_decoding.normalized_rmse_tol" - - - topic: nSTATPaperExamples - notebook: notebooks/nSTATPaperExamples.ipynb - help_page: docs/help/examples/nSTATPaperExamples.md - modules: - - nstat.spikes - - nstat.cif - - nstat.analysis - - nstat.fit - - nstat.decoding - expected_metrics: - - name: poisson_coefficient_error - tolerance_key: "poisson_glm.coefficient_abs_tol" - - name: decoding_normalized_rmse - tolerance_key: "decoding.normalized_rmse_tol" diff --git a/baseline/validation/notebook_images/AnalysisExamples/AnalysisExamples_001.png b/baseline/validation/notebook_images/AnalysisExamples/AnalysisExamples_001.png deleted file mode 100644 index 3d1ac5c5..00000000 Binary files a/baseline/validation/notebook_images/AnalysisExamples/AnalysisExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/AnalysisExamples2/AnalysisExamples2_001.png b/baseline/validation/notebook_images/AnalysisExamples2/AnalysisExamples2_001.png deleted file mode 100644 index 358d27c5..00000000 Binary files a/baseline/validation/notebook_images/AnalysisExamples2/AnalysisExamples2_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/ConfigCollExamples/ConfigCollExamples_001.png b/baseline/validation/notebook_images/ConfigCollExamples/ConfigCollExamples_001.png deleted file mode 100644 index a184611d..00000000 Binary files a/baseline/validation/notebook_images/ConfigCollExamples/ConfigCollExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/CovCollExamples/CovCollExamples_001.png b/baseline/validation/notebook_images/CovCollExamples/CovCollExamples_001.png deleted file mode 100644 index 86a2c2e4..00000000 Binary files a/baseline/validation/notebook_images/CovCollExamples/CovCollExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/CovariateExamples/CovariateExamples_001.png b/baseline/validation/notebook_images/CovariateExamples/CovariateExamples_001.png deleted file mode 100644 index ea83e407..00000000 Binary files a/baseline/validation/notebook_images/CovariateExamples/CovariateExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/CovariateExamples/CovariateExamples_002.png b/baseline/validation/notebook_images/CovariateExamples/CovariateExamples_002.png deleted file mode 100644 index cb40c9e3..00000000 Binary files a/baseline/validation/notebook_images/CovariateExamples/CovariateExamples_002.png and /dev/null differ diff --git a/baseline/validation/notebook_images/DecodingExample/DecodingExample_001.png b/baseline/validation/notebook_images/DecodingExample/DecodingExample_001.png deleted file mode 100644 index 400e6cbc..00000000 Binary files a/baseline/validation/notebook_images/DecodingExample/DecodingExample_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/DecodingExampleWithHist/DecodingExampleWithHist_001.png b/baseline/validation/notebook_images/DecodingExampleWithHist/DecodingExampleWithHist_001.png deleted file mode 100644 index 78ab5adc..00000000 Binary files a/baseline/validation/notebook_images/DecodingExampleWithHist/DecodingExampleWithHist_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/DocumentationSetup2025b/DocumentationSetup2025b_001.png b/baseline/validation/notebook_images/DocumentationSetup2025b/DocumentationSetup2025b_001.png deleted file mode 100644 index 1c68913e..00000000 Binary files a/baseline/validation/notebook_images/DocumentationSetup2025b/DocumentationSetup2025b_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/EventsExamples/EventsExamples_001.png b/baseline/validation/notebook_images/EventsExamples/EventsExamples_001.png deleted file mode 100644 index bc258f28..00000000 Binary files a/baseline/validation/notebook_images/EventsExamples/EventsExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/EventsExamples/EventsExamples_002.png b/baseline/validation/notebook_images/EventsExamples/EventsExamples_002.png deleted file mode 100644 index bc258f28..00000000 Binary files a/baseline/validation/notebook_images/EventsExamples/EventsExamples_002.png and /dev/null differ diff --git a/baseline/validation/notebook_images/EventsExamples/EventsExamples_003.png b/baseline/validation/notebook_images/EventsExamples/EventsExamples_003.png deleted file mode 100644 index bc258f28..00000000 Binary files a/baseline/validation/notebook_images/EventsExamples/EventsExamples_003.png and /dev/null differ diff --git a/baseline/validation/notebook_images/EventsExamples/EventsExamples_004.png b/baseline/validation/notebook_images/EventsExamples/EventsExamples_004.png deleted file mode 100644 index bc258f28..00000000 Binary files a/baseline/validation/notebook_images/EventsExamples/EventsExamples_004.png and /dev/null differ diff --git a/baseline/validation/notebook_images/ExplicitStimulusWhiskerData/ExplicitStimulusWhiskerData_001.png b/baseline/validation/notebook_images/ExplicitStimulusWhiskerData/ExplicitStimulusWhiskerData_001.png deleted file mode 100644 index 776d2baa..00000000 Binary files a/baseline/validation/notebook_images/ExplicitStimulusWhiskerData/ExplicitStimulusWhiskerData_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/FitResSummaryExamples/FitResSummaryExamples_001.png b/baseline/validation/notebook_images/FitResSummaryExamples/FitResSummaryExamples_001.png deleted file mode 100644 index 2eed4e3f..00000000 Binary files a/baseline/validation/notebook_images/FitResSummaryExamples/FitResSummaryExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/FitResultExamples/FitResultExamples_001.png b/baseline/validation/notebook_images/FitResultExamples/FitResultExamples_001.png deleted file mode 100644 index 07bd16b4..00000000 Binary files a/baseline/validation/notebook_images/FitResultExamples/FitResultExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/FitResultReference/FitResultReference_001.png b/baseline/validation/notebook_images/FitResultReference/FitResultReference_001.png deleted file mode 100644 index c05c3169..00000000 Binary files a/baseline/validation/notebook_images/FitResultReference/FitResultReference_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/HippocampalPlaceCellExample/HippocampalPlaceCellExample_001.png b/baseline/validation/notebook_images/HippocampalPlaceCellExample/HippocampalPlaceCellExample_001.png deleted file mode 100644 index 902d6403..00000000 Binary files a/baseline/validation/notebook_images/HippocampalPlaceCellExample/HippocampalPlaceCellExample_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/HistoryExamples/HistoryExamples_001.png b/baseline/validation/notebook_images/HistoryExamples/HistoryExamples_001.png deleted file mode 100644 index cc8b1d9b..00000000 Binary files a/baseline/validation/notebook_images/HistoryExamples/HistoryExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/HybridFilterExample/HybridFilterExample_001.png b/baseline/validation/notebook_images/HybridFilterExample/HybridFilterExample_001.png deleted file mode 100644 index 6f5a4b40..00000000 Binary files a/baseline/validation/notebook_images/HybridFilterExample/HybridFilterExample_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/HybridFilterExample/HybridFilterExample_002.png b/baseline/validation/notebook_images/HybridFilterExample/HybridFilterExample_002.png deleted file mode 100644 index 5d3726c0..00000000 Binary files a/baseline/validation/notebook_images/HybridFilterExample/HybridFilterExample_002.png and /dev/null differ diff --git a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_001.png b/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_001.png deleted file mode 100644 index 29e3bf39..00000000 Binary files a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_002.png b/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_002.png deleted file mode 100644 index 95f1e294..00000000 Binary files a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_002.png and /dev/null differ diff --git a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_003.png b/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_003.png deleted file mode 100644 index 539f7e70..00000000 Binary files a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_003.png and /dev/null differ diff --git a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_004.png b/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_004.png deleted file mode 100644 index 24b60cda..00000000 Binary files a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_004.png and /dev/null differ diff --git a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_005.png b/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_005.png deleted file mode 100644 index d64c2a09..00000000 Binary files a/baseline/validation/notebook_images/NetworkTutorial/NetworkTutorial_005.png and /dev/null differ diff --git a/baseline/validation/notebook_images/PPSimExample/PPSimExample_001.png b/baseline/validation/notebook_images/PPSimExample/PPSimExample_001.png deleted file mode 100644 index d22efe9f..00000000 Binary files a/baseline/validation/notebook_images/PPSimExample/PPSimExample_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/PPSimExample/PPSimExample_002.png b/baseline/validation/notebook_images/PPSimExample/PPSimExample_002.png deleted file mode 100644 index b388151d..00000000 Binary files a/baseline/validation/notebook_images/PPSimExample/PPSimExample_002.png and /dev/null differ diff --git a/baseline/validation/notebook_images/PPSimExample/PPSimExample_003.png b/baseline/validation/notebook_images/PPSimExample/PPSimExample_003.png deleted file mode 100644 index 8ebdf7d6..00000000 Binary files a/baseline/validation/notebook_images/PPSimExample/PPSimExample_003.png and /dev/null differ diff --git a/baseline/validation/notebook_images/PPThinning/PPThinning_001.png b/baseline/validation/notebook_images/PPThinning/PPThinning_001.png deleted file mode 100644 index d0ffc9d1..00000000 Binary files a/baseline/validation/notebook_images/PPThinning/PPThinning_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/PPThinning/PPThinning_002.png b/baseline/validation/notebook_images/PPThinning/PPThinning_002.png deleted file mode 100644 index d3b363e2..00000000 Binary files a/baseline/validation/notebook_images/PPThinning/PPThinning_002.png and /dev/null differ diff --git a/baseline/validation/notebook_images/PPThinning/PPThinning_003.png b/baseline/validation/notebook_images/PPThinning/PPThinning_003.png deleted file mode 100644 index 0fee1f22..00000000 Binary files a/baseline/validation/notebook_images/PPThinning/PPThinning_003.png and /dev/null differ diff --git a/baseline/validation/notebook_images/PPThinning/PPThinning_004.png b/baseline/validation/notebook_images/PPThinning/PPThinning_004.png deleted file mode 100644 index 1b81814b..00000000 Binary files a/baseline/validation/notebook_images/PPThinning/PPThinning_004.png and /dev/null differ diff --git a/baseline/validation/notebook_images/PSTHEstimation/PSTHEstimation_001.png b/baseline/validation/notebook_images/PSTHEstimation/PSTHEstimation_001.png deleted file mode 100644 index e257dfdc..00000000 Binary files a/baseline/validation/notebook_images/PSTHEstimation/PSTHEstimation_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_001.png b/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_001.png deleted file mode 100644 index cfb125fd..00000000 Binary files a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_002.png b/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_002.png deleted file mode 100644 index 6a2126ac..00000000 Binary files a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_002.png and /dev/null differ diff --git a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_003.png b/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_003.png deleted file mode 100644 index f51804e3..00000000 Binary files a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_003.png and /dev/null differ diff --git a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_004.png b/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_004.png deleted file mode 100644 index a80cce10..00000000 Binary files a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_004.png and /dev/null differ diff --git a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_005.png b/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_005.png deleted file mode 100644 index ba175d65..00000000 Binary files a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_005.png and /dev/null differ diff --git a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_006.png b/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_006.png deleted file mode 100644 index ab1c3fcd..00000000 Binary files a/baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_006.png and /dev/null differ diff --git a/baseline/validation/notebook_images/StimulusDecode2D/StimulusDecode2D_001.png b/baseline/validation/notebook_images/StimulusDecode2D/StimulusDecode2D_001.png deleted file mode 100644 index a9c2a831..00000000 Binary files a/baseline/validation/notebook_images/StimulusDecode2D/StimulusDecode2D_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/TrialConfigExamples/TrialConfigExamples_001.png b/baseline/validation/notebook_images/TrialConfigExamples/TrialConfigExamples_001.png deleted file mode 100644 index f5e9d7ac..00000000 Binary files a/baseline/validation/notebook_images/TrialConfigExamples/TrialConfigExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/TrialExamples/TrialExamples_001.png b/baseline/validation/notebook_images/TrialExamples/TrialExamples_001.png deleted file mode 100644 index bf1ed1b3..00000000 Binary files a/baseline/validation/notebook_images/TrialExamples/TrialExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/ValidationDataSet/ValidationDataSet_001.png b/baseline/validation/notebook_images/ValidationDataSet/ValidationDataSet_001.png deleted file mode 100644 index 443a41b4..00000000 Binary files a/baseline/validation/notebook_images/ValidationDataSet/ValidationDataSet_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/mEPSCAnalysis/mEPSCAnalysis_001.png b/baseline/validation/notebook_images/mEPSCAnalysis/mEPSCAnalysis_001.png deleted file mode 100644 index 3cbe6e44..00000000 Binary files a/baseline/validation/notebook_images/mEPSCAnalysis/mEPSCAnalysis_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/nSTATPaperExamples/nSTATPaperExamples_001.png b/baseline/validation/notebook_images/nSTATPaperExamples/nSTATPaperExamples_001.png deleted file mode 100644 index 0221abd3..00000000 Binary files a/baseline/validation/notebook_images/nSTATPaperExamples/nSTATPaperExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/nSpikeTrainExamples/nSpikeTrainExamples_001.png b/baseline/validation/notebook_images/nSpikeTrainExamples/nSpikeTrainExamples_001.png deleted file mode 100644 index fdbd4bbb..00000000 Binary files a/baseline/validation/notebook_images/nSpikeTrainExamples/nSpikeTrainExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/nstCollExamples/nstCollExamples_001.png b/baseline/validation/notebook_images/nstCollExamples/nstCollExamples_001.png deleted file mode 100644 index 1af76721..00000000 Binary files a/baseline/validation/notebook_images/nstCollExamples/nstCollExamples_001.png and /dev/null differ diff --git a/baseline/validation/notebook_images/publish_all_helpfiles/publish_all_helpfiles_001.png b/baseline/validation/notebook_images/publish_all_helpfiles/publish_all_helpfiles_001.png deleted file mode 100644 index 47ff1672..00000000 Binary files a/baseline/validation/notebook_images/publish_all_helpfiles/publish_all_helpfiles_001.png and /dev/null differ diff --git a/data/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat b/data/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat new file mode 100644 index 00000000..b8a024c7 Binary files /dev/null and b/data/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat differ diff --git a/data/Place Cells/PlaceCellDataAnimal1.mat b/data/Place Cells/PlaceCellDataAnimal1.mat new file mode 100644 index 00000000..3bb0d52f Binary files /dev/null and b/data/Place Cells/PlaceCellDataAnimal1.mat differ diff --git a/data/README.md b/data/README.md deleted file mode 100644 index f6a9ec5e..00000000 --- a/data/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Shared Example Data Policy - -This directory tracks only shared example datasets. - -Rules: -- Data may be shared with MATLAB nSTAT when explicitly listed in `datasets_manifest.json`. -- Every dataset record must include immutable version and SHA256 checksum. -- No non-data files are shared across repositories. - -Recommended flow: -1. Publish immutable data artifacts (for example, GitHub Release assets). -2. Add records to `datasets_manifest.json` with URL and checksum. -3. Update `tools/compliance/shared_data_allowlist.yml` with approved overlaps. - -Current shared records: -- `mEPSC-epsc2` (source: `cajigaslab/nSTAT`, path `data/mEPSCs/epsc2.txt`) - -MATLAB example-data mirror workflow: -0. One-command workflow (recommended): - - `python tools/data_mirror/run_mirror_workflow.py --source-root --version --clean` - -1. Build source snapshot manifest: - - `python tools/data_mirror/build_manifest.py --source-root --version --out data/shared/matlab_source_.manifest.json` -2. Sync exact mirrored copy into this repository: - - `python tools/data_mirror/sync_matlab_data.py --source-root --version --dest-root data/shared --clean` -3. Regenerate clean-room allowlist entries from mirror manifest: - - `python tools/compliance/update_shared_data_allowlist.py --manifest data/shared/matlab_gold_.manifest.json --allowlist tools/compliance/shared_data_allowlist.yml` -4. Regenerate dataset API manifest entries: - - `python tools/compliance/update_datasets_manifest_from_mirror.py --manifest data/shared/matlab_gold_.manifest.json --datasets-manifest data/datasets_manifest.json` -5. Verify the mirrored tree against manifest: - - `python tools/data_mirror/verify_matlab_data.py --manifest data/shared/matlab_gold_.manifest.json --strict` diff --git a/data/SSGLMExampleData.mat b/data/SSGLMExampleData.mat new file mode 100644 index 00000000..7e77367a Binary files /dev/null and b/data/SSGLMExampleData.mat differ diff --git a/data/datasets_manifest.json b/data/datasets_manifest.json deleted file mode 100644 index 046f53a8..00000000 --- a/data/datasets_manifest.json +++ /dev/null @@ -1,307 +0,0 @@ -{ - "schema_version": 1, - "notes": "Only shared example data are listed here. Non-data assets are never shared with MATLAB nSTAT.", - "datasets": [ - { - "name": "mEPSC-epsc2", - "version": "2026-02-27", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/mEPSCs/epsc2.txt", - "sha256": "65a130b7af4bc34eeaf943da76df6ebf9ba0ae9720eb98b6813f9f44a43ff435", - "filename": "mEPSCs/epsc2.txt" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat", - "sha256": "cbf9dfa3b39b1bf4b712eb2bde37320b9d58d451504c5620519cd6cacec90431", - "filename": "Explicit Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat", - "sha256": "effc8975d3b8ea8f423a5e5476bb5becd7cbee9fcddf0c2cb5bf1f06dadf9a31", - "filename": "Explicit Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat", - "sha256": "e00711145e693815e6d7f92968fab06c0833680c32a6eca13190d9a00e91fae1", - "filename": "Explicit Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat", - "sha256": "ef9d41d34ca7ab49fe34022dda24220b41f6814d6220d4b7f111d39ccaf0159f", - "filename": "Explicit Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat", - "sha256": "f45bb73ba9fc1129e1134e3c28d238ed0df72d3b2ff94f62d26b231358f0a957", - "filename": "Explicit Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat", - "sha256": "c9161723ded0cb9ef4044e518d4bc6605666a4d3a92343d418964179c71516b5", - "filename": "Explicit Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat", - "sha256": "c579c52b0d6f979177992ef0c382a55b867de02ec8b17275b695a10c04779c67", - "filename": "Explicit Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat", - "sha256": "0e3557598c0ac2777d8d0c9af7d6f92d019d905b73742fe1a472549594f17325", - "filename": "Explicit Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat", - "sha256": "9faf006a195ac193015aead58f3e541e4840ff4e7bb376f4e27fcab664049210", - "filename": "Explicit Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat", - "sha256": "b0db8069ed3c4c800e0c5b3fe1aa6406415035ddba4f486d1548383b1e2e1093", - "filename": "Explicit Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat", - "sha256": "24b79facf077f68c5b16b9778a2cce8c2df61d3c9124064826aa7696c9472c17", - "filename": "Explicit Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat", - "sha256": "824e3cde647b97e6c7c6f1649d56d52f79f17e6274610fafce817cc844770e5d", - "filename": "Explicit Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat", - "sha256": "c848a13bef8f4e5a47dd027c0abf0f3904911cf699c698dfd5621ac7b602b324", - "filename": "Explicit Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat", - "sha256": "ad2e4a639155382b7462c0dc0f43663f6b94ca69b5cfe618d439926bceecec9a", - "filename": "Explicit Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps", - "sha256": "839dd534e216d5d31b266b7efd18b96f934cac86cef4d65da93d8c58551ed772", - "filename": "Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps", - "sha256": "d972186f79323f89d021d17a50f746fbbcd431d196d4685fb26d0998aea2d893", - "filename": "Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat", - "sha256": "440ec83724ae2a9a707eb1db33b9ebc3d9260cef15c9fb4b280a352a70432321", - "filename": "Explicit Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat", - "sha256": "f4b4299a1e977db37bab8a11d107b6d2a73541d3e5bb017ab68b1d9885def3f2", - "filename": "Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat", - "sha256": "998568271174ffbb79abd850846d3a38b193221689aa8c2a7f6f1b247721851f", - "filename": "Explicit Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat", - "sha256": "3561b3c90931f1a06d757624717ace69686767630918e18cac0b118ef5b9d370", - "filename": "Explicit Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat", - "sha256": "48d34a2478f310d0becb92e03fc47c56598529d6bae67f4f8c097ffb5d1328a1", - "filename": "Explicit Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat", - "sha256": "ae2c905af5c95881fbef989cbd175404b287723186ffacdbdaa7a13488202e23", - "filename": "Explicit Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat", - "sha256": "9047cf6ea92d4d0dcf1215c4b41addf312d156dd22777958343607db1c440161", - "filename": "Explicit Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat", - "sha256": "6f26dd402d2893b8ae06dcb8514ef82a9ece6373ae6da974bde99895bc57f1d3", - "filename": "Explicit Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat", - "sha256": "b243c1091d2d97efd291871cae2b4793bf2bb381fe6741748ccb95b9e32b6da7", - "filename": "Explicit Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat", - "sha256": "ae1a19ba2ad50b69bad1ff8a9927cbf6e18f541a8ad332c4d51334e576abc8b7", - "filename": "Explicit Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat" - }, - { - "name": "matlab_gold_20260302/Explicit Stimulus/GenCovMat.m", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Explicit%20Stimulus/GenCovMat.m", - "sha256": "79a87fc52fe5637b351bc8565f576989d9ef1a23b44522621b1a33facfcf89b4", - "filename": "Explicit Stimulus/GenCovMat.m" - }, - { - "name": "matlab_gold_20260302/PSTH/Data Description.pdf", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/PSTH/Data%20Description.pdf", - "sha256": "79574d56122d0aab30aad7cf13120916f278b28b7f84052689e8c58da4818140", - "filename": "PSTH/Data Description.pdf" - }, - { - "name": "matlab_gold_20260302/PSTH/Results.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/PSTH/Results.mat", - "sha256": "685438f83a6df49cb9b5d260749107d401c14f1d1bc5cbabf6f00f16ebddb4fb", - "filename": "PSTH/Results.mat" - }, - { - "name": "matlab_gold_20260302/Place Cells/PlaceCellDataAnimal1.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Place%20Cells/PlaceCellDataAnimal1.mat", - "sha256": "8806ab38c62a04ee1bec9cabab907a8f9fa3d66e0799fa09de8acd01789fc77b", - "filename": "Place Cells/PlaceCellDataAnimal1.mat" - }, - { - "name": "matlab_gold_20260302/Place Cells/PlaceCellDataAnimal2.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Place%20Cells/PlaceCellDataAnimal2.mat", - "sha256": "e8f22ab469ae30427cac8401dbeacfc2a7a5d4ba1a62fd339a8834ab489e750f", - "filename": "Place Cells/PlaceCellDataAnimal2.mat" - }, - { - "name": "matlab_gold_20260302/Place Cells/Readme.txt", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Place%20Cells/Readme.txt", - "sha256": "53c6d51d6b2a64b622da3a60e9f5d9ad8c9b7362480635c9a6460a30c29044de", - "filename": "Place Cells/Readme.txt" - }, - { - "name": "matlab_gold_20260302/Place Cells/license.txt", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/Place%20Cells/license.txt", - "sha256": "4587991e9404c291513292886f98dd432cbb772a9f873da1d406a799646fe377", - "filename": "Place Cells/license.txt" - }, - { - "name": "matlab_gold_20260302/PlaceCellAnimal1Results.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/PlaceCellAnimal1Results.mat", - "sha256": "15b53a0da12338551d7edfce03666195c7f95b355e2b1f483f0ba0850f8915d5", - "filename": "PlaceCellAnimal1Results.mat" - }, - { - "name": "matlab_gold_20260302/PlaceCellAnimal2Results.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/PlaceCellAnimal2Results.mat", - "sha256": "fef2a2a0ad54012d5e1ecab96dde72a8c7ce0116afa0df038c0aed9437021f77", - "filename": "PlaceCellAnimal2Results.mat" - }, - { - "name": "matlab_gold_20260302/SSGLMExampleData.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/SSGLMExampleData.mat", - "sha256": "fc1d4730267b49e3af534f6572b28ce1ba746708a49a1e4f1e8fb082cdabc360", - "filename": "SSGLMExampleData.mat" - }, - { - "name": "matlab_gold_20260302/glm_data.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/glm_data.mat", - "sha256": "4152d93a660acf62b46b77f2dee3f14d2147dd100748c16fa3922f6c2f8ad577", - "filename": "glm_data.mat" - }, - { - "name": "matlab_gold_20260302/glm_data_orig.mat", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/glm_data_orig.mat", - "sha256": "a11ab318f9c8042453c043ed79764b18ba727ceac31672e42b7ed30024ab2a4b", - "filename": "glm_data_orig.mat" - }, - { - "name": "matlab_gold_20260302/mEPSCs/epsc2.txt", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/mEPSCs/epsc2.txt", - "sha256": "65a130b7af4bc34eeaf943da76df6ebf9ba0ae9720eb98b6813f9f44a43ff435", - "filename": "mEPSCs/epsc2.txt" - }, - { - "name": "matlab_gold_20260302/mEPSCs/mEPSCAnalysis.asv", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/mEPSCs/mEPSCAnalysis.asv", - "sha256": "c3d99d7de863a501f2d57ffbe09ff2c94fdf6b7ea8c6292641337b9a80ee7249", - "filename": "mEPSCs/mEPSCAnalysis.asv" - }, - { - "name": "matlab_gold_20260302/mEPSCs/washout1.txt", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/mEPSCs/washout1.txt", - "sha256": "4791531b54dd3f98c8cf756bd253d61d09113338b0dbe98ed09ef2df2d18e00e", - "filename": "mEPSCs/washout1.txt" - }, - { - "name": "matlab_gold_20260302/mEPSCs/washout2.txt", - "version": "20260302", - "url": "https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/mEPSCs/washout2.txt", - "sha256": "ab35f26d4bccc48d2dc91e5007ba64d2527891666d2653e0a6118e397a4985fa", - "filename": "mEPSCs/washout2.txt" - } - ] -} diff --git a/data/shared/mEPSCs/epsc2.txt b/data/mEPSCs/epsc2.txt similarity index 100% rename from data/shared/mEPSCs/epsc2.txt rename to data/mEPSCs/epsc2.txt diff --git a/data/shared/matlab_gold_20260302/mEPSCs/washout1.txt b/data/mEPSCs/washout1.txt similarity index 100% rename from data/shared/matlab_gold_20260302/mEPSCs/washout1.txt rename to data/mEPSCs/washout1.txt diff --git a/data/shared/matlab_gold_20260302/mEPSCs/washout2.txt b/data/mEPSCs/washout2.txt similarity index 100% rename from data/shared/matlab_gold_20260302/mEPSCs/washout2.txt rename to data/mEPSCs/washout2.txt diff --git a/data/shared/matlab_gold_20260302.manifest.json b/data/shared/matlab_gold_20260302.manifest.json deleted file mode 100644 index 1731af75..00000000 --- a/data/shared/matlab_gold_20260302.manifest.json +++ /dev/null @@ -1,265 +0,0 @@ -{ - "schema_version": 1, - "dataset_name": "matlab_example_data", - "dataset_version": "20260302", - "generated_at_utc": "2026-03-02T19:27:10.705500+00:00", - "generated_by": "tools/data_mirror/sync_matlab_data.py", - "source_root": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/data", - "file_count": 42, - "total_size_bytes": 504513862, - "files": [ - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat", - "size_bytes": 27547, - "mtime_epoch_s": 1499022214.0, - "sha256": "cbf9dfa3b39b1bf4b712eb2bde37320b9d58d451504c5620519cd6cacec90431" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat", - "size_bytes": 14290, - "mtime_epoch_s": 1499022214.0, - "sha256": "effc8975d3b8ea8f423a5e5476bb5becd7cbee9fcddf0c2cb5bf1f06dadf9a31" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat", - "size_bytes": 41710, - "mtime_epoch_s": 1499022214.0, - "sha256": "e00711145e693815e6d7f92968fab06c0833680c32a6eca13190d9a00e91fae1" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat", - "size_bytes": 21532, - "mtime_epoch_s": 1499022214.0, - "sha256": "ef9d41d34ca7ab49fe34022dda24220b41f6814d6220d4b7f111d39ccaf0159f" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat", - "size_bytes": 77726, - "mtime_epoch_s": 1499022214.0, - "sha256": "f45bb73ba9fc1129e1134e3c28d238ed0df72d3b2ff94f62d26b231358f0a957" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat", - "size_bytes": 40262, - "mtime_epoch_s": 1499022214.0, - "sha256": "c9161723ded0cb9ef4044e518d4bc6605666a4d3a92343d418964179c71516b5" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat", - "size_bytes": 25419, - "mtime_epoch_s": 1499022214.0, - "sha256": "c579c52b0d6f979177992ef0c382a55b867de02ec8b17275b695a10c04779c67" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat", - "size_bytes": 13203, - "mtime_epoch_s": 1499022214.0, - "sha256": "0e3557598c0ac2777d8d0c9af7d6f92d019d905b73742fe1a472549594f17325" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat", - "size_bytes": 39588, - "mtime_epoch_s": 1499022214.0, - "sha256": "9faf006a195ac193015aead58f3e541e4840ff4e7bb376f4e27fcab664049210" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat", - "size_bytes": 20564, - "mtime_epoch_s": 1499022214.0, - "sha256": "b0db8069ed3c4c800e0c5b3fe1aa6406415035ddba4f486d1548383b1e2e1093" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat", - "size_bytes": 75178, - "mtime_epoch_s": 1499022214.0, - "sha256": "24b79facf077f68c5b16b9778a2cce8c2df61d3c9124064826aa7696c9472c17" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat", - "size_bytes": 39038, - "mtime_epoch_s": 1499022214.0, - "sha256": "824e3cde647b97e6c7c6f1649d56d52f79f17e6274610fafce817cc844770e5d" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat", - "size_bytes": 25075, - "mtime_epoch_s": 1499022214.0, - "sha256": "c848a13bef8f4e5a47dd027c0abf0f3904911cf699c698dfd5621ac7b602b324" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat", - "size_bytes": 13115, - "mtime_epoch_s": 1499022214.0, - "sha256": "ad2e4a639155382b7462c0dc0f43663f6b94ca69b5cfe618d439926bceecec9a" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps", - "size_bytes": 167205, - "mtime_epoch_s": 1499022214.0, - "sha256": "839dd534e216d5d31b266b7efd18b96f934cac86cef4d65da93d8c58551ed772" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps", - "size_bytes": 67314, - "mtime_epoch_s": 1499022214.0, - "sha256": "d972186f79323f89d021d17a50f746fbbcd431d196d4685fb26d0998aea2d893" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat", - "size_bytes": 38760, - "mtime_epoch_s": 1499022214.0, - "sha256": "440ec83724ae2a9a707eb1db33b9ebc3d9260cef15c9fb4b280a352a70432321" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat", - "size_bytes": 20190, - "mtime_epoch_s": 1499022214.0, - "sha256": "f4b4299a1e977db37bab8a11d107b6d2a73541d3e5bb017ab68b1d9885def3f2" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat", - "size_bytes": 75629, - "mtime_epoch_s": 1499022214.0, - "sha256": "998568271174ffbb79abd850846d3a38b193221689aa8c2a7f6f1b247721851f" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat", - "size_bytes": 39102, - "mtime_epoch_s": 1499022214.0, - "sha256": "3561b3c90931f1a06d757624717ace69686767630918e18cac0b118ef5b9d370" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat", - "size_bytes": 25255, - "mtime_epoch_s": 1499022214.0, - "sha256": "48d34a2478f310d0becb92e03fc47c56598529d6bae67f4f8c097ffb5d1328a1" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat", - "size_bytes": 13217, - "mtime_epoch_s": 1499022214.0, - "sha256": "ae2c905af5c95881fbef989cbd175404b287723186ffacdbdaa7a13488202e23" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat", - "size_bytes": 39257, - "mtime_epoch_s": 1499022214.0, - "sha256": "9047cf6ea92d4d0dcf1215c4b41addf312d156dd22777958343607db1c440161" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat", - "size_bytes": 20186, - "mtime_epoch_s": 1499022214.0, - "sha256": "6f26dd402d2893b8ae06dcb8514ef82a9ece6373ae6da974bde99895bc57f1d3" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat", - "size_bytes": 75026, - "mtime_epoch_s": 1499022214.0, - "sha256": "b243c1091d2d97efd291871cae2b4793bf2bb381fe6741748ccb95b9e32b6da7" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat", - "size_bytes": 38830, - "mtime_epoch_s": 1499022214.0, - "sha256": "ae1a19ba2ad50b69bad1ff8a9927cbf6e18f541a8ad332c4d51334e576abc8b7" - }, - { - "relative_path": "Explicit Stimulus/GenCovMat.m", - "size_bytes": 1706, - "mtime_epoch_s": 1499022214.0, - "sha256": "79a87fc52fe5637b351bc8565f576989d9ef1a23b44522621b1a33facfcf89b4" - }, - { - "relative_path": "PSTH/Data Description.pdf", - "size_bytes": 78971, - "mtime_epoch_s": 1499022216.0, - "sha256": "79574d56122d0aab30aad7cf13120916f278b28b7f84052689e8c58da4818140" - }, - { - "relative_path": "PSTH/Results.mat", - "size_bytes": 23426906, - "mtime_epoch_s": 1499022216.0, - "sha256": "685438f83a6df49cb9b5d260749107d401c14f1d1bc5cbabf6f00f16ebddb4fb" - }, - { - "relative_path": "Place Cells/PlaceCellDataAnimal1.mat", - "size_bytes": 2722517, - "mtime_epoch_s": 1499022214.0, - "sha256": "8806ab38c62a04ee1bec9cabab907a8f9fa3d66e0799fa09de8acd01789fc77b" - }, - { - "relative_path": "Place Cells/PlaceCellDataAnimal2.mat", - "size_bytes": 2045164, - "mtime_epoch_s": 1499022214.0, - "sha256": "e8f22ab469ae30427cac8401dbeacfc2a7a5d4ba1a62fd339a8834ab489e750f" - }, - { - "relative_path": "Place Cells/Readme.txt", - "size_bytes": 148, - "mtime_epoch_s": 1499022214.0, - "sha256": "53c6d51d6b2a64b622da3a60e9f5d9ad8c9b7362480635c9a6460a30c29044de" - }, - { - "relative_path": "Place Cells/license.txt", - "size_bytes": 1551, - "mtime_epoch_s": 1499022214.0, - "sha256": "4587991e9404c291513292886f98dd432cbb772a9f873da1d406a799646fe377" - }, - { - "relative_path": "PlaceCellAnimal1Results.mat", - "size_bytes": 266683050, - "mtime_epoch_s": 1499022214.0, - "sha256": "15b53a0da12338551d7edfce03666195c7f95b355e2b1f483f0ba0850f8915d5" - }, - { - "relative_path": "PlaceCellAnimal2Results.mat", - "size_bytes": 190070438, - "mtime_epoch_s": 1499022216.0, - "sha256": "fef2a2a0ad54012d5e1ecab96dde72a8c7ce0116afa0df038c0aed9437021f77" - }, - { - "relative_path": "SSGLMExampleData.mat", - "size_bytes": 13832869, - "mtime_epoch_s": 1499022216.0, - "sha256": "fc1d4730267b49e3af534f6572b28ce1ba746708a49a1e4f1e8fb082cdabc360" - }, - { - "relative_path": "glm_data.mat", - "size_bytes": 2420384, - "mtime_epoch_s": 1499022214.0, - "sha256": "4152d93a660acf62b46b77f2dee3f14d2147dd100748c16fa3922f6c2f8ad577" - }, - { - "relative_path": "glm_data_orig.mat", - "size_bytes": 1870988, - "mtime_epoch_s": 1499022214.0, - "sha256": "a11ab318f9c8042453c043ed79764b18ba727ceac31672e42b7ed30024ab2a4b" - }, - { - "relative_path": "mEPSCs/epsc2.txt", - "size_bytes": 59770, - "mtime_epoch_s": 1499022214.0, - "sha256": "65a130b7af4bc34eeaf943da76df6ebf9ba0ae9720eb98b6813f9f44a43ff435" - }, - { - "relative_path": "mEPSCs/mEPSCAnalysis.asv", - "size_bytes": 4992, - "mtime_epoch_s": 1499022214.0, - "sha256": "c3d99d7de863a501f2d57ffbe09ff2c94fdf6b7ea8c6292641337b9a80ee7249" - }, - { - "relative_path": "mEPSCs/washout1.txt", - "size_bytes": 72338, - "mtime_epoch_s": 1499022214.0, - "sha256": "4791531b54dd3f98c8cf756bd253d61d09113338b0dbe98ed09ef2df2d18e00e" - }, - { - "relative_path": "mEPSCs/washout2.txt", - "size_bytes": 127852, - "mtime_epoch_s": 1499022214.0, - "sha256": "ab35f26d4bccc48d2dc91e5007ba64d2527891666d2653e0a6118e397a4985fa" - } - ], - "mirror_root": "data/shared/matlab_gold_20260302" -} diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat deleted file mode 100644 index f57693c8..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cbf9dfa3b39b1bf4b712eb2bde37320b9d58d451504c5620519cd6cacec90431 -size 27547 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat deleted file mode 100644 index acb96a58..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:effc8975d3b8ea8f423a5e5476bb5becd7cbee9fcddf0c2cb5bf1f06dadf9a31 -size 14290 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat deleted file mode 100644 index d5ea962d..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e00711145e693815e6d7f92968fab06c0833680c32a6eca13190d9a00e91fae1 -size 41710 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat deleted file mode 100644 index 04801f14..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ef9d41d34ca7ab49fe34022dda24220b41f6814d6220d4b7f111d39ccaf0159f -size 21532 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat deleted file mode 100644 index bb35016c..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f45bb73ba9fc1129e1134e3c28d238ed0df72d3b2ff94f62d26b231358f0a957 -size 77726 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat deleted file mode 100644 index 27601402..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c9161723ded0cb9ef4044e518d4bc6605666a4d3a92343d418964179c71516b5 -size 40262 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat deleted file mode 100644 index 4baf343c..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c579c52b0d6f979177992ef0c382a55b867de02ec8b17275b695a10c04779c67 -size 25419 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat deleted file mode 100644 index 7499bc79..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e3557598c0ac2777d8d0c9af7d6f92d019d905b73742fe1a472549594f17325 -size 13203 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat deleted file mode 100644 index a466df35..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9faf006a195ac193015aead58f3e541e4840ff4e7bb376f4e27fcab664049210 -size 39588 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat deleted file mode 100644 index 7b22e21a..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b0db8069ed3c4c800e0c5b3fe1aa6406415035ddba4f486d1548383b1e2e1093 -size 20564 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat deleted file mode 100644 index 26516a39..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:24b79facf077f68c5b16b9778a2cce8c2df61d3c9124064826aa7696c9472c17 -size 75178 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat deleted file mode 100644 index 9a53ee19..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:824e3cde647b97e6c7c6f1649d56d52f79f17e6274610fafce817cc844770e5d -size 39038 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat deleted file mode 100644 index 44e840c5..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c848a13bef8f4e5a47dd027c0abf0f3904911cf699c698dfd5621ac7b602b324 -size 25075 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat deleted file mode 100644 index c55b7ad7..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad2e4a639155382b7462c0dc0f43663f6b94ca69b5cfe618d439926bceecec9a -size 13115 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps deleted file mode 100644 index 7503f19e..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:839dd534e216d5d31b266b7efd18b96f934cac86cef4d65da93d8c58551ed772 -size 167205 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps deleted file mode 100644 index df6c3470..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d972186f79323f89d021d17a50f746fbbcd431d196d4685fb26d0998aea2d893 -size 67314 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat deleted file mode 100644 index 317398ae..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:440ec83724ae2a9a707eb1db33b9ebc3d9260cef15c9fb4b280a352a70432321 -size 38760 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat deleted file mode 100644 index b850e444..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f4b4299a1e977db37bab8a11d107b6d2a73541d3e5bb017ab68b1d9885def3f2 -size 20190 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat deleted file mode 100644 index f83f57aa..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:998568271174ffbb79abd850846d3a38b193221689aa8c2a7f6f1b247721851f -size 75629 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat deleted file mode 100644 index ff6ee875..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3561b3c90931f1a06d757624717ace69686767630918e18cac0b118ef5b9d370 -size 39102 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat deleted file mode 100644 index 2a3d56b0..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:48d34a2478f310d0becb92e03fc47c56598529d6bae67f4f8c097ffb5d1328a1 -size 25255 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat deleted file mode 100644 index 8b4b7e60..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ae2c905af5c95881fbef989cbd175404b287723186ffacdbdaa7a13488202e23 -size 13217 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat deleted file mode 100644 index af152666..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9047cf6ea92d4d0dcf1215c4b41addf312d156dd22777958343607db1c440161 -size 39257 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat deleted file mode 100644 index 14ffa5c1..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6f26dd402d2893b8ae06dcb8514ef82a9ece6373ae6da974bde99895bc57f1d3 -size 20186 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat deleted file mode 100644 index 4393dc83..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b243c1091d2d97efd291871cae2b4793bf2bb381fe6741748ccb95b9e32b6da7 -size 75026 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat b/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat deleted file mode 100644 index 18d44e65..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ae1a19ba2ad50b69bad1ff8a9927cbf6e18f541a8ad332c4d51334e576abc8b7 -size 38830 diff --git a/data/shared/matlab_gold_20260302/Explicit Stimulus/GenCovMat.m b/data/shared/matlab_gold_20260302/Explicit Stimulus/GenCovMat.m deleted file mode 100644 index 4305f448..00000000 --- a/data/shared/matlab_gold_20260302/Explicit Stimulus/GenCovMat.m +++ /dev/null @@ -1,57 +0,0 @@ -function [X,yframe] = GenCovMat(t,J,y,K) - -% Data parameters -trialen = 3000; %trialen = 5; -numtrials = length(t)/trialen; -avsples = max(J,K+1); -numsples = length(y); -framelength = trialen - avsples + 1; -numframes = floor((numsples - avsples + 1)/framelength); - -% if J <= 0 -% disp('Output must at least depend on covariates!'); -% return; -% end -% -% if framelength < J + K + 1 -% fprintf('\nIll-posed problem:\n'); -% fprintf('\tYou need at least as many observations as the number of parameters you are trying to estimate!\n'); -% return; -% end -% -% -% fprintf('\nEstimating parameters:\n'); -% fprintf('\tThe length of the covariate kernel is %d and that of the output kernel %d\n',J,K); -% fprintf('\tThe data consists of a total of %d samples.\n',numsples); -% fprintf('\tThe 1st %d samples were assumed to be available.\n',avsples); -% fprintf('\tThere are a total of %d frame(s) to be processed, each of length %d.\n',numframes,framelength); - - -startframe = avsples;% + (i-1)*framelength; -endframe = avsples + framelength - 1;%i*framelength -1; - -% Build data vector - -T = reshape(t,trialen,numtrials)'; -Y = reshape(y,trialen,numtrials)'; - -X = zeros(numtrials*framelength,J+K+1); -X(:,1) = ones(numtrials*framelength,1); -yframe = zeros(numtrials*framelength,1); - -for i=1:numtrials - - for j=0:J-1 - X((i-1)*framelength + 1:i*framelength,j+K+1+1) = T(i,avsples-j:avsples-j+framelength-1)'; - end - - for k=1:K - X((i-1)*framelength + 1:i*framelength,k+1) = Y(i,avsples-k:avsples-k+framelength-1)'; - end - - yframe((i-1)*framelength+1:i*framelength) = Y(i,avsples:end); - -end - -%Xframe = X(:,2:end); -X = X(:,2:end); diff --git a/data/shared/matlab_gold_20260302/PSTH/Data Description.pdf b/data/shared/matlab_gold_20260302/PSTH/Data Description.pdf deleted file mode 100644 index 93dcc368..00000000 Binary files a/data/shared/matlab_gold_20260302/PSTH/Data Description.pdf and /dev/null differ diff --git a/data/shared/matlab_gold_20260302/PSTH/Results.mat b/data/shared/matlab_gold_20260302/PSTH/Results.mat deleted file mode 100644 index dcc13e0b..00000000 --- a/data/shared/matlab_gold_20260302/PSTH/Results.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:685438f83a6df49cb9b5d260749107d401c14f1d1bc5cbabf6f00f16ebddb4fb -size 23426906 diff --git a/data/shared/matlab_gold_20260302/Place Cells/PlaceCellDataAnimal1.mat b/data/shared/matlab_gold_20260302/Place Cells/PlaceCellDataAnimal1.mat deleted file mode 100644 index 2a0b6e19..00000000 --- a/data/shared/matlab_gold_20260302/Place Cells/PlaceCellDataAnimal1.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8806ab38c62a04ee1bec9cabab907a8f9fa3d66e0799fa09de8acd01789fc77b -size 2722517 diff --git a/data/shared/matlab_gold_20260302/Place Cells/PlaceCellDataAnimal2.mat b/data/shared/matlab_gold_20260302/Place Cells/PlaceCellDataAnimal2.mat deleted file mode 100644 index 2ce9505d..00000000 --- a/data/shared/matlab_gold_20260302/Place Cells/PlaceCellDataAnimal2.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8f22ab469ae30427cac8401dbeacfc2a7a5d4ba1a62fd339a8834ab489e750f -size 2045164 diff --git a/data/shared/matlab_gold_20260302/Place Cells/Readme.txt b/data/shared/matlab_gold_20260302/Place Cells/Readme.txt deleted file mode 100644 index 817b6655..00000000 --- a/data/shared/matlab_gold_20260302/Place Cells/Readme.txt +++ /dev/null @@ -1,3 +0,0 @@ -three columns, x, y axes, and time of spike, -the 'phe' file is the theta phase (but you don't need it) -and the longer one is the position file. \ No newline at end of file diff --git a/data/shared/matlab_gold_20260302/Place Cells/license.txt b/data/shared/matlab_gold_20260302/Place Cells/license.txt deleted file mode 100644 index fb7c123b..00000000 --- a/data/shared/matlab_gold_20260302/Place Cells/license.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009, The MathWorks, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution - * Neither the name of the The MathWorks, Inc. nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/data/shared/matlab_gold_20260302/PlaceCellAnimal1Results.mat b/data/shared/matlab_gold_20260302/PlaceCellAnimal1Results.mat deleted file mode 100644 index 2a49e480..00000000 --- a/data/shared/matlab_gold_20260302/PlaceCellAnimal1Results.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:15b53a0da12338551d7edfce03666195c7f95b355e2b1f483f0ba0850f8915d5 -size 266683050 diff --git a/data/shared/matlab_gold_20260302/PlaceCellAnimal2Results.mat b/data/shared/matlab_gold_20260302/PlaceCellAnimal2Results.mat deleted file mode 100644 index 889086ec..00000000 --- a/data/shared/matlab_gold_20260302/PlaceCellAnimal2Results.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fef2a2a0ad54012d5e1ecab96dde72a8c7ce0116afa0df038c0aed9437021f77 -size 190070438 diff --git a/data/shared/matlab_gold_20260302/SSGLMExampleData.mat b/data/shared/matlab_gold_20260302/SSGLMExampleData.mat deleted file mode 100644 index af1a4a46..00000000 --- a/data/shared/matlab_gold_20260302/SSGLMExampleData.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fc1d4730267b49e3af534f6572b28ce1ba746708a49a1e4f1e8fb082cdabc360 -size 13832869 diff --git a/data/shared/matlab_gold_20260302/glm_data.mat b/data/shared/matlab_gold_20260302/glm_data.mat deleted file mode 100644 index 0981d86f..00000000 --- a/data/shared/matlab_gold_20260302/glm_data.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4152d93a660acf62b46b77f2dee3f14d2147dd100748c16fa3922f6c2f8ad577 -size 2420384 diff --git a/data/shared/matlab_gold_20260302/glm_data_orig.mat b/data/shared/matlab_gold_20260302/glm_data_orig.mat deleted file mode 100644 index 388e3ed7..00000000 --- a/data/shared/matlab_gold_20260302/glm_data_orig.mat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a11ab318f9c8042453c043ed79764b18ba727ceac31672e42b7ed30024ab2a4b -size 1870988 diff --git a/data/shared/matlab_gold_20260302/mEPSCs/epsc2.txt b/data/shared/matlab_gold_20260302/mEPSCs/epsc2.txt deleted file mode 100644 index 5630c67c..00000000 --- a/data/shared/matlab_gold_20260302/mEPSCs/epsc2.txt +++ /dev/null @@ -1,574 +0,0 @@ - Time (ms) Amplitude Rise (ms) Decay (ms) Area Baseline Noise Group Channel 10-90Rise HalfWidth Rise50 Peak Dir Burst# BurstE# 10-90Slope Rel Time -1.00 10.50 27.46 0.80 2.90 64.09 8.41 2.16 0.00 0.00 0.50 2.63 0.50 -1.00 0.00 0.00 -43.97 10.50 -2.00 374.30 11.21 0.80 2.30 21.33 9.82 0.45 0.00 0.00 0.61 1.76 0.60 -1.00 0.00 0.00 -14.79 67.10 -3.00 411.00 10.04 1.80 1.70 20.59 9.47 -1.20 0.00 0.00 1.20 2.31 1.10 -1.00 0.00 0.00 -6.68 103.80 -4.00 587.00 20.69 1.30 12.20 153.82 10.45 0.92 0.00 0.00 0.41 1.80 0.50 -1.00 0.00 0.00 -39.99 23.80 -5.00 590.90 22.18 5.20 8.40 167.16 11.37 -0.52 255.00 0.00 4.31 3.01 0.70 -1.00 0.00 0.00 -4.12 78.90 -6.00 672.80 11.91 0.80 4.80 44.82 8.16 2.19 0.00 0.00 0.69 3.99 0.60 -1.00 0.00 0.00 -13.87 32.80 -7.00 693.90 6.56 6.00 1.70 27.38 8.31 1.31 0.00 0.00 5.33 2.79 1.30 -1.00 0.00 0.00 -0.98 53.90 -8.00 824.80 6.75 3.20 0.70 11.72 8.79 0.38 0.00 0.00 2.16 0.86 0.70 -1.00 0.00 0.00 -2.50 56.80 -9.00 920.00 11.07 0.90 3.00 30.07 8.61 0.89 0.00 0.00 0.72 3.17 0.60 -1.00 0.00 0.00 -12.21 24.00 -10.00 926.90 7.32 0.50 2.60 15.14 3.38 1.42 0.00 0.00 0.32 2.10 0.30 -1.00 0.00 0.00 -18.38 107.70 -11.00 1273.30 18.01 0.80 3.60 51.89 11.01 0.12 0.00 0.00 0.34 2.46 0.50 -1.00 0.00 0.00 -42.54 121.30 -12.00 1620.00 11.37 0.70 1.60 15.03 11.50 0.88 0.00 0.00 0.49 1.43 0.40 -1.00 0.00 0.00 -18.73 32.80 -13.00 1624.10 13.64 0.60 3.80 36.45 10.68 0.03 255.00 0.00 0.43 1.80 0.40 -1.00 0.00 0.00 -25.35 88.10 -14.00 1667.50 10.39 1.50 2.20 22.28 11.06 0.28 0.00 0.00 1.26 1.90 0.80 -1.00 0.00 0.00 -6.60 3.50 -15.00 1743.80 7.32 3.10 1.20 11.95 11.53 -0.82 0.00 0.00 1.87 0.38 0.20 -1.00 0.00 0.00 -3.13 79.80 -16.00 1815.00 20.14 1.30 3.00 51.33 11.07 0.64 0.00 0.00 0.89 2.27 0.50 -1.00 0.00 0.00 -18.04 23.00 -17.00 2323.20 36.70 1.10 3.20 96.54 10.92 -0.26 0.00 0.00 0.51 2.77 0.90 -1.00 0.00 0.00 -57.12 19.20 -18.00 2361.10 6.20 1.70 1.80 11.59 10.43 0.35 0.00 0.00 1.48 0.64 0.30 -1.00 0.00 0.00 -3.35 57.10 -19.00 2366.50 8.11 0.70 1.40 11.09 8.32 -0.19 0.00 0.00 0.55 1.29 0.60 -1.00 0.00 0.00 -11.73 11.30 -20.00 2469.20 9.17 0.80 1.40 12.41 10.11 -0.34 0.00 0.00 0.72 1.71 0.60 -1.00 0.00 0.00 -10.24 37.20 -21.00 2599.80 17.00 1.20 2.60 37.50 10.75 -0.41 0.00 0.00 0.47 2.46 0.40 -1.00 0.00 0.00 -28.87 39.80 -22.00 2843.40 6.17 1.50 1.00 10.03 11.95 -0.35 0.00 0.00 1.21 2.00 1.30 -1.00 0.00 0.00 -4.06 27.40 -23.00 3327.00 14.68 0.60 1.90 24.23 7.73 1.02 0.00 0.00 0.38 1.64 0.40 -1.00 0.00 0.00 -30.75 127.00 -24.00 3434.80 11.37 0.90 1.90 18.33 11.01 -0.22 0.00 0.00 0.63 1.48 0.40 -1.00 0.00 0.00 -14.55 106.80 -25.00 3621.50 13.92 0.50 2.00 20.23 10.04 -0.71 0.00 0.00 0.33 1.51 0.30 -1.00 0.00 0.00 -33.66 37.50 -26.00 3904.90 15.11 1.80 3.00 36.92 10.01 -0.24 0.00 0.00 0.35 2.24 0.40 -1.00 0.00 0.00 -34.45 64.90 -27.00 3910.70 19.88 7.60 4.20 103.33 10.10 1.40 255.00 0.00 6.18 2.22 0.50 -1.00 0.00 0.00 -2.57 70.70 -28.00 4105.00 10.45 0.70 4.00 33.53 10.97 0.41 0.00 0.00 0.50 4.07 0.60 -1.00 0.00 0.00 -16.77 85.80 -29.00 4319.70 6.09 0.90 5.30 25.68 12.07 -1.92 0.00 0.00 0.71 2.79 0.60 -1.00 0.00 0.00 -6.87 95.70 -30.00 4558.60 23.37 1.00 2.50 46.11 10.42 -1.13 0.00 0.00 0.55 1.94 0.60 -1.00 0.00 0.00 -34.14 78.60 -31.00 4637.60 8.43 0.50 2.40 16.59 6.57 4.30 0.00 0.00 0.35 2.20 0.40 -1.00 0.00 0.00 -19.46 29.60 -32.00 4678.00 8.32 3.00 0.80 15.33 9.09 1.29 0.00 0.00 1.89 1.89 1.20 -1.00 0.00 0.00 -3.52 70.00 -33.00 4776.80 20.53 1.40 3.80 54.01 9.45 0.43 0.00 0.00 0.47 2.16 0.50 -1.00 0.00 0.00 -35.25 40.80 -34.00 4799.30 11.05 1.00 2.50 23.39 6.70 0.66 0.00 0.00 0.79 1.27 0.60 -1.00 0.00 0.00 -11.13 63.30 -35.00 4812.60 6.31 0.90 0.90 4.60 5.47 -1.26 0.00 0.00 0.35 0.46 0.30 -1.00 0.00 0.00 -14.51 76.60 -36.00 4848.80 6.20 1.70 1.60 9.77 7.84 1.35 0.00 0.00 1.32 1.11 0.20 -1.00 0.00 0.00 -3.75 112.80 -37.00 4889.20 6.36 1.10 0.40 4.40 7.51 0.52 0.00 0.00 0.58 0.66 0.50 -1.00 0.00 0.00 -8.70 25.20 -38.00 4997.00 6.27 0.90 1.60 8.36 9.91 -0.39 0.00 0.00 0.73 0.82 0.50 -1.00 0.00 0.00 -6.88 5.00 -39.00 5041.40 6.39 0.70 0.90 5.42 9.84 1.32 0.00 0.00 0.63 0.42 0.20 -1.00 0.00 0.00 -8.14 49.40 -40.00 5056.60 12.42 0.80 2.80 25.86 9.99 -0.84 0.00 0.00 0.49 1.24 0.50 -1.00 0.00 0.00 -20.09 64.60 -41.00 5073.60 9.24 0.80 4.60 30.92 9.66 -0.18 0.00 0.00 0.50 2.76 0.60 -1.00 0.00 0.00 -14.79 81.60 -42.00 5127.80 6.39 1.20 2.00 10.24 9.45 2.01 0.00 0.00 0.72 1.22 0.20 -1.00 0.00 0.00 -7.06 84.60 -43.00 5314.30 7.44 1.10 0.90 10.51 9.94 -0.10 0.00 0.00 0.81 1.48 1.00 -1.00 0.00 0.00 -7.39 66.30 -44.00 5399.70 16.65 0.60 3.80 47.71 9.93 -0.19 0.00 0.00 0.34 2.91 0.50 -1.00 0.00 0.00 -38.71 23.70 -45.00 5500.10 6.89 1.40 0.80 6.79 10.49 -0.39 0.00 0.00 0.92 0.78 0.50 -1.00 0.00 0.00 -6.01 124.10 -46.00 6013.20 12.27 4.00 2.00 33.41 11.51 -0.57 0.00 0.00 3.24 2.20 0.80 -1.00 0.00 0.00 -3.03 125.20 -47.00 6213.80 7.02 0.70 0.80 4.80 11.17 1.98 0.00 0.00 0.54 0.44 0.40 -1.00 0.00 0.00 -10.35 69.80 -48.00 6436.90 10.41 1.10 1.80 19.49 9.81 1.64 0.00 0.00 0.96 2.35 0.90 -1.00 0.00 0.00 -8.64 36.90 -49.00 6459.90 7.28 1.70 1.00 8.87 9.23 -1.11 0.00 0.00 1.55 0.43 0.30 -1.00 0.00 0.00 -3.75 59.90 -50.00 6526.10 9.21 1.40 1.20 13.22 9.80 1.15 0.00 0.00 1.16 1.58 1.10 -1.00 0.00 0.00 -6.34 126.10 -51.00 6582.80 6.81 2.70 1.10 12.80 10.16 2.23 0.00 0.00 1.97 1.17 0.50 -1.00 0.00 0.00 -2.77 54.80 -52.00 6666.20 15.35 0.90 2.50 31.46 9.49 0.44 0.00 0.00 0.49 1.89 0.70 -1.00 0.00 0.00 -25.16 10.20 -53.00 6752.70 12.03 1.00 2.00 23.88 9.84 -0.21 0.00 0.00 0.86 1.96 0.60 -1.00 0.00 0.00 -11.20 96.70 -54.00 7634.60 13.35 0.90 2.00 25.02 7.77 0.58 0.00 0.00 0.69 1.67 0.80 -1.00 0.00 0.00 -15.56 82.60 -55.00 7708.30 6.13 1.70 2.00 11.83 11.13 -0.15 0.00 0.00 1.48 0.93 0.50 -1.00 0.00 0.00 -3.31 28.30 -56.00 7806.30 7.58 1.10 0.80 8.73 11.29 -1.94 0.00 0.00 0.85 1.29 0.70 -1.00 0.00 0.00 -7.17 126.30 -57.00 8213.70 9.16 0.80 2.40 18.03 10.95 0.57 0.00 0.00 0.64 1.44 0.30 -1.00 0.00 0.00 -11.46 21.70 -58.00 8254.60 13.28 0.80 2.00 25.32 10.22 -0.43 0.00 0.00 0.45 2.27 0.60 -1.00 0.00 0.00 -23.88 62.60 -59.00 8466.60 9.36 0.90 2.50 22.05 10.50 1.20 0.00 0.00 0.68 2.61 0.40 -1.00 0.00 0.00 -11.05 18.60 -60.00 8723.20 11.43 2.60 2.30 25.13 10.93 -0.56 0.00 0.00 0.62 1.72 0.50 -1.00 0.00 0.00 -14.81 19.20 -61.00 8813.70 11.52 0.70 2.00 18.71 10.88 0.45 0.00 0.00 0.43 1.26 0.50 -1.00 0.00 0.00 -21.24 109.70 -62.00 8832.30 13.50 2.20 1.90 23.85 10.68 -0.01 0.00 0.00 0.40 1.58 0.40 -1.00 0.00 0.00 -26.98 51.50 -63.00 8872.90 7.69 1.00 1.00 9.27 10.26 0.74 0.00 0.00 0.86 1.30 0.50 -1.00 0.00 0.00 -7.18 40.90 -64.00 8881.70 6.42 1.50 0.70 6.86 10.53 -1.25 0.00 0.00 1.10 1.12 0.50 -1.00 0.00 0.00 -4.68 49.70 -65.00 9007.60 6.32 0.60 4.60 22.96 10.03 -0.19 0.00 0.00 0.40 2.75 0.30 -1.00 0.00 0.00 -12.65 47.60 -66.00 9104.70 12.60 1.30 1.60 20.88 10.27 1.42 0.00 0.00 1.06 1.58 0.90 -1.00 0.00 0.00 -9.55 16.70 -67.00 9117.70 10.40 0.60 1.30 14.08 7.49 -0.34 0.00 0.00 0.47 1.56 0.50 -1.00 0.00 0.00 -17.74 29.70 -68.00 9373.30 17.79 2.70 3.30 54.81 10.52 1.33 0.00 0.00 0.77 3.13 0.70 -1.00 0.00 0.00 -18.52 29.30 -69.00 9412.70 11.90 0.70 4.30 34.43 10.61 0.69 0.00 0.00 0.49 2.28 0.50 -1.00 0.00 0.00 -19.61 68.70 -70.00 9585.00 14.71 0.80 3.60 42.41 11.66 2.13 0.00 0.00 0.36 2.63 0.60 -1.00 0.00 0.00 -32.30 113.00 -71.00 9597.80 23.32 0.90 3.40 64.35 9.20 0.13 0.00 0.00 0.42 2.54 0.70 -1.00 0.00 0.00 -44.53 125.80 -72.00 9660.40 13.30 0.80 1.80 19.35 9.69 0.40 0.00 0.00 0.54 1.58 0.50 -1.00 0.00 0.00 -19.81 9.20 -73.00 9676.90 26.85 1.20 3.90 84.18 8.60 -2.12 0.00 0.00 0.74 3.17 0.90 -1.00 0.00 0.00 -28.89 76.90 -74.00 9766.40 6.53 1.80 1.50 8.94 10.33 -0.59 0.00 0.00 1.67 0.60 0.40 -1.00 0.00 0.00 -3.12 38.40 -75.00 9781.50 6.12 0.60 2.00 9.67 8.13 0.64 0.00 0.00 0.42 1.74 0.20 -1.00 0.00 0.00 -11.64 53.50 -76.00 9802.90 12.81 0.60 3.10 30.83 11.46 0.26 0.00 0.00 0.46 2.29 0.40 -1.00 0.00 0.00 -22.49 74.90 -77.00 9884.40 6.75 3.30 1.70 15.17 9.62 -1.06 0.00 0.00 2.10 1.40 0.40 -1.00 0.00 0.00 -2.57 28.40 -78.00 9902.10 8.77 0.60 2.80 17.70 10.36 1.32 0.00 0.00 0.38 1.40 0.30 -1.00 0.00 0.00 -18.28 46.10 -79.00 9918.90 9.93 0.80 1.30 11.86 9.32 0.02 0.00 0.00 0.57 1.25 0.50 -1.00 0.00 0.00 -13.85 62.90 -80.00 9980.50 6.94 0.40 0.50 4.01 10.14 0.99 0.00 0.00 0.30 0.56 0.30 -1.00 0.00 0.00 -18.77 124.50 -81.00 10086.80 19.18 0.80 2.10 34.67 11.64 0.46 0.00 0.00 0.52 1.89 0.60 -1.00 0.00 0.00 -29.41 102.80 -82.00 10130.40 6.28 0.80 1.20 6.87 10.33 0.06 0.00 0.00 0.61 0.88 0.30 -1.00 0.00 0.00 -8.18 18.40 -83.00 10174.10 13.81 1.10 1.90 29.44 10.28 1.27 0.00 0.00 0.78 2.27 0.90 -1.00 0.00 0.00 -14.20 36.50 -84.00 10233.50 13.28 1.10 2.80 27.92 9.81 0.64 0.00 0.00 0.82 1.40 0.80 -1.00 0.00 0.00 -12.98 95.90 -85.00 10475.40 14.08 0.60 1.90 23.34 9.50 -0.46 0.00 0.00 0.43 1.78 0.30 -1.00 0.00 0.00 -26.10 107.40 -86.00 10604.20 12.29 0.90 3.20 33.45 9.97 0.26 0.00 0.00 0.54 3.04 0.60 -1.00 0.00 0.00 -18.21 108.20 -87.00 10613.70 9.04 10.40 0.80 66.76 10.78 -0.55 255.00 0.00 3.14 0.97 0.70 -1.00 0.00 0.00 -2.30 117.70 -88.00 10702.10 7.62 2.10 1.00 12.08 12.96 -1.12 0.00 0.00 1.34 1.12 0.70 -1.00 0.00 0.00 -4.55 78.10 -89.00 11182.20 22.16 2.00 2.70 53.83 10.90 1.45 0.00 0.00 1.21 2.09 0.70 -1.00 0.00 0.00 -14.63 46.20 -90.00 11215.90 6.91 1.10 1.10 8.53 8.07 -1.22 0.00 0.00 0.96 1.16 0.90 -1.00 0.00 0.00 -5.74 79.90 -91.00 11218.40 13.33 3.80 4.70 65.28 11.07 1.53 255.00 0.00 3.46 4.08 1.00 -1.00 0.00 0.00 -3.09 82.40 -92.00 11405.90 7.43 2.70 0.40 11.75 10.90 0.79 0.00 0.00 1.53 0.51 0.30 -1.00 0.00 0.00 -3.88 13.90 -93.00 11474.60 7.22 0.70 1.20 8.45 8.89 1.11 0.00 0.00 0.54 1.19 0.30 -1.00 0.00 0.00 -10.63 82.60 -94.00 11521.90 15.35 1.00 2.40 35.33 10.21 1.27 0.00 0.00 0.73 2.89 0.90 -1.00 0.00 0.00 -16.83 1.90 -95.00 11530.40 7.67 1.70 1.10 9.01 7.90 -1.29 0.00 0.00 0.84 0.86 0.60 -1.00 0.00 0.00 -7.27 10.40 -96.00 11578.60 6.45 2.50 0.80 11.04 10.05 1.21 0.00 0.00 2.37 0.95 0.60 -1.00 0.00 0.00 -2.18 58.60 -97.00 11598.70 11.78 0.90 2.20 20.57 11.26 0.29 0.00 0.00 0.56 1.71 0.50 -1.00 0.00 0.00 -16.84 78.70 -98.00 11680.60 6.15 1.20 1.20 7.43 11.62 1.00 0.00 0.00 1.03 0.55 0.30 -1.00 0.00 0.00 -4.79 7.00 -99.00 11687.40 7.54 3.00 1.70 20.12 12.19 -2.31 0.00 0.00 2.67 2.84 1.40 -1.00 0.00 0.00 -2.26 39.40 -100.00 11698.40 7.25 2.70 5.00 30.11 11.31 -1.94 0.00 0.00 2.40 1.70 0.90 -1.00 0.00 0.00 -2.41 50.40 -101.00 11744.50 22.50 0.70 2.90 50.40 11.35 0.54 0.00 0.00 0.43 2.11 0.50 -1.00 0.00 0.00 -41.53 96.50 -102.00 11792.10 8.01 0.80 1.00 9.70 9.34 -0.60 0.00 0.00 0.53 1.27 0.60 -1.00 0.00 0.00 -12.11 16.10 -103.00 11814.60 6.37 1.50 0.80 5.99 9.92 -1.25 0.00 0.00 0.33 0.44 0.20 -1.00 0.00 0.00 -15.62 38.60 -104.00 12033.30 17.96 1.20 2.30 34.32 10.04 0.42 0.00 0.00 0.97 1.86 0.70 -1.00 0.00 0.00 -14.88 1.30 -105.00 12052.00 6.58 1.20 1.60 9.75 11.07 0.10 0.00 0.00 1.05 0.73 0.30 -1.00 0.00 0.00 -5.02 20.00 -106.00 12117.60 10.32 1.10 2.10 20.01 11.00 -1.86 0.00 0.00 0.58 1.65 0.60 -1.00 0.00 0.00 -14.30 85.60 -107.00 12267.20 14.37 0.60 1.90 24.05 11.14 2.05 0.00 0.00 0.47 2.16 0.40 -1.00 0.00 0.00 -24.57 107.20 -108.00 12458.30 20.94 1.00 3.00 49.74 10.27 1.19 0.00 0.00 0.52 1.99 0.50 -1.00 0.00 0.00 -32.50 42.30 -109.00 12491.00 6.72 0.60 1.30 8.24 7.26 -2.38 0.00 0.00 0.33 1.07 0.40 -1.00 0.00 0.00 -16.12 75.00 -110.00 12566.70 6.47 2.60 1.80 16.24 9.95 -0.06 0.00 0.00 2.45 1.94 1.20 -1.00 0.00 0.00 -2.11 22.70 -111.00 12639.50 8.20 4.60 0.90 16.05 10.70 -0.97 0.00 0.00 2.13 0.77 0.30 -1.00 0.00 0.00 -3.08 95.50 -112.00 12643.30 11.46 0.50 1.50 15.81 8.26 1.73 0.00 0.00 0.32 1.28 0.40 -1.00 0.00 0.00 -28.80 99.30 -113.00 12653.10 7.39 2.40 2.60 20.13 10.75 -0.26 0.00 0.00 1.64 2.83 1.50 -1.00 0.00 0.00 -3.60 109.10 -114.00 12687.20 12.35 1.10 1.40 17.60 11.12 0.43 0.00 0.00 0.86 1.45 0.60 -1.00 0.00 0.00 -11.44 15.20 -115.00 12838.60 11.29 1.40 6.10 55.18 12.33 1.25 0.00 0.00 0.89 2.38 0.90 -1.00 0.00 0.00 -10.10 38.60 -116.00 12841.50 10.83 4.00 1.40 40.00 11.05 0.78 255.00 0.00 3.53 1.74 1.20 -1.00 0.00 0.00 -2.45 41.50 -117.00 12899.50 7.10 3.70 1.80 21.45 10.92 -0.17 0.00 0.00 2.87 3.18 1.60 -1.00 0.00 0.00 -1.98 99.50 -118.00 12942.00 10.37 0.70 1.50 14.31 11.52 -1.69 0.00 0.00 0.43 1.32 0.40 -1.00 0.00 0.00 -19.31 14.00 -119.00 12942.80 8.00 1.50 2.70 22.88 11.63 0.10 0.00 0.00 0.34 1.81 1.30 -1.00 0.00 0.00 -18.71 14.80 -120.00 13013.70 9.29 0.90 1.50 13.42 12.10 1.53 0.00 0.00 0.72 1.80 0.70 -1.00 0.00 0.00 -10.26 85.70 -121.00 13028.10 16.16 1.10 2.80 38.13 10.43 -0.48 0.00 0.00 0.84 2.03 0.90 -1.00 0.00 0.00 -15.31 100.10 -122.00 13172.60 10.46 1.30 1.80 22.98 10.89 -0.36 0.00 0.00 1.15 2.23 1.10 -1.00 0.00 0.00 -7.27 116.60 -123.00 13176.00 7.25 4.70 2.50 36.85 10.07 0.02 255.00 0.00 1.41 1.24 0.90 -1.00 0.00 0.00 -4.12 120.00 -124.00 13444.90 12.69 2.00 4.40 39.54 11.78 0.47 0.00 0.00 0.80 1.40 0.70 -1.00 0.00 0.00 -12.65 4.90 -125.00 13521.30 7.09 6.30 0.30 23.61 11.37 0.89 0.00 0.00 5.76 2.24 2.10 -1.00 0.00 0.00 -0.99 81.30 -126.00 13547.20 7.64 1.70 1.80 14.61 10.70 -0.59 0.00 0.00 1.48 1.03 0.90 -1.00 0.00 0.00 -4.12 107.20 -127.00 13575.10 16.76 0.70 3.20 40.67 9.85 -1.43 0.00 0.00 0.27 2.14 0.50 -1.00 0.00 0.00 -49.02 7.10 -128.00 13592.80 6.07 6.00 0.60 17.16 10.26 -0.21 0.00 0.00 3.45 0.61 0.40 -1.00 0.00 0.00 -1.41 24.80 -129.00 13620.40 7.39 1.00 1.10 8.95 10.74 0.60 0.00 0.00 0.83 1.03 0.80 -1.00 0.00 0.00 -7.09 52.40 -130.00 13802.40 7.33 1.50 1.60 12.70 11.20 -0.71 0.00 0.00 1.05 1.83 0.50 -1.00 0.00 0.00 -5.57 106.40 -131.00 13845.00 8.51 0.70 3.50 23.48 11.08 -0.25 0.00 0.00 0.52 1.69 0.50 -1.00 0.00 0.00 -13.19 21.00 -132.00 13847.80 8.22 3.50 0.70 22.45 10.83 0.60 255.00 0.00 3.27 0.68 0.40 -1.00 0.00 0.00 -2.01 23.80 -133.00 14038.90 20.31 1.90 2.70 52.46 11.37 -0.21 0.00 0.00 1.39 2.36 0.90 -1.00 0.00 0.00 -11.67 86.90 -134.00 14223.80 18.10 0.70 4.40 53.56 11.33 0.56 0.00 0.00 0.43 2.56 0.40 -1.00 0.00 0.00 -33.85 15.80 -135.00 14345.70 40.99 0.90 3.70 105.35 10.79 0.81 0.00 0.00 0.51 2.26 0.50 -1.00 0.00 0.00 -64.53 9.70 -136.00 14362.60 18.63 17.80 3.70 251.87 10.93 0.10 255.00 0.00 17.34 2.49 0.80 -1.00 0.00 0.00 -0.86 26.60 -137.00 15138.50 11.05 0.40 1.90 17.33 8.84 1.64 0.00 0.00 0.28 1.65 0.30 -1.00 0.00 0.00 -32.14 34.50 -138.00 15320.50 12.27 0.40 1.30 13.67 10.89 1.50 0.00 0.00 0.25 1.22 0.30 -1.00 0.00 0.00 -38.86 216.50 -139.00 15323.60 8.90 3.60 1.10 28.91 11.33 -1.52 255.00 0.00 3.41 1.53 1.00 -1.00 0.00 0.00 -2.09 66.00 -140.00 15393.00 7.83 7.70 2.00 37.65 10.96 1.32 0.00 0.00 6.28 1.66 0.40 -1.00 0.00 0.00 -1.00 33.00 -141.00 15448.30 6.37 2.50 1.40 14.04 10.06 -1.67 0.00 0.00 2.35 1.49 0.40 -1.00 0.00 0.00 -2.16 88.30 -142.00 15463.50 16.21 0.80 1.60 24.61 9.56 0.40 0.00 0.00 0.60 1.51 0.60 -1.00 0.00 0.00 -21.44 103.50 -143.00 15478.20 46.36 1.90 3.10 119.60 9.45 -0.18 0.00 0.00 0.54 2.31 0.90 -1.00 0.00 0.00 -68.44 118.20 -144.00 15490.60 19.50 13.50 8.50 284.36 8.08 0.79 255.00 0.00 13.35 3.66 1.00 -1.00 0.00 0.00 -1.17 28.20 -145.00 15649.90 8.18 0.40 2.70 16.69 9.61 -0.13 0.00 0.00 0.27 2.31 0.30 -1.00 0.00 0.00 -24.50 33.90 -146.00 15759.20 14.31 1.10 1.90 24.97 10.41 0.87 0.00 0.00 0.44 1.98 0.50 -1.00 0.00 0.00 -26.29 15.20 -147.00 15775.60 9.67 0.70 1.60 15.31 8.15 -0.28 0.00 0.00 0.57 1.71 0.60 -1.00 0.00 0.00 -13.59 31.60 -148.00 15782.20 6.49 7.30 1.70 36.58 8.28 0.64 255.00 0.00 2.00 1.14 0.30 -1.00 0.00 0.00 -2.60 12.60 -149.00 15879.60 10.66 2.60 9.10 117.24 11.42 -0.59 0.00 0.00 2.40 9.56 1.80 -1.00 0.00 0.00 -3.55 7.60 -150.00 15882.10 23.86 5.10 4.70 103.47 11.22 0.53 255.00 0.00 4.43 2.88 0.60 -1.00 0.00 0.00 -4.31 10.10 -151.00 15969.20 13.52 0.90 2.10 22.30 9.14 -0.96 0.00 0.00 0.61 1.44 0.50 -1.00 0.00 0.00 -17.75 97.20 -152.00 16217.30 17.80 1.20 1.90 28.28 11.14 -0.18 0.00 0.00 0.56 1.56 0.60 -1.00 0.00 0.00 -25.46 89.30 -153.00 16269.70 6.58 1.10 1.00 5.80 9.61 0.68 0.00 0.00 0.55 0.61 0.30 -1.00 0.00 0.00 -9.52 13.70 -154.00 16419.50 6.60 1.00 2.30 12.92 11.73 0.24 0.00 0.00 0.76 1.41 0.70 -1.00 0.00 0.00 -6.92 35.50 -155.00 16585.40 6.62 1.80 0.80 10.13 9.81 0.43 0.00 0.00 1.59 1.11 0.50 -1.00 0.00 0.00 -3.34 73.40 -156.00 16602.70 8.87 1.90 1.50 15.60 9.99 0.21 0.00 0.00 1.13 1.58 1.00 -1.00 0.00 0.00 -6.28 90.70 -157.00 16684.60 7.32 0.70 3.70 18.19 11.66 0.46 0.00 0.00 0.47 1.64 0.30 -1.00 0.00 0.00 -12.53 44.60 -158.00 17067.80 10.83 0.80 1.70 15.96 11.87 -1.03 0.00 0.00 0.52 1.47 0.60 -1.00 0.00 0.00 -16.78 43.80 -159.00 17725.60 6.55 1.00 1.50 9.91 12.32 -0.01 0.00 0.00 0.87 1.42 0.60 -1.00 0.00 0.00 -5.99 61.60 -160.00 17895.10 13.40 3.70 2.10 34.76 13.04 1.60 0.00 0.00 2.66 2.60 0.70 -1.00 0.00 0.00 -4.03 26.30 -161.00 17978.10 9.20 0.80 1.50 13.22 11.51 0.24 0.00 0.00 0.54 1.42 0.50 -1.00 0.00 0.00 -13.54 58.10 -162.00 18027.60 24.14 1.60 1.60 50.70 10.19 -0.06 0.00 0.00 1.33 2.20 1.30 -1.00 0.00 0.00 -14.54 107.60 -163.00 18053.20 6.48 1.70 0.60 6.93 9.61 2.37 0.00 0.00 1.37 0.68 0.40 -1.00 0.00 0.00 -3.79 5.20 -164.00 18144.00 15.40 1.70 1.40 25.64 11.10 0.35 0.00 0.00 0.43 1.64 0.80 -1.00 0.00 0.00 -28.77 96.00 -165.00 18240.40 25.80 0.90 2.40 51.64 11.07 0.20 0.00 0.00 0.46 1.94 0.60 -1.00 0.00 0.00 -45.33 64.40 -166.00 18246.90 10.53 11.00 5.40 109.68 11.41 -0.02 255.00 0.00 1.11 1.72 0.50 -1.00 0.00 0.00 -7.59 19.70 -167.00 18493.30 6.49 2.60 1.30 11.30 12.38 -1.07 0.00 0.00 2.37 1.29 0.40 -1.00 0.00 0.00 -2.19 61.30 -168.00 18524.10 7.61 1.10 1.50 12.10 12.05 -0.95 0.00 0.00 0.94 1.39 0.50 -1.00 0.00 0.00 -6.48 92.10 -169.00 18549.90 10.96 0.90 1.90 17.46 11.66 1.64 0.00 0.00 0.65 1.72 0.70 -1.00 0.00 0.00 -13.56 15.50 -170.00 18725.10 24.82 1.10 3.70 75.15 9.92 1.07 0.00 0.00 0.41 2.62 0.90 -1.00 0.00 0.00 -48.89 62.70 -171.00 18755.20 10.63 0.80 1.90 16.46 8.04 -0.03 0.00 0.00 0.53 1.32 0.40 -1.00 0.00 0.00 -16.09 92.80 -172.00 18809.30 18.21 0.90 4.20 57.27 8.77 1.00 0.00 0.00 0.50 3.18 0.60 -1.00 0.00 0.00 -29.37 18.90 -173.00 18870.20 14.89 0.70 1.40 18.91 10.00 -2.65 0.00 0.00 0.44 1.09 0.50 -1.00 0.00 0.00 -27.07 79.80 -174.00 18936.30 7.90 1.90 2.30 20.77 11.71 0.27 0.00 0.00 1.68 1.95 1.50 -1.00 0.00 0.00 -3.77 17.90 -175.00 19244.40 16.58 1.00 2.50 33.55 11.17 0.43 0.00 0.00 0.52 1.96 0.40 -1.00 0.00 0.00 -25.42 70.00 -176.00 19386.40 6.91 1.70 1.30 9.84 12.59 1.67 0.00 0.00 1.47 0.73 0.30 -1.00 0.00 0.00 -3.77 84.00 -177.00 19442.50 19.08 0.80 3.00 43.88 11.99 1.68 0.00 0.00 0.46 2.02 0.50 -1.00 0.00 0.00 -33.16 12.10 -178.00 19454.50 14.22 0.60 1.90 23.41 10.14 -0.50 0.00 0.00 0.37 2.06 0.40 -1.00 0.00 0.00 -30.62 24.10 -179.00 19549.40 7.10 1.20 6.80 34.81 11.86 -0.03 0.00 0.00 1.01 1.38 0.90 -1.00 0.00 0.00 -5.63 119.00 -180.00 19742.10 6.11 1.00 0.90 5.24 10.79 1.65 0.00 0.00 0.83 0.53 0.30 -1.00 0.00 0.00 -5.91 55.70 -181.00 19749.90 19.36 1.10 2.50 40.69 8.65 2.02 0.00 0.00 0.73 2.13 0.70 -1.00 0.00 0.00 -21.31 63.50 -182.00 19770.30 6.37 1.50 0.40 7.25 8.00 0.60 0.00 0.00 1.36 0.66 0.40 -1.00 0.00 0.00 -3.75 83.90 -183.00 19781.00 6.22 1.30 0.60 6.43 8.07 0.42 0.00 0.00 1.15 0.57 0.20 -1.00 0.00 0.00 -4.33 94.60 -184.00 19918.90 9.28 1.60 2.90 22.57 11.29 -0.13 0.00 0.00 0.56 1.44 0.40 -1.00 0.00 0.00 -13.23 78.90 -185.00 19930.70 15.61 1.00 1.80 25.68 8.79 -0.07 0.00 0.00 0.51 1.90 0.50 -1.00 0.00 0.00 -24.41 116.30 -186.00 19943.90 10.53 0.80 1.60 17.89 8.99 -1.36 0.00 0.00 0.58 1.88 0.50 -1.00 0.00 0.00 -14.64 1.50 -187.00 19946.80 6.75 3.70 1.30 24.18 7.91 -1.68 255.00 0.00 3.57 0.88 0.40 -1.00 0.00 0.00 -1.51 81.20 -188.00 19955.50 9.34 1.60 1.50 18.57 9.13 0.10 0.00 0.00 1.39 2.24 1.10 -1.00 0.00 0.00 -5.38 13.10 -189.00 20048.50 15.66 0.90 2.70 31.56 9.16 1.31 0.00 0.00 0.62 2.01 0.50 -1.00 0.00 0.00 -20.32 106.10 -190.00 20163.60 6.94 2.10 1.10 12.67 10.80 0.95 0.00 0.00 1.90 1.75 0.90 -1.00 0.00 0.00 -2.91 93.20 -191.00 20348.10 8.63 0.80 1.50 12.00 9.66 -0.34 0.00 0.00 0.50 1.35 0.60 -1.00 0.00 0.00 -13.83 21.70 -192.00 20463.60 17.05 0.80 2.90 42.37 12.39 -0.83 0.00 0.00 0.49 3.13 0.50 -1.00 0.00 0.00 -27.61 9.20 -193.00 20725.10 11.60 1.60 2.20 24.08 10.94 0.79 0.00 0.00 1.38 1.60 1.20 -1.00 0.00 0.00 -6.71 14.70 -194.00 20949.40 6.36 1.60 1.20 8.82 10.76 -0.87 0.00 0.00 1.10 0.99 0.80 -1.00 0.00 0.00 -4.64 85.40 -195.00 21119.60 15.06 0.90 3.90 44.04 11.49 -0.49 0.00 0.00 0.59 2.36 0.60 -1.00 0.00 0.00 -20.53 25.20 -196.00 21142.00 21.24 3.20 1.70 39.19 8.16 0.26 0.00 0.00 0.69 1.65 0.60 -1.00 0.00 0.00 -24.73 47.60 -197.00 21160.30 13.21 0.90 2.70 31.38 8.47 0.65 0.00 0.00 0.36 2.43 0.40 -1.00 0.00 0.00 -29.35 65.90 -198.00 21167.80 11.83 4.00 2.30 31.32 7.51 1.05 255.00 0.00 1.74 2.05 0.50 -1.00 0.00 0.00 -5.43 73.40 -199.00 21177.10 16.25 1.00 2.30 31.64 7.13 -0.03 0.00 0.00 0.71 1.46 0.70 -1.00 0.00 0.00 -18.19 82.70 -200.00 21180.80 12.57 7.90 1.40 66.60 9.70 -0.36 255.00 0.00 4.73 1.59 0.50 -1.00 0.00 0.00 -2.13 86.40 -201.00 21209.30 8.66 0.90 2.10 15.18 8.27 -1.11 0.00 0.00 0.75 1.72 0.30 -1.00 0.00 0.00 -9.29 114.90 -202.00 21564.20 6.07 2.20 1.10 9.03 9.57 -0.46 0.00 0.00 1.85 0.95 0.30 -1.00 0.00 0.00 -2.63 85.80 -203.00 21689.00 8.02 0.50 2.50 16.80 10.58 -0.66 0.00 0.00 0.39 2.30 0.30 -1.00 0.00 0.00 -16.62 82.60 -204.00 21710.00 8.59 6.40 1.70 31.07 10.62 0.05 0.00 0.00 6.24 1.86 0.80 -1.00 0.00 0.00 -1.10 1.20 -205.00 21746.20 9.46 2.20 3.20 27.63 11.67 2.60 0.00 0.00 0.91 1.82 1.00 -1.00 0.00 0.00 -8.32 11.80 -206.00 21806.90 11.74 0.60 1.80 17.01 10.87 0.17 0.00 0.00 0.38 1.21 0.30 -1.00 0.00 0.00 -24.97 72.50 -207.00 21930.80 7.14 2.90 1.50 16.76 11.23 -2.98 0.00 0.00 2.44 0.99 0.20 -1.00 0.00 0.00 -2.34 68.40 -208.00 22102.20 14.37 1.00 2.50 31.27 11.68 -0.60 0.00 0.00 0.65 2.26 0.70 -1.00 0.00 0.00 -17.70 111.80 -209.00 22199.70 6.47 1.50 0.30 6.53 11.59 -0.86 0.00 0.00 1.25 0.99 0.90 -1.00 0.00 0.00 -4.13 81.30 -210.00 22325.50 9.67 5.00 3.10 36.44 12.41 -0.51 255.00 0.00 3.32 1.70 0.80 -1.00 0.00 0.00 -2.33 2.30 -211.00 22407.60 9.74 1.60 1.60 15.96 12.13 0.80 0.00 0.00 1.03 1.21 0.60 -1.00 0.00 0.00 -7.58 33.20 -212.00 22622.50 9.51 0.70 2.40 17.74 11.54 -0.13 0.00 0.00 0.50 1.68 0.60 -1.00 0.00 0.00 -15.18 120.10 -213.00 22733.60 13.86 1.20 2.50 30.52 11.78 0.42 0.00 0.00 0.73 1.86 0.80 -1.00 0.00 0.00 -15.28 103.20 -214.00 22855.30 12.96 1.60 2.10 24.90 11.62 -1.90 0.00 0.00 0.59 1.84 0.60 -1.00 0.00 0.00 -17.67 96.90 -215.00 22896.30 17.37 1.20 3.20 44.54 13.42 -0.06 0.00 0.00 0.44 2.75 0.30 -1.00 0.00 0.00 -31.88 9.90 -216.00 22904.80 11.37 1.30 18.50 195.06 11.98 -0.91 0.00 0.00 1.14 2.33 1.00 -1.00 0.00 0.00 -7.97 120.80 -217.00 22907.50 16.26 4.00 2.90 63.18 10.92 0.47 255.00 0.00 3.29 2.43 1.00 -1.00 0.00 0.00 -3.95 72.30 -218.00 22912.30 26.36 8.80 3.10 135.55 11.19 1.38 255.00 0.00 8.43 2.68 0.50 -1.00 0.00 0.00 -2.50 77.10 -219.00 23126.30 6.50 1.10 0.80 5.33 10.81 0.72 0.00 0.00 0.98 0.40 0.30 -1.00 0.00 0.00 -5.32 111.90 -220.00 23242.00 6.79 1.70 1.60 13.15 11.48 -0.70 0.00 0.00 1.52 1.13 1.00 -1.00 0.00 0.00 -3.57 74.00 -221.00 23326.20 16.93 1.00 4.60 52.84 10.30 -1.97 0.00 0.00 0.36 2.09 0.80 -1.00 0.00 0.00 -37.38 55.80 -222.00 23371.30 21.07 3.40 4.40 65.74 9.50 -0.49 0.00 0.00 0.48 1.43 0.50 -1.00 0.00 0.00 -35.26 100.90 -223.00 23390.60 9.75 1.30 2.10 19.70 7.48 0.88 0.00 0.00 0.85 2.28 0.70 -1.00 0.00 0.00 -9.14 17.80 -224.00 23395.30 7.91 1.60 2.10 16.20 7.40 -0.87 255.00 0.00 1.49 0.93 0.20 -1.00 0.00 0.00 -4.24 48.10 -225.00 23400.90 24.94 0.80 2.50 51.07 3.65 1.08 255.00 0.00 0.34 2.35 0.40 -1.00 0.00 0.00 -58.08 28.10 -226.00 23556.70 12.21 0.90 1.80 17.98 11.64 0.01 0.00 0.00 0.54 1.41 0.30 -1.00 0.00 0.00 -18.06 55.90 -227.00 23626.10 21.52 0.50 3.30 50.16 10.32 1.05 0.00 0.00 0.33 2.28 0.40 -1.00 0.00 0.00 -51.42 125.30 -228.00 23642.20 8.50 0.80 4.00 22.97 9.05 0.59 0.00 0.00 0.60 1.40 0.60 -1.00 0.00 0.00 -11.32 13.40 -229.00 23670.90 8.88 0.70 3.00 17.85 10.97 0.74 0.00 0.00 0.45 1.13 0.30 -1.00 0.00 0.00 -15.67 42.10 -230.00 23802.70 19.59 1.10 3.20 47.43 11.17 -2.79 0.00 0.00 0.47 1.82 0.80 -1.00 0.00 0.00 -33.66 45.90 -231.00 23877.80 8.38 1.60 1.60 13.82 11.11 0.65 0.00 0.00 0.76 1.72 0.80 -1.00 0.00 0.00 -8.80 121.00 -232.00 23923.30 10.01 1.60 1.90 21.28 10.81 1.69 0.00 0.00 1.46 2.22 1.40 -1.00 0.00 0.00 -5.49 38.50 -233.00 24064.90 9.34 1.20 1.30 11.20 11.24 -0.25 0.00 0.00 0.62 1.17 0.50 -1.00 0.00 0.00 -12.12 52.10 -234.00 24185.20 10.42 0.60 2.00 16.71 11.86 1.16 0.00 0.00 0.49 1.35 0.40 -1.00 0.00 0.00 -16.89 44.40 -235.00 24202.20 12.29 0.80 2.20 24.02 10.26 0.29 0.00 0.00 0.49 2.13 0.40 -1.00 0.00 0.00 -20.06 61.40 -236.00 24244.20 15.04 1.10 2.80 34.55 10.56 0.32 0.00 0.00 0.43 1.77 0.50 -1.00 0.00 0.00 -28.25 103.40 -237.00 24269.20 9.02 0.50 2.20 13.99 10.72 0.81 0.00 0.00 0.30 1.11 0.30 -1.00 0.00 0.00 -23.88 128.40 -238.00 24317.00 15.87 0.90 2.60 31.14 8.97 0.01 0.00 0.00 0.48 1.69 0.60 -1.00 0.00 0.00 -26.58 48.20 -239.00 24567.20 8.09 1.10 1.10 9.50 11.26 0.43 0.00 0.00 0.91 1.00 0.60 -1.00 0.00 0.00 -7.10 42.40 -240.00 24586.30 11.14 0.80 1.40 13.74 9.44 -0.74 0.00 0.00 0.52 1.51 0.50 -1.00 0.00 0.00 -17.20 61.50 -241.00 25310.20 6.16 1.20 0.70 6.23 10.85 1.24 0.00 0.00 1.07 1.17 0.70 -1.00 0.00 0.00 -4.60 17.40 -242.00 25408.80 6.07 1.90 1.00 9.23 10.35 1.00 0.00 0.00 1.55 1.25 0.50 -1.00 0.00 0.00 -3.13 116.00 -243.00 25417.50 8.38 1.00 3.30 23.53 11.42 0.13 0.00 0.00 0.84 3.72 0.80 -1.00 0.00 0.00 -7.97 124.70 -244.00 25429.00 8.40 1.00 1.20 12.28 10.62 0.46 0.00 0.00 0.81 1.71 0.70 -1.00 0.00 0.00 -8.29 8.20 -245.00 25615.10 15.17 0.90 3.00 36.93 10.26 2.51 0.00 0.00 0.63 2.09 0.70 -1.00 0.00 0.00 -19.27 66.30 -246.00 25715.50 19.57 0.90 1.90 38.08 11.79 -1.22 0.00 0.00 0.48 2.07 0.60 -1.00 0.00 0.00 -32.83 38.70 -247.00 25725.10 7.49 1.00 1.20 9.12 9.00 -2.16 255.00 0.00 0.61 1.25 0.60 -1.00 0.00 0.00 -9.75 125.10 -248.00 25800.70 12.39 2.00 3.50 35.91 11.03 0.35 0.00 0.00 1.17 2.22 1.10 -1.00 0.00 0.00 -8.46 123.90 -249.00 26417.80 13.80 0.60 1.80 21.06 10.03 0.53 0.00 0.00 0.51 1.37 0.40 -1.00 0.00 0.00 -21.67 101.00 -250.00 26451.40 11.81 1.60 3.90 37.14 9.17 -0.38 0.00 0.00 1.03 1.99 1.00 -1.00 0.00 0.00 -9.15 6.60 -251.00 26453.90 11.74 6.40 3.50 64.51 11.34 -1.03 255.00 0.00 4.05 4.87 3.50 -1.00 0.00 0.00 -2.32 85.90 -252.00 26542.20 6.82 1.50 0.40 7.46 7.31 -0.54 0.00 0.00 1.34 1.27 1.00 -1.00 0.00 0.00 -4.08 97.40 -253.00 26545.60 6.35 1.20 0.70 6.29 8.07 -0.78 0.00 0.00 0.89 1.12 0.80 -1.00 0.00 0.00 -5.69 75.20 -254.00 26570.90 7.38 1.40 1.00 9.24 9.66 -0.80 0.00 0.00 1.12 0.70 0.30 -1.00 0.00 0.00 -5.28 126.10 -255.00 26578.60 8.92 1.30 2.30 19.66 9.82 0.74 0.00 0.00 0.75 2.63 0.60 -1.00 0.00 0.00 -9.58 5.80 -256.00 26580.30 7.88 2.90 0.50 17.05 9.13 -0.80 255.00 0.00 2.49 2.61 2.30 -1.00 0.00 0.00 -2.53 84.30 -257.00 26745.90 13.32 0.60 3.60 37.53 11.36 -0.80 0.00 0.00 0.34 3.76 0.50 -1.00 0.00 0.00 -31.53 45.10 -258.00 26812.70 6.13 1.30 0.60 5.56 9.54 -1.13 0.00 0.00 0.88 0.74 0.40 -1.00 0.00 0.00 -5.56 86.30 -259.00 26870.60 7.89 1.30 1.60 12.31 11.38 1.15 0.00 0.00 0.87 1.55 0.70 -1.00 0.00 0.00 -7.24 41.80 -260.00 27146.10 6.35 2.00 0.40 7.15 12.23 1.65 0.00 0.00 1.91 0.41 0.20 -1.00 0.00 0.00 -2.66 61.30 -261.00 27176.30 7.11 1.00 1.80 11.29 12.17 -0.89 0.00 0.00 0.83 1.32 0.50 -1.00 0.00 0.00 -6.84 91.50 -262.00 27292.30 13.78 0.60 1.90 20.82 10.80 -1.40 0.00 0.00 0.41 1.49 0.40 -1.00 0.00 0.00 -27.01 79.50 -263.00 27374.80 12.18 1.60 3.00 34.45 10.16 0.05 0.00 0.00 1.41 2.40 0.40 -1.00 0.00 0.00 -6.92 34.00 -264.00 27458.00 15.30 0.90 1.40 23.20 7.18 0.33 0.00 0.00 0.31 1.61 0.70 -1.00 0.00 0.00 -39.59 117.20 -265.00 27532.90 7.75 2.10 1.90 15.71 9.09 0.25 0.00 0.00 1.92 1.60 0.50 -1.00 0.00 0.00 -3.23 64.10 -266.00 27551.60 6.51 2.20 4.10 21.79 10.25 -0.16 0.00 0.00 2.05 1.01 0.30 -1.00 0.00 0.00 -2.54 57.20 -267.00 27672.10 6.08 1.00 1.80 9.29 10.14 -0.52 0.00 0.00 0.75 1.50 0.40 -1.00 0.00 0.00 -6.47 75.30 -268.00 28151.20 11.12 2.00 1.30 19.76 10.08 0.24 0.00 0.00 0.96 1.79 0.70 -1.00 0.00 0.00 -9.27 16.80 -269.00 28285.20 6.80 2.60 1.50 13.90 11.92 0.10 0.00 0.00 1.58 2.33 1.10 -1.00 0.00 0.00 -3.45 48.40 -270.00 28423.00 9.56 3.00 1.80 20.25 10.61 -0.42 0.00 0.00 2.10 1.25 0.50 -1.00 0.00 0.00 -3.64 58.20 -271.00 28663.10 16.06 1.40 1.20 20.36 10.16 -0.88 0.00 0.00 1.05 1.30 0.50 -1.00 0.00 0.00 -12.29 42.30 -272.00 28666.40 6.92 1.70 1.80 12.78 8.90 0.39 255.00 0.00 1.58 1.45 0.60 -1.00 0.00 0.00 -3.51 122.40 -273.00 28694.10 6.29 1.10 0.50 5.01 13.01 0.29 0.00 0.00 0.93 0.50 0.20 -1.00 0.00 0.00 -5.38 73.30 -274.00 28762.00 6.12 0.50 1.60 9.02 10.51 0.15 0.00 0.00 0.39 1.82 0.40 -1.00 0.00 0.00 -12.40 13.20 -275.00 28811.00 6.44 3.20 1.00 11.57 10.54 0.16 0.00 0.00 2.30 1.08 0.20 -1.00 0.00 0.00 -2.24 62.20 -276.00 28969.60 14.92 1.40 1.40 26.91 10.31 -0.35 0.00 0.00 0.48 1.96 1.10 -1.00 0.00 0.00 -24.94 92.80 -277.00 28991.50 15.73 1.50 1.70 33.57 7.85 1.51 0.00 0.00 1.11 2.49 1.30 -1.00 0.00 0.00 -11.35 114.70 -278.00 29189.00 9.67 1.30 3.20 24.75 11.02 0.67 0.00 0.00 1.10 1.46 0.70 -1.00 0.00 0.00 -7.01 56.20 -279.00 29245.30 12.46 2.80 1.70 32.90 11.51 0.23 0.00 0.00 1.94 2.71 1.60 -1.00 0.00 0.00 -5.13 112.50 -280.00 29603.80 17.15 0.70 2.50 35.61 11.50 -0.36 0.00 0.00 0.42 1.95 0.40 -1.00 0.00 0.00 -32.43 87.00 -281.00 29712.30 8.83 1.30 1.70 13.38 11.19 -0.42 0.00 0.00 0.69 1.36 0.30 -1.00 0.00 0.00 -10.17 67.50 -282.00 29843.00 20.52 1.00 2.80 47.30 11.62 -0.20 0.00 0.00 0.42 2.32 0.60 -1.00 0.00 0.00 -39.51 70.20 -283.00 29991.10 6.41 1.80 1.30 11.53 10.43 0.63 0.00 0.00 1.56 1.09 0.50 -1.00 0.00 0.00 -3.28 90.30 -284.00 30167.40 11.17 1.80 2.00 25.27 10.86 -1.91 0.00 0.00 1.67 2.49 1.30 -1.00 0.00 0.00 -5.36 10.60 -285.00 30268.10 7.71 6.70 0.80 24.39 10.81 0.98 0.00 0.00 5.25 1.12 0.80 -1.00 0.00 0.00 -1.18 60.10 -286.00 30436.30 19.77 1.20 3.10 53.12 10.49 0.21 0.00 0.00 0.91 2.20 1.00 -1.00 0.00 0.00 -17.39 23.50 -287.00 30508.00 12.21 1.40 2.50 22.88 10.19 -0.80 0.00 0.00 0.65 1.12 0.50 -1.00 0.00 0.00 -14.99 95.20 -288.00 30560.10 9.87 0.80 3.60 25.77 10.34 1.87 0.00 0.00 0.65 2.63 0.30 -1.00 0.00 0.00 -12.13 19.30 -289.00 30572.30 8.79 0.60 2.40 15.53 8.00 0.37 0.00 0.00 0.41 1.21 0.40 -1.00 0.00 0.00 -17.28 31.50 -290.00 30617.90 9.03 1.30 1.30 12.74 11.19 -1.97 0.00 0.00 0.94 1.14 0.50 -1.00 0.00 0.00 -7.66 77.10 -291.00 30657.00 18.06 1.90 4.60 76.15 12.55 0.01 0.00 0.00 0.99 4.66 1.10 -1.00 0.00 0.00 -14.61 116.20 -292.00 30779.50 14.13 0.90 3.30 32.69 11.63 -1.28 0.00 0.00 0.58 2.04 0.60 -1.00 0.00 0.00 -19.43 110.70 -293.00 30824.10 18.23 0.70 2.00 29.13 11.08 -1.34 0.00 0.00 0.35 1.36 0.50 -1.00 0.00 0.00 -41.74 27.30 -294.00 30831.60 20.76 8.30 2.30 98.04 11.45 0.20 255.00 0.00 7.86 2.16 0.70 -1.00 0.00 0.00 -2.11 111.60 -295.00 30951.70 7.76 0.60 1.00 8.07 10.28 -2.73 0.00 0.00 0.43 1.09 0.50 -1.00 0.00 0.00 -14.49 26.90 -296.00 30976.90 14.89 1.30 2.50 30.34 11.52 -1.18 0.00 0.00 0.75 1.67 0.70 -1.00 0.00 0.00 -15.81 52.10 -297.00 30984.90 11.00 9.10 1.80 69.74 11.08 -0.23 255.00 0.00 8.84 2.11 0.90 -1.00 0.00 0.00 -1.00 8.90 -298.00 31129.60 14.46 1.20 2.80 31.10 12.21 -0.64 0.00 0.00 0.36 1.86 0.40 -1.00 0.00 0.00 -32.35 76.80 -299.00 31155.10 8.77 1.60 0.80 9.75 10.79 -0.74 0.00 0.00 1.24 0.90 0.60 -1.00 0.00 0.00 -5.64 102.30 -300.00 31286.80 6.35 3.20 2.30 18.65 9.60 -0.34 0.00 0.00 2.42 1.86 1.10 -1.00 0.00 0.00 -2.10 54.80 -301.00 31383.00 28.78 0.90 4.90 97.82 10.18 0.06 0.00 0.00 0.67 1.80 0.70 -1.00 0.00 0.00 -34.20 23.00 -302.00 31390.10 18.88 11.80 6.30 217.40 13.09 -0.96 255.00 0.00 8.44 3.18 0.90 -1.00 0.00 0.00 -1.79 30.10 -303.00 31516.40 16.72 1.00 5.80 70.55 9.31 2.29 0.00 0.00 0.52 4.41 0.80 -1.00 0.00 0.00 -25.96 79.60 -304.00 31689.30 6.40 3.50 1.20 11.02 10.81 0.72 0.00 0.00 2.07 0.44 0.30 -1.00 0.00 0.00 -2.47 124.50 -305.00 31738.40 19.76 0.80 4.10 59.44 11.46 -0.80 0.00 0.00 0.50 3.50 0.50 -1.00 0.00 0.00 -31.45 45.60 -306.00 31783.60 26.43 0.70 2.10 45.81 10.26 0.07 0.00 0.00 0.50 1.80 0.50 -1.00 0.00 0.00 -42.34 90.80 -307.00 31987.60 8.08 0.60 3.10 18.72 9.10 -1.55 0.00 0.00 0.42 1.63 0.30 -1.00 0.00 0.00 -15.55 38.80 -308.00 32072.00 9.10 1.70 5.20 44.15 11.47 -1.17 255.00 0.00 1.44 3.22 0.70 -1.00 0.00 0.00 -5.07 97.60 -309.00 32073.30 13.82 3.00 3.80 49.09 12.23 -0.97 0.00 0.00 2.72 1.81 0.70 -1.00 0.00 0.00 -4.07 73.30 -310.00 32155.40 14.04 0.80 1.80 22.94 11.36 -0.22 0.00 0.00 0.55 1.47 0.60 -1.00 0.00 0.00 -20.61 78.60 -311.00 32267.10 9.52 0.80 4.10 29.43 11.39 0.95 0.00 0.00 0.34 3.11 0.20 -1.00 0.00 0.00 -22.63 62.30 -312.00 32356.40 17.16 0.80 2.10 29.68 11.17 -1.18 0.00 0.00 0.45 1.86 0.40 -1.00 0.00 0.00 -30.38 23.60 -313.00 32469.10 6.20 1.50 1.00 9.77 10.61 1.86 0.00 0.00 1.28 1.47 0.70 -1.00 0.00 0.00 -3.87 85.10 -314.00 32608.10 11.30 0.80 2.30 19.75 11.74 0.12 0.00 0.00 0.49 1.58 0.60 -1.00 0.00 0.00 -18.54 19.30 -315.00 32687.50 11.82 0.60 2.50 20.81 10.79 -0.94 0.00 0.00 0.33 1.58 0.50 -1.00 0.00 0.00 -28.60 98.70 -316.00 33050.50 7.45 0.70 1.70 9.40 10.81 0.10 0.00 0.00 0.52 0.64 0.50 -1.00 0.00 0.00 -11.40 77.70 -317.00 33165.90 6.60 0.80 1.30 8.63 11.03 1.00 0.00 0.00 0.62 1.44 0.30 -1.00 0.00 0.00 -8.50 65.10 -318.00 33206.40 10.72 0.80 2.90 25.12 11.04 -0.70 0.00 0.00 0.53 2.97 0.40 -1.00 0.00 0.00 -16.28 105.60 -319.00 33510.90 16.43 0.90 2.00 30.79 11.50 0.45 0.00 0.00 0.59 1.81 0.60 -1.00 0.00 0.00 -22.35 26.10 -320.00 33592.20 6.12 2.50 0.80 12.65 12.52 -0.25 0.00 0.00 1.74 2.27 1.70 -1.00 0.00 0.00 -2.81 56.20 -321.00 33645.70 6.14 2.30 1.20 9.82 12.16 -2.83 0.00 0.00 1.14 0.93 0.40 -1.00 0.00 0.00 -4.31 32.90 -322.00 33701.20 7.09 2.90 1.80 14.22 11.85 -1.84 0.00 0.00 1.90 1.39 0.40 -1.00 0.00 0.00 -2.99 88.40 -323.00 33752.30 12.94 0.60 1.70 18.60 10.48 -0.09 0.00 0.00 0.44 1.27 0.30 -1.00 0.00 0.00 -23.38 11.50 -324.00 33974.10 6.46 1.30 1.80 10.40 9.85 0.58 0.00 0.00 1.14 0.94 0.20 -1.00 0.00 0.00 -4.53 105.30 -325.00 34023.20 26.30 1.20 4.40 82.97 11.94 -1.10 0.00 0.00 0.64 2.66 0.70 -1.00 0.00 0.00 -32.80 26.40 -326.00 34129.90 12.45 0.80 2.30 23.61 9.69 -1.11 0.00 0.00 0.62 1.74 0.50 -1.00 0.00 0.00 -15.97 5.10 -327.00 34152.40 24.19 0.80 2.60 52.11 10.22 -0.14 0.00 0.00 0.42 2.21 0.40 -1.00 0.00 0.00 -46.47 27.60 -328.00 34311.90 7.33 7.60 0.60 22.21 11.29 0.10 0.00 0.00 4.15 1.51 1.10 -1.00 0.00 0.00 -1.41 7.90 -329.00 34498.70 31.93 1.00 3.00 74.95 12.06 0.70 0.00 0.00 0.49 2.31 0.60 -1.00 0.00 0.00 -51.65 117.90 -330.00 34539.90 7.74 1.60 0.60 8.77 9.97 -0.53 0.00 0.00 1.19 0.87 0.70 -1.00 0.00 0.00 -5.21 31.10 -331.00 34611.30 6.45 1.70 0.90 10.04 9.76 -2.08 0.00 0.00 1.50 1.53 1.40 -1.00 0.00 0.00 -3.44 51.30 -332.00 34630.80 6.14 1.10 0.50 4.66 8.45 1.72 0.00 0.00 0.94 0.62 0.40 -1.00 0.00 0.00 -5.23 122.00 -333.00 34632.20 9.31 2.60 1.10 16.84 9.03 0.29 255.00 0.00 0.70 1.46 0.60 -1.00 0.00 0.00 -10.67 72.20 -334.00 34700.60 21.80 1.20 7.70 112.68 10.35 -1.08 0.00 0.00 0.44 2.78 0.60 -1.00 0.00 0.00 -39.88 63.80 -335.00 34705.10 16.47 5.60 3.40 111.66 10.11 -0.05 255.00 0.00 4.85 8.00 5.10 -1.00 0.00 0.00 -2.72 17.10 -336.00 34875.50 12.63 0.90 1.60 19.14 11.84 -0.93 0.00 0.00 0.68 1.60 0.60 -1.00 0.00 0.00 -14.80 110.70 -337.00 34879.00 9.42 4.40 1.40 39.54 12.74 -0.75 255.00 0.00 4.20 1.17 0.50 -1.00 0.00 0.00 -1.79 63.00 -338.00 34985.40 12.52 2.60 3.20 34.60 11.70 -0.81 0.00 0.00 0.39 2.13 0.40 -1.00 0.00 0.00 -25.86 92.60 -339.00 35389.70 10.88 3.20 1.70 24.84 12.79 0.32 0.00 0.00 2.56 1.73 0.80 -1.00 0.00 0.00 -3.40 112.90 -340.00 35510.80 7.88 0.90 1.70 12.72 10.44 2.70 0.00 0.00 0.78 1.37 0.60 -1.00 0.00 0.00 -8.09 106.00 -341.00 35553.80 13.21 0.50 1.90 21.82 8.57 -1.35 0.00 0.00 0.29 1.76 0.30 -1.00 0.00 0.00 -37.07 21.00 -342.00 35661.90 13.59 1.10 4.10 40.84 10.70 0.23 0.00 0.00 0.79 2.87 0.40 -1.00 0.00 0.00 -13.71 1.10 -343.00 35690.20 14.93 0.80 3.70 38.86 9.79 -0.16 0.00 0.00 0.58 2.34 0.30 -1.00 0.00 0.00 -20.71 29.40 -344.00 35895.20 6.12 2.20 1.40 11.16 12.11 0.53 0.00 0.00 1.82 1.48 0.80 -1.00 0.00 0.00 -2.69 55.20 -345.00 36050.20 11.88 1.20 2.10 24.12 11.36 1.20 0.00 0.00 0.44 1.61 1.00 -1.00 0.00 0.00 -21.81 5.40 -346.00 36209.70 15.66 0.70 1.80 25.92 11.18 -0.19 0.00 0.00 0.46 1.97 0.50 -1.00 0.00 0.00 -27.46 36.90 -347.00 36283.40 6.11 1.60 0.80 6.86 10.54 1.12 0.00 0.00 1.32 0.77 0.40 -1.00 0.00 0.00 -3.71 110.60 -348.00 36557.00 9.25 0.60 1.80 13.18 9.53 -0.64 0.00 0.00 0.53 0.88 0.40 -1.00 0.00 0.00 -13.89 77.00 -349.00 36568.10 28.59 1.00 2.00 52.76 9.14 0.58 0.00 0.00 0.48 1.77 0.70 -1.00 0.00 0.00 -47.83 11.30 -350.00 36794.10 7.06 0.80 0.40 4.41 11.08 0.55 0.00 0.00 0.69 0.60 0.50 -1.00 0.00 0.00 -8.23 58.10 -351.00 36827.50 12.67 0.50 1.90 19.14 9.23 1.06 0.00 0.00 0.39 1.43 0.30 -1.00 0.00 0.00 -25.96 14.70 -352.00 36837.50 6.48 1.70 2.70 16.32 9.51 0.21 255.00 0.00 1.55 0.95 0.50 -1.00 0.00 0.00 -3.34 101.50 -353.00 36911.70 6.89 3.60 1.50 15.72 10.22 1.57 0.00 0.00 1.45 1.41 0.30 -1.00 0.00 0.00 -3.80 22.10 -354.00 36917.90 7.13 1.20 3.20 18.10 11.12 -0.46 0.00 0.00 0.99 1.02 0.70 -1.00 0.00 0.00 -5.76 53.90 -355.00 37046.60 7.62 1.40 2.60 20.19 11.62 0.39 0.00 0.00 1.11 3.26 1.00 -1.00 0.00 0.00 -5.49 29.00 -356.00 37133.80 33.31 1.30 3.20 86.12 11.56 -0.79 0.00 0.00 0.67 2.52 0.80 -1.00 0.00 0.00 -40.02 116.20 -357.00 37217.10 6.67 3.80 0.90 16.17 10.58 -1.35 0.00 0.00 3.25 1.95 1.40 -1.00 0.00 0.00 -1.64 97.10 -358.00 37322.80 7.09 2.20 2.50 19.02 12.95 -0.13 0.00 0.00 2.05 2.13 0.50 -1.00 0.00 0.00 -2.77 49.20 -359.00 37332.00 6.21 1.10 1.60 9.82 9.57 0.41 0.00 0.00 0.86 1.21 0.80 -1.00 0.00 0.00 -5.77 58.40 -360.00 37568.70 13.85 1.10 3.00 32.15 10.69 -0.26 0.00 0.00 0.33 1.98 0.30 -1.00 0.00 0.00 -33.21 39.10 -361.00 37595.90 11.18 10.40 3.00 68.01 9.32 2.14 255.00 0.00 6.23 2.39 0.70 -1.00 0.00 0.00 -1.44 91.90 -362.00 37618.90 7.14 1.70 0.40 5.76 9.58 0.03 0.00 0.00 0.64 0.51 0.30 -1.00 0.00 0.00 -8.86 89.30 -363.00 37711.70 6.71 4.10 1.50 18.07 11.79 0.93 0.00 0.00 3.69 1.05 0.30 -1.00 0.00 0.00 -1.45 79.70 -364.00 37790.20 6.07 0.70 1.60 8.69 10.39 2.28 0.00 0.00 0.56 1.74 0.40 -1.00 0.00 0.00 -8.66 4.60 -365.00 37849.90 31.42 1.30 3.50 88.78 12.68 -0.24 0.00 0.00 0.81 3.13 0.80 -1.00 0.00 0.00 -30.88 64.30 -366.00 37855.50 12.70 10.00 2.70 146.62 13.34 -0.01 255.00 0.00 6.56 8.73 6.60 -1.00 0.00 0.00 -1.55 95.50 -367.00 38032.50 20.14 1.00 1.90 36.30 10.44 0.23 0.00 0.00 0.61 1.89 0.70 -1.00 0.00 0.00 -26.24 118.90 -368.00 38123.20 7.89 1.70 1.20 10.67 11.44 -1.29 0.00 0.00 0.69 1.11 0.30 -1.00 0.00 0.00 -9.20 81.60 -369.00 38226.80 19.71 1.30 3.10 56.95 12.66 0.20 0.00 0.00 0.97 3.01 0.90 -1.00 0.00 0.00 -16.28 57.20 -370.00 38303.00 10.02 3.60 4.50 46.75 12.17 0.31 0.00 0.00 1.14 5.11 1.00 -1.00 0.00 0.00 -7.03 5.40 -371.00 38306.80 10.22 7.40 0.70 48.71 12.41 0.85 255.00 0.00 4.82 5.13 4.80 -1.00 0.00 0.00 -1.70 34.80 -372.00 38688.60 24.03 0.80 2.00 43.48 12.04 0.18 0.00 0.00 0.61 1.84 0.60 -1.00 0.00 0.00 -31.68 7.00 -373.00 38750.70 8.99 2.30 2.20 21.68 10.59 1.32 0.00 0.00 2.07 2.22 0.40 -1.00 0.00 0.00 -3.48 69.10 -374.00 38978.50 6.25 0.60 0.80 4.53 10.83 0.69 0.00 0.00 0.26 0.59 0.30 -1.00 0.00 0.00 -18.91 40.90 -375.00 39014.10 11.24 0.80 2.40 19.97 11.33 -0.32 0.00 0.00 0.51 1.34 0.50 -1.00 0.00 0.00 -17.57 76.50 -376.00 39043.30 9.02 1.20 1.90 17.11 11.63 1.11 0.00 0.00 0.76 1.62 0.70 -1.00 0.00 0.00 -9.46 105.70 -377.00 39123.50 6.32 2.50 1.70 15.06 11.55 -1.85 0.00 0.00 1.25 2.16 1.20 -1.00 0.00 0.00 -4.05 57.90 -378.00 39174.40 7.23 4.70 1.30 15.52 13.35 -1.32 0.00 0.00 1.44 0.74 0.20 -1.00 0.00 0.00 -4.02 108.80 -379.00 39387.00 7.04 2.50 3.40 22.68 11.98 -0.09 0.00 0.00 1.55 3.30 0.40 -1.00 0.00 0.00 -3.63 65.40 -380.00 39553.30 18.55 0.80 1.80 29.68 10.53 -2.64 0.00 0.00 0.47 1.30 0.50 -1.00 0.00 0.00 -31.81 103.70 -381.00 39586.70 7.47 3.30 1.50 18.14 11.09 1.29 0.00 0.00 3.16 0.62 0.20 -1.00 0.00 0.00 -1.89 9.10 -382.00 39596.80 17.05 1.40 3.30 48.41 11.06 -0.78 0.00 0.00 0.81 2.65 0.80 -1.00 0.00 0.00 -16.83 19.20 -383.00 39629.60 12.24 0.70 2.20 22.16 9.29 0.02 0.00 0.00 0.49 1.34 0.60 -1.00 0.00 0.00 -20.06 52.00 -384.00 39653.50 7.21 4.20 1.90 19.45 11.12 -1.36 0.00 0.00 0.57 1.96 0.20 -1.00 0.00 0.00 -10.17 75.90 -385.00 39705.20 11.11 1.20 1.50 17.41 10.90 -0.35 0.00 0.00 0.88 1.68 0.60 -1.00 0.00 0.00 -10.09 -0.40 -386.00 39711.10 6.26 7.80 0.60 34.46 11.26 -0.15 255.00 0.00 7.03 0.66 0.20 -1.00 0.00 0.00 -0.71 31.10 -387.00 40122.80 11.49 1.40 1.20 18.82 10.78 -0.32 0.00 0.00 0.67 1.84 0.90 -1.00 0.00 0.00 -13.64 33.20 -388.00 40206.70 6.56 1.50 2.10 12.11 11.91 -1.26 0.00 0.00 1.39 0.46 0.20 -1.00 0.00 0.00 -3.78 14.70 -389.00 40636.40 19.36 1.80 3.90 66.69 12.65 -0.97 0.00 0.00 1.33 3.23 1.30 -1.00 0.00 0.00 -11.62 34.80 -390.00 40703.30 7.65 1.10 3.70 22.06 10.15 0.42 0.00 0.00 0.88 2.88 0.80 -1.00 0.00 0.00 -6.92 101.70 -391.00 41039.20 6.29 4.30 2.40 21.99 12.62 -0.97 0.00 0.00 4.14 1.89 0.60 -1.00 0.00 0.00 -1.22 79.20 -392.00 41531.20 30.04 1.80 3.40 83.31 11.92 -1.76 0.00 0.00 0.58 2.44 0.70 -1.00 0.00 0.00 -41.48 33.60 -393.00 41640.30 16.57 0.90 3.40 44.71 9.73 -0.14 0.00 0.00 0.44 2.61 0.70 -1.00 0.00 0.00 -30.04 14.70 -394.00 41729.80 19.16 0.60 7.10 90.48 10.60 -0.89 0.00 0.00 0.35 3.85 0.30 -1.00 0.00 0.00 -43.23 104.20 -395.00 41735.80 13.61 7.10 2.20 109.63 11.95 1.36 255.00 0.00 6.42 7.42 6.40 -1.00 0.00 0.00 -1.70 7.80 -396.00 41778.90 6.98 1.00 2.90 18.12 9.44 0.54 0.00 0.00 0.91 2.43 0.60 -1.00 0.00 0.00 -6.11 25.30 -397.00 41785.90 6.77 9.00 1.10 40.39 11.15 0.20 255.00 0.00 0.71 1.17 0.50 -1.00 0.00 0.00 -7.58 57.90 -398.00 41807.00 13.07 0.70 2.40 21.93 11.02 1.58 0.00 0.00 0.53 1.61 0.50 -1.00 0.00 0.00 -19.62 53.40 -399.00 41862.20 8.16 0.70 1.10 9.40 9.49 1.13 0.00 0.00 0.45 1.39 0.50 -1.00 0.00 0.00 -14.36 108.60 -400.00 41877.00 7.96 3.90 1.90 25.03 9.78 -0.42 0.00 0.00 3.74 2.10 1.00 -1.00 0.00 0.00 -1.70 123.40 -401.00 41992.70 16.15 1.10 1.60 27.05 10.77 0.92 0.00 0.00 0.72 1.77 0.80 -1.00 0.00 0.00 -18.02 111.10 -402.00 42107.90 6.68 2.20 0.80 13.67 12.75 -0.13 0.00 0.00 2.07 2.31 2.00 -1.00 0.00 0.00 -2.58 21.50 -403.00 42142.00 6.34 0.40 1.60 10.20 12.50 -0.23 0.00 0.00 0.31 1.70 0.30 -1.00 0.00 0.00 -16.61 30.00 -404.00 42242.50 6.77 4.60 2.00 20.98 11.23 -0.97 0.00 0.00 4.18 1.55 1.20 -1.00 0.00 0.00 -1.30 104.90 -405.00 42284.00 7.81 3.80 0.80 13.32 11.11 0.04 0.00 0.00 3.45 0.77 0.60 -1.00 0.00 0.00 -1.81 18.40 -406.00 42347.90 6.25 3.10 2.00 15.70 10.74 0.34 0.00 0.00 2.71 0.90 0.60 -1.00 0.00 0.00 -1.85 82.30 -407.00 42539.30 9.00 2.50 4.10 31.18 12.74 -0.39 0.00 0.00 0.57 2.61 0.60 -1.00 0.00 0.00 -12.55 17.70 -408.00 42556.40 17.02 0.90 3.90 48.80 13.01 -0.67 0.00 0.00 0.43 2.30 0.70 -1.00 0.00 0.00 -31.91 34.80 -409.00 42580.40 6.06 1.80 0.90 8.58 12.08 -0.30 0.00 0.00 1.57 1.23 1.20 -1.00 0.00 0.00 -3.08 58.80 -410.00 42752.40 6.49 4.00 1.00 14.36 11.19 2.66 0.00 0.00 0.75 1.20 0.60 -1.00 0.00 0.00 -6.90 102.80 -411.00 42876.40 27.91 1.20 1.90 53.35 11.88 -0.61 0.00 0.00 0.53 2.27 0.90 -1.00 0.00 0.00 -42.47 98.80 -412.00 43107.10 6.20 0.90 0.90 5.82 12.15 -0.83 0.00 0.00 0.73 0.71 0.40 -1.00 0.00 0.00 -6.81 73.50 -413.00 43359.10 17.65 0.90 2.10 37.44 11.53 -0.68 0.00 0.00 0.60 2.15 0.60 -1.00 0.00 0.00 -23.68 18.30 -414.00 43418.60 8.97 1.20 2.00 17.48 10.98 0.57 0.00 0.00 0.96 1.72 0.80 -1.00 0.00 0.00 -7.50 129.00 -415.00 43447.90 19.12 0.90 2.60 44.31 10.54 0.99 0.00 0.00 0.44 2.47 0.70 -1.00 0.00 0.00 -34.92 30.30 -416.00 43635.10 6.55 1.60 1.30 9.61 11.01 2.31 0.00 0.00 1.24 0.55 0.40 -1.00 0.00 0.00 -4.24 89.50 -417.00 43672.50 7.83 6.40 2.60 25.45 12.90 0.63 0.00 0.00 0.68 1.44 0.40 -1.00 0.00 0.00 -9.15 24.50 -418.00 43762.70 10.90 1.30 2.50 27.35 11.83 0.79 0.00 0.00 1.06 1.89 0.90 -1.00 0.00 0.00 -8.26 89.10 -419.00 43891.80 6.07 0.90 3.10 15.62 12.13 -0.29 0.00 0.00 0.52 2.62 0.50 -1.00 0.00 0.00 -9.31 90.20 -420.00 44264.40 9.60 0.80 1.50 13.32 13.00 0.68 0.00 0.00 0.58 1.54 0.60 -1.00 0.00 0.00 -13.22 78.80 -421.00 44343.60 6.33 2.50 0.50 10.15 13.67 -1.39 0.00 0.00 2.40 1.34 1.10 -1.00 0.00 0.00 -2.11 30.00 -422.00 44465.20 14.02 0.90 2.40 30.82 12.08 0.05 0.00 0.00 0.76 2.52 0.70 -1.00 0.00 0.00 -14.69 23.60 -423.00 44650.10 20.94 0.80 4.10 63.64 13.21 0.34 0.00 0.00 0.46 2.53 0.60 -1.00 0.00 0.00 -36.32 80.50 -424.00 45072.10 6.99 1.40 2.40 13.03 11.79 0.23 0.00 0.00 0.91 1.35 0.50 -1.00 0.00 0.00 -6.13 118.50 -425.00 45140.60 22.67 1.00 2.90 49.61 12.01 0.77 0.00 0.00 0.49 1.79 0.50 -1.00 0.00 0.00 -36.90 59.00 -426.00 45638.70 7.27 1.60 0.70 8.17 11.82 -0.30 0.00 0.00 1.23 0.97 0.50 -1.00 0.00 0.00 -4.74 45.10 -427.00 45665.50 6.68 1.10 1.50 9.36 11.57 -0.76 0.00 0.00 0.46 1.28 0.40 -1.00 0.00 0.00 -11.54 71.90 -428.00 45678.00 7.97 1.40 1.60 14.91 10.60 -1.40 0.00 0.00 1.18 2.04 1.20 -1.00 0.00 0.00 -5.39 84.40 -429.00 45901.20 13.35 1.00 1.50 22.24 11.00 1.14 0.00 0.00 0.87 1.71 0.90 -1.00 0.00 0.00 -12.25 51.60 -430.00 45901.30 13.87 1.10 1.40 22.42 11.05 0.08 0.00 0.00 0.90 1.69 1.00 -1.00 0.00 0.00 -12.36 51.70 -431.00 46063.00 11.10 0.90 2.50 22.60 10.99 -1.99 0.00 0.00 0.76 1.90 0.60 -1.00 0.00 0.00 -11.63 85.40 -432.00 46333.60 6.77 2.80 1.10 12.24 13.24 -1.08 0.00 0.00 2.13 0.55 0.40 -1.00 0.00 0.00 -2.54 100.00 -433.00 46463.50 35.48 0.80 2.30 75.07 10.52 0.10 0.00 0.00 0.39 2.26 0.60 -1.00 0.00 0.00 -72.79 101.90 -434.00 46786.10 14.94 0.80 2.50 26.65 11.09 0.58 0.00 0.00 0.44 1.46 0.50 -1.00 0.00 0.00 -27.02 40.50 -435.00 46904.70 7.22 0.90 0.70 7.62 10.08 -1.77 0.00 0.00 0.70 1.09 0.80 -1.00 0.00 0.00 -8.20 31.10 -436.00 46928.20 24.85 0.80 3.70 71.29 10.28 -2.24 0.00 0.00 0.48 2.75 0.50 -1.00 0.00 0.00 -41.09 54.60 -437.00 47121.50 9.80 1.30 2.00 18.79 10.71 0.81 0.00 0.00 1.12 1.90 0.80 -1.00 0.00 0.00 -7.02 119.90 -438.00 47155.60 9.02 3.60 3.30 34.80 11.87 0.96 0.00 0.00 2.55 2.96 0.50 -1.00 0.00 0.00 -2.83 51.60 -439.00 47249.10 8.26 1.40 1.30 12.21 10.28 1.36 0.00 0.00 1.26 1.42 0.40 -1.00 0.00 0.00 -5.23 119.50 -440.00 47312.20 13.22 1.10 3.20 36.61 10.07 2.56 0.00 0.00 0.84 2.92 0.90 -1.00 0.00 0.00 -12.60 54.60 -441.00 47342.50 12.95 1.20 2.20 23.98 10.10 1.34 0.00 0.00 0.65 1.74 0.40 -1.00 0.00 0.00 -16.04 84.90 -442.00 47357.80 13.71 1.20 2.90 34.72 10.48 1.30 0.00 0.00 0.78 2.28 0.70 -1.00 0.00 0.00 -14.01 100.20 -443.00 47389.90 8.15 3.10 1.40 19.50 10.01 0.02 0.00 0.00 2.90 0.85 0.60 -1.00 0.00 0.00 -2.25 4.30 -444.00 47405.90 10.51 2.30 2.90 29.81 9.63 -0.91 0.00 0.00 1.33 2.96 1.20 -1.00 0.00 0.00 -6.34 20.30 -445.00 47430.00 39.24 1.00 2.70 90.85 10.58 0.04 0.00 0.00 0.49 2.53 0.70 -1.00 0.00 0.00 -63.83 44.40 -446.00 47437.40 9.78 8.30 1.90 125.02 9.24 1.39 255.00 0.00 8.02 1.57 0.70 -1.00 0.00 0.00 -0.97 77.40 -447.00 47530.50 7.48 1.30 2.80 18.30 11.04 -0.41 0.00 0.00 1.15 1.13 0.90 -1.00 0.00 0.00 -5.21 16.90 -448.00 47587.00 6.63 1.00 2.50 13.12 11.24 -0.27 0.00 0.00 0.77 0.90 0.60 -1.00 0.00 0.00 -6.88 73.40 -449.00 48062.60 7.03 2.40 1.30 13.24 12.10 0.07 0.00 0.00 2.19 1.49 0.90 -1.00 0.00 0.00 -2.56 62.60 -450.00 48077.10 28.24 1.20 4.30 93.31 10.61 -1.73 0.00 0.00 0.36 3.02 0.80 -1.00 0.00 0.00 -62.29 51.50 -451.00 48193.20 9.75 0.80 3.30 22.97 11.49 -1.00 0.00 0.00 0.67 2.40 0.40 -1.00 0.00 0.00 -11.65 39.60 -452.00 48288.10 15.34 1.50 1.90 27.96 11.91 -0.57 0.00 0.00 0.54 2.16 0.60 -1.00 0.00 0.00 -22.81 6.50 -453.00 48380.80 13.51 1.10 2.50 25.01 11.63 -0.08 0.00 0.00 0.41 1.99 0.40 -1.00 0.00 0.00 -26.46 99.20 -454.00 48524.50 13.79 1.10 2.90 37.03 12.16 -0.10 0.00 0.00 0.96 2.34 1.00 -1.00 0.00 0.00 -11.49 114.90 -455.00 48692.90 26.18 1.00 2.90 60.56 12.02 -0.31 0.00 0.00 0.36 2.07 0.70 -1.00 0.00 0.00 -58.25 27.30 -456.00 48714.80 10.04 2.20 1.80 20.70 8.08 -0.44 255.00 0.00 1.89 1.77 0.40 -1.00 0.00 0.00 -4.25 74.80 -457.00 48764.80 27.87 1.10 2.80 71.57 10.09 1.28 0.00 0.00 0.50 2.52 0.80 -1.00 0.00 0.00 -44.83 99.20 -458.00 49009.80 6.36 2.50 1.20 11.13 10.78 0.54 0.00 0.00 1.54 1.64 0.60 -1.00 0.00 0.00 -3.30 88.20 -459.00 49028.80 6.79 2.20 1.10 10.68 9.81 -0.70 0.00 0.00 1.99 1.22 0.60 -1.00 0.00 0.00 -2.73 107.20 -460.00 49219.10 13.32 0.80 1.60 21.12 9.43 -0.64 0.00 0.00 0.49 1.91 0.60 -1.00 0.00 0.00 -21.98 41.50 -461.00 49374.70 26.15 2.60 8.30 145.82 9.36 1.18 0.00 0.00 0.50 3.50 1.10 -1.00 0.00 0.00 -41.92 69.10 -462.00 49405.00 7.49 0.80 0.80 7.45 5.33 -1.11 255.00 0.00 0.63 1.11 0.60 -1.00 0.00 0.00 -9.51 125.00 -463.00 49457.50 7.19 1.70 0.30 6.37 9.39 -1.07 0.00 0.00 1.56 0.59 0.50 -1.00 0.00 0.00 -3.69 23.90 -464.00 49496.90 11.44 0.60 3.80 27.07 10.15 -0.99 0.00 0.00 0.38 1.55 0.40 -1.00 0.00 0.00 -23.92 63.30 -465.00 49522.00 7.62 2.40 0.90 9.66 8.21 0.24 0.00 0.00 0.37 0.97 0.30 -1.00 0.00 0.00 -16.30 114.00 -466.00 49595.80 26.56 1.00 4.60 84.79 9.70 0.33 0.00 0.00 0.61 3.27 0.60 -1.00 0.00 0.00 -34.91 34.20 -467.00 49753.50 15.36 1.60 1.60 24.69 9.15 -1.35 0.00 0.00 0.55 1.53 0.60 -1.00 0.00 0.00 -22.17 63.90 -468.00 49807.10 6.75 9.70 0.70 36.67 9.45 1.34 0.00 0.00 2.94 0.85 0.30 -1.00 0.00 0.00 -1.84 117.50 -469.00 49880.30 9.66 0.80 2.80 25.34 10.50 1.41 0.00 0.00 0.38 2.82 0.40 -1.00 0.00 0.00 -20.26 62.70 -470.00 49961.00 19.31 0.70 3.10 40.09 10.43 1.05 0.00 0.00 0.43 1.55 0.50 -1.00 0.00 0.00 -36.04 15.40 -471.00 50074.70 6.87 0.90 2.00 11.36 12.17 0.96 0.00 0.00 0.67 1.22 0.70 -1.00 0.00 0.00 -8.22 1.10 -472.00 50107.30 9.41 0.30 2.30 20.45 10.23 -1.33 0.00 0.00 0.19 2.21 0.20 -1.00 0.00 0.00 -40.38 8.10 -473.00 50268.00 21.34 0.90 4.70 73.88 11.39 2.63 0.00 0.00 0.36 3.64 0.60 -1.00 0.00 0.00 -47.65 66.40 -474.00 50305.60 12.40 0.80 2.70 29.84 9.90 0.63 0.00 0.00 0.59 2.65 0.60 -1.00 0.00 0.00 -16.89 104.00 -475.00 50350.10 6.09 1.00 0.50 4.87 7.53 -0.68 0.00 0.00 0.66 0.80 0.50 -1.00 0.00 0.00 -7.36 20.50 -476.00 50585.60 6.33 4.10 4.10 28.45 12.55 -0.14 0.00 0.00 3.62 2.16 1.30 -1.00 0.00 0.00 -1.40 25.60 -477.00 50633.30 9.46 1.10 1.70 16.37 11.24 0.49 0.00 0.00 0.88 1.97 0.70 -1.00 0.00 0.00 -8.60 47.70 -478.00 50666.70 7.27 1.10 2.20 15.39 9.97 0.69 0.00 0.00 0.92 2.04 0.80 -1.00 0.00 0.00 -6.31 81.10 -479.00 51052.70 15.74 0.90 2.20 35.40 11.17 -2.29 0.00 0.00 0.38 2.70 0.80 -1.00 0.00 0.00 -32.73 83.10 -480.00 51675.80 16.91 0.90 4.50 53.74 11.89 0.59 0.00 0.00 0.57 2.73 0.60 -1.00 0.00 0.00 -23.54 66.20 -481.00 51831.60 27.03 1.10 3.20 71.41 12.15 -0.87 0.00 0.00 0.55 2.62 0.80 -1.00 0.00 0.00 -39.67 94.00 -482.00 51849.80 22.00 1.00 1.60 36.29 8.94 -0.93 0.00 0.00 0.72 1.91 0.60 -1.00 0.00 0.00 -24.58 112.20 -483.00 52043.00 7.55 4.60 1.50 20.40 12.25 0.09 0.00 0.00 4.22 1.28 0.80 -1.00 0.00 0.00 -1.43 49.40 -484.00 52122.60 8.82 1.50 3.10 25.14 9.45 1.07 0.00 0.00 1.31 1.92 1.40 -1.00 0.00 0.00 -5.38 1.00 -485.00 52165.20 14.77 1.50 2.20 30.09 12.12 -0.74 0.00 0.00 0.51 1.67 0.90 -1.00 0.00 0.00 -22.95 43.60 -486.00 52336.90 17.65 0.60 2.20 32.02 10.65 0.78 0.00 0.00 0.30 1.74 0.40 -1.00 0.00 0.00 -47.82 10.50 -487.00 52390.70 6.81 2.60 1.40 13.37 11.34 -1.00 0.00 0.00 2.06 0.57 0.30 -1.00 0.00 0.00 -2.64 13.10 -488.00 52410.30 17.53 0.90 3.00 44.18 11.64 -1.48 0.00 0.00 0.43 2.84 0.70 -1.00 0.00 0.00 -32.77 83.90 -489.00 52448.00 17.24 0.90 2.20 35.15 9.24 -0.37 0.00 0.00 0.67 2.42 0.70 -1.00 0.00 0.00 -20.60 121.60 -490.00 52706.80 12.49 0.90 4.80 41.47 10.34 -0.98 0.00 0.00 0.39 3.14 0.60 -1.00 0.00 0.00 -25.90 124.40 -491.00 52764.20 7.17 2.00 0.90 10.24 11.68 0.56 0.00 0.00 1.18 0.87 0.50 -1.00 0.00 0.00 -4.88 53.80 -492.00 52772.40 16.23 0.90 2.20 30.04 11.37 -0.10 0.00 0.00 0.55 1.50 0.60 -1.00 0.00 0.00 -23.42 62.00 -493.00 52784.80 6.85 1.10 0.60 6.23 10.52 -0.13 0.00 0.00 1.00 0.69 0.20 -1.00 0.00 0.00 -5.47 23.20 -494.00 53048.20 22.27 1.00 2.20 42.24 11.09 1.19 0.00 0.00 0.52 1.65 0.70 -1.00 0.00 0.00 -34.55 81.80 -495.00 53114.90 13.48 1.20 2.50 33.08 10.43 -1.74 0.00 0.00 0.95 2.48 1.00 -1.00 0.00 0.00 -11.32 20.50 -496.00 53268.90 8.43 2.30 6.60 39.46 11.54 0.29 0.00 0.00 1.53 3.34 1.30 -1.00 0.00 0.00 -4.41 123.30 -497.00 53375.00 7.73 1.40 2.10 15.76 10.99 0.14 0.00 0.00 1.25 1.59 1.20 -1.00 0.00 0.00 -4.96 24.60 -498.00 53503.50 15.43 0.70 4.40 47.48 11.33 -0.95 0.00 0.00 0.51 2.44 0.50 -1.00 0.00 0.00 -23.99 25.10 -499.00 53618.40 17.64 0.80 2.60 37.32 11.21 0.02 0.00 0.00 0.47 1.80 0.60 -1.00 0.00 0.00 -29.75 12.00 -500.00 53647.30 7.78 1.10 1.60 14.49 10.33 -1.65 0.00 0.00 0.93 2.20 1.00 -1.00 0.00 0.00 -6.66 40.90 -501.00 53681.90 6.31 3.00 1.00 12.73 10.56 -1.14 0.00 0.00 2.47 0.73 0.40 -1.00 0.00 0.00 -2.05 75.50 -502.00 53848.10 6.30 2.90 1.40 11.52 11.67 -0.82 0.00 0.00 1.19 1.17 1.00 -1.00 0.00 0.00 -4.22 113.70 -503.00 54151.80 12.02 0.80 4.00 33.48 11.96 0.44 0.00 0.00 0.52 1.84 0.60 -1.00 0.00 0.00 -18.32 33.40 -504.00 54326.20 9.48 1.30 1.40 14.84 12.02 -0.20 0.00 0.00 0.78 1.60 0.70 -1.00 0.00 0.00 -9.67 79.80 -505.00 54357.10 13.87 1.40 3.90 40.26 11.92 -0.96 0.00 0.00 0.99 2.18 0.90 -1.00 0.00 0.00 -11.23 110.70 -506.00 54420.70 11.64 1.50 2.40 31.71 11.57 1.78 0.00 0.00 1.25 2.61 1.30 -1.00 0.00 0.00 -7.45 123.10 -507.00 54449.10 6.30 1.50 0.40 6.53 9.56 -0.16 0.00 0.00 1.36 0.62 0.30 -1.00 0.00 0.00 -3.71 74.70 -508.00 54481.20 13.67 1.10 1.50 21.03 8.69 -0.58 0.00 0.00 0.69 1.41 0.70 -1.00 0.00 0.00 -15.95 106.80 -509.00 54512.40 12.81 0.70 1.80 18.95 8.67 0.89 0.00 0.00 0.47 1.57 0.50 -1.00 0.00 0.00 -21.66 10.00 -510.00 54790.80 8.83 0.80 5.00 31.49 8.33 0.02 0.00 0.00 0.46 1.18 0.30 -1.00 0.00 0.00 -15.19 32.40 -511.00 54793.50 8.49 3.60 2.40 34.44 8.81 0.17 255.00 0.00 3.18 2.51 0.80 -1.00 0.00 0.00 -2.13 9.50 -512.00 54826.70 18.54 1.00 3.20 45.64 10.53 -0.67 0.00 0.00 0.74 2.04 0.70 -1.00 0.00 0.00 -20.05 68.30 -513.00 55055.40 15.31 1.80 2.70 37.18 9.63 0.52 0.00 0.00 0.57 2.63 0.60 -1.00 0.00 0.00 -21.65 41.00 -514.00 55111.80 19.36 1.50 2.40 39.74 11.79 0.57 0.00 0.00 1.00 2.11 0.60 -1.00 0.00 0.00 -15.47 97.40 -515.00 55172.50 13.97 0.70 3.30 33.41 9.41 0.22 0.00 0.00 0.53 2.48 0.40 -1.00 0.00 0.00 -20.91 4.50 -516.00 55191.80 8.19 1.90 0.60 8.37 9.77 -0.60 0.00 0.00 0.89 1.18 0.80 -1.00 0.00 0.00 -7.40 49.40 -517.00 55214.90 18.52 0.90 6.60 77.33 9.48 -1.72 0.00 0.00 0.38 2.35 0.50 -1.00 0.00 0.00 -38.79 72.50 -518.00 55288.20 6.49 2.70 2.10 13.62 10.57 -0.51 0.00 0.00 0.70 1.10 0.70 -1.00 0.00 0.00 -7.39 94.60 -519.00 55327.90 9.05 2.10 2.30 20.29 11.18 0.94 0.00 0.00 1.89 1.42 0.50 -1.00 0.00 0.00 -3.83 57.50 -520.00 55472.10 21.12 1.10 7.20 93.36 11.51 -0.39 0.00 0.00 0.48 3.26 0.70 -1.00 0.00 0.00 -35.53 73.70 -521.00 55496.40 14.04 2.50 2.00 43.05 8.68 0.80 0.00 0.00 2.17 3.80 2.10 -1.00 0.00 0.00 -5.17 98.00 -522.00 55551.20 6.14 1.70 0.40 6.26 9.14 0.59 0.00 0.00 1.47 0.65 0.50 -1.00 0.00 0.00 -3.34 101.60 -523.00 55560.90 15.12 0.60 3.90 41.05 9.27 -0.32 0.00 0.00 0.41 2.38 0.40 -1.00 0.00 0.00 -29.45 34.50 -524.00 55879.50 7.79 4.10 1.20 17.66 11.27 0.23 0.00 0.00 2.23 1.52 0.80 -1.00 0.00 0.00 -2.79 97.10 -525.00 56347.70 17.21 0.80 3.30 37.16 11.05 -0.76 0.00 0.00 0.47 1.70 0.50 -1.00 0.00 0.00 -29.14 53.30 -526.00 56411.60 10.47 1.90 2.70 27.02 10.57 0.43 0.00 0.00 0.51 2.41 0.40 -1.00 0.00 0.00 -16.45 117.20 -527.00 56634.50 11.38 1.00 5.70 43.80 11.18 -1.48 0.00 0.00 0.82 2.37 0.70 -1.00 0.00 0.00 -11.17 84.10 -528.00 56829.30 7.25 0.90 1.00 7.73 11.99 -0.11 0.00 0.00 0.74 1.04 0.50 -1.00 0.00 0.00 -7.86 22.90 -529.00 56879.10 6.87 1.70 0.80 9.79 12.06 -1.04 0.00 0.00 1.47 1.39 1.20 -1.00 0.00 0.00 -3.74 72.70 -530.00 57013.30 17.74 0.80 2.30 33.77 12.22 0.07 0.00 0.00 0.46 1.78 0.50 -1.00 0.00 0.00 -31.12 27.70 -531.00 57025.30 7.34 0.60 5.20 25.18 10.33 1.66 0.00 0.00 0.40 0.93 0.40 -1.00 0.00 0.00 -14.70 90.90 -532.00 57035.20 7.51 1.00 2.20 15.74 11.46 1.65 0.00 0.00 0.77 1.95 0.60 -1.00 0.00 0.00 -7.80 100.80 -533.00 57066.70 6.27 3.20 2.60 15.36 11.34 1.12 255.00 0.00 2.31 1.56 0.60 -1.00 0.00 0.00 -2.17 4.30 -534.00 57595.20 6.52 1.90 1.70 14.90 10.62 0.86 0.00 0.00 1.69 1.72 1.60 -1.00 0.00 0.00 -3.09 20.80 -535.00 57803.90 6.26 1.10 2.60 13.72 11.86 -2.14 0.00 0.00 0.96 2.24 0.50 -1.00 0.00 0.00 -5.22 75.90 -536.00 57925.90 8.10 1.50 2.60 17.79 12.73 -2.50 0.00 0.00 0.93 1.31 0.50 -1.00 0.00 0.00 -7.00 95.50 -537.00 57948.80 6.61 4.00 0.40 11.07 12.80 0.85 0.00 0.00 1.40 0.96 0.70 -1.00 0.00 0.00 -3.78 92.80 -538.00 57976.50 16.55 0.90 2.20 35.82 10.95 0.75 0.00 0.00 0.55 2.17 0.60 -1.00 0.00 0.00 -23.94 18.10 -539.00 58130.20 13.07 1.20 3.10 33.05 12.20 -0.41 0.00 0.00 0.59 2.03 1.00 -1.00 0.00 0.00 -17.66 43.80 -540.00 58135.70 6.08 0.60 0.80 4.49 11.54 -1.17 0.00 0.00 0.39 0.45 0.30 -1.00 0.00 0.00 -12.56 126.10 -541.00 58156.60 7.72 1.10 1.60 12.39 9.98 -0.74 0.00 0.00 0.90 1.53 0.80 -1.00 0.00 0.00 -6.89 70.20 -542.00 58159.20 10.00 3.70 2.00 29.33 9.51 0.93 255.00 0.00 0.77 1.99 0.40 -1.00 0.00 0.00 -10.41 47.20 -543.00 58249.00 6.15 0.90 3.00 13.68 11.79 0.75 0.00 0.00 0.34 1.04 0.20 -1.00 0.00 0.00 -14.46 34.60 -544.00 58549.40 6.28 1.50 1.30 11.23 11.87 -1.16 0.00 0.00 1.04 1.90 0.80 -1.00 0.00 0.00 -4.84 53.40 -545.00 58583.20 19.47 1.30 7.30 92.18 12.55 -0.78 0.00 0.00 0.50 2.72 0.60 -1.00 0.00 0.00 -30.85 112.80 -546.00 58733.10 16.48 1.50 2.50 38.30 11.55 -0.57 0.00 0.00 0.40 2.60 0.70 -1.00 0.00 0.00 -32.85 6.70 -547.00 58800.00 19.79 1.10 2.20 40.80 11.00 0.04 0.00 0.00 0.88 1.78 1.00 -1.00 0.00 0.00 -18.00 73.60 -548.00 58825.30 8.73 1.20 0.60 9.16 11.40 0.28 0.00 0.00 1.04 1.17 0.80 -1.00 0.00 0.00 -6.70 98.90 -549.00 58847.30 7.14 1.00 1.50 9.77 8.75 -1.19 0.00 0.00 0.70 1.08 0.70 -1.00 0.00 0.00 -8.22 95.30 -550.00 58989.10 20.85 0.60 3.00 43.33 11.47 -0.06 0.00 0.00 0.36 2.18 0.40 -1.00 0.00 0.00 -46.09 6.70 -551.00 59064.50 8.46 1.60 3.30 17.87 11.86 -0.75 0.00 0.00 0.75 1.02 0.40 -1.00 0.00 0.00 -9.04 82.10 -552.00 59162.40 8.76 1.30 1.50 15.51 11.88 0.47 0.00 0.00 1.10 1.89 1.00 -1.00 0.00 0.00 -6.35 26.40 -553.00 59276.30 15.78 0.80 2.80 34.36 11.99 0.95 0.00 0.00 0.35 1.92 0.40 -1.00 0.00 0.00 -36.13 37.90 -554.00 59294.10 11.34 0.60 2.00 18.36 9.56 0.44 0.00 0.00 0.33 1.88 0.30 -1.00 0.00 0.00 -27.47 55.70 -555.00 59299.90 7.31 0.50 0.80 5.78 0.35 -0.07 255.00 0.00 0.29 0.84 0.30 -1.00 0.00 0.00 -20.22 35.90 -556.00 59360.90 6.70 2.70 2.20 16.18 9.62 -1.33 0.00 0.00 2.12 1.02 0.20 -1.00 0.00 0.00 -2.52 122.50 -557.00 59625.60 6.17 0.80 0.80 5.66 11.50 1.43 0.00 0.00 0.65 1.01 0.40 -1.00 0.00 0.00 -7.55 3.20 -558.00 59785.80 6.09 0.50 1.20 4.53 12.93 -0.35 0.00 0.00 0.40 0.39 0.20 -1.00 0.00 0.00 -12.22 35.40 -559.00 59809.40 10.42 2.20 1.80 27.53 13.72 -0.24 0.00 0.00 2.00 2.79 1.50 -1.00 0.00 0.00 -4.16 59.00 -560.00 59893.80 29.29 0.80 2.60 64.01 12.12 0.72 0.00 0.00 0.41 2.33 0.60 -1.00 0.00 0.00 -57.18 15.40 -561.00 60064.70 9.09 0.70 2.70 18.01 12.22 -0.40 0.00 0.00 0.48 1.69 0.50 -1.00 0.00 0.00 -15.03 58.30 -562.00 60101.30 8.33 1.80 1.00 14.76 12.77 1.59 0.00 0.00 1.64 1.87 1.00 -1.00 0.00 0.00 -4.05 69.30 -563.00 60105.60 6.15 0.90 1.40 7.66 12.80 0.20 0.00 0.00 0.66 0.99 0.30 -1.00 0.00 0.00 -7.42 73.60 -564.00 60445.80 7.15 2.00 1.40 11.20 13.14 -1.61 0.00 0.00 1.41 0.93 0.70 -1.00 0.00 0.00 -4.06 55.40 -565.00 60726.90 8.78 1.20 3.40 26.03 11.89 0.08 0.00 0.00 0.95 2.71 0.90 -1.00 0.00 0.00 -7.42 80.50 -566.00 60748.40 12.86 1.00 2.30 25.90 11.55 -0.46 0.00 0.00 0.74 1.74 0.70 -1.00 0.00 0.00 -13.96 102.00 -567.00 60813.90 6.58 1.90 0.90 8.72 11.82 -0.37 0.00 0.00 1.12 1.06 0.80 -1.00 0.00 0.00 -4.70 13.90 -568.00 60890.80 6.46 1.30 3.50 18.73 13.61 1.28 0.00 0.00 1.10 2.36 0.60 -1.00 0.00 0.00 -4.70 90.80 -569.00 60924.90 23.72 0.80 3.40 68.74 12.69 0.35 0.00 0.00 0.58 3.44 0.50 -1.00 0.00 0.00 -32.69 124.90 -570.00 60976.50 8.08 3.90 1.00 18.91 10.91 0.93 0.00 0.00 3.31 1.66 1.00 -1.00 0.00 0.00 -1.95 48.50 -571.00 61089.50 7.25 1.80 1.10 12.71 11.85 0.06 0.00 0.00 1.68 1.49 0.60 -1.00 0.00 0.00 -3.45 33.50 -572.00 61790.70 7.72 1.40 1.40 13.06 12.26 -0.33 0.00 0.00 1.20 1.63 0.90 -1.00 0.00 0.00 -5.15 94.70 -573.00 62059.20 9.40 4.20 2.70 30.88 12.64 0.31 0.00 0.00 2.96 1.90 0.70 -1.00 0.00 0.00 -2.54 107.20 diff --git a/data/shared/matlab_gold_20260302/mEPSCs/mEPSCAnalysis.asv b/data/shared/matlab_gold_20260302/mEPSCs/mEPSCAnalysis.asv deleted file mode 100644 index 32ac282e..00000000 --- a/data/shared/matlab_gold_20260302/mEPSCs/mEPSCAnalysis.asv +++ /dev/null @@ -1,128 +0,0 @@ -%% miniature excitatory post-synaptic currents (mEPSCs) -% Data from Marnie Phillips - -%Iahn Cajigas 03/01/2011 -%% Data Description -% epsc2.txt: -% Event times of selected, constant rate, miniature excitatory -% post-synaptic currents (mEPSCs) in 0mM magnesium condition] -% -% epsc2_TRS_autocorr.fig -% Matlab plots of the time-rescaled values compared to exponential model, -% and autocorrelation using time-rescaled values. -% Event selection criteria were: amplitude > 6.06pA, 10-90% rise -% time < 20ms, Groups: 0 and 255] -% -% washout1.txt -% Variable rate recording: Event times of selected events, beginning -% approximately 260 seconds after magnesium is first removed. -% -% washout2.txt -% Event times of selected events from the same recording, beginning -% 745 seconds after magnesium is first removed -% -% Figure-3.jpg -% The figure from our paper showing that magnesium removal increases -% the rate, but not amplitude, of synaptic miniature EPSCs. -% -% Column headers in the text files explain what each column represents, -% let me know if you have any questions or need more data, -% -% * Event selection criteria for the "washout1" and "washout2" condition were: -% -% Amplitude > 10pA -% 10-90% rise time < 20ms -% -% Iahn, you should know that for this washout experiment, the recording -% duration was so long, and there were so many events, that the minimum -% amplitude threshold was conservative. -% -% The mean RMS noise was only 1.36pA, and a usual threshold would be -% 5*RMS = 6.8pA. Also, not all concurrent events were counted (ie, events -% which interrupt other events by occurring in the decay phase of a -% preceding event). - - -%% Constant Magnesium Concentration - Constant rate poisson - epsc2 = importdata('epsc2.txt'); - sampleRate = 1000; - spikeTimes = epsc2.data(:,1)*1/sampleRate; %in seconds - nst = nspikeTrain(spikeTimes); - time = 0:(1/sampleRate):nst.maxTime; - - % Define Covariates for the analysis - baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',{'mu'}); - covarColl = CovColl({baseline}); - - % Create the trial structure - spikeColl = nstColl(nst); - trial = Trial(spikeColl,covarColl); - - - % Define how we want to analyze the data - tc{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline'); - tcc = ConfigColl(tc); - - % Perform Analysis (Commented to since data already saved) - results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); - results.plotResults; - - - %% Varying Magnesium Concentration - Piecewise Constant rate poisson - clear all; - - washout1 = importdata('washout1.txt'); - washout2 = importdata('washout2.txt'); - - sampleRate = 1000; - % Magnesium removed at t=0 - spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds - spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds - nst = nspikeTrain([spikeTimes1; spikeTimes2]); - time = 260:(1/sampleRate):nst.maxTime; - - nst.plot; - %% - % Visual inspection of the spike train is used to pick three regions - % where the firing rate appears to be different. Here we do not - % estimate where these transitions happen but pick times in an ad-hoc - % manner. - - % Define Covariates for the analysis - - timeInd1 =find(time<495,1,'last'); - timeInd2 =find(time<765,1,'last'); - constantRate = ones(length(time),1); - rate1 = zeros(length(time),1); rate1(1:timeInd1)=1; - rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1; - rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1; - baseline = Covariate(time,[constantRate,rate1, rate2, rate3],'Baseline','time','s','',{'\mu','\mu_{1}','\mu_{2}','\mu_{3}'}); - covarColl = CovColl({baseline}); - - % Create the trial structure - spikeColl = nstColl(nst); - trial = Trial(spikeColl,covarColl); - - %30ms history in logarithmic spacing (chosen after using - %Analysis.computeHistLagForAll for various window lengths - maxWindow=.3; numWindows=20; - windowTimes =unique(round([0 logspace(log10(delta),... - log10(maxWindow),numWindows)]*sampleRate)./sampleRate); - windowTimes = windowTimes(1:11); - % Define how we want to analyze the data - tc{1} = TrialConfig({{'Baseline','\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline'); - tc{2} = TrialConfig({{'Baseline','\mu_{1}','\mu_{2}','\mu_{3}'}},sampleRate,[]); tc{2}.setName('Diff Baseline'); - tc{3} = TrialConfig({{'Baseline','\mu_{1}','\mu_{2}','\mu_{3}'}},sampleRate,windowTimes); tc{3}.setName('Diff Baseline+Hist'); - - tcc = ConfigColl(tc); - - % Perform Analysis (Commented to since data already saved) - results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); - results.plotResults; - Summary = FitResSummary(results); - - %% - - - - \ No newline at end of file diff --git a/data/shared/matlab_source_20260302.manifest.json b/data/shared/matlab_source_20260302.manifest.json deleted file mode 100644 index 08e3c13b..00000000 --- a/data/shared/matlab_source_20260302.manifest.json +++ /dev/null @@ -1,264 +0,0 @@ -{ - "schema_version": 1, - "dataset_name": "matlab_example_data", - "dataset_version": "20260302", - "generated_at_utc": "2026-03-02T19:27:09.812399+00:00", - "generated_by": "tools/data_mirror/build_manifest.py", - "source_root": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/data", - "file_count": 42, - "total_size_bytes": 504513862, - "files": [ - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat", - "size_bytes": 27547, - "mtime_epoch_s": 1499022214.0, - "sha256": "cbf9dfa3b39b1bf4b712eb2bde37320b9d58d451504c5620519cd6cacec90431" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat", - "size_bytes": 14290, - "mtime_epoch_s": 1499022214.0, - "sha256": "effc8975d3b8ea8f423a5e5476bb5becd7cbee9fcddf0c2cb5bf1f06dadf9a31" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat", - "size_bytes": 41710, - "mtime_epoch_s": 1499022214.0, - "sha256": "e00711145e693815e6d7f92968fab06c0833680c32a6eca13190d9a00e91fae1" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat", - "size_bytes": 21532, - "mtime_epoch_s": 1499022214.0, - "sha256": "ef9d41d34ca7ab49fe34022dda24220b41f6814d6220d4b7f111d39ccaf0159f" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat", - "size_bytes": 77726, - "mtime_epoch_s": 1499022214.0, - "sha256": "f45bb73ba9fc1129e1134e3c28d238ed0df72d3b2ff94f62d26b231358f0a957" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat", - "size_bytes": 40262, - "mtime_epoch_s": 1499022214.0, - "sha256": "c9161723ded0cb9ef4044e518d4bc6605666a4d3a92343d418964179c71516b5" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat", - "size_bytes": 25419, - "mtime_epoch_s": 1499022214.0, - "sha256": "c579c52b0d6f979177992ef0c382a55b867de02ec8b17275b695a10c04779c67" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat", - "size_bytes": 13203, - "mtime_epoch_s": 1499022214.0, - "sha256": "0e3557598c0ac2777d8d0c9af7d6f92d019d905b73742fe1a472549594f17325" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat", - "size_bytes": 39588, - "mtime_epoch_s": 1499022214.0, - "sha256": "9faf006a195ac193015aead58f3e541e4840ff4e7bb376f4e27fcab664049210" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat", - "size_bytes": 20564, - "mtime_epoch_s": 1499022214.0, - "sha256": "b0db8069ed3c4c800e0c5b3fe1aa6406415035ddba4f486d1548383b1e2e1093" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat", - "size_bytes": 75178, - "mtime_epoch_s": 1499022214.0, - "sha256": "24b79facf077f68c5b16b9778a2cce8c2df61d3c9124064826aa7696c9472c17" - }, - { - "relative_path": "Explicit Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat", - "size_bytes": 39038, - "mtime_epoch_s": 1499022214.0, - "sha256": "824e3cde647b97e6c7c6f1649d56d52f79f17e6274610fafce817cc844770e5d" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat", - "size_bytes": 25075, - "mtime_epoch_s": 1499022214.0, - "sha256": "c848a13bef8f4e5a47dd027c0abf0f3904911cf699c698dfd5621ac7b602b324" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat", - "size_bytes": 13115, - "mtime_epoch_s": 1499022214.0, - "sha256": "ad2e4a639155382b7462c0dc0f43663f6b94ca69b5cfe618d439926bceecec9a" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps", - "size_bytes": 167205, - "mtime_epoch_s": 1499022214.0, - "sha256": "839dd534e216d5d31b266b7efd18b96f934cac86cef4d65da93d8c58551ed772" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps", - "size_bytes": 67314, - "mtime_epoch_s": 1499022214.0, - "sha256": "d972186f79323f89d021d17a50f746fbbcd431d196d4685fb26d0998aea2d893" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat", - "size_bytes": 38760, - "mtime_epoch_s": 1499022214.0, - "sha256": "440ec83724ae2a9a707eb1db33b9ebc3d9260cef15c9fb4b280a352a70432321" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat", - "size_bytes": 20190, - "mtime_epoch_s": 1499022214.0, - "sha256": "f4b4299a1e977db37bab8a11d107b6d2a73541d3e5bb017ab68b1d9885def3f2" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat", - "size_bytes": 75629, - "mtime_epoch_s": 1499022214.0, - "sha256": "998568271174ffbb79abd850846d3a38b193221689aa8c2a7f6f1b247721851f" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat", - "size_bytes": 39102, - "mtime_epoch_s": 1499022214.0, - "sha256": "3561b3c90931f1a06d757624717ace69686767630918e18cac0b118ef5b9d370" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat", - "size_bytes": 25255, - "mtime_epoch_s": 1499022214.0, - "sha256": "48d34a2478f310d0becb92e03fc47c56598529d6bae67f4f8c097ffb5d1328a1" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat", - "size_bytes": 13217, - "mtime_epoch_s": 1499022214.0, - "sha256": "ae2c905af5c95881fbef989cbd175404b287723186ffacdbdaa7a13488202e23" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat", - "size_bytes": 39257, - "mtime_epoch_s": 1499022214.0, - "sha256": "9047cf6ea92d4d0dcf1215c4b41addf312d156dd22777958343607db1c440161" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat", - "size_bytes": 20186, - "mtime_epoch_s": 1499022214.0, - "sha256": "6f26dd402d2893b8ae06dcb8514ef82a9ece6373ae6da974bde99895bc57f1d3" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat", - "size_bytes": 75026, - "mtime_epoch_s": 1499022214.0, - "sha256": "b243c1091d2d97efd291871cae2b4793bf2bb381fe6741748ccb95b9e32b6da7" - }, - { - "relative_path": "Explicit Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat", - "size_bytes": 38830, - "mtime_epoch_s": 1499022214.0, - "sha256": "ae1a19ba2ad50b69bad1ff8a9927cbf6e18f541a8ad332c4d51334e576abc8b7" - }, - { - "relative_path": "Explicit Stimulus/GenCovMat.m", - "size_bytes": 1706, - "mtime_epoch_s": 1499022214.0, - "sha256": "79a87fc52fe5637b351bc8565f576989d9ef1a23b44522621b1a33facfcf89b4" - }, - { - "relative_path": "PSTH/Data Description.pdf", - "size_bytes": 78971, - "mtime_epoch_s": 1499022216.0, - "sha256": "79574d56122d0aab30aad7cf13120916f278b28b7f84052689e8c58da4818140" - }, - { - "relative_path": "PSTH/Results.mat", - "size_bytes": 23426906, - "mtime_epoch_s": 1499022216.0, - "sha256": "685438f83a6df49cb9b5d260749107d401c14f1d1bc5cbabf6f00f16ebddb4fb" - }, - { - "relative_path": "Place Cells/PlaceCellDataAnimal1.mat", - "size_bytes": 2722517, - "mtime_epoch_s": 1499022214.0, - "sha256": "8806ab38c62a04ee1bec9cabab907a8f9fa3d66e0799fa09de8acd01789fc77b" - }, - { - "relative_path": "Place Cells/PlaceCellDataAnimal2.mat", - "size_bytes": 2045164, - "mtime_epoch_s": 1499022214.0, - "sha256": "e8f22ab469ae30427cac8401dbeacfc2a7a5d4ba1a62fd339a8834ab489e750f" - }, - { - "relative_path": "Place Cells/Readme.txt", - "size_bytes": 148, - "mtime_epoch_s": 1499022214.0, - "sha256": "53c6d51d6b2a64b622da3a60e9f5d9ad8c9b7362480635c9a6460a30c29044de" - }, - { - "relative_path": "Place Cells/license.txt", - "size_bytes": 1551, - "mtime_epoch_s": 1499022214.0, - "sha256": "4587991e9404c291513292886f98dd432cbb772a9f873da1d406a799646fe377" - }, - { - "relative_path": "PlaceCellAnimal1Results.mat", - "size_bytes": 266683050, - "mtime_epoch_s": 1499022214.0, - "sha256": "15b53a0da12338551d7edfce03666195c7f95b355e2b1f483f0ba0850f8915d5" - }, - { - "relative_path": "PlaceCellAnimal2Results.mat", - "size_bytes": 190070438, - "mtime_epoch_s": 1499022216.0, - "sha256": "fef2a2a0ad54012d5e1ecab96dde72a8c7ce0116afa0df038c0aed9437021f77" - }, - { - "relative_path": "SSGLMExampleData.mat", - "size_bytes": 13832869, - "mtime_epoch_s": 1499022216.0, - "sha256": "fc1d4730267b49e3af534f6572b28ce1ba746708a49a1e4f1e8fb082cdabc360" - }, - { - "relative_path": "glm_data.mat", - "size_bytes": 2420384, - "mtime_epoch_s": 1499022214.0, - "sha256": "4152d93a660acf62b46b77f2dee3f14d2147dd100748c16fa3922f6c2f8ad577" - }, - { - "relative_path": "glm_data_orig.mat", - "size_bytes": 1870988, - "mtime_epoch_s": 1499022214.0, - "sha256": "a11ab318f9c8042453c043ed79764b18ba727ceac31672e42b7ed30024ab2a4b" - }, - { - "relative_path": "mEPSCs/epsc2.txt", - "size_bytes": 59770, - "mtime_epoch_s": 1499022214.0, - "sha256": "65a130b7af4bc34eeaf943da76df6ebf9ba0ae9720eb98b6813f9f44a43ff435" - }, - { - "relative_path": "mEPSCs/mEPSCAnalysis.asv", - "size_bytes": 4992, - "mtime_epoch_s": 1499022214.0, - "sha256": "c3d99d7de863a501f2d57ffbe09ff2c94fdf6b7ea8c6292641337b9a80ee7249" - }, - { - "relative_path": "mEPSCs/washout1.txt", - "size_bytes": 72338, - "mtime_epoch_s": 1499022214.0, - "sha256": "4791531b54dd3f98c8cf756bd253d61d09113338b0dbe98ed09ef2df2d18e00e" - }, - { - "relative_path": "mEPSCs/washout2.txt", - "size_bytes": 127852, - "mtime_epoch_s": 1499022214.0, - "sha256": "ab35f26d4bccc48d2dc91e5007ba64d2527891666d2653e0a6118e397a4985fa" - } - ] -} diff --git a/docs/_static/.gitkeep b/docs/_static/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/api.md b/docs/api.md deleted file mode 100644 index 979b6748..00000000 --- a/docs/api.md +++ /dev/null @@ -1,22 +0,0 @@ -# API Reference - -```{eval-rst} -.. automodule:: nstat - :members: -``` - -## Core modules - -- `nstat.signal` -- `nstat.confidence` -- `nstat.events` -- `nstat.history` -- `nstat.spikes` -- `nstat.trial` -- `nstat.cif` -- `nstat.analysis` -- `nstat.fit` -- `nstat.decoding` -- `nstat.datasets` -- `nstat.install` -- `nstat.compat.matlab` diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 00000000..14736bf4 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,25 @@ +API Reference +============= + +Core modules: + +- ``nstat.signal`` +- ``nstat.spikes`` +- ``nstat.events`` +- ``nstat.history`` +- ``nstat.trial`` +- ``nstat.cif`` +- ``nstat.analysis`` +- ``nstat.fit`` +- ``nstat.decoding`` +- ``nstat.datasets`` + +Compatibility adapters: + +- ``nstat.SignalObj`` +- ``nstat.nspikeTrain`` +- ``nstat.FitResult`` +- ``nstat.FitResSummary`` +- ``nstat.ConfigColl`` +- ``nstat.CovColl`` +- ``nstat.TrialConfig`` diff --git a/docs/assets/reports/image_mode_parity_summary_latest.json b/docs/assets/reports/image_mode_parity_summary_latest.json deleted file mode 100644 index 10b8daa8..00000000 --- a/docs/assets/reports/image_mode_parity_summary_latest.json +++ /dev/null @@ -1,4268 +0,0 @@ -{ - "schema_version": 1, - "python_pdf": "/home/runner/work/nSTAT-python/nSTAT-python/output/pdf/image_mode_parity/python_pages.pdf", - "matlab_pdf": "/home/runner/work/nSTAT-python/nSTAT-python/output/pdf/image_mode_parity/matlab_pages.pdf", - "dpi": 150, - "thresholds": { - "ssim_threshold": 0.7, - "nrmse_threshold": 0.2, - "max_failing_pages": 0 - }, - "environment": { - "python": "3.11.14", - "platform": "Linux-6.14.0-1017-azure-x86_64-with-glibc2.39", - "numpy": "2.4.2", - "omp_num_threads": "1", - "mkl_num_threads": "1", - "openblas_num_threads": "1", - "fitz": "1.27.1:", - "scipy": "1.17.1", - "ssim_backend": "skimage" - }, - "page_counts": { - "python": 174, - "matlab": 174, - "compared": 174, - "mismatch": false - }, - "failed_page_count": 0, - "worst_pages": [ - { - "page": 64, - "metric": "ssim", - "score": 0.8556401192855638, - "passed": true, - "ignored": false - }, - { - "page": 63, - "metric": "ssim", - "score": 0.881080176469529, - "passed": true, - "ignored": false - }, - { - "page": 65, - "metric": "ssim", - "score": 0.9071385348298472, - "passed": true, - "ignored": false - }, - { - "page": 67, - "metric": "ssim", - "score": 0.9319396663489173, - "passed": true, - "ignored": false - }, - { - "page": 62, - "metric": "ssim", - "score": 0.9439399362040465, - "passed": true, - "ignored": false - }, - { - "page": 66, - "metric": "ssim", - "score": 0.9679693360454448, - "passed": true, - "ignored": false - }, - { - "page": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "ignored": false - }, - { - "page": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "ignored": false - }, - { - "page": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "ignored": false - }, - { - "page": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "ignored": false - } - ], - "pages": [ - { - "page": 1, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 2, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 3, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 4, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 5, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 6, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 7, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 8, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 9, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 10, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 11, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 12, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 13, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 14, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 15, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 16, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 17, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 18, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 19, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 20, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 21, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 22, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 23, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 24, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 25, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 26, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 27, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 28, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 29, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 30, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 31, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 32, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 33, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 34, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 35, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 36, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 37, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 38, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 39, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 40, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 41, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 42, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 43, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 44, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 45, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 46, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 47, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 48, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 49, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 50, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 51, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 52, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 53, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 54, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 55, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 56, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 57, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 58, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 59, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 60, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 61, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 62, - "ignored": false, - "metric": "ssim", - "score": 0.9439399362040465, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 63, - "ignored": false, - "metric": "ssim", - "score": 0.881080176469529, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 64, - "ignored": false, - "metric": "ssim", - "score": 0.8556401192855638, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 65, - "ignored": false, - "metric": "ssim", - "score": 0.9071385348298472, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 66, - "ignored": false, - "metric": "ssim", - "score": 0.9679693360454448, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 67, - "ignored": false, - "metric": "ssim", - "score": 0.9319396663489173, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 68, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 69, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 70, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 71, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 72, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 73, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 74, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 75, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 76, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 77, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 78, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 79, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 80, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 81, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 82, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 83, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 84, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 85, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 86, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 87, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 88, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 89, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 90, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 91, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 92, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 93, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 94, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 95, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 96, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 97, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 98, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 99, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 100, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 101, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 102, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 103, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 104, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 105, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 106, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 107, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 108, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 109, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 110, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 111, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 112, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 113, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 114, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 115, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 116, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 117, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 118, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 119, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 120, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 121, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 122, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 123, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 124, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 125, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 126, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 127, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 128, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 129, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 130, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 131, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 132, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 133, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 134, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 135, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 136, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 137, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 138, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 139, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 140, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 141, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 142, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 143, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 144, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 145, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 146, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 147, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 148, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 149, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 150, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 151, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 152, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 153, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 154, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 155, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 156, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 157, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 158, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 159, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 160, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 161, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 162, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 163, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 164, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 165, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 166, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 167, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 168, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 169, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 170, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 171, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 172, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 173, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - }, - { - "page": 174, - "ignored": false, - "metric": "ssim", - "score": 1.0, - "passed": true, - "python_shape": [ - 1650, - 1275 - ], - "matlab_shape": [ - 1650, - 1275 - ], - "diff_image": null - } - ], - "topics": { - "AnalysisExamples": { - "expected_figures": 5, - "produced_figures": 5, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "CovCollExamples": { - "expected_figures": 3, - "produced_figures": 3, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "CovariateExamples": { - "expected_figures": 3, - "produced_figures": 3, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "DecodingExample": { - "expected_figures": 7, - "produced_figures": 7, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 7, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "DecodingExampleWithHist": { - "expected_figures": 3, - "produced_figures": 3, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "EventsExamples": { - "expected_figures": 5, - "produced_figures": 5, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "ExplicitStimulusWhiskerData": { - "expected_figures": 10, - "produced_figures": 10, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 7, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 8, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 9, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 10, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "HippocampalPlaceCellExample": { - "expected_figures": 12, - "produced_figures": 12, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 7, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 8, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 9, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 10, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 11, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 12, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "HistoryExamples": { - "expected_figures": 5, - "produced_figures": 5, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "NetworkTutorial": { - "expected_figures": 8, - "produced_figures": 8, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 7, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 8, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "PPSimExample": { - "expected_figures": 6, - "produced_figures": 6, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 0.9439399362040465, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 0.881080176469529, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 0.8556401192855638, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 0.9071385348298472, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 0.9679693360454448, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 0.9319396663489173, - "passed": true, - "diff_image": null - } - ] - }, - "PPThinning": { - "expected_figures": 5, - "produced_figures": 5, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "PSTHEstimation": { - "expected_figures": 3, - "produced_figures": 3, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "SignalObjExamples": { - "expected_figures": 21, - "produced_figures": 21, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 7, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 8, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 9, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 10, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 11, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 12, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 13, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 14, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 15, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 16, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 17, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 18, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 19, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 20, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 21, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "StimulusDecode2D": { - "expected_figures": 7, - "produced_figures": 7, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 7, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "TrialExamples": { - "expected_figures": 7, - "produced_figures": 7, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 7, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "ValidationDataSet": { - "expected_figures": 13, - "produced_figures": 13, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 7, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 8, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 9, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 10, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 11, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 12, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 13, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "mEPSCAnalysis": { - "expected_figures": 6, - "produced_figures": 6, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "nSTATPaperExamples": { - "expected_figures": 26, - "produced_figures": 26, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 7, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 8, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 9, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 10, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 11, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 12, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 13, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 14, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 15, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 16, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 17, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 18, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 19, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 20, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 21, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 22, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 23, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 24, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 25, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 26, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "nSpikeTrainExamples": { - "expected_figures": 6, - "produced_figures": 6, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "nstCollExamples": { - "expected_figures": 4, - "produced_figures": 4, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "AnalysisExamples2": { - "expected_figures": 6, - "produced_figures": 6, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 4, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 5, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 6, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - }, - "HybridFilterExample": { - "expected_figures": 3, - "produced_figures": 3, - "failing_figures": [], - "figure_scores": [ - { - "ordinal": 1, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 2, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - }, - { - "ordinal": 3, - "metric": "ssim", - "score": 1.0, - "passed": true, - "diff_image": null - } - ] - } - } -} diff --git a/docs/assets/reports/nstat_python_validation_report_full_latest.pdf b/docs/assets/reports/nstat_python_validation_report_full_latest.pdf deleted file mode 100644 index a22e9133..00000000 Binary files a/docs/assets/reports/nstat_python_validation_report_full_latest.pdf and /dev/null differ diff --git a/docs/assets/reports/validation_gate_mode_latest.csv b/docs/assets/reports/validation_gate_mode_latest.csv deleted file mode 100644 index 9acde6b4..00000000 --- a/docs/assets/reports/validation_gate_mode_latest.csv +++ /dev/null @@ -1,31 +0,0 @@ -topic,class_hint,notebook,run_group,executed,execution_pass,duration_s,parity_pass,alignment_status,numeric_drift_pass,numeric_drift_failed_metric_count,similarity_score,expected_figures,produced_figures,figure_count_match,image_count,unique_image_count,duplicate_image_count,matched_python_image,matched_matlab_image,diff_artifacts,error -AnalysisExamples,Analysis,notebooks/helpfiles/AnalysisExamples.ipynb,smoke,True,True,3.0821980480000093,True,validated,True,,,,,,5,5,0,,,, -ConfigCollExamples,ConfigCollection,notebooks/helpfiles/ConfigCollExamples.ipynb,full,True,True,2.201825616000008,True,validated,True,,,,,,0,0,0,,,, -CovCollExamples,CovariateCollection,notebooks/helpfiles/CovCollExamples.ipynb,full,True,True,2.3624851680000063,True,validated,True,,,,,,3,3,0,,,, -CovariateExamples,Covariate,notebooks/helpfiles/CovariateExamples.ipynb,smoke,True,True,2.4871463609999864,True,validated,True,,,,,,3,3,0,,,, -DecodingExample,DecodingAlgorithms,notebooks/helpfiles/DecodingExample.ipynb,smoke,True,True,2.967853312000017,True,validated,True,,,,,,7,6,1,,,, -DecodingExampleWithHist,DecodingAlgorithms,notebooks/helpfiles/DecodingExampleWithHist.ipynb,smoke,True,True,3.4290413390000083,True,validated,True,,,,,,3,3,0,,,, -EventsExamples,Events,notebooks/helpfiles/EventsExamples.ipynb,full,True,True,2.247922650999982,True,validated,True,,,,,,5,2,3,,,, -ExplicitStimulusWhiskerData,Workflow,notebooks/helpfiles/ExplicitStimulusWhiskerData.ipynb,full,True,True,2.645337226999999,True,validated,True,,,,,,10,10,0,,,, -FitResSummaryExamples,FitSummary,notebooks/helpfiles/FitResSummaryExamples.ipynb,full,True,True,2.234180730999981,True,matlab_doc_only,True,,,,,,0,0,0,,,, -FitResultExamples,FitResult,notebooks/helpfiles/FitResultExamples.ipynb,full,True,True,2.2499652429999912,True,matlab_doc_only,True,,,,,,0,0,0,,,, -HippocampalPlaceCellExample,Workflow,notebooks/helpfiles/HippocampalPlaceCellExample.ipynb,full,True,True,3.4273853310000106,True,validated,True,,,,,,12,10,2,,,, -HistoryExamples,HistoryBasis,notebooks/helpfiles/HistoryExamples.ipynb,full,True,True,2.4204823240000053,True,validated,True,,,,,,5,5,0,,,, -NetworkTutorial,Workflow,notebooks/helpfiles/NetworkTutorial.ipynb,full,True,True,2.7460317529999827,True,validated,True,,,,,,8,7,1,,,, -PPSimExample,Workflow,notebooks/helpfiles/PPSimExample.ipynb,smoke,True,True,2.55882717099999,True,validated,True,,,,,,6,6,0,,,, -PPThinning,Workflow,notebooks/helpfiles/PPThinning.ipynb,full,True,True,2.384122337000008,True,validated,True,,,,,,5,4,1,,,, -PSTHEstimation,Workflow,notebooks/helpfiles/PSTHEstimation.ipynb,full,True,True,2.4936691260000146,True,validated,True,,,,,,3,3,0,,,, -SignalObjExamples,Signal,notebooks/helpfiles/SignalObjExamples.ipynb,smoke,True,True,2.756258195999976,True,validated,True,,,,,,21,18,3,,,, -StimulusDecode2D,DecodingAlgorithms,notebooks/helpfiles/StimulusDecode2D.ipynb,full,True,True,2.4795702549999987,True,validated,True,,,,,,7,6,1,,,, -TrialConfigExamples,TrialConfig,notebooks/helpfiles/TrialConfigExamples.ipynb,full,True,True,2.1496448729999997,True,validated,True,,,,,,0,0,0,,,, -TrialExamples,Trial,notebooks/helpfiles/TrialExamples.ipynb,smoke,True,True,2.7361148710000123,True,validated,True,,,,,,7,7,0,,,, -ValidationDataSet,Workflow,notebooks/helpfiles/ValidationDataSet.ipynb,full,True,True,2.7128817349999963,True,validated,True,,,,,,13,11,2,,,, -mEPSCAnalysis,Workflow,notebooks/helpfiles/mEPSCAnalysis.ipynb,full,True,True,2.565191610999989,True,validated,True,,,,,,6,5,1,,,, -nSTATPaperExamples,nSTATPaper,notebooks/helpfiles/nSTATPaperExamples.ipynb,smoke,True,True,6.260054120999996,True,validated,True,,,,,,26,26,0,,,, -nSpikeTrainExamples,SpikeTrain,notebooks/helpfiles/nSpikeTrainExamples.ipynb,smoke,True,True,2.3887158400000317,True,validated,True,,,,,,6,5,1,,,, -nstCollExamples,SpikeTrainCollection,notebooks/helpfiles/nstCollExamples.ipynb,full,True,True,2.343621245999998,True,validated,True,,,,,,4,4,0,,,, -AnalysisExamples2,Analysis,notebooks/helpfiles/AnalysisExamples2.ipynb,full,True,True,2.782037406000029,True,validated,True,,,,,,6,6,0,,,, -DocumentationSetup2025b,Workflow,notebooks/helpfiles/DocumentationSetup2025b.ipynb,full,True,True,2.2632713059999787,True,matlab_doc_only,True,,,,,,0,0,0,,,, -FitResultReference,FitResult,notebooks/helpfiles/FitResultReference.ipynb,full,True,True,2.3238267979999705,True,matlab_doc_only,True,,,,,,0,0,0,,,, -HybridFilterExample,Workflow,notebooks/helpfiles/HybridFilterExample.ipynb,full,True,True,3.1979228390000003,True,validated,True,,,,,,3,3,0,,,, -publish_all_helpfiles,Workflow,notebooks/helpfiles/publish_all_helpfiles.ipynb,full,True,True,2.4891688220000106,True,validated,True,,,,,,0,0,0,,,, diff --git a/docs/assets/reports/validation_gate_mode_latest.json b/docs/assets/reports/validation_gate_mode_latest.json deleted file mode 100644 index e35afae2..00000000 --- a/docs/assets/reports/validation_gate_mode_latest.json +++ /dev/null @@ -1,2807 +0,0 @@ -{ - "schema_version": 1, - "generated_at_utc": "2026-03-04T21:38:42Z", - "repo_root": "/home/runner/work/nSTAT-python/nSTAT-python", - "report_pdf": "/home/runner/work/nSTAT-python/nSTAT-python/output/pdf/nstat_python_validation_report_20260304_213716.pdf", - "matlab_help_root": "/tmp/upstream-nstat/helpfiles", - "notebook_group": "all", - "parity_mode": "gate", - "parity_threshold": 0.8, - "aggregate": { - "total_notebooks": 30, - "executed": 30, - "execution_failures": 0, - "parity_checked": 30, - "parity_failures": 0, - "numeric_drift_checked": 30, - "numeric_drift_failures": 0, - "command_checks_total": 0, - "command_checks_failed": 0, - "uniqueness_violations": 0, - "uniqueness": { - "total_image_instances": 174, - "total_unique_hashes": 155, - "cross_topic_reused_hashes": 3, - "repeated_instances": 19, - "cross_topic_reuse_ratio": 0.01935483870967742 - } - }, - "command_checks": [], - "notebooks": [ - { - "topic": "AnalysisExamples", - "class_hint": "Analysis", - "notebook": "notebooks/helpfiles/AnalysisExamples.ipynb", - "run_group": "smoke", - "executed": true, - "duration_s": 3.0821980480000093, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 5, - "produced_figures": 5, - "figure_count_match": true, - "figure_scores": [], - "image_count": 5, - "unique_image_count": 5, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/AnalysisExamples/fig_001.png", - "output/notebook_images/AnalysisExamples/fig_002.png", - "output/notebook_images/AnalysisExamples/fig_003.png", - "output/notebook_images/AnalysisExamples/fig_004.png", - "output/notebook_images/AnalysisExamples/fig_005.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/AnalysisExamples.png", - "/tmp/upstream-nstat/helpfiles/AnalysisExamples_01.png", - "/tmp/upstream-nstat/helpfiles/AnalysisExamples_02.png", - "/tmp/upstream-nstat/helpfiles/AnalysisExamples_03.png", - "/tmp/upstream-nstat/helpfiles/AnalysisExamples_04.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 59, - "python_code_lines": 179, - "python_to_matlab_line_ratio": 3.0338983050847457, - "matlab_reference_image_count": 5, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 4, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 4.076575980909476e-06, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 4, - "numeric_drift_metric_rows": [ - { - "name": "rate_max_abs_error", - "value": 1.4268015933183165e-06, - "threshold": 0.35, - "pass": true, - "ratio_to_threshold": 4.076575980909476e-06 - }, - { - "name": "intercept_abs_error", - "value": 1.8674006518892838e-07, - "threshold": 0.35, - "pass": true, - "ratio_to_threshold": 5.335430433969383e-07 - }, - { - "name": "rmse_abs_error", - "value": 4.0125002875868176e-08, - "threshold": 0.25, - "pass": true, - "ratio_to_threshold": 1.605000115034727e-07 - }, - { - "name": "coeff_max_abs_error", - "value": 7.80078663947456e-09, - "threshold": 0.35, - "pass": true, - "ratio_to_threshold": 2.2287961827070176e-08 - } - ] - } - }, - { - "topic": "ConfigCollExamples", - "class_hint": "ConfigCollection", - "notebook": "notebooks/helpfiles/ConfigCollExamples.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.201825616000008, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 0, - "produced_figures": 0, - "figure_count_match": true, - "figure_scores": [], - "image_count": 0, - "unique_image_count": 0, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [], - "matlab_reference_images": [], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 3, - "python_code_lines": 79, - "python_to_matlab_line_ratio": 26.333333333333332, - "matlab_reference_image_count": 0, - "python_validation_image_count": 1, - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "CovCollExamples", - "class_hint": "CovariateCollection", - "notebook": "notebooks/helpfiles/CovCollExamples.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.3624851680000063, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 3, - "produced_figures": 3, - "figure_count_match": true, - "figure_scores": [], - "image_count": 3, - "unique_image_count": 3, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/CovCollExamples/fig_001.png", - "output/notebook_images/CovCollExamples/fig_002.png", - "output/notebook_images/CovCollExamples/fig_003.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/CovCollExamples.png", - "/tmp/upstream-nstat/helpfiles/CovCollExamples_01.png", - "/tmp/upstream-nstat/helpfiles/CovCollExamples_02.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 10, - "python_code_lines": 118, - "python_to_matlab_line_ratio": 11.8, - "matlab_reference_image_count": 3, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "ctx_max_abs_error", - "value": 0.0, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "design_max_abs_error", - "value": 0.0, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "stim_max_abs_error", - "value": 0.0, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "CovariateExamples", - "class_hint": "Covariate", - "notebook": "notebooks/helpfiles/CovariateExamples.ipynb", - "run_group": "smoke", - "executed": true, - "duration_s": 2.4871463609999864, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 3, - "produced_figures": 3, - "figure_count_match": true, - "figure_scores": [], - "image_count": 3, - "unique_image_count": 3, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/CovariateExamples/fig_001.png", - "output/notebook_images/CovariateExamples/fig_002.png", - "output/notebook_images/CovariateExamples/fig_003.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/CovariateExamples.png", - "/tmp/upstream-nstat/helpfiles/CovariateExamples_01.png", - "/tmp/upstream-nstat/helpfiles/CovariateExamples_02.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 19, - "python_code_lines": 83, - "python_to_matlab_line_ratio": 4.368421052631579, - "matlab_reference_image_count": 3, - "python_validation_image_count": 2, - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "DecodingExample", - "class_hint": "DecodingAlgorithms", - "notebook": "notebooks/helpfiles/DecodingExample.ipynb", - "run_group": "smoke", - "executed": true, - "duration_s": 2.967853312000017, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 7, - "produced_figures": 7, - "figure_count_match": true, - "figure_scores": [], - "image_count": 7, - "unique_image_count": 6, - "duplicate_image_count": 1, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/DecodingExample/fig_001.png", - "output/notebook_images/DecodingExample/fig_002.png", - "output/notebook_images/DecodingExample/fig_003.png", - "output/notebook_images/DecodingExample/fig_004.png", - "output/notebook_images/DecodingExample/fig_005.png", - "output/notebook_images/DecodingExample/fig_006.png", - "output/notebook_images/DecodingExample/fig_007.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/DecodingExample.png", - "/tmp/upstream-nstat/helpfiles/DecodingExample_01.png", - "/tmp/upstream-nstat/helpfiles/DecodingExample_02.png", - "/tmp/upstream-nstat/helpfiles/DecodingExample_03.png", - "/tmp/upstream-nstat/helpfiles/DecodingExample_04.png", - "/tmp/upstream-nstat/helpfiles/DecodingExample_05.png", - "/tmp/upstream-nstat/helpfiles/DecodingExample_06.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 57, - "python_code_lines": 191, - "python_to_matlab_line_ratio": 3.3508771929824563, - "matlab_reference_image_count": 7, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.022530207560711446, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "posterior_max_abs_error", - "value": 2.2530207560711446e-10, - "threshold": 1e-08, - "pass": true, - "ratio_to_threshold": 0.022530207560711446 - }, - { - "name": "decoded_mismatch_count", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "rmse_abs_error", - "value": 0.0, - "threshold": 1e-08, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "DecodingExampleWithHist", - "class_hint": "DecodingAlgorithms", - "notebook": "notebooks/helpfiles/DecodingExampleWithHist.ipynb", - "run_group": "smoke", - "executed": true, - "duration_s": 3.4290413390000083, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 3, - "produced_figures": 3, - "figure_count_match": true, - "figure_scores": [], - "image_count": 3, - "unique_image_count": 3, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/DecodingExampleWithHist/fig_001.png", - "output/notebook_images/DecodingExampleWithHist/fig_002.png", - "output/notebook_images/DecodingExampleWithHist/fig_003.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/DecodingExampleWithHist.png", - "/tmp/upstream-nstat/helpfiles/DecodingExampleWithHist_01.png", - "/tmp/upstream-nstat/helpfiles/DecodingExampleWithHist_02.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 55, - "python_code_lines": 143, - "python_to_matlab_line_ratio": 2.6, - "matlab_reference_image_count": 3, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 2, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.04167062250814979, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 2, - "numeric_drift_metric_rows": [ - { - "name": "posterior_max_abs_error", - "value": 4.167062250814979e-10, - "threshold": 1e-08, - "pass": true, - "ratio_to_threshold": 0.04167062250814979 - }, - { - "name": "decoded_mismatch_count", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "EventsExamples", - "class_hint": "Events", - "notebook": "notebooks/helpfiles/EventsExamples.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.247922650999982, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 5, - "produced_figures": 5, - "figure_count_match": true, - "figure_scores": [], - "image_count": 5, - "unique_image_count": 2, - "duplicate_image_count": 3, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/EventsExamples/fig_001.png", - "output/notebook_images/EventsExamples/fig_002.png", - "output/notebook_images/EventsExamples/fig_003.png", - "output/notebook_images/EventsExamples/fig_004.png", - "output/notebook_images/EventsExamples/fig_005.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/EventsExamples.png", - "/tmp/upstream-nstat/helpfiles/EventsExamples_01.png", - "/tmp/upstream-nstat/helpfiles/EventsExamples_02.png", - "/tmp/upstream-nstat/helpfiles/EventsExamples_03.png", - "/tmp/upstream-nstat/helpfiles/EventsExamples_04.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 8, - "python_code_lines": 67, - "python_to_matlab_line_ratio": 8.375, - "matlab_reference_image_count": 5, - "python_validation_image_count": 4, - "assertion_count": 2, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 1, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 1, - "numeric_drift_metric_rows": [ - { - "name": "subset_max_abs_error", - "value": 0.0, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "ExplicitStimulusWhiskerData", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/ExplicitStimulusWhiskerData.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.645337226999999, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 10, - "produced_figures": 10, - "figure_count_match": true, - "figure_scores": [], - "image_count": 10, - "unique_image_count": 10, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/ExplicitStimulusWhiskerData/fig_001.png", - "output/notebook_images/ExplicitStimulusWhiskerData/fig_002.png", - "output/notebook_images/ExplicitStimulusWhiskerData/fig_003.png", - "output/notebook_images/ExplicitStimulusWhiskerData/fig_004.png", - "output/notebook_images/ExplicitStimulusWhiskerData/fig_005.png", - "output/notebook_images/ExplicitStimulusWhiskerData/fig_006.png", - "output/notebook_images/ExplicitStimulusWhiskerData/fig_007.png", - "output/notebook_images/ExplicitStimulusWhiskerData/fig_008.png", - "output/notebook_images/ExplicitStimulusWhiskerData/fig_009.png", - "output/notebook_images/ExplicitStimulusWhiskerData/fig_010.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData.png", - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData_01.png", - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData_02.png", - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData_03.png", - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData_04.png", - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData_05.png", - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData_06.png", - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData_07.png", - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData_08.png", - "/tmp/upstream-nstat/helpfiles/ExplicitStimulusWhiskerData_09.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 115, - "python_code_lines": 248, - "python_to_matlab_line_ratio": 2.1565217391304348, - "matlab_reference_image_count": 10, - "python_validation_image_count": 1, - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 4, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 1.0307532605224878e-09, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 4, - "numeric_drift_metric_rows": [ - { - "name": "intercept_abs_error", - "value": 2.0615065210449757e-10, - "threshold": 0.2, - "pass": true, - "ratio_to_threshold": 1.0307532605224878e-09 - }, - { - "name": "coeff_abs_error", - "value": 1.4483514387819696e-10, - "threshold": 0.2, - "pass": true, - "ratio_to_threshold": 7.241757193909848e-10 - }, - { - "name": "prob_max_abs_error", - "value": 2.3744395338809454e-11, - "threshold": 0.1, - "pass": true, - "ratio_to_threshold": 2.3744395338809454e-10 - }, - { - "name": "rmse_abs_error", - "value": 8.271161533457416e-15, - "threshold": 0.1, - "pass": true, - "ratio_to_threshold": 8.271161533457416e-14 - } - ] - } - }, - { - "topic": "FitResSummaryExamples", - "class_hint": "FitSummary", - "notebook": "notebooks/helpfiles/FitResSummaryExamples.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.234180730999981, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "matlab_doc_only", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 0, - "produced_figures": 0, - "figure_count_match": true, - "figure_scores": [], - "image_count": 0, - "unique_image_count": 0, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [], - "matlab_reference_images": [], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 0, - "python_code_lines": 102, - "python_to_matlab_line_ratio": null, - "matlab_reference_image_count": 0, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "FitResultExamples", - "class_hint": "FitResult", - "notebook": "notebooks/helpfiles/FitResultExamples.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.2499652429999912, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "matlab_doc_only", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 0, - "produced_figures": 0, - "figure_count_match": true, - "figure_scores": [], - "image_count": 0, - "unique_image_count": 0, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [], - "matlab_reference_images": [], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 0, - "python_code_lines": 102, - "python_to_matlab_line_ratio": null, - "matlab_reference_image_count": 0, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "HippocampalPlaceCellExample", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/HippocampalPlaceCellExample.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 3.4273853310000106, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 12, - "produced_figures": 12, - "figure_count_match": true, - "figure_scores": [], - "image_count": 12, - "unique_image_count": 10, - "duplicate_image_count": 2, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/HippocampalPlaceCellExample/fig_001.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_002.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_003.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_004.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_005.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_006.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_007.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_008.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_009.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_010.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_011.png", - "output/notebook_images/HippocampalPlaceCellExample/fig_012.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_01.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_02.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_03.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_04.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_05.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_06.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_07.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_08.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_09.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_10.png", - "/tmp/upstream-nstat/helpfiles/HippocampalPlaceCellExample_11.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 155, - "python_code_lines": 521, - "python_to_matlab_line_ratio": 3.361290322580645, - "matlab_reference_image_count": 12, - "python_validation_image_count": 1, - "assertion_count": 5, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 1, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 1.4210854715202004e-06, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 1, - "numeric_drift_metric_rows": [ - { - "name": "weighted_center_max_abs_error", - "value": 1.4210854715202004e-14, - "threshold": 1e-08, - "pass": true, - "ratio_to_threshold": 1.4210854715202004e-06 - } - ] - } - }, - { - "topic": "HistoryExamples", - "class_hint": "HistoryBasis", - "notebook": "notebooks/helpfiles/HistoryExamples.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.4204823240000053, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 5, - "produced_figures": 5, - "figure_count_match": true, - "figure_scores": [], - "image_count": 5, - "unique_image_count": 5, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/HistoryExamples/fig_001.png", - "output/notebook_images/HistoryExamples/fig_002.png", - "output/notebook_images/HistoryExamples/fig_003.png", - "output/notebook_images/HistoryExamples/fig_004.png", - "output/notebook_images/HistoryExamples/fig_005.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/HistoryExamples.png", - "/tmp/upstream-nstat/helpfiles/HistoryExamples_01.png", - "/tmp/upstream-nstat/helpfiles/HistoryExamples_02.png", - "/tmp/upstream-nstat/helpfiles/HistoryExamples_03.png", - "/tmp/upstream-nstat/helpfiles/HistoryExamples_04.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 18, - "python_code_lines": 101, - "python_to_matlab_line_ratio": 5.611111111111111, - "matlab_reference_image_count": 5, - "python_validation_image_count": 1, - "assertion_count": 5, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "history_bins_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "history_filter_max_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "history_matrix_max_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "NetworkTutorial", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/NetworkTutorial.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.7460317529999827, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 8, - "produced_figures": 8, - "figure_count_match": true, - "figure_scores": [], - "image_count": 8, - "unique_image_count": 7, - "duplicate_image_count": 1, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/NetworkTutorial/fig_001.png", - "output/notebook_images/NetworkTutorial/fig_002.png", - "output/notebook_images/NetworkTutorial/fig_003.png", - "output/notebook_images/NetworkTutorial/fig_004.png", - "output/notebook_images/NetworkTutorial/fig_005.png", - "output/notebook_images/NetworkTutorial/fig_006.png", - "output/notebook_images/NetworkTutorial/fig_007.png", - "output/notebook_images/NetworkTutorial/fig_008.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/NetworkTutorial.png", - "/tmp/upstream-nstat/helpfiles/NetworkTutorial_01.png", - "/tmp/upstream-nstat/helpfiles/NetworkTutorial_02.png", - "/tmp/upstream-nstat/helpfiles/NetworkTutorial_03.png", - "/tmp/upstream-nstat/helpfiles/NetworkTutorial_04.png", - "/tmp/upstream-nstat/helpfiles/NetworkTutorial_05.png", - "/tmp/upstream-nstat/helpfiles/PPSimExample-BlockDiagram.png", - "/tmp/upstream-nstat/helpfiles/SimulatedNetwork2.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 88, - "python_code_lines": 243, - "python_to_matlab_line_ratio": 2.7613636363636362, - "matlab_reference_image_count": 8, - "python_validation_image_count": 5, - "assertion_count": 9, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0005030698080332741, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "xc_max_abs_error", - "value": 5.030698080332741e-16, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0005030698080332741 - }, - { - "name": "rates_max_abs_error", - "value": 0.0, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "shape_mismatch_count", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "PPSimExample", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/PPSimExample.ipynb", - "run_group": "smoke", - "executed": true, - "duration_s": 2.55882717099999, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 6, - "produced_figures": 6, - "figure_count_match": true, - "figure_scores": [], - "image_count": 6, - "unique_image_count": 6, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/PPSimExample/fig_001.png", - "output/notebook_images/PPSimExample/fig_002.png", - "output/notebook_images/PPSimExample/fig_003.png", - "output/notebook_images/PPSimExample/fig_004.png", - "output/notebook_images/PPSimExample/fig_005.png", - "output/notebook_images/PPSimExample/fig_006.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/PPSimExample.png", - "/tmp/upstream-nstat/helpfiles/PPSimExample_01.png", - "/tmp/upstream-nstat/helpfiles/PPSimExample_02.png", - "/tmp/upstream-nstat/helpfiles/PPSimExample_03.png", - "/tmp/upstream-nstat/helpfiles/PPSimExample_04.png", - "/tmp/upstream-nstat/helpfiles/PPSimExample-BlockDiagram.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 41, - "python_code_lines": 176, - "python_to_matlab_line_ratio": 4.2926829268292686, - "matlab_reference_image_count": 6, - "python_validation_image_count": 3, - "assertion_count": 2, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 1, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 2.209081474249503e-06, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 1, - "numeric_drift_metric_rows": [ - { - "name": "mean_relative_rate_error", - "value": 5.522703685623757e-07, - "threshold": 0.25, - "pass": true, - "ratio_to_threshold": 2.209081474249503e-06 - } - ] - } - }, - { - "topic": "PPThinning", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/PPThinning.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.384122337000008, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 5, - "produced_figures": 5, - "figure_count_match": true, - "figure_scores": [], - "image_count": 5, - "unique_image_count": 4, - "duplicate_image_count": 1, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/PPThinning/fig_001.png", - "output/notebook_images/PPThinning/fig_002.png", - "output/notebook_images/PPThinning/fig_003.png", - "output/notebook_images/PPThinning/fig_004.png", - "output/notebook_images/PPThinning/fig_005.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/PPThinning.png", - "/tmp/upstream-nstat/helpfiles/PPThinning_01.png", - "/tmp/upstream-nstat/helpfiles/PPThinning_02.png", - "/tmp/upstream-nstat/helpfiles/PPThinning_03.png", - "/tmp/upstream-nstat/helpfiles/PPThinning_04.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 40, - "python_code_lines": 124, - "python_to_matlab_line_ratio": 3.1, - "matlab_reference_image_count": 5, - "python_validation_image_count": 4, - "assertion_count": 5, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "accept_ratio_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "accepted_count_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "accepted_spike_max_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "PSTHEstimation", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/PSTHEstimation.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.4936691260000146, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 3, - "produced_figures": 3, - "figure_count_match": true, - "figure_scores": [], - "image_count": 3, - "unique_image_count": 3, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/PSTHEstimation/fig_001.png", - "output/notebook_images/PSTHEstimation/fig_002.png", - "output/notebook_images/PSTHEstimation/fig_003.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/PSTHEstimation.png", - "/tmp/upstream-nstat/helpfiles/PSTHEstimation_01.png", - "/tmp/upstream-nstat/helpfiles/PSTHEstimation_02.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 28, - "python_code_lines": 110, - "python_to_matlab_line_ratio": 3.9285714285714284, - "matlab_reference_image_count": 3, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 2.220446049250313e-06, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "prob_max_abs_error", - "value": 2.220446049250313e-16, - "threshold": 1e-10, - "pass": true, - "ratio_to_threshold": 2.220446049250313e-06 - }, - { - "name": "rate_max_abs_error", - "value": 0.0, - "threshold": 1e-10, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "sig_mismatch_count", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "SignalObjExamples", - "class_hint": "Signal", - "notebook": "notebooks/helpfiles/SignalObjExamples.ipynb", - "run_group": "smoke", - "executed": true, - "duration_s": 2.756258195999976, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 21, - "produced_figures": 21, - "figure_count_match": true, - "figure_scores": [], - "image_count": 21, - "unique_image_count": 18, - "duplicate_image_count": 3, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/SignalObjExamples/fig_001.png", - "output/notebook_images/SignalObjExamples/fig_002.png", - "output/notebook_images/SignalObjExamples/fig_003.png", - "output/notebook_images/SignalObjExamples/fig_004.png", - "output/notebook_images/SignalObjExamples/fig_005.png", - "output/notebook_images/SignalObjExamples/fig_006.png", - "output/notebook_images/SignalObjExamples/fig_007.png", - "output/notebook_images/SignalObjExamples/fig_008.png", - "output/notebook_images/SignalObjExamples/fig_009.png", - "output/notebook_images/SignalObjExamples/fig_010.png", - "output/notebook_images/SignalObjExamples/fig_011.png", - "output/notebook_images/SignalObjExamples/fig_012.png", - "output/notebook_images/SignalObjExamples/fig_013.png", - "output/notebook_images/SignalObjExamples/fig_014.png", - "output/notebook_images/SignalObjExamples/fig_015.png", - "output/notebook_images/SignalObjExamples/fig_016.png", - "output/notebook_images/SignalObjExamples/fig_017.png", - "output/notebook_images/SignalObjExamples/fig_018.png", - "output/notebook_images/SignalObjExamples/fig_019.png", - "output/notebook_images/SignalObjExamples/fig_020.png", - "output/notebook_images/SignalObjExamples/fig_021.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/SignalObjExamples.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_01.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_02.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_03.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_04.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_05.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_06.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_07.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_08.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_09.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_10.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_11.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_12.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_13.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_14.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_15.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_16.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_17.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_18.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_19.png", - "/tmp/upstream-nstat/helpfiles/SignalObjExamples_20.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 81, - "python_code_lines": 313, - "python_to_matlab_line_ratio": 3.8641975308641974, - "matlab_reference_image_count": 21, - "python_validation_image_count": 6, - "assertion_count": 10, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 4, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 4, - "numeric_drift_metric_rows": [ - { - "name": "masked_cols_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "periodogram_peak_idx_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "resampled_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "window_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "StimulusDecode2D", - "class_hint": "DecodingAlgorithms", - "notebook": "notebooks/helpfiles/StimulusDecode2D.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.4795702549999987, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 7, - "produced_figures": 7, - "figure_count_match": true, - "figure_scores": [], - "image_count": 7, - "unique_image_count": 6, - "duplicate_image_count": 1, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/StimulusDecode2D/fig_001.png", - "output/notebook_images/StimulusDecode2D/fig_002.png", - "output/notebook_images/StimulusDecode2D/fig_003.png", - "output/notebook_images/StimulusDecode2D/fig_004.png", - "output/notebook_images/StimulusDecode2D/fig_005.png", - "output/notebook_images/StimulusDecode2D/fig_006.png", - "output/notebook_images/StimulusDecode2D/fig_007.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/StimulusDecode2D.png", - "/tmp/upstream-nstat/helpfiles/StimulusDecode2D_01.png", - "/tmp/upstream-nstat/helpfiles/StimulusDecode2D_02.png", - "/tmp/upstream-nstat/helpfiles/StimulusDecode2D_03.png", - "/tmp/upstream-nstat/helpfiles/StimulusDecode2D_04.png", - "/tmp/upstream-nstat/helpfiles/StimulusDecode2D_05.png", - "/tmp/upstream-nstat/helpfiles/StimulusDecode2D_06.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 92, - "python_code_lines": 178, - "python_to_matlab_line_ratio": 1.934782608695652, - "matlab_reference_image_count": 7, - "python_validation_image_count": 1, - "assertion_count": 2, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 8.526512829121202e-06, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "decoded_center_max_abs_error", - "value": 8.526512829121202e-14, - "threshold": 1e-08, - "pass": true, - "ratio_to_threshold": 8.526512829121202e-06 - }, - { - "name": "decoded_mismatch_count", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "rmse_abs_error", - "value": 0.0, - "threshold": 1e-10, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "TrialConfigExamples", - "class_hint": "TrialConfig", - "notebook": "notebooks/helpfiles/TrialConfigExamples.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.1496448729999997, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 0, - "produced_figures": 0, - "figure_count_match": true, - "figure_scores": [], - "image_count": 0, - "unique_image_count": 0, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [], - "matlab_reference_images": [], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 3, - "python_code_lines": 79, - "python_to_matlab_line_ratio": 26.333333333333332, - "matlab_reference_image_count": 0, - "python_validation_image_count": 1, - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "TrialExamples", - "class_hint": "Trial", - "notebook": "notebooks/helpfiles/TrialExamples.ipynb", - "run_group": "smoke", - "executed": true, - "duration_s": 2.7361148710000123, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 7, - "produced_figures": 7, - "figure_count_match": true, - "figure_scores": [], - "image_count": 7, - "unique_image_count": 7, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/TrialExamples/fig_001.png", - "output/notebook_images/TrialExamples/fig_002.png", - "output/notebook_images/TrialExamples/fig_003.png", - "output/notebook_images/TrialExamples/fig_004.png", - "output/notebook_images/TrialExamples/fig_005.png", - "output/notebook_images/TrialExamples/fig_006.png", - "output/notebook_images/TrialExamples/fig_007.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/TrialExamples.png", - "/tmp/upstream-nstat/helpfiles/TrialExamples_01.png", - "/tmp/upstream-nstat/helpfiles/TrialExamples_02.png", - "/tmp/upstream-nstat/helpfiles/TrialExamples_03.png", - "/tmp/upstream-nstat/helpfiles/TrialExamples_04.png", - "/tmp/upstream-nstat/helpfiles/TrialExamples_05.png", - "/tmp/upstream-nstat/helpfiles/TrialExamples_06.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 25, - "python_code_lines": 133, - "python_to_matlab_line_ratio": 5.32, - "matlab_reference_image_count": 7, - "python_validation_image_count": 1, - "assertion_count": 5, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.00011102230246251565, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "t_bins_max_abs_error", - "value": 1.1102230246251565e-16, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.00011102230246251565 - }, - { - "name": "X_max_abs_error", - "value": 0.0, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "y_max_abs_error", - "value": 0.0, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "ValidationDataSet", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/ValidationDataSet.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.7128817349999963, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 13, - "produced_figures": 13, - "figure_count_match": true, - "figure_scores": [], - "image_count": 13, - "unique_image_count": 11, - "duplicate_image_count": 2, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/ValidationDataSet/fig_001.png", - "output/notebook_images/ValidationDataSet/fig_002.png", - "output/notebook_images/ValidationDataSet/fig_003.png", - "output/notebook_images/ValidationDataSet/fig_004.png", - "output/notebook_images/ValidationDataSet/fig_005.png", - "output/notebook_images/ValidationDataSet/fig_006.png", - "output/notebook_images/ValidationDataSet/fig_007.png", - "output/notebook_images/ValidationDataSet/fig_008.png", - "output/notebook_images/ValidationDataSet/fig_009.png", - "output/notebook_images/ValidationDataSet/fig_010.png", - "output/notebook_images/ValidationDataSet/fig_011.png", - "output/notebook_images/ValidationDataSet/fig_012.png", - "output/notebook_images/ValidationDataSet/fig_013.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/ValidationDataSet.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_01.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_02.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_03.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_04.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_05.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_06.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_07.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_08.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_09.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_10.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_11.png", - "/tmp/upstream-nstat/helpfiles/ValidationDataSet_12.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 77, - "python_code_lines": 221, - "python_to_matlab_line_ratio": 2.8701298701298703, - "matlab_reference_image_count": 13, - "python_validation_image_count": 1, - "assertion_count": 2, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 2.220446049250313e-06, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "prob_max_abs_error", - "value": 2.220446049250313e-16, - "threshold": 1e-10, - "pass": true, - "ratio_to_threshold": 2.220446049250313e-06 - }, - { - "name": "rate_max_abs_error", - "value": 0.0, - "threshold": 1e-10, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "sig_mismatch_count", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "mEPSCAnalysis", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/mEPSCAnalysis.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.565191610999989, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 6, - "produced_figures": 6, - "figure_count_match": true, - "figure_scores": [], - "image_count": 6, - "unique_image_count": 5, - "duplicate_image_count": 1, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/mEPSCAnalysis/fig_001.png", - "output/notebook_images/mEPSCAnalysis/fig_002.png", - "output/notebook_images/mEPSCAnalysis/fig_003.png", - "output/notebook_images/mEPSCAnalysis/fig_004.png", - "output/notebook_images/mEPSCAnalysis/fig_005.png", - "output/notebook_images/mEPSCAnalysis/fig_006.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/mEPSCAnalysis.png", - "/tmp/upstream-nstat/helpfiles/mEPSCAnalysis_01.png", - "/tmp/upstream-nstat/helpfiles/mEPSCAnalysis_02.png", - "/tmp/upstream-nstat/helpfiles/mEPSCAnalysis_03.png", - "/tmp/upstream-nstat/helpfiles/mEPSCAnalysis_04.png", - "/tmp/upstream-nstat/helpfiles/mEPSCAnalysis_05.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 48, - "python_code_lines": 177, - "python_to_matlab_line_ratio": 3.6875, - "matlab_reference_image_count": 6, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 4, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 5.551115123125782e-08, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 4, - "numeric_drift_metric_rows": [ - { - "name": "mean_amp_abs_error", - "value": 5.551115123125783e-17, - "threshold": 1e-09, - "pass": true, - "ratio_to_threshold": 5.551115123125782e-08 - }, - { - "name": "detected_amp_max_abs_error", - "value": 0.0, - "threshold": 1e-09, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "detected_time_max_abs_error", - "value": 0.0, - "threshold": 0.001, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "event_count_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "nSTATPaperExamples", - "class_hint": "nSTATPaper", - "notebook": "notebooks/helpfiles/nSTATPaperExamples.ipynb", - "run_group": "smoke", - "executed": true, - "duration_s": 6.260054120999996, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 26, - "produced_figures": 26, - "figure_count_match": true, - "figure_scores": [], - "image_count": 26, - "unique_image_count": 26, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/nSTATPaperExamples/fig_001.png", - "output/notebook_images/nSTATPaperExamples/fig_002.png", - "output/notebook_images/nSTATPaperExamples/fig_003.png", - "output/notebook_images/nSTATPaperExamples/fig_004.png", - "output/notebook_images/nSTATPaperExamples/fig_005.png", - "output/notebook_images/nSTATPaperExamples/fig_006.png", - "output/notebook_images/nSTATPaperExamples/fig_007.png", - "output/notebook_images/nSTATPaperExamples/fig_008.png", - "output/notebook_images/nSTATPaperExamples/fig_009.png", - "output/notebook_images/nSTATPaperExamples/fig_010.png", - "output/notebook_images/nSTATPaperExamples/fig_011.png", - "output/notebook_images/nSTATPaperExamples/fig_012.png", - "output/notebook_images/nSTATPaperExamples/fig_013.png", - "output/notebook_images/nSTATPaperExamples/fig_014.png", - "output/notebook_images/nSTATPaperExamples/fig_015.png", - "output/notebook_images/nSTATPaperExamples/fig_016.png", - "output/notebook_images/nSTATPaperExamples/fig_017.png", - "output/notebook_images/nSTATPaperExamples/fig_018.png", - "output/notebook_images/nSTATPaperExamples/fig_019.png", - "output/notebook_images/nSTATPaperExamples/fig_020.png", - "output/notebook_images/nSTATPaperExamples/fig_021.png", - "output/notebook_images/nSTATPaperExamples/fig_022.png", - "output/notebook_images/nSTATPaperExamples/fig_023.png", - "output/notebook_images/nSTATPaperExamples/fig_024.png", - "output/notebook_images/nSTATPaperExamples/fig_025.png", - "output/notebook_images/nSTATPaperExamples/fig_026.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_01.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_02.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_03.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_04.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_05.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_06.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_07.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_08.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_09.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_10.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_11.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_12.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_13.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_14.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_15.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_16.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_17.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_18.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_19.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_20.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_21.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_22.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_23.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_24.png", - "/tmp/upstream-nstat/helpfiles/nSTATPaperExamples_25.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 1576, - "python_code_lines": 2073, - "python_to_matlab_line_ratio": 1.3153553299492386, - "matlab_reference_image_count": 26, - "python_validation_image_count": 1, - "assertion_count": 15, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "nSpikeTrainExamples", - "class_hint": "SpikeTrain", - "notebook": "notebooks/helpfiles/nSpikeTrainExamples.ipynb", - "run_group": "smoke", - "executed": true, - "duration_s": 2.3887158400000317, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 6, - "produced_figures": 6, - "figure_count_match": true, - "figure_scores": [], - "image_count": 6, - "unique_image_count": 5, - "duplicate_image_count": 1, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/nSpikeTrainExamples/fig_001.png", - "output/notebook_images/nSpikeTrainExamples/fig_002.png", - "output/notebook_images/nSpikeTrainExamples/fig_003.png", - "output/notebook_images/nSpikeTrainExamples/fig_004.png", - "output/notebook_images/nSpikeTrainExamples/fig_005.png", - "output/notebook_images/nSpikeTrainExamples/fig_006.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/nSpikeTrainExamples.png", - "/tmp/upstream-nstat/helpfiles/nSpikeTrainExamples_01.png", - "/tmp/upstream-nstat/helpfiles/nSpikeTrainExamples_02.png", - "/tmp/upstream-nstat/helpfiles/nSpikeTrainExamples_03.png", - "/tmp/upstream-nstat/helpfiles/nSpikeTrainExamples_04.png", - "/tmp/upstream-nstat/helpfiles/nSpikeTrainExamples_05.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 10, - "python_code_lines": 86, - "python_to_matlab_line_ratio": 8.6, - "matlab_reference_image_count": 6, - "python_validation_image_count": 1, - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "nstCollExamples", - "class_hint": "SpikeTrainCollection", - "notebook": "notebooks/helpfiles/nstCollExamples.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.343621245999998, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 4, - "produced_figures": 4, - "figure_count_match": true, - "figure_scores": [], - "image_count": 4, - "unique_image_count": 4, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/nstCollExamples/fig_001.png", - "output/notebook_images/nstCollExamples/fig_002.png", - "output/notebook_images/nstCollExamples/fig_003.png", - "output/notebook_images/nstCollExamples/fig_004.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/nstCollExamples.png", - "/tmp/upstream-nstat/helpfiles/nstCollExamples_01.png", - "/tmp/upstream-nstat/helpfiles/nstCollExamples_02.png", - "/tmp/upstream-nstat/helpfiles/nstCollExamples_03.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 16, - "python_code_lines": 89, - "python_to_matlab_line_ratio": 5.5625, - "matlab_reference_image_count": 4, - "python_validation_image_count": 1, - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 4, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0002220446049250313, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 4, - "numeric_drift_metric_rows": [ - { - "name": "center_max_abs_error", - "value": 2.220446049250313e-16, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0002220446049250313 - }, - { - "name": "binary_mismatch_count", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "count_matrix_max_abs_error", - "value": 0.0, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "merged_max_abs_error", - "value": 0.0, - "threshold": 1e-12, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "AnalysisExamples2", - "class_hint": "Analysis", - "notebook": "notebooks/helpfiles/AnalysisExamples2.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.782037406000029, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 6, - "produced_figures": 6, - "figure_count_match": true, - "figure_scores": [], - "image_count": 6, - "unique_image_count": 6, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/AnalysisExamples2/fig_001.png", - "output/notebook_images/AnalysisExamples2/fig_002.png", - "output/notebook_images/AnalysisExamples2/fig_003.png", - "output/notebook_images/AnalysisExamples2/fig_004.png", - "output/notebook_images/AnalysisExamples2/fig_005.png", - "output/notebook_images/AnalysisExamples2/fig_006.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/AnalysisExamples2.png", - "/tmp/upstream-nstat/helpfiles/AnalysisExamples2_01.png", - "/tmp/upstream-nstat/helpfiles/AnalysisExamples2_02.png", - "/tmp/upstream-nstat/helpfiles/AnalysisExamples2_03.png", - "/tmp/upstream-nstat/helpfiles/AnalysisExamples2_04.png", - "/tmp/upstream-nstat/helpfiles/AnalysisExamples2_05.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 61, - "python_code_lines": 187, - "python_to_matlab_line_ratio": 3.0655737704918034, - "matlab_reference_image_count": 6, - "python_validation_image_count": 1, - "assertion_count": 2, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "DocumentationSetup2025b", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/DocumentationSetup2025b.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.2632713059999787, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "matlab_doc_only", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 0, - "produced_figures": 0, - "figure_count_match": true, - "figure_scores": [], - "image_count": 0, - "unique_image_count": 0, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [], - "matlab_reference_images": [], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 0, - "python_code_lines": 71, - "python_to_matlab_line_ratio": null, - "matlab_reference_image_count": 0, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "FitResultReference", - "class_hint": "FitResult", - "notebook": "notebooks/helpfiles/FitResultReference.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.3238267979999705, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "matlab_doc_only", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 0, - "produced_figures": 0, - "figure_count_match": true, - "figure_scores": [], - "image_count": 0, - "unique_image_count": 0, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [], - "matlab_reference_images": [], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 0, - "python_code_lines": 94, - "python_to_matlab_line_ratio": null, - "matlab_reference_image_count": 0, - "python_validation_image_count": 1, - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "HybridFilterExample", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/HybridFilterExample.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 3.1979228390000003, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 3, - "produced_figures": 3, - "figure_count_match": true, - "figure_scores": [], - "image_count": 3, - "unique_image_count": 3, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [ - "output/notebook_images/HybridFilterExample/fig_001.png", - "output/notebook_images/HybridFilterExample/fig_002.png", - "output/notebook_images/HybridFilterExample/fig_003.png" - ], - "matlab_reference_images": [ - "/tmp/upstream-nstat/helpfiles/HybridFilterExample.png", - "/tmp/upstream-nstat/helpfiles/HybridFilterExample_01.png", - "/tmp/upstream-nstat/helpfiles/HybridFilterExample_02.png" - ], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 288, - "python_code_lines": 413, - "python_to_matlab_line_ratio": 1.4340277777777777, - "matlab_reference_image_count": 3, - "python_validation_image_count": 2, - "assertion_count": 5, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 3, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 6.938893903907228e-08, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 3, - "numeric_drift_metric_rows": [ - { - "name": "rmse_notransition_abs_error", - "value": 6.938893903907228e-18, - "threshold": 1e-10, - "pass": true, - "ratio_to_threshold": 6.938893903907228e-08 - }, - { - "name": "rmse_abs_error", - "value": 0.0, - "threshold": 1e-10, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "state_length_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - }, - { - "topic": "publish_all_helpfiles", - "class_hint": "Workflow", - "notebook": "notebooks/helpfiles/publish_all_helpfiles.ipynb", - "run_group": "full", - "executed": true, - "duration_s": 2.4891688220000106, - "execution_pass": true, - "parity_pass": true, - "alignment_status": "validated", - "numeric_drift_pass": true, - "numeric_drift_failed_metric_count": null, - "similarity_score": null, - "expected_figures": 0, - "produced_figures": 0, - "figure_count_match": true, - "figure_scores": [], - "image_count": 0, - "unique_image_count": 0, - "duplicate_image_count": 0, - "error": "", - "matched_python_image": "", - "matched_matlab_image": "", - "python_images": [], - "matlab_reference_images": [], - "figure_pairs": [], - "diff_artifacts": [], - "parity_metrics": { - "matlab_code_lines": 126, - "python_code_lines": 292, - "python_to_matlab_line_ratio": 2.3174603174603177, - "matlab_reference_image_count": 0, - "python_validation_image_count": 1, - "assertion_count": 14, - "has_plot_call": true, - "has_topic_checkpoint": true, - "numeric_drift_pass": true, - "numeric_drift_checked_metrics": 8, - "numeric_drift_failed_metrics": 0, - "numeric_drift_worst_ratio": 0.0, - "numeric_drift_first_failed": "-", - "numeric_drift_metric_count": 8, - "numeric_drift_metric_rows": [ - { - "name": "alignment_status_mismatch", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "assertion_count_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_code_lines_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "matlab_reference_image_count_abs_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "plot_call_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "python_validation_image_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_checkpoint_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - }, - { - "name": "topic_row_missing_error", - "value": 0.0, - "threshold": 0.0, - "pass": true, - "ratio_to_threshold": 0.0 - } - ] - } - } - ] -} \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 08da5967..ed1e91ea 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,39 +1,6 @@ -from __future__ import annotations - -import os -import sys - - -sys.path.insert(0, os.path.abspath("../src")) - -project = "nSTAT-python" +project = "nSTAT Python" author = "Cajigas Lab" release = "0.1.0" - -extensions = [ - "myst_parser", - "sphinx.ext.autodoc", - "sphinx.ext.napoleon", -] - -source_suffix = { - ".md": "markdown", -} - -autosummary_generate = True -autodoc_typehints = "description" - -templates_path = ["_templates"] +extensions = [] exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - -html_theme = "sphinx_rtd_theme" -html_static_path = ["_static"] -html_title = "nSTAT-python Documentation" - -# PubMed/PMC frequently block automated HEAD/GET requests with 403 in CI. -# We keep these references in docs but exclude them from linkcheck enforcement. -linkcheck_ignore = [ - r"https://pubmed\.ncbi\.nlm\.nih\.gov/.*", - r"https://pmc\.ncbi\.nlm\.nih\.gov/articles/.*", - r"https://github\.com/cajigaslab/nSTAT-python/blob/main/notebooks/.*", -] +master_doc = "index" diff --git a/docs/help/class_definitions.md b/docs/help/class_definitions.md deleted file mode 100644 index bd18716e..00000000 --- a/docs/help/class_definitions.md +++ /dev/null @@ -1,22 +0,0 @@ -# Class Definitions - -Each MATLAB nSTAT class has a corresponding Python help page and implementation. - -| MATLAB class | Python target | -|---|---| -| SignalObj | nstat.signal.Signal | -| Covariate | nstat.signal.Covariate | -| ConfidenceInterval | nstat.confidence.ConfidenceInterval | -| Events | nstat.events.Events | -| History | nstat.history.HistoryBasis | -| nspikeTrain | nstat.spikes.SpikeTrain | -| nstColl | nstat.spikes.SpikeTrainCollection | -| CovColl | nstat.trial.CovariateCollection | -| TrialConfig | nstat.trial.TrialConfig | -| ConfigColl | nstat.trial.ConfigCollection | -| Trial | nstat.trial.Trial | -| CIF | nstat.cif.CIFModel | -| Analysis | nstat.analysis.Analysis | -| FitResult | nstat.fit.FitResult | -| FitResSummary | nstat.fit.FitSummary | -| DecodingAlgorithms | nstat.decoding.DecodingAlgorithms | diff --git a/docs/help/classes/Analysis.md b/docs/help/classes/Analysis.md deleted file mode 100644 index 23b6dd0d..00000000 --- a/docs/help/classes/Analysis.md +++ /dev/null @@ -1,19 +0,0 @@ -# Analysis - -Python implementation: `nstat.analysis.Analysis` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [AnalysisExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/AnalysisExamples.ipynb) -- [AnalysisExamples help page](../examples/AnalysisExamples.md) -- [nSTATPaperExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nSTATPaperExamples.ipynb) -- [nSTATPaperExamples help page](../examples/nSTATPaperExamples.md) diff --git a/docs/help/classes/CIF.md b/docs/help/classes/CIF.md deleted file mode 100644 index 8b39b169..00000000 --- a/docs/help/classes/CIF.md +++ /dev/null @@ -1,19 +0,0 @@ -# CIF - -Python implementation: `nstat.cif.CIFModel` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [PPSimExample notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/PPSimExample.ipynb) -- [PPSimExample help page](../examples/PPSimExample.md) -- [PPThinning notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/PPThinning.ipynb) -- [PPThinning help page](../examples/PPThinning.md) diff --git a/docs/help/classes/ConfidenceInterval.md b/docs/help/classes/ConfidenceInterval.md deleted file mode 100644 index 6ed895db..00000000 --- a/docs/help/classes/ConfidenceInterval.md +++ /dev/null @@ -1,19 +0,0 @@ -# ConfidenceInterval - -Python implementation: `nstat.confidence.ConfidenceInterval` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [DecodingExample notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/DecodingExample.ipynb) -- [DecodingExample help page](../examples/DecodingExample.md) -- [FitResSummaryExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/FitResSummaryExamples.ipynb) -- [FitResSummaryExamples help page](../examples/FitResSummaryExamples.md) diff --git a/docs/help/classes/ConfigColl.md b/docs/help/classes/ConfigColl.md deleted file mode 100644 index f743b83b..00000000 --- a/docs/help/classes/ConfigColl.md +++ /dev/null @@ -1,19 +0,0 @@ -# ConfigColl - -Python implementation: `nstat.trial.ConfigCollection` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [ConfigCollExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/ConfigCollExamples.ipynb) -- [ConfigCollExamples help page](../examples/ConfigCollExamples.md) -- [AnalysisExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/AnalysisExamples.ipynb) -- [AnalysisExamples help page](../examples/AnalysisExamples.md) diff --git a/docs/help/classes/CovColl.md b/docs/help/classes/CovColl.md deleted file mode 100644 index 533e6c06..00000000 --- a/docs/help/classes/CovColl.md +++ /dev/null @@ -1,19 +0,0 @@ -# CovColl - -Python implementation: `nstat.trial.CovariateCollection` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [CovCollExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/CovCollExamples.ipynb) -- [CovCollExamples help page](../examples/CovCollExamples.md) -- [TrialExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/TrialExamples.ipynb) -- [TrialExamples help page](../examples/TrialExamples.md) diff --git a/docs/help/classes/Covariate.md b/docs/help/classes/Covariate.md deleted file mode 100644 index 09cc57e7..00000000 --- a/docs/help/classes/Covariate.md +++ /dev/null @@ -1,19 +0,0 @@ -# Covariate - -Python implementation: `nstat.signal.Covariate` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [CovariateExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/CovariateExamples.ipynb) -- [CovariateExamples help page](../examples/CovariateExamples.md) -- [TrialExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/TrialExamples.ipynb) -- [TrialExamples help page](../examples/TrialExamples.md) diff --git a/docs/help/classes/DecodingAlgorithms.md b/docs/help/classes/DecodingAlgorithms.md deleted file mode 100644 index 2b19e652..00000000 --- a/docs/help/classes/DecodingAlgorithms.md +++ /dev/null @@ -1,19 +0,0 @@ -# DecodingAlgorithms - -Python implementation: `nstat.decoding.DecodingAlgorithms` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [DecodingExample notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/DecodingExample.ipynb) -- [DecodingExample help page](../examples/DecodingExample.md) -- [StimulusDecode2D notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/StimulusDecode2D.ipynb) -- [StimulusDecode2D help page](../examples/StimulusDecode2D.md) diff --git a/docs/help/classes/Events.md b/docs/help/classes/Events.md deleted file mode 100644 index afd2e8dd..00000000 --- a/docs/help/classes/Events.md +++ /dev/null @@ -1,19 +0,0 @@ -# Events - -Python implementation: `nstat.events.Events` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [EventsExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/EventsExamples.ipynb) -- [EventsExamples help page](../examples/EventsExamples.md) -- [NetworkTutorial notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/NetworkTutorial.ipynb) -- [NetworkTutorial help page](../examples/NetworkTutorial.md) diff --git a/docs/help/classes/FitResSummary.md b/docs/help/classes/FitResSummary.md deleted file mode 100644 index f7acf007..00000000 --- a/docs/help/classes/FitResSummary.md +++ /dev/null @@ -1,19 +0,0 @@ -# FitResSummary - -Python implementation: `nstat.fit.FitSummary` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [FitResSummaryExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/FitResSummaryExamples.ipynb) -- [FitResSummaryExamples help page](../examples/FitResSummaryExamples.md) -- [nSTATPaperExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nSTATPaperExamples.ipynb) -- [nSTATPaperExamples help page](../examples/nSTATPaperExamples.md) diff --git a/docs/help/classes/FitResult.md b/docs/help/classes/FitResult.md deleted file mode 100644 index 462bbe6f..00000000 --- a/docs/help/classes/FitResult.md +++ /dev/null @@ -1,19 +0,0 @@ -# FitResult - -Python implementation: `nstat.fit.FitResult` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [FitResultExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/FitResultExamples.ipynb) -- [FitResultExamples help page](../examples/FitResultExamples.md) -- [nSTATPaperExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nSTATPaperExamples.ipynb) -- [nSTATPaperExamples help page](../examples/nSTATPaperExamples.md) diff --git a/docs/help/classes/History.md b/docs/help/classes/History.md deleted file mode 100644 index bc1ab75a..00000000 --- a/docs/help/classes/History.md +++ /dev/null @@ -1,19 +0,0 @@ -# History - -Python implementation: `nstat.history.HistoryBasis` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [HistoryExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/HistoryExamples.ipynb) -- [HistoryExamples help page](../examples/HistoryExamples.md) -- [DecodingExampleWithHist notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/DecodingExampleWithHist.ipynb) -- [DecodingExampleWithHist help page](../examples/DecodingExampleWithHist.md) diff --git a/docs/help/classes/SignalObj.md b/docs/help/classes/SignalObj.md deleted file mode 100644 index e7851b05..00000000 --- a/docs/help/classes/SignalObj.md +++ /dev/null @@ -1,19 +0,0 @@ -# SignalObj - -Python implementation: `nstat.signal.Signal` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [SignalObjExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/SignalObjExamples.ipynb) -- [SignalObjExamples help page](../examples/SignalObjExamples.md) -- [AnalysisExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/AnalysisExamples.ipynb) -- [AnalysisExamples help page](../examples/AnalysisExamples.md) diff --git a/docs/help/classes/Trial.md b/docs/help/classes/Trial.md deleted file mode 100644 index 81d09c09..00000000 --- a/docs/help/classes/Trial.md +++ /dev/null @@ -1,19 +0,0 @@ -# Trial - -Python implementation: `nstat.trial.Trial` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [TrialExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/TrialExamples.ipynb) -- [TrialExamples help page](../examples/TrialExamples.md) -- [AnalysisExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/AnalysisExamples.ipynb) -- [AnalysisExamples help page](../examples/AnalysisExamples.md) diff --git a/docs/help/classes/TrialConfig.md b/docs/help/classes/TrialConfig.md deleted file mode 100644 index af3d6a83..00000000 --- a/docs/help/classes/TrialConfig.md +++ /dev/null @@ -1,19 +0,0 @@ -# TrialConfig - -Python implementation: `nstat.trial.TrialConfig` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [TrialConfigExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/TrialConfigExamples.ipynb) -- [TrialConfigExamples help page](../examples/TrialConfigExamples.md) -- [AnalysisExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/AnalysisExamples.ipynb) -- [AnalysisExamples help page](../examples/AnalysisExamples.md) diff --git a/docs/help/classes/nspikeTrain.md b/docs/help/classes/nspikeTrain.md deleted file mode 100644 index d95c0b38..00000000 --- a/docs/help/classes/nspikeTrain.md +++ /dev/null @@ -1,19 +0,0 @@ -# nspikeTrain - -Python implementation: `nstat.spikes.SpikeTrain` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [nSpikeTrainExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nSpikeTrainExamples.ipynb) -- [nSpikeTrainExamples help page](../examples/nSpikeTrainExamples.md) -- [PPSimExample notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/PPSimExample.ipynb) -- [PPSimExample help page](../examples/PPSimExample.md) diff --git a/docs/help/classes/nstColl.md b/docs/help/classes/nstColl.md deleted file mode 100644 index de4a973d..00000000 --- a/docs/help/classes/nstColl.md +++ /dev/null @@ -1,19 +0,0 @@ -# nstColl - -Python implementation: `nstat.spikes.SpikeTrainCollection` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference](../../api.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -- [nstCollExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nstCollExamples.ipynb) -- [nstCollExamples help page](../examples/nstCollExamples.md) -- [TrialExamples notebook](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/TrialExamples.ipynb) -- [TrialExamples help page](../examples/TrialExamples.md) diff --git a/docs/help/examples/AnalysisExamples.md b/docs/help/examples/AnalysisExamples.md deleted file mode 100644 index 858db1fc..00000000 --- a/docs/help/examples/AnalysisExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# AnalysisExamples - -Python-native tutorial page for `AnalysisExamples`. - -## Notebook -- [AnalysisExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/AnalysisExamples.ipynb) -- Execution group: `smoke` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/AnalysisExamples2.md b/docs/help/examples/AnalysisExamples2.md deleted file mode 100644 index 9f98ed7a..00000000 --- a/docs/help/examples/AnalysisExamples2.md +++ /dev/null @@ -1,14 +0,0 @@ -# AnalysisExamples2 - -Python-native tutorial page for `AnalysisExamples2`. - -## Notebook -- [AnalysisExamples2.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/AnalysisExamples2.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/ConfigCollExamples.md b/docs/help/examples/ConfigCollExamples.md deleted file mode 100644 index 6803906a..00000000 --- a/docs/help/examples/ConfigCollExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# ConfigCollExamples - -Python-native tutorial page for `ConfigCollExamples`. - -## Notebook -- [ConfigCollExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/ConfigCollExamples.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/CovCollExamples.md b/docs/help/examples/CovCollExamples.md deleted file mode 100644 index 9b7471f5..00000000 --- a/docs/help/examples/CovCollExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# CovCollExamples - -Python-native tutorial page for `CovCollExamples`. - -## Notebook -- [CovCollExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/CovCollExamples.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/CovariateExamples.md b/docs/help/examples/CovariateExamples.md deleted file mode 100644 index a336b78b..00000000 --- a/docs/help/examples/CovariateExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# CovariateExamples - -Python-native tutorial page for `CovariateExamples`. - -## Notebook -- [CovariateExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/CovariateExamples.ipynb) -- Execution group: `smoke` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/DecodingExample.md b/docs/help/examples/DecodingExample.md deleted file mode 100644 index 95b20de8..00000000 --- a/docs/help/examples/DecodingExample.md +++ /dev/null @@ -1,14 +0,0 @@ -# DecodingExample - -Python-native tutorial page for `DecodingExample`. - -## Notebook -- [DecodingExample.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/DecodingExample.ipynb) -- Execution group: `smoke` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/DecodingExampleWithHist.md b/docs/help/examples/DecodingExampleWithHist.md deleted file mode 100644 index d4e0cb28..00000000 --- a/docs/help/examples/DecodingExampleWithHist.md +++ /dev/null @@ -1,14 +0,0 @@ -# DecodingExampleWithHist - -Python-native tutorial page for `DecodingExampleWithHist`. - -## Notebook -- [DecodingExampleWithHist.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/DecodingExampleWithHist.ipynb) -- Execution group: `smoke` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/DocumentationSetup2025b.md b/docs/help/examples/DocumentationSetup2025b.md deleted file mode 100644 index e1b07c39..00000000 --- a/docs/help/examples/DocumentationSetup2025b.md +++ /dev/null @@ -1,14 +0,0 @@ -# DocumentationSetup2025b - -Python-native tutorial page for `DocumentationSetup2025b`. - -## Notebook -- [DocumentationSetup2025b.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/DocumentationSetup2025b.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/EventsExamples.md b/docs/help/examples/EventsExamples.md deleted file mode 100644 index 53d95b33..00000000 --- a/docs/help/examples/EventsExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# EventsExamples - -Python-native tutorial page for `EventsExamples`. - -## Notebook -- [EventsExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/EventsExamples.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/ExplicitStimulusWhiskerData.md b/docs/help/examples/ExplicitStimulusWhiskerData.md deleted file mode 100644 index 3dd4130a..00000000 --- a/docs/help/examples/ExplicitStimulusWhiskerData.md +++ /dev/null @@ -1,14 +0,0 @@ -# ExplicitStimulusWhiskerData - -Python-native tutorial page for `ExplicitStimulusWhiskerData`. - -## Notebook -- [ExplicitStimulusWhiskerData.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/ExplicitStimulusWhiskerData.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/FitResSummaryExamples.md b/docs/help/examples/FitResSummaryExamples.md deleted file mode 100644 index ad9e9136..00000000 --- a/docs/help/examples/FitResSummaryExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# FitResSummaryExamples - -Python-native tutorial page for `FitResSummaryExamples`. - -## Notebook -- [FitResSummaryExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/FitResSummaryExamples.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/FitResultExamples.md b/docs/help/examples/FitResultExamples.md deleted file mode 100644 index a7264908..00000000 --- a/docs/help/examples/FitResultExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# FitResultExamples - -Python-native tutorial page for `FitResultExamples`. - -## Notebook -- [FitResultExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/FitResultExamples.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/FitResultReference.md b/docs/help/examples/FitResultReference.md deleted file mode 100644 index 27f08913..00000000 --- a/docs/help/examples/FitResultReference.md +++ /dev/null @@ -1,14 +0,0 @@ -# FitResultReference - -Python-native tutorial page for `FitResultReference`. - -## Notebook -- [FitResultReference.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/FitResultReference.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/HippocampalPlaceCellExample.md b/docs/help/examples/HippocampalPlaceCellExample.md deleted file mode 100644 index 6a2bc3cb..00000000 --- a/docs/help/examples/HippocampalPlaceCellExample.md +++ /dev/null @@ -1,14 +0,0 @@ -# HippocampalPlaceCellExample - -Python-native tutorial page for `HippocampalPlaceCellExample`. - -## Notebook -- [HippocampalPlaceCellExample.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/HippocampalPlaceCellExample.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/HistoryExamples.md b/docs/help/examples/HistoryExamples.md deleted file mode 100644 index a708b644..00000000 --- a/docs/help/examples/HistoryExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# HistoryExamples - -Python-native tutorial page for `HistoryExamples`. - -## Notebook -- [HistoryExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/HistoryExamples.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/HybridFilterExample.md b/docs/help/examples/HybridFilterExample.md deleted file mode 100644 index 0e9962cb..00000000 --- a/docs/help/examples/HybridFilterExample.md +++ /dev/null @@ -1,14 +0,0 @@ -# HybridFilterExample - -Python-native tutorial page for `HybridFilterExample`. - -## Notebook -- [HybridFilterExample.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/HybridFilterExample.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/NetworkTutorial.md b/docs/help/examples/NetworkTutorial.md deleted file mode 100644 index 9813c4c1..00000000 --- a/docs/help/examples/NetworkTutorial.md +++ /dev/null @@ -1,14 +0,0 @@ -# NetworkTutorial - -Python-native tutorial page for `NetworkTutorial`. - -## Notebook -- [NetworkTutorial.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/NetworkTutorial.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/PPSimExample.md b/docs/help/examples/PPSimExample.md deleted file mode 100644 index e66e8ea7..00000000 --- a/docs/help/examples/PPSimExample.md +++ /dev/null @@ -1,14 +0,0 @@ -# PPSimExample - -Python-native tutorial page for `PPSimExample`. - -## Notebook -- [PPSimExample.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/PPSimExample.ipynb) -- Execution group: `smoke` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/PPThinning.md b/docs/help/examples/PPThinning.md deleted file mode 100644 index f5035127..00000000 --- a/docs/help/examples/PPThinning.md +++ /dev/null @@ -1,14 +0,0 @@ -# PPThinning - -Python-native tutorial page for `PPThinning`. - -## Notebook -- [PPThinning.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/PPThinning.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/PSTHEstimation.md b/docs/help/examples/PSTHEstimation.md deleted file mode 100644 index eb6c5b53..00000000 --- a/docs/help/examples/PSTHEstimation.md +++ /dev/null @@ -1,14 +0,0 @@ -# PSTHEstimation - -Python-native tutorial page for `PSTHEstimation`. - -## Notebook -- [PSTHEstimation.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/PSTHEstimation.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/SignalObjExamples.md b/docs/help/examples/SignalObjExamples.md deleted file mode 100644 index 7a900f03..00000000 --- a/docs/help/examples/SignalObjExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# SignalObjExamples - -Python-native tutorial page for `SignalObjExamples`. - -## Notebook -- [SignalObjExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/SignalObjExamples.ipynb) -- Execution group: `smoke` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/StimulusDecode2D.md b/docs/help/examples/StimulusDecode2D.md deleted file mode 100644 index 060bda6f..00000000 --- a/docs/help/examples/StimulusDecode2D.md +++ /dev/null @@ -1,14 +0,0 @@ -# StimulusDecode2D - -Python-native tutorial page for `StimulusDecode2D`. - -## Notebook -- [StimulusDecode2D.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/StimulusDecode2D.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/TrialConfigExamples.md b/docs/help/examples/TrialConfigExamples.md deleted file mode 100644 index c2f86b27..00000000 --- a/docs/help/examples/TrialConfigExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# TrialConfigExamples - -Python-native tutorial page for `TrialConfigExamples`. - -## Notebook -- [TrialConfigExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/TrialConfigExamples.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/TrialExamples.md b/docs/help/examples/TrialExamples.md deleted file mode 100644 index 33d6324c..00000000 --- a/docs/help/examples/TrialExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# TrialExamples - -Python-native tutorial page for `TrialExamples`. - -## Notebook -- [TrialExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/TrialExamples.ipynb) -- Execution group: `smoke` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/ValidationDataSet.md b/docs/help/examples/ValidationDataSet.md deleted file mode 100644 index f26c35ae..00000000 --- a/docs/help/examples/ValidationDataSet.md +++ /dev/null @@ -1,14 +0,0 @@ -# ValidationDataSet - -Python-native tutorial page for `ValidationDataSet`. - -## Notebook -- [ValidationDataSet.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/ValidationDataSet.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/mEPSCAnalysis.md b/docs/help/examples/mEPSCAnalysis.md deleted file mode 100644 index 65977bea..00000000 --- a/docs/help/examples/mEPSCAnalysis.md +++ /dev/null @@ -1,14 +0,0 @@ -# mEPSCAnalysis - -Python-native tutorial page for `mEPSCAnalysis`. - -## Notebook -- [mEPSCAnalysis.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/mEPSCAnalysis.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/nSTATPaperExamples.md b/docs/help/examples/nSTATPaperExamples.md deleted file mode 100644 index 0eb30f27..00000000 --- a/docs/help/examples/nSTATPaperExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# nSTATPaperExamples - -Python-native tutorial page for `nSTATPaperExamples`. - -## Notebook -- [nSTATPaperExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nSTATPaperExamples.ipynb) -- Execution group: `smoke` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/nSpikeTrainExamples.md b/docs/help/examples/nSpikeTrainExamples.md deleted file mode 100644 index d504bb92..00000000 --- a/docs/help/examples/nSpikeTrainExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# nSpikeTrainExamples - -Python-native tutorial page for `nSpikeTrainExamples`. - -## Notebook -- [nSpikeTrainExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nSpikeTrainExamples.ipynb) -- Execution group: `smoke` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/nstCollExamples.md b/docs/help/examples/nstCollExamples.md deleted file mode 100644 index 2a8f89cc..00000000 --- a/docs/help/examples/nstCollExamples.md +++ /dev/null @@ -1,14 +0,0 @@ -# nstCollExamples - -Python-native tutorial page for `nstCollExamples`. - -## Notebook -- [nstCollExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nstCollExamples.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples/publish_all_helpfiles.md b/docs/help/examples/publish_all_helpfiles.md deleted file mode 100644 index 56eb73fa..00000000 --- a/docs/help/examples/publish_all_helpfiles.md +++ /dev/null @@ -1,14 +0,0 @@ -# publish_all_helpfiles - -Python-native tutorial page for `publish_all_helpfiles`. - -## Notebook -- [publish_all_helpfiles.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/publish_all_helpfiles.ipynb) -- Execution group: `full` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` diff --git a/docs/help/examples_index.md b/docs/help/examples_index.md deleted file mode 100644 index 384db28d..00000000 --- a/docs/help/examples_index.md +++ /dev/null @@ -1,37 +0,0 @@ -# Examples Index - -The topics below map clean-room Python workflows to executable notebooks. - -- [AnalysisExamples](examples/AnalysisExamples.md) -- [ConfigCollExamples](examples/ConfigCollExamples.md) -- [CovCollExamples](examples/CovCollExamples.md) -- [CovariateExamples](examples/CovariateExamples.md) -- [DecodingExample](examples/DecodingExample.md) -- [DecodingExampleWithHist](examples/DecodingExampleWithHist.md) -- [EventsExamples](examples/EventsExamples.md) -- [ExplicitStimulusWhiskerData](examples/ExplicitStimulusWhiskerData.md) -- [FitResSummaryExamples](examples/FitResSummaryExamples.md) -- [FitResultExamples](examples/FitResultExamples.md) -- [HippocampalPlaceCellExample](examples/HippocampalPlaceCellExample.md) -- [HistoryExamples](examples/HistoryExamples.md) -- [NetworkTutorial](examples/NetworkTutorial.md) -- [PPSimExample](examples/PPSimExample.md) -- [PPThinning](examples/PPThinning.md) -- [PSTHEstimation](examples/PSTHEstimation.md) -- [SignalObjExamples](examples/SignalObjExamples.md) -- [StimulusDecode2D](examples/StimulusDecode2D.md) -- [TrialConfigExamples](examples/TrialConfigExamples.md) -- [TrialExamples](examples/TrialExamples.md) -- [ValidationDataSet](examples/ValidationDataSet.md) -- [mEPSCAnalysis](examples/mEPSCAnalysis.md) -- [nSTATPaperExamples](examples/nSTATPaperExamples.md) -- [nSpikeTrainExamples](examples/nSpikeTrainExamples.md) -- [nstCollExamples](examples/nstCollExamples.md) -- [AnalysisExamples2](examples/AnalysisExamples2.md) -- [DocumentationSetup2025b](examples/DocumentationSetup2025b.md) -- [FitResultReference](examples/FitResultReference.md) -- [HybridFilterExample](examples/HybridFilterExample.md) -- [publish_all_helpfiles](examples/publish_all_helpfiles.md) - -All notebooks are available in the repository's `notebooks/` directory and are -validated in CI. diff --git a/docs/help/helptoc.yml b/docs/help/helptoc.yml deleted file mode 100644 index 067f9729..00000000 --- a/docs/help/helptoc.yml +++ /dev/null @@ -1,108 +0,0 @@ -root: help/index.md -entries: -- title: Home - target: help/index.md -- title: Class Definitions - target: help/class_definitions.md -- title: Examples Index - target: help/examples_index.md -- title: Paper Overview - target: help/paper_overview.md -- title: Parity Dashboard - target: help/parity_dashboard.md -- title: Classes - children: - - title: SignalObj - target: help/classes/SignalObj.md - - title: Covariate - target: help/classes/Covariate.md - - title: ConfidenceInterval - target: help/classes/ConfidenceInterval.md - - title: Events - target: help/classes/Events.md - - title: History - target: help/classes/History.md - - title: nspikeTrain - target: help/classes/nspikeTrain.md - - title: nstColl - target: help/classes/nstColl.md - - title: CovColl - target: help/classes/CovColl.md - - title: TrialConfig - target: help/classes/TrialConfig.md - - title: ConfigColl - target: help/classes/ConfigColl.md - - title: Trial - target: help/classes/Trial.md - - title: CIF - target: help/classes/CIF.md - - title: Analysis - target: help/classes/Analysis.md - - title: FitResult - target: help/classes/FitResult.md - - title: FitResSummary - target: help/classes/FitResSummary.md - - title: DecodingAlgorithms - target: help/classes/DecodingAlgorithms.md -- title: Examples - children: - - title: AnalysisExamples - target: help/examples/AnalysisExamples.md - - title: ConfigCollExamples - target: help/examples/ConfigCollExamples.md - - title: CovCollExamples - target: help/examples/CovCollExamples.md - - title: CovariateExamples - target: help/examples/CovariateExamples.md - - title: DecodingExample - target: help/examples/DecodingExample.md - - title: DecodingExampleWithHist - target: help/examples/DecodingExampleWithHist.md - - title: EventsExamples - target: help/examples/EventsExamples.md - - title: ExplicitStimulusWhiskerData - target: help/examples/ExplicitStimulusWhiskerData.md - - title: FitResSummaryExamples - target: help/examples/FitResSummaryExamples.md - - title: FitResultExamples - target: help/examples/FitResultExamples.md - - title: HippocampalPlaceCellExample - target: help/examples/HippocampalPlaceCellExample.md - - title: HistoryExamples - target: help/examples/HistoryExamples.md - - title: NetworkTutorial - target: help/examples/NetworkTutorial.md - - title: PPSimExample - target: help/examples/PPSimExample.md - - title: PPThinning - target: help/examples/PPThinning.md - - title: PSTHEstimation - target: help/examples/PSTHEstimation.md - - title: SignalObjExamples - target: help/examples/SignalObjExamples.md - - title: StimulusDecode2D - target: help/examples/StimulusDecode2D.md - - title: TrialConfigExamples - target: help/examples/TrialConfigExamples.md - - title: TrialExamples - target: help/examples/TrialExamples.md - - title: ValidationDataSet - target: help/examples/ValidationDataSet.md - - title: mEPSCAnalysis - target: help/examples/mEPSCAnalysis.md - - title: nSTATPaperExamples - target: help/examples/nSTATPaperExamples.md - - title: nSpikeTrainExamples - target: help/examples/nSpikeTrainExamples.md - - title: nstCollExamples - target: help/examples/nstCollExamples.md - - title: AnalysisExamples2 - target: help/examples/AnalysisExamples2.md - - title: DocumentationSetup2025b - target: help/examples/DocumentationSetup2025b.md - - title: FitResultReference - target: help/examples/FitResultReference.md - - title: HybridFilterExample - target: help/examples/HybridFilterExample.md - - title: publish_all_helpfiles - target: help/examples/publish_all_helpfiles.md diff --git a/docs/help/index.md b/docs/help/index.md deleted file mode 100644 index 48648744..00000000 --- a/docs/help/index.md +++ /dev/null @@ -1,67 +0,0 @@ -# nSTAT-python Help Home - -Welcome to the clean-room Python help system for `nSTAT-python`. - -This site preserves class/workflow structure of MATLAB nSTAT while keeping -all implementation, docs, and tooling Python-specific. - -## Navigation -- [Class Definitions](class_definitions.md) -- [Examples Index](examples_index.md) -- [Paper Overview](paper_overview.md) -- [Parity Dashboard](parity_dashboard.md) - -```{toctree} -:maxdepth: 2 - -class_definitions -examples_index -paper_overview -parity_dashboard -classes/SignalObj -classes/Covariate -classes/ConfidenceInterval -classes/Events -classes/History -classes/nspikeTrain -classes/nstColl -classes/CovColl -classes/TrialConfig -classes/ConfigColl -classes/Trial -classes/CIF -classes/Analysis -classes/FitResult -classes/FitResSummary -classes/DecodingAlgorithms -examples/AnalysisExamples -examples/ConfigCollExamples -examples/CovCollExamples -examples/CovariateExamples -examples/DecodingExample -examples/DecodingExampleWithHist -examples/EventsExamples -examples/ExplicitStimulusWhiskerData -examples/FitResSummaryExamples -examples/FitResultExamples -examples/HippocampalPlaceCellExample -examples/HistoryExamples -examples/NetworkTutorial -examples/PPSimExample -examples/PPThinning -examples/PSTHEstimation -examples/SignalObjExamples -examples/StimulusDecode2D -examples/TrialConfigExamples -examples/TrialExamples -examples/ValidationDataSet -examples/mEPSCAnalysis -examples/nSTATPaperExamples -examples/nSpikeTrainExamples -examples/nstCollExamples -examples/AnalysisExamples2 -examples/DocumentationSetup2025b -examples/FitResultReference -examples/HybridFilterExample -examples/publish_all_helpfiles -``` diff --git a/docs/help/paper_overview.md b/docs/help/paper_overview.md deleted file mode 100644 index 9e4f489f..00000000 --- a/docs/help/paper_overview.md +++ /dev/null @@ -1,20 +0,0 @@ -# Paper Overview and Equation Mapping - -Primary reference: - -- Cajigas I, Malik WQ, Brown EN. nSTAT: Open-source neural spike train analysis toolbox for Matlab. - *Journal of Neuroscience Methods* 211:245-264 (2012). -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` -- PubMed: -- Full text: - -## Equation/Section mapping - -| Python module/class | Mathematical role | Paper mapping | -|---|---|---| -| `nstat.cif.CIFModel` | Conditional intensity models | Sec. 2, Sec. 3 examples | -| `nstat.analysis.Analysis` | GLM fitting and model estimation | Sec. 2.2, Sec. 3 | -| `nstat.history.HistoryBasis` | Spike-history effects | Sec. 2 methodology | -| `nstat.decoding.DecodingAlgorithms` | Decoding and confidence comparisons | Sec. 3.4 workflows | -| `nstat.fit.FitResult`/`FitSummary` | AIC/BIC/log-likelihood summaries | Sec. 2 model assessment | diff --git a/docs/help/parity_dashboard.md b/docs/help/parity_dashboard.md deleted file mode 100644 index 0a337124..00000000 --- a/docs/help/parity_dashboard.md +++ /dev/null @@ -1,67 +0,0 @@ -# Parity Dashboard - -This dashboard summarizes current MATLAB-to-Python parity status from generated -artifacts in the `parity/` directory. - -## Structural parity -| Metric | Value | -|---|---:| -| High gaps | 0 | -| Medium gaps | 0 | -| Low gaps | 0 | -| Total gaps | 0 | - -## Functional parity (methods) -| Metric | Value | -|---|---:| -| Total methods | 501 | -| Contract-verified | 480 | -| Contract-explicit verified | 480 | -| Probe-verified | 0 | -| Excluded methods | 21 | -| Missing symbols | 0 | -| Unverified behavior | 0 | - -## Example parity -| Metric | Value | -|---|---:| -| Total topics | 30 | -| Validated topics | 26 | -| MATLAB doc-only topics | 4 | -| Pending manual review topics | 0 | -| Missing executable topics | 0 | - -### Out-of-scope example topics -- `DocumentationSetup2025b` -- `FitResSummaryExamples` -- `FitResultExamples` -- `FitResultReference` - -## Numeric drift -| Metric | Value | -|---|---:| -| Topics checked | 31 | -| Required notebook topics | 30 | -| Required topics checked | 30 | -| Topics passed | 31 | -| Topics failed | 0 | -| Metrics checked | 146 | -| Metrics failed | 0 | - -## Frozen MATLAB data snapshot -| Metric | Value | -|---|---| -| Snapshot file | `matlab_gold_snapshot_20260302.yml` | -| Snapshot id | `matlab_gold_20260302` | -| Snapshot date | `2026-03-02` | -| Mirror file count | `42` | -| Source manifest SHA256 | `578a20db6433efed11466eb64ab23d77a1f106f3a2da8937c28849511e9385e7` | -| Mirror manifest SHA256 | `b980cb16f5872b53e841f360e9a81a34c9e6b4a5149a9ef3b7fd96314899bfe4` | - -## Artifact links -- [parity_gap_report.json](https://github.com/cajigaslab/nSTAT-python/blob/main/parity/parity_gap_report.json) -- [function_example_alignment_report.json](https://github.com/cajigaslab/nSTAT-python/blob/main/parity/function_example_alignment_report.json) -- [numeric_drift_report.json](https://github.com/cajigaslab/nSTAT-python/blob/main/parity/numeric_drift_report.json) -- [example_output_spec.yml](https://github.com/cajigaslab/nSTAT-python/blob/main/parity/example_output_spec.yml) -- [method_closure_sprint.md](https://github.com/cajigaslab/nSTAT-python/blob/main/parity/method_closure_sprint.md) -- [Full validation report PDF](../assets/reports/nstat_python_validation_report_full_latest.pdf) diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 5d6dcf13..00000000 --- a/docs/index.md +++ /dev/null @@ -1,11 +0,0 @@ -# nSTAT-python Documentation - -This documentation site contains a clean-room Python help system for nSTAT-like workflows. - -```{toctree} -:maxdepth: 2 - -help/index -notebooks -api -``` diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..c1cf8ec2 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,9 @@ +nSTAT Python Documentation +========================== + +Minimal documentation for the standalone Python nSTAT core package. + +.. toctree:: + :maxdepth: 2 + + api diff --git a/docs/notebooks.md b/docs/notebooks.md deleted file mode 100644 index ea25acb5..00000000 --- a/docs/notebooks.md +++ /dev/null @@ -1,34 +0,0 @@ -# Notebook Catalog - -The notebooks below are generated from a clean-room manifest and executed in CI. - -- [AnalysisExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/AnalysisExamples.ipynb) (`smoke`) -- [ConfigCollExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/ConfigCollExamples.ipynb) (`full`) -- [CovCollExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/CovCollExamples.ipynb) (`full`) -- [CovariateExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/CovariateExamples.ipynb) (`smoke`) -- [DecodingExample.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/DecodingExample.ipynb) (`smoke`) -- [DecodingExampleWithHist.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/DecodingExampleWithHist.ipynb) (`smoke`) -- [EventsExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/EventsExamples.ipynb) (`full`) -- [ExplicitStimulusWhiskerData.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/ExplicitStimulusWhiskerData.ipynb) (`full`) -- [FitResSummaryExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/FitResSummaryExamples.ipynb) (`full`) -- [FitResultExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/FitResultExamples.ipynb) (`full`) -- [HippocampalPlaceCellExample.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/HippocampalPlaceCellExample.ipynb) (`full`) -- [HistoryExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/HistoryExamples.ipynb) (`full`) -- [NetworkTutorial.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/NetworkTutorial.ipynb) (`full`) -- [PPSimExample.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/PPSimExample.ipynb) (`smoke`) -- [PPThinning.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/PPThinning.ipynb) (`full`) -- [PSTHEstimation.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/PSTHEstimation.ipynb) (`full`) -- [SignalObjExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/SignalObjExamples.ipynb) (`smoke`) -- [StimulusDecode2D.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/StimulusDecode2D.ipynb) (`full`) -- [TrialConfigExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/TrialConfigExamples.ipynb) (`full`) -- [TrialExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/TrialExamples.ipynb) (`smoke`) -- [ValidationDataSet.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/ValidationDataSet.ipynb) (`full`) -- [mEPSCAnalysis.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/mEPSCAnalysis.ipynb) (`full`) -- [nSTATPaperExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nSTATPaperExamples.ipynb) (`smoke`) -- [nSpikeTrainExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nSpikeTrainExamples.ipynb) (`smoke`) -- [nstCollExamples.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/nstCollExamples.ipynb) (`full`) -- [AnalysisExamples2.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/AnalysisExamples2.ipynb) (`full`) -- [DocumentationSetup2025b.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/DocumentationSetup2025b.ipynb) (`full`) -- [FitResultReference.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/FitResultReference.ipynb) (`full`) -- [HybridFilterExample.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/HybridFilterExample.ipynb) (`full`) -- [publish_all_helpfiles.ipynb](https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks/publish_all_helpfiles.ipynb) (`full`) diff --git a/docs/repo_split_status.rst b/docs/repo_split_status.rst new file mode 100644 index 00000000..1afe51fb --- /dev/null +++ b/docs/repo_split_status.rst @@ -0,0 +1,57 @@ +Repo Split Status +================= + +Scope +----- + +This document tracks readiness for splitting the current monorepo into: + +- ``nSTAT`` (MATLAB-focused repository) +- ``nSTAT-python`` (Python-focused repository) + +Inventory Source +---------------- + +Generated via: + +.. code-block:: bash + + python3 tools/generate_repo_split_inventory.py + +Output directory: + +- ``python/reports/repo_split_inventory`` +- ``reports/repo_split_inventory`` + +Current Snapshot +---------------- + +- TOC topics: 31 +- TOC example topics: 25 +- Python docs coverage (TOC topics): 31/31 +- Python notebook coverage (TOC topics): 29/31 +- Python example script coverage (TOC examples): 25/25 +- Python example full coverage (docs + notebook + script): 25/25 +- MATLAB example topics with ``.mlx``: 18/25 + +MATLAB MLX Gaps +--------------- + +The following example topics currently do not have a matching ``helpfiles/.mlx``: + +- ``ExplicitStimulusWhiskerData`` +- ``NetworkTutorial`` +- ``PPThinning`` +- ``PSTHEstimation`` +- ``StimulusDecode2D`` +- ``ValidationDataSet`` +- ``mEPSCAnalysis`` + +Immediate Next Actions +---------------------- + +1. Keep ``nSTAT`` as source-of-truth for MATLAB ``helpfiles`` and create missing ``.mlx`` examples for the 7 topics above. +2. Keep ``nSTAT-python`` standalone and run parity/docs/notebook CI in this repository. +3. Update cross-repo README links: + - ``nSTAT`` -> points Python users to ``nSTAT-python``. + - ``nSTAT-python`` -> points MATLAB users to ``nSTAT``. diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..cfffe48b --- /dev/null +++ b/examples/README.md @@ -0,0 +1,17 @@ +# Python nSTAT Examples + +## Basic examples + +```bash +python3 examples/basic_data_workflow.py +python3 examples/fit_poisson_glm.py +python3 examples/simulate_population_psth.py +``` + +## Paper-style example workflow + +```bash +python3 examples/nstat_paper_examples.py --repo-root .. +``` + +This mirrors key analyses described in the nSTAT paper using the bundled Python APIs. diff --git a/examples/basic_data_workflow.py b/examples/basic_data_workflow.py new file mode 100644 index 00000000..47d27d5c --- /dev/null +++ b/examples/basic_data_workflow.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +from pathlib import Path +import sys + +import numpy as np + +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from nstat import Covariate, psth, simulate_cif_from_stimulus # noqa: E402 + + +def main() -> None: + rng = np.random.default_rng(42) + t = np.arange(0.0, 20.0, 0.001) + stim = np.sin(2.0 * np.pi * 2.0 * t) + + stimulus = Covariate(time=t, values=stim, name="sin_2hz", units="a.u.") + spike_train, rate_hz, _ = simulate_cif_from_stimulus( + time=stimulus.time, stimulus=stimulus.values, beta0=-1.7, beta1=0.9, rng=rng + ) + + edges = np.arange(0.0, 20.0 + 0.25, 0.25) + mean_rate_hz, counts = psth([spike_train], edges) + + print("Example: basic_data_workflow") + print(f"Duration (s): {spike_train.duration:.3f}") + print(f"Spikes: {spike_train.n_spikes}") + print(f"Mean simulated rate (Hz): {rate_hz.mean():.3f}") + print(f"PSTH bins: {counts.shape[1]}") + print(f"PSTH first 5 rates (Hz): {np.round(mean_rate_hz[:5], 3)}") + + +if __name__ == "__main__": + main() diff --git a/examples/fit_poisson_glm.py b/examples/fit_poisson_glm.py new file mode 100644 index 00000000..5fb9eb15 --- /dev/null +++ b/examples/fit_poisson_glm.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +from pathlib import Path +import sys + +import numpy as np + +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from nstat import fit_poisson_glm, simulate_cif_from_stimulus # noqa: E402 + + +def main() -> None: + rng = np.random.default_rng(123) + t = np.arange(0.0, 60.0, 0.001) + stim = np.sin(2.0 * np.pi * 1.0 * t) + + true_beta0 = -2.4 + true_beta1 = 0.9 + spikes, _, _ = simulate_cif_from_stimulus( + time=t, stimulus=stim, beta0=true_beta0, beta1=true_beta1, rng=rng + ) + bin_width = 0.01 + edges = np.arange(0.0, 60.0 + bin_width, bin_width) + y = spikes.to_binned_counts(edges) + + samples_per_bin = int(round(bin_width / (t[1] - t[0]))) + x = stim.reshape(-1, samples_per_bin).mean(axis=1)[:, None] + offset = np.full(y.shape, np.log(bin_width)) + + fit = fit_poisson_glm(x, y, offset=offset, l2=1e-4, max_iter=80, tol=1e-9) + + print("Example: fit_poisson_glm") + print(f"True intercept: {true_beta0:.4f}") + print(f"Estimated intercept: {fit.intercept:.4f}") + print(f"True stim beta: {true_beta1:.4f}") + print(f"Estimated stim beta: {fit.coefficients[0]:.4f}") + print(f"Converged: {fit.converged} in {fit.n_iter} iterations") + print(f"Log-likelihood: {fit.log_likelihood:.4f}") + + +if __name__ == "__main__": + main() diff --git a/examples/nSTATPaperExamples.py b/examples/nSTATPaperExamples.py new file mode 100644 index 00000000..f02d46b1 --- /dev/null +++ b/examples/nSTATPaperExamples.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +import sys +from pathlib import Path + +THIS_DIR = Path(__file__).resolve().parent +PKG_ROOT = THIS_DIR.parent +if str(PKG_ROOT) not in sys.path: + sys.path.insert(0, str(PKG_ROOT)) + +from nstat.paper_examples_full import main + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/nSTATPaperExamples/manifest.yml b/examples/nSTATPaperExamples/manifest.yml new file mode 100644 index 00000000..7eb4d9ff --- /dev/null +++ b/examples/nSTATPaperExamples/manifest.yml @@ -0,0 +1,92 @@ +version: 1 +examples: +- name: AnalysisExamples + relative_path: notebooks/AnalysisExamples.ipynb + description: Notebook generated from MATLAB help source for AnalysisExamples. +- name: ConfigCollExamples + relative_path: notebooks/ConfigCollExamples.ipynb + description: Notebook generated from MATLAB help source for ConfigCollExamples. +- name: CovCollExamples + relative_path: notebooks/CovCollExamples.ipynb + description: Notebook generated from MATLAB help source for CovCollExamples. +- name: CovariateExamples + relative_path: notebooks/CovariateExamples.ipynb + description: Notebook generated from MATLAB help source for CovariateExamples. +- name: DecodingExample + relative_path: notebooks/DecodingExample.ipynb + description: Notebook generated from MATLAB help source for DecodingExample. +- name: DecodingExampleWithHist + relative_path: notebooks/DecodingExampleWithHist.ipynb + description: Notebook generated from MATLAB help source for DecodingExampleWithHist. +- name: EventsExamples + relative_path: notebooks/EventsExamples.ipynb + description: Notebook generated from MATLAB help source for EventsExamples. +- name: ExplicitStimulusWhiskerData + relative_path: notebooks/ExplicitStimulusWhiskerData.ipynb + description: Notebook generated from MATLAB help source for ExplicitStimulusWhiskerData. +- name: FitResSummaryExamples + relative_path: notebooks/FitResSummaryExamples.ipynb + description: Notebook generated from MATLAB help source for FitResSummaryExamples. +- name: FitResultExamples + relative_path: notebooks/FitResultExamples.ipynb + description: Notebook generated from MATLAB help source for FitResultExamples. +- name: HippocampalPlaceCellExample + relative_path: notebooks/HippocampalPlaceCellExample.ipynb + description: Notebook generated from MATLAB help source for HippocampalPlaceCellExample. +- name: HistoryExamples + relative_path: notebooks/HistoryExamples.ipynb + description: Notebook generated from MATLAB help source for HistoryExamples. +- name: NetworkTutorial + relative_path: notebooks/NetworkTutorial.ipynb + description: Notebook generated from MATLAB help source for NetworkTutorial. +- name: PPSimExample + relative_path: notebooks/PPSimExample.ipynb + description: Notebook generated from MATLAB help source for PPSimExample. +- name: PPThinning + relative_path: notebooks/PPThinning.ipynb + description: Notebook generated from MATLAB help source for PPThinning. +- name: PSTHEstimation + relative_path: notebooks/PSTHEstimation.ipynb + description: Notebook generated from MATLAB help source for PSTHEstimation. +- name: SignalObjExamples + relative_path: notebooks/SignalObjExamples.ipynb + description: Notebook generated from MATLAB help source for SignalObjExamples. +- name: StimulusDecode2D + relative_path: notebooks/StimulusDecode2D.ipynb + description: Notebook generated from MATLAB help source for StimulusDecode2D. +- name: TrialConfigExamples + relative_path: notebooks/TrialConfigExamples.ipynb + description: Notebook generated from MATLAB help source for TrialConfigExamples. +- name: TrialExamples + relative_path: notebooks/TrialExamples.ipynb + description: Notebook generated from MATLAB help source for TrialExamples. +- name: ValidationDataSet + relative_path: notebooks/ValidationDataSet.ipynb + description: Notebook generated from MATLAB help source for ValidationDataSet. +- name: mEPSCAnalysis + relative_path: notebooks/mEPSCAnalysis.ipynb + description: Notebook generated from MATLAB help source for mEPSCAnalysis. +- name: nSTATPaperExamples + relative_path: notebooks/nSTATPaperExamples.ipynb + description: Notebook generated from MATLAB help source for nSTATPaperExamples. +- name: nSpikeTrainExamples + relative_path: notebooks/nSpikeTrainExamples.ipynb + description: Notebook generated from MATLAB help source for nSpikeTrainExamples. +- name: nstCollExamples + relative_path: notebooks/nstCollExamples.ipynb + description: Notebook generated from MATLAB help source for nstCollExamples. +- name: AnalysisExamples2 + relative_path: notebooks/AnalysisExamples2.ipynb + description: Notebook generated from MATLAB help source for AnalysisExamples2. +- name: DocumentationSetup2025b + relative_path: notebooks/DocumentationSetup2025b.ipynb + description: Notebook generated from MATLAB help source for DocumentationSetup2025b. +- name: FitResultReference + relative_path: notebooks/FitResultReference.ipynb + description: Notebook generated from MATLAB help source for FitResultReference. +- name: HybridFilterExample + relative_path: notebooks/HybridFilterExample.ipynb + description: Notebook generated from MATLAB help source for HybridFilterExample. +- name: publish_all_helpfiles + relative_path: notebooks/publish_all_helpfiles.ipynb + description: Notebook generated from MATLAB help source for publish_all_helpfiles. diff --git a/examples/nstat_paper_examples.py b/examples/nstat_paper_examples.py new file mode 100644 index 00000000..12ad4713 --- /dev/null +++ b/examples/nstat_paper_examples.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +import sys +from pathlib import Path + +# Ensure local package import works when run directly. +THIS_DIR = Path(__file__).resolve().parent +PKG_ROOT = THIS_DIR.parent +if str(PKG_ROOT) not in sys.path: + sys.path.insert(0, str(PKG_ROOT)) + +from nstat.paper_examples import main + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/simulate_population_psth.py b/examples/simulate_population_psth.py new file mode 100644 index 00000000..f472c3e8 --- /dev/null +++ b/examples/simulate_population_psth.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +from pathlib import Path +import sys + +import numpy as np + +ROOT = Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from nstat import psth, simulate_cif_from_stimulus # noqa: E402 + + +def main() -> None: + rng = np.random.default_rng(7) + t = np.arange(0.0, 20.0, 0.001) + stim = np.sin(2.0 * np.pi * 1.5 * t) + + trials = [] + n_trials = 20 + for _ in range(n_trials): + spikes, _, _ = simulate_cif_from_stimulus( + time=t, stimulus=stim, beta0=-2.0, beta1=1.1, rng=rng + ) + trials.append(spikes) + + edges = np.arange(0.0, 20.0 + 0.1, 0.1) + mean_rate_hz, counts = psth(trials, edges) + + print("Example: simulate_population_psth") + print(f"Trials: {n_trials}") + print(f"Total spikes: {int(counts.sum())}") + print(f"Average rate over all bins (Hz): {mean_rate_hz.mean():.3f}") + print(f"Peak bin rate (Hz): {mean_rate_hz.max():.3f}") + + +if __name__ == "__main__": + main() diff --git a/helpfiles/helptoc.xml b/helpfiles/helptoc.xml new file mode 100644 index 00000000..5314082e --- /dev/null +++ b/helpfiles/helptoc.xml @@ -0,0 +1,41 @@ + + + nSTAT Neural Spike Train Analysis Toolbox + Overview + MATLAB 2025b Help Integration + + Class Definitions + SignalObj Reference + FitResult Reference + + Examples + Using the SignalObj Class + Using the Covariate Class + Using the CovColl Class + Using the nSpikeTrain Class + Using the nstColl Class + Using the Events Class + Using the History Class + Using the Trial Class + Using the TrialConfig Class + Using the ConfigColl Class + Using the Analysis Class + Using the FitResult Class + Using the FitResSummary Class + Point Process Simulation via Thinning + Example Data Analysis - Simulated Data - Computing a Peri-Stimulus Time Histogram (PSTH) + Example Data Analysis - Simulated Constant (Piecewise Constant) Rate Poisson + Example Data Analysis - Miniature Excitatory Post-Synaptic Currents (mEPSCs) + Example Data Analysis - Simulated Explicit Stimulus and History + Example Data Analysis - Explicit Stimulus + Example Data Analysis - Hippocampal Place Cell Receptive Field Estimation + Example Data Analysis - Decoding Univariate Simulated Stimuli (No History Effect) + Example Data Analysis - Decoding Univariate Simulated Stimuli with and without History Effect + Example Data Analysis - Decoding Bivariate Simulated Stimuli + Example Data Analysis - Two Neuron Network Simulation and Estimation of Ensemble Effect + nSTAT Paper Examples + + + Neuroscience Statistics Research Laboratory + + diff --git a/helpfiles/paperHybridFilterExample.mat b/helpfiles/paperHybridFilterExample.mat new file mode 100644 index 00000000..355e2232 Binary files /dev/null and b/helpfiles/paperHybridFilterExample.mat differ diff --git a/matlab/benchmark/run_matlab_performance_benchmarks.m b/matlab/benchmark/run_matlab_performance_benchmarks.m deleted file mode 100644 index bed48236..00000000 --- a/matlab/benchmark/run_matlab_performance_benchmarks.m +++ /dev/null @@ -1,314 +0,0 @@ -function run_matlab_performance_benchmarks(outputJson, outputCsv, nstatRoot) -%RUN_MATLAB_PERFORMANCE_BENCHMARKS Build MATLAB baseline performance report. -% -% Usage: -% run_matlab_performance_benchmarks(outputJson, outputCsv, nstatRoot) -% -% Inputs: -% outputJson - JSON report path -% outputCsv - CSV report path -% nstatRoot - path to MATLAB nSTAT source repo - -if nargin < 1 || isempty(outputJson) - outputJson = fullfile(pwd, 'output', 'performance', 'matlab_performance_report.json'); -end -if nargin < 2 || isempty(outputCsv) - outputCsv = fullfile(pwd, 'output', 'performance', 'matlab_performance_report.csv'); -end -if nargin < 3 || isempty(nstatRoot) - nstatRoot = getenv('NSTAT_MATLAB_ROOT'); -end -if isempty(nstatRoot) - error('nstatRoot is required (arg 3 or NSTAT_MATLAB_ROOT env var).'); -end -if exist(nstatRoot, 'dir') ~= 7 - error('nSTAT root does not exist: %s', nstatRoot); -end - -addpath(nstatRoot, '-begin'); - -[jsonDir, ~, ~] = fileparts(outputJson); -[csvDir, ~, ~] = fileparts(outputCsv); -if exist(jsonDir, 'dir') ~= 7 - mkdir(jsonDir); -end -if exist(csvDir, 'dir') ~= 7 - mkdir(csvDir); -end - -cases = {'unit_impulse_basis', 'covariate_resample', 'history_design_matrix', 'simulate_cif_thinning', 'decoding_spike_rate_cis'}; -tiers = {'S', 'M', 'L'}; -repeats = 7; -warmup = 2; -seedBase = 20260303; -rows = {}; - -for iCase = 1:numel(cases) - for iTier = 1:numel(tiers) - caseName = cases{iCase}; - tierName = tiers{iTier}; - runtimesMs = zeros(1, repeats); - memoryMb = zeros(1, repeats); - summary = struct(); - - for rep = 1:(warmup + repeats) - rng(seedBase + rep, 'twister'); - tStart = tic; - summary = run_case(caseName, tierName); - elapsedMs = toc(tStart) * 1000; - - if rep > warmup - idx = rep - warmup; - runtimesMs(idx) = elapsedMs; - if isfield(summary, 'memory_proxy_mb') - memoryMb(idx) = summary.memory_proxy_mb; - else - memoryMb(idx) = NaN; - end - end - end - - row = struct(); - row.case = caseName; - row.tier = tierName; - row.repeats = repeats; - row.warmup = warmup; - row.median_runtime_ms = median(runtimesMs); - row.mean_runtime_ms = mean(runtimesMs); - row.std_runtime_ms = std(runtimesMs); - row.median_peak_memory_mb = median(memoryMb); - row.summary = summary; - row.samples_runtime_ms = runtimesMs; - row.samples_peak_memory_mb = memoryMb; - rows{end + 1} = row; %#ok - end -end - -report.schema_version = 1; -report.generated_at_utc = char(datetime('now', 'TimeZone', 'UTC', 'Format', 'yyyy-MM-dd''T''HH:mm:ss''Z''')); -report.implementation = 'matlab'; -report.nstat_root = nstatRoot; -report.reference_sha = resolve_git_sha(nstatRoot); -report.tiers = tiers; -report.cases = rows; -report.environment = collect_environment(); - -jsonText = jsonencode(report, 'PrettyPrint', true); -fid = fopen(outputJson, 'w'); -if fid < 0 - error('Failed to open output JSON for write: %s', outputJson); -end -fwrite(fid, jsonText, 'char'); -fclose(fid); - -write_csv(rows, outputCsv); - -fprintf('Wrote MATLAB performance JSON: %s\n', outputJson); -fprintf('Wrote MATLAB performance CSV: %s\n', outputCsv); -fprintf('Benchmarked case-tier pairs: %d\n', numel(rows)); -end - -function summary = run_case(caseName, tier) -cfg = get_case_config(caseName, tier); - -switch caseName - case 'unit_impulse_basis' - basis = nstColl.generateUnitImpulseBasis(cfg.basis_width_s, 0.0, cfg.max_time_s, cfg.sample_rate_hz); - mat = basis.data; - summary.rows = size(mat, 1); - summary.cols = size(mat, 2); - summary.total_mass = sum(mat(:)); - summary.memory_proxy_mb = bytes_to_mb(whos('mat')); - - case 'covariate_resample' - t = linspace(0.0, cfg.duration_s, cfg.n_grid)'; - y = sin(2.0 * pi * 3.0 * t) + 0.2 * cos(2.0 * pi * 9.0 * t); - stim = Covariate(t, y, 'Stimulus', 'time', 's', 'V', {'stim'}); - stimRes = stim.resample(cfg.sample_rate_hz); - mat = stimRes.data; - summary.rows = size(mat, 1); - summary.cols = size(mat, 2); - summary.signal_energy = mean(mat(:, 1) .^ 2); - summary.memory_proxy_mb = bytes_to_mb(whos('mat')); - - case 'history_design_matrix' - spikeTimes = deterministic_spike_times(cfg.n_spikes, cfg.duration_s); - tn = linspace(0.0, cfg.duration_s, cfg.n_grid)'; - histObj = History([0.0, 0.01, 0.02, 0.05, 0.10], 0.0, cfg.duration_s); - nst = nspikeTrain(spikeTimes); - nst.setMinTime(0.0); - nst.setMaxTime(cfg.duration_s); - cov = histObj.computeHistory(nst, [], tn); - mat = cov.dataToMatrix(); - summary.rows = size(mat, 1); - summary.cols = size(mat, 2); - summary.total_count = sum(mat(:)); - summary.memory_proxy_mb = bytes_to_mb(whos('mat')); - - case 'simulate_cif_thinning' - t = linspace(0.0, cfg.duration_s, floor(cfg.duration_s * 1000) + 1)'; - lam = 12.0 + 8.0 * sin(2.0 * pi * 3.0 * t); - lam(lam < 0.2) = 0.2; - lambdaCov = Covariate(t, lam, 'Lambda', 'time', 's', 'Hz', {'lambda'}); - coll = CIF.simulateCIFByThinningFromLambda(lambdaCov, cfg.n_realizations, cfg.max_time_res_s); - totalSpikes = 0; - for i = 1:coll.numSpikeTrains - totalSpikes = totalSpikes + numel(coll.getNST(i).getSpikeTimes()); - end - summary.num_units = coll.numSpikeTrains; - summary.total_spikes = totalSpikes; - summary.mean_spikes_per_unit = totalSpikes / max(coll.numSpikeTrains, 1); - summary.memory_proxy_mb = bytes_to_mb(whos('lam')); - - case 'decoding_spike_rate_cis' - [xK, Wku, dN] = deterministic_decode_inputs(cfg); - t0 = 0.0; - tf = (cfg.n_bins - 1) * cfg.decode_delta_s; - [spikeRateSig, probMat, sigMat] = DecodingAlgorithms.computeSpikeRateCIs( ... - xK, Wku, dN, t0, tf, 'binomial', cfg.decode_delta_s, 0.0, [], cfg.mc_draws, 0.05); - rate = spikeRateSig.data; - summary.num_trials = size(probMat, 1); - summary.prob_mean = mean(probMat(:)); - summary.sig_count = sum(sigMat(:)); - summary.rate_mean = mean(rate(:)); - summary.memory_proxy_mb = bytes_to_mb(whos('probMat')); - - otherwise - error('Unknown benchmark case: %s', caseName); -end -end - -function cfg = get_case_config(caseName, tier) -switch caseName - case 'unit_impulse_basis' - switch tier - case 'S' - cfg.max_time_s = 1.0; cfg.sample_rate_hz = 500.0; - case 'M' - cfg.max_time_s = 2.0; cfg.sample_rate_hz = 1000.0; - case 'L' - cfg.max_time_s = 4.0; cfg.sample_rate_hz = 1500.0; - otherwise - error('Unknown tier: %s', tier); - end - cfg.basis_width_s = 0.02; - - case 'covariate_resample' - switch tier - case 'S' - cfg.duration_s = 2.0; cfg.n_grid = 2001; cfg.sample_rate_hz = 500.0; - case 'M' - cfg.duration_s = 4.0; cfg.n_grid = 4001; cfg.sample_rate_hz = 750.0; - case 'L' - cfg.duration_s = 6.0; cfg.n_grid = 6001; cfg.sample_rate_hz = 1000.0; - otherwise - error('Unknown tier: %s', tier); - end - - case 'history_design_matrix' - switch tier - case 'S' - cfg.n_spikes = 200; cfg.n_grid = 1000; cfg.duration_s = 2.0; - case 'M' - cfg.n_spikes = 1000; cfg.n_grid = 5000; cfg.duration_s = 2.0; - case 'L' - cfg.n_spikes = 3000; cfg.n_grid = 10000; cfg.duration_s = 2.0; - otherwise - error('Unknown tier: %s', tier); - end - - case 'simulate_cif_thinning' - switch tier - case 'S' - cfg.duration_s = 1.0; cfg.n_realizations = 5; cfg.max_time_res_s = 0.001; - case 'M' - cfg.duration_s = 2.0; cfg.n_realizations = 10; cfg.max_time_res_s = 0.001; - case 'L' - cfg.duration_s = 3.0; cfg.n_realizations = 20; cfg.max_time_res_s = 0.001; - otherwise - error('Unknown tier: %s', tier); - end - - case 'decoding_spike_rate_cis' - switch tier - case 'S' - cfg.num_basis = 4; cfg.num_trials = 6; cfg.n_bins = 120; cfg.mc_draws = 30; - case 'M' - cfg.num_basis = 6; cfg.num_trials = 8; cfg.n_bins = 200; cfg.mc_draws = 50; - case 'L' - cfg.num_basis = 8; cfg.num_trials = 12; cfg.n_bins = 320; cfg.mc_draws = 80; - otherwise - error('Unknown tier: %s', tier); - end - cfg.decode_delta_s = 0.01; - - otherwise - error('Unknown benchmark case: %s', caseName); -end -end - -function spikes = deterministic_spike_times(nSpikes, duration_s) -idx = (1:nSpikes)'; -phi = 0.6180339887498949; -spikes = mod(idx .* phi, 1.0) .* duration_s; -spikes = sort(spikes); -end - -function [xK, Wku, dN] = deterministic_decode_inputs(cfg) -[basisGrid, trialGrid] = ndgrid(1:cfg.num_basis, 1:cfg.num_trials); -xK = 0.06 * sin(0.37 * (basisGrid .* trialGrid)) + 0.04 * cos(0.19 * (basisGrid .* trialGrid)); - -Wku = zeros(cfg.num_basis, cfg.num_basis, cfg.num_trials, cfg.num_trials); -for r = 1:cfg.num_basis - Wku(r, r, :, :) = 0.05 * eye(cfg.num_trials); -end - -grid = reshape(0:(cfg.num_trials * cfg.n_bins - 1), cfg.num_trials, cfg.n_bins); -dN = double((sin(0.173 * grid) + cos(0.037 * grid)) > 1.15); -end - -function value = bytes_to_mb(whosStruct) -if isempty(whosStruct) - value = NaN; -else - value = double(whosStruct.bytes) / (1024.0 * 1024.0); -end -end - -function sha = resolve_git_sha(repoRoot) -sha = 'unknown'; -[status, out] = system(sprintf('git -C "%s" rev-parse HEAD', repoRoot)); -if status == 0 - sha = strtrim(out); -end -end - -function env = collect_environment() -env.matlab_version = version; -env.matlab_release = version('-release'); -env.os = computer; -try - env.blas = version('-blas'); -catch - env.blas = ''; -end -env.omp_num_threads = getenv('OMP_NUM_THREADS'); -env.mkl_num_threads = getenv('MKL_NUM_THREADS'); -env.openblas_num_threads = getenv('OPENBLAS_NUM_THREADS'); -end - -function write_csv(rows, outCsv) -fid = fopen(outCsv, 'w'); -if fid < 0 - error('Failed to open CSV output: %s', outCsv); -end -fprintf(fid, 'case,tier,repeats,median_runtime_ms,mean_runtime_ms,std_runtime_ms,median_peak_memory_mb,summary\n'); -for i = 1:numel(rows) - row = rows{i}; - summaryText = strrep(jsonencode(row.summary), '"', '""'); - fprintf(fid, '%s,%s,%d,%.9f,%.9f,%.9f,%.9f,"%s"\n', ... - row.case, row.tier, row.repeats, row.median_runtime_ms, ... - row.mean_runtime_ms, row.std_runtime_ms, row.median_peak_memory_mb, summaryText); -end -fclose(fid); -end diff --git a/matlab/fixture_gen/export_helpfile_figures.m b/matlab/fixture_gen/export_helpfile_figures.m new file mode 100644 index 00000000..39bd7ec0 --- /dev/null +++ b/matlab/fixture_gen/export_helpfile_figures.m @@ -0,0 +1,151 @@ +function export_helpfile_figures(manifestJsonPath, outputRoot, reportJsonPath) +% Export helpfile figures in strict fig_### order for parity checks. +% +% Inputs: +% manifestJsonPath - JSON with `topics` entries containing: +% topic, source_path, source_type, expected_figure_count +% outputRoot - destination root for /fig_###.png +% reportJsonPath - output JSON report path + +if nargin < 3 + error('export_helpfile_figures:InvalidArgs', ... + 'Usage: export_helpfile_figures(manifestJsonPath, outputRoot, reportJsonPath)'); +end + +manifestJsonPath = char(manifestJsonPath); +outputRoot = char(outputRoot); +reportJsonPath = char(reportJsonPath); + +if ~exist(manifestJsonPath, 'file') + error('export_helpfile_figures:MissingManifest', ... + 'Manifest JSON not found: %s', manifestJsonPath); +end + +manifestPayload = jsondecode(fileread(manifestJsonPath)); +topics = manifestPayload.topics; +if ~isstruct(topics) + error('export_helpfile_figures:InvalidManifest', ... + 'Expected manifest.topics to be a struct array.'); +end + +if ~exist(outputRoot, 'dir') + mkdir(outputRoot); +end + +% Add source roots to path so script-local dependencies resolve. +sourceRoots = {}; +for i = 1:numel(topics) + sourcePath = char(topics(i).source_path); + helpDir = fileparts(sourcePath); + toolboxRoot = fileparts(helpDir); + if ~any(strcmp(sourceRoots, toolboxRoot)) + sourceRoots{end+1} = toolboxRoot; %#ok + end +end +for i = 1:numel(sourceRoots) + addpath(genpath(sourceRoots{i})); +end + +reportRows = repmat(struct( ... + 'topic', '', ... + 'source_path', '', ... + 'source_type', '', ... + 'expected_figures', 0, ... + 'produced_figures', 0, ... + 'status', '', ... + 'error', ''), numel(topics), 1); + +for i = 1:numel(topics) + topic = char(topics(i).topic); + sourcePath = char(topics(i).source_path); + sourceType = char(topics(i).source_type); + expectedFigures = double(topics(i).expected_figure_count); + outDir = fullfile(outputRoot, topic); + + if exist(outDir, 'dir') + rmdir(outDir, 's'); + end + mkdir(outDir); + + close all force; + drawnow; + + reportRows(i).topic = topic; + reportRows(i).source_path = sourcePath; + reportRows(i).source_type = sourceType; + reportRows(i).expected_figures = expectedFigures; + + try + if strcmpi(sourceType, 'mlx') + convertedPath = fullfile(tempdir(), [topic '__converted__.m']); + if exist(convertedPath, 'file') + delete(convertedPath); + end + matlab.internal.liveeditor.openAndConvert(sourcePath, convertedPath); + run_script_in_base(convertedPath); + else + run_script_in_base(sourcePath); + end + + figs = findall(groot, 'Type', 'figure'); + if isempty(figs) + produced = 0; + else + figNums = arrayfun(@(h) h.Number, figs); + [~, order] = sort(figNums); + figs = figs(order); + produced = numel(figs); + for j = 1:produced + outFile = fullfile(outDir, sprintf('fig_%03d.png', j)); + try + exportgraphics(figs(j), outFile, 'Resolution', 180); + catch + % Fallback for older MATLAB releases. + saveas(figs(j), outFile); + end + end + end + + reportRows(i).produced_figures = produced; + if produced == expectedFigures + reportRows(i).status = 'ok'; + else + reportRows(i).status = 'count_mismatch'; + reportRows(i).error = sprintf('produced=%d expected=%d', produced, expectedFigures); + end + catch ME + reportRows(i).status = 'error'; + reportRows(i).produced_figures = 0; + reportRows(i).error = ME.message; + end + + close all force; + evalin('base', 'clearvars'); + drawnow; +end + +report = struct(); +report.generated_utc = char(datetime('now', 'TimeZone', 'UTC', ... + 'Format', 'yyyy-MM-dd''T''HH:mm:ss''Z''')); +report.output_root = outputRoot; +report.topic_count = numel(topics); +report.results = reportRows; + +reportDir = fileparts(reportJsonPath); +if ~isempty(reportDir) && ~exist(reportDir, 'dir') + mkdir(reportDir); +end +fid = fopen(reportJsonPath, 'w'); +if fid < 0 + error('export_helpfile_figures:ReportWriteFailed', ... + 'Could not open report output path: %s', reportJsonPath); +end +cleanupObj = onCleanup(@() fclose(fid)); +fprintf(fid, '%s', jsonencode(report, 'PrettyPrint', true)); + +end + +function run_script_in_base(scriptPath) +scriptEscaped = strrep(scriptPath, '''', ''''''); +evalin('base', sprintf('run(''%s'');', scriptEscaped)); +end diff --git a/matlab/fixtures/export_class_equivalence_fixtures.m b/matlab/fixtures/export_class_equivalence_fixtures.m deleted file mode 100644 index 35625557..00000000 --- a/matlab/fixtures/export_class_equivalence_fixtures.m +++ /dev/null @@ -1,195 +0,0 @@ -function export_class_equivalence_fixtures(nstatRoot, outRoot) -%EXPORT_CLASS_EQUIVALENCE_FIXTURES Create MATLAB-gold fixtures for class contracts. -% export_class_equivalence_fixtures(nstatRoot, outRoot) -% -% Inputs -% nstatRoot - path to MATLAB nSTAT source-of-truth repo -% outRoot - output root where class fixture .mat files are written -% -% Notes -% - This script is deterministic (rng fixed). -% - It writes compact fixtures used by Python class-contract tests. - -if nargin < 1 || isempty(nstatRoot) - envRoot = getenv('NSTAT_MATLAB_ROOT'); - if isempty(envRoot) - error(['nstatRoot not provided. Pass source root explicitly or set ', ... - 'NSTAT_MATLAB_ROOT environment variable.']); - end - nstatRoot = envRoot; -end - -if nargin < 2 || isempty(outRoot) - here = fileparts(mfilename('fullpath')); - outRoot = fullfile(here, '..', '..', 'tests', 'parity', 'fixtures', 'matlab_gold', 'classes'); -end - -if exist(nstatRoot, 'dir') ~= 7 - error('nstatRoot does not exist: %s', nstatRoot); -end - -addpath(nstatRoot); -rng(0, 'twister'); - -if exist(outRoot, 'dir') ~= 7 - mkdir(outRoot); -end - -write_confidence_interval_fixture(outRoot); -write_trialconfig_fixture(outRoot); -write_configcoll_fixture(outRoot); -write_cif_fixture(outRoot); -write_fitresult_and_summary_fixtures(outRoot); - -fprintf('Wrote class fixtures to %s\n', outRoot); -end - -function write_confidence_interval_fixture(outRoot) -classDir = fullfile(outRoot, 'ConfidenceInterval'); -if exist(classDir, 'dir') ~= 7 - mkdir(classDir); -end - -time = (0:0.25:1.0)'; -ci_data = [time, time + 0.5]; -ci = ConfidenceInterval(time, ci_data, 'CI', 'time', 's', 'a.u.', {'low', 'high'}); -ci.setColor('r'); -ci.setValue(0.90); - -width = ci_data(:, 2) - ci_data(:, 1); -ci_color = ci.color; -ci_value = ci.value; - -save(fullfile(classDir, 'basic.mat'), ... - 'time', 'ci_data', 'width', 'ci_color', 'ci_value', '-v7'); -end - -function write_trialconfig_fixture(outRoot) -classDir = fullfile(outRoot, 'TrialConfig'); -if exist(classDir, 'dir') ~= 7 - mkdir(classDir); -end - -tc = TrialConfig({'stim'}, 1000, [], [], [], 0, 'cfg'); -tc_struct = tc.toStructure; -tc_roundtrip = TrialConfig.fromStructure(tc_struct); - -tc_name = tc.getName; -tc_sample_rate = tc.sampleRate; -tc_cov_mask = tc.covMask; -tc_cov_lag = tc.covLag; -tc_roundtrip_name = tc_roundtrip.getName; -tc_roundtrip_sample_rate = tc_roundtrip.sampleRate; - -save(fullfile(classDir, 'basic.mat'), ... - 'tc_name', 'tc_sample_rate', 'tc_cov_mask', 'tc_cov_lag', ... - 'tc_roundtrip_name', 'tc_roundtrip_sample_rate', '-v7'); -end - -function write_configcoll_fixture(outRoot) -classDir = fullfile(outRoot, 'ConfigColl'); -if exist(classDir, 'dir') ~= 7 - mkdir(classDir); -end - -tc1 = TrialConfig({'stim'}, 1000, [], [], [], 0, 'cfg1'); -tc2 = TrialConfig({'stim2'}, 500, [], [], [], 0, 'cfg2'); -cc = ConfigColl({tc1, tc2}); -names = cc.getConfigNames; -subset = cc.getSubsetConfigs([1]); - -num_configs = cc.numConfigs; -subset_num_configs = subset.numConfigs; - -save(fullfile(classDir, 'basic.mat'), ... - 'num_configs', 'names', 'subset_num_configs', '-v7'); -end - -function write_cif_fixture(outRoot) -classDir = fullfile(outRoot, 'CIF'); -if exist(classDir, 'dir') ~= 7 - mkdir(classDir); -end - -dt = 0.001; -time = (0:dt:2.0)'; -lambda_values = max(12 + 4 * sin(2 * pi * 1 * time), 0.2); -lambda_cov = Covariate(time, lambda_values, 'Lambda', 'time', 's', 'sp/s', {'lambda'}); - -rng(0, 'twister'); -coll = CIF.simulateCIFByThinningFromLambda(lambda_cov, 3, dt); -spike_counts = zeros(3, 1); -first_five_spikes = cell(3, 1); -for i = 1:3 - st = coll.getNST(i); - spike_counts(i) = length(st.spikeTimes); - first_five_spikes{i} = st.spikeTimes(1:min(5, end)); -end - -save(fullfile(classDir, 'basic.mat'), ... - 'time', 'lambda_values', 'dt', 'spike_counts', 'first_five_spikes', '-v7'); -end - -function write_fitresult_and_summary_fixtures(outRoot) -fitDir = fullfile(outRoot, 'FitResult'); -if exist(fitDir, 'dir') ~= 7 - mkdir(fitDir); -end -sumDir = fullfile(outRoot, 'FitResSummary'); -if exist(sumDir, 'dir') ~= 7 - mkdir(sumDir); -end - -time = (0:0.1:1.0)'; -lambda_cov = Covariate(time, ones(size(time)), 'Lambda', 'time', 's', 'sp/s', {'lambda'}); -spike_obj = nspikeTrain([0.2 0.4 0.8]', '1', 0.001, 0, 1); - -tc = TrialConfig(); -tc.setName('cfg1'); -cc = ConfigColl(tc); - -cov_labels = {{'Baseline'}}; -num_hist = {0}; -hist_objects = {[]}; -ens_hist_obj = {[]}; -b = {[0.1]}; -dev = 1; -stats = {struct('se', 0.1, 'p', 0.5)}; -AIC = 2; -BIC = 3; -logLL = -1; - -fit_obj = FitResult( ... - spike_obj, cov_labels, num_hist, hist_objects, ens_hist_obj, lambda_cov, ... - b, dev, stats, AIC, BIC, logLL, cc, {}, {}, 'poisson'); - -Z = [0.1; 0.2; 0.3]; -U = [0.05; 0.1; 0.2]; -xAxis = [0.1; 0.2; 0.3]; -ksSorted = [0.11; 0.21; 0.29]; -ks_stat = 0.05; -fit_obj.setKSStats(Z, U, xAxis, ksSorted, ks_stat); - -fit_num_results = fit_obj.numResults; -fit_aic = fit_obj.AIC; -fit_bic = fit_obj.BIC; -fit_logll = fit_obj.logLL; -fit_neuron_number = fit_obj.neuronNumber; -fit_ks_stat = fit_obj.KSStats.ks_stat; -fit_p_value = fit_obj.KSStats.pValue; - -save(fullfile(fitDir, 'basic.mat'), ... - 'fit_num_results', 'fit_aic', 'fit_bic', 'fit_logll', ... - 'fit_neuron_number', 'fit_ks_stat', 'fit_p_value', '-v7'); - -frs = FitResSummary(fit_obj); -summary_num_neurons = frs.numNeurons; -summary_num_results = frs.numResults; -summary_aic = frs.AIC; -summary_bic = frs.BIC; -summary_fit_names = frs.fitNames; - -save(fullfile(sumDir, 'basic.mat'), ... - 'summary_num_neurons', 'summary_num_results', ... - 'summary_aic', 'summary_bic', 'summary_fit_names', '-v7'); -end diff --git a/notebooks/AnalysisExamples.ipynb b/notebooks/AnalysisExamples.ipynb index 4848282c..af080421 100644 --- a/notebooks/AnalysisExamples.ipynb +++ b/notebooks/AnalysisExamples.ipynb @@ -3,265 +3,269 @@ { "cell_type": "code", "execution_count": null, - "id": "analysisexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: AnalysisExamples\n", - "# Execution group: smoke\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/AnalysisExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "analysisexamples-01", + "id": "07d8f6d3", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB AnalysisExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"AnalysisExamples\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"AnalysisExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"AnalysisExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"AnalysisExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"AnalysisExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "analysisexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"warning off;\",\n", - " \"installPath = which('nSTAT_Install');\",\n", - " \"if isempty(installPath)\",\n", - " \"error('AnalysisExamples:MissingInstallPath', ...\",\n", - " \"'Could not locate nSTAT_Install.m on the MATLAB path.');\",\n", - " \"end\",\n", - " \"glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat');\",\n", - " \"load(glmDataPath);\",\n", - " \"figure;\",\n", - " \"plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", - " \"[b,dev,stats] = glmfit([xN yN (xN.^2-mean(xN.^2)) (yN.^2-mean(yN.^2)) (xN.*yN-mean(xN.*yN))],spikes_binned,'poisson');\",\n", - " \"figure;\",\n", - " \"errorbar(1:length(b), b, stats.se,'.');\",\n", - " \"xticks=1:length(b);\",\n", - " \"xtickLabels= {'baseline','x','y','x^2','y^2','x*y'};\",\n", - " \"set(gca,'xtick',xticks,'xtickLabel',xtickLabels);\",\n", - " \"figure;\",\n", - " \"[x_new,y_new]=meshgrid(-1:.1:1);\",\n", - " \"y_new = flipud(y_new);\",\n", - " \"x_new = fliplr(x_new);\",\n", - " \"lambda = exp(b(1) + b(2)*x_new + b(3)*y_new + b(4)*x_new.^2 + b(5)*y_new.^2 + b(6)*x_new.*y_new);\",\n", - " \"lambda((x_new.^2+y_new.^2>1))=nan;\",\n", - " \"h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\",\n", - " \"get(h_mesh,'AlphaData');\",\n", - " \"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor','b');\",\n", - " \"hold on;\",\n", - " \"plot3(cos(-pi:1e-2:pi),sin(-pi:1e-2:pi),zeros(size(-pi:1e-2:pi))); hold on;\",\n", - " \"plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", - " \"[b_lin,dev_lin,stats_lin] = glmfit([xN yN],spikes_binned,'poisson');\",\n", - " \"[b_quad,dev_quad,stats_quad] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\",\n", - " \"lambdaEst_lin = exp( b_lin(1) + b_lin(2)*xN+b_lin(3)*yN); % based on our GLM model with the log \\\"link function\\\"\",\n", - " \"lambdaEst_quad = exp( b_quad(1) + b_quad(2)*xN+b_quad(3)*yN+b_quad(4)*xN.^2 +b_quad(5)*yN.^2 +b_quad(6)*xN.*yN);\",\n", - " \"lambdaEst=[lambdaEst_lin, lambdaEst_quad];\",\n", - " \"timestep = 1;\",\n", - " \"lambdaInt = 0;\",\n", - " \"j=0;\",\n", - " \"KS=[];\",\n", - " \"for t=1:length(spikes_binned)\",\n", - " \"lambdaInt = lambdaInt + lambdaEst(t,:)*timestep;\",\n", - " \"if (spikes_binned(t))\",\n", - " \"j = j + 1;\",\n", - " \"KS(j,:) = 1-exp(-lambdaInt);\",\n", - " \"lambdaInt = [0 0];\",\n", - " \"end\",\n", - " \"end\",\n", - " \"KSSorted = sort( KS );\",\n", - " \"N = length( KSSorted);\",\n", - " \"figure;\",\n", - " \"plot( ([1:N]-.5)/N, KSSorted, 0:.01:1,0:.01:1, 'g',0:.01:1, [0:.01:1]+1.36/sqrt(N), 'r', 0:.01:1,[0:.01:1]-1.36/sqrt(N), 'r' );\",\n", - " \"axis( [0 1 0 1] );\",\n", - " \"xlabel('Uniform CDF');\",\n", - " \"ylabel('Empirical CDF of Rescaled ISIs');\",\n", - " \"title('KS Plot with 95% Confidence Intervals');\",\n", - " \"legend('Linear','Quadratic');\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for AnalysisExamples.\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "analysisexamples-03", - "metadata": {}, - "outputs": [], - "source": [ - "# AnalysisExamples: spatial firing-rate modeling with x-y covariates.\n", - "n_t = 4500\n", - "dt = 0.01\n", - "time = np.arange(n_t) * dt\n", - "\n", - "xy = np.zeros((n_t, 2), dtype=float)\n", - "xy[0] = np.array([45.0, 55.0])\n", - "vel = np.zeros(2, dtype=float)\n", - "for t in range(1, n_t):\n", - " vel = 0.92 * vel + 2.0 * rng.normal(size=2)\n", - " xy[t] = np.clip(xy[t - 1] + vel, 0.0, 100.0)\n", - "\n", - "xc, yc, sigma = 62.0, 38.0, 16.0\n", - "r2 = (xy[:, 0] - xc) ** 2 + (xy[:, 1] - yc) ** 2\n", - "true_rate = 1.2 + 18.0 * np.exp(-0.5 * r2 / (sigma**2))\n", - "counts = rng.poisson(true_rate * dt)\n", - "\n", - "X_lin = np.column_stack([xy[:, 0], xy[:, 1]])\n", - "fit_lin = Analysis.fit_glm(X=X_lin, y=counts, fit_type=\"poisson\", dt=dt)\n", - "est_rate = fit_lin.predict(X_lin)\n", - "\n", - "grid = np.linspace(0.0, 100.0, 35)\n", - "gx, gy = np.meshgrid(grid, grid, indexing=\"xy\")\n", - "Xg = np.column_stack([gx.ravel(), gy.ravel()])\n", - "true_map = 1.2 + 18.0 * np.exp(-0.5 * (((Xg[:, 0] - xc) ** 2 + (Xg[:, 1] - yc) ** 2) / (sigma**2)))\n", - "est_map = fit_lin.predict(Xg)\n", - "\n", - "spike_mask = counts > 0\n", - "\n", - "fig, axes = plt.subplots(2, 2, figsize=(10, 8))\n", - "axes[0, 0].plot(xy[:, 0], xy[:, 1], color=\"0.75\", linewidth=0.8)\n", - "axes[0, 0].scatter(xy[spike_mask, 0], xy[spike_mask, 1], s=5, c=\"tab:red\", alpha=0.6)\n", - "axes[0, 0].set_title(f\"{TOPIC}: trajectory and spikes\")\n", - "axes[0, 0].set_xlabel(\"x\")\n", - "axes[0, 0].set_ylabel(\"y\")\n", - "axes[0, 0].set_aspect(\"equal\", adjustable=\"box\")\n", - "\n", - "im1 = axes[0, 1].imshow(true_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[0, 1].set_title(\"True place field\")\n", - "axes[0, 1].set_xlabel(\"x\")\n", - "axes[0, 1].set_ylabel(\"y\")\n", - "fig.colorbar(im1, ax=axes[0, 1], fraction=0.04, pad=0.03)\n", - "\n", - "im2 = axes[1, 0].imshow(est_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[1, 0].set_title(\"Estimated linear model field\")\n", - "axes[1, 0].set_xlabel(\"x\")\n", - "axes[1, 0].set_ylabel(\"y\")\n", - "fig.colorbar(im2, ax=axes[1, 0], fraction=0.04, pad=0.03)\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "axes[1, 1].plot(time[:800], true_rate[:800], label=\"true\", linewidth=1.1)\n", - "axes[1, 1].plot(time[:800], est_rate[:800], label=\"estimated\", linewidth=1.0)\n", - "axes[1, 1].set_title(\"Rate trace (first 8 s)\")\n", - "axes[1, 1].set_xlabel(\"time [s]\")\n", - "axes[1, 1].set_ylabel(\"Hz\")\n", - "axes[1, 1].legend(loc=\"upper right\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='AnalysisExamples', output_root=OUTPUT_ROOT, expected_count=4)\n", "\n", - "plt.tight_layout()\n", - "plt.show()\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "rmse_rate = float(np.sqrt(np.mean((est_rate - true_rate) ** 2)))\n", - "print(\"rmse_rate\", rmse_rate, \"aic\", float(fit_lin.aic()))\n", - "assert np.isfinite(rmse_rate)\n", - "assert rmse_rate < 8.0\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_rate\": float(rmse_rate),\n", - " \"mean_true_rate\": float(np.mean(true_rate)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_rate\": (0.0, 8.0),\n", - " \"mean_true_rate\": (0.2, 30.0),\n", - "}\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Analysis Examples\n", + "# Analysis Examples\n", + "# MATLAB L200: % This is an example on the standard approach to fitting GLM models to spike train data. This data set was obtained at the Society For Neuroscience '08 Workshop on Workshop on Neural Signal Processing Compare to analysis with Neural Spike Analysis Toolbox\n", + "# This is an example on the standard approach to fitting GLM models to spike train data. This data set was obtained at the Society For Neuroscience '08 Workshop on Workshop on Neural Signal Processing Compare to analysis with Neural Spike Analysis Toolbox\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "analysisexamples-04", + "id": "41ce02e5", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 1: Example 1: Tradition Preliminary Analysis\n", + "# MATLAB L400: % Script glm_part1.m\n", + "# Script glm_part1.m\n", + "# MATLAB L401: % MATLAB code to visualize data, fit a GLM model of the relation between\n", + "# MATLAB code to visualize data, fit a GLM model of the relation between\n", + "# MATLAB L402: % spiking and the rat's position, and visualize this model for the\n", + "# spiking and the rat's position, and visualize this model for the\n", + "# MATLAB L403: % Neuroinformatics GLM problem set.\n", + "# Neuroinformatics GLM problem set.\n", + "# MATLAB L404: % The code is initialized with an overly simple GLM model construction.\n", + "# The code is initialized with an overly simple GLM model construction.\n", + "# MATLAB L405: % Please improve it!\n", + "# Please improve it!\n", + "# MATLAB L406: \n", + "#\n", + "# MATLAB L407: % load the rat trajectory and spiking data;\n", + "# load the rat trajectory and spiking data;\n", + "# MATLAB L408: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L409: warning off;\n", + "_matlab('warning off;')\n", + "# MATLAB L410: load('glm_data.mat');\n", + "globals().update(_load_matlab_globals('glm_data.mat'))\n", + "# MATLAB L600: % visualize the raw data\n", + "# visualize the raw data\n", + "# MATLAB L700: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L701: plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.');\n", + "__tracker.annotate(\"plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.')\")\n", + "ax = plt.gca()\n", + "ax.cla()\n", + "plt.gcf().set_size_inches(8.0, 8.0, forward=True)\n", + "ax.plot(np.ravel(xN), np.ravel(yN), color=(0.0, 0.4470, 0.7410), linewidth=0.6)\n", + "ax.plot(np.ravel(x_at_spiketimes), np.ravel(y_at_spiketimes), 'r.', markersize=2.5)\n", + "# MATLAB L702: axis tight square;\n", + "ax = plt.gca()\n", + "ax.relim()\n", + "ax.autoscale_view(tight=True)\n", + "ax.set_aspect('equal', adjustable='box')\n", + "ax.tick_params(top=True, right=True, direction='in')\n", + "# MATLAB L703: xlabel('x position (m)'); ylabel('y position (m)');\n", + "plt.xlabel('x position (m)')\n", + "plt.ylabel('y position (m)')\n", + "# MATLAB L900: % fit a GLM model to the x and y positions.\n", + "# fit a GLM model to the x and y positions.\n", + "# MATLAB L1000: [b,dev,stats] = glmfit([xN yN (xN.^2-mean(xN.^2)) (yN.^2-mean(yN.^2)) (xN.*yN-mean(xN.*yN))],spikes_binned,'poisson');\n", + "_matlab(\"[b,dev,stats] = glmfit([xN yN (xN.^2-mean(xN.^2)) (yN.^2-mean(yN.^2)) (xN.*yN-mean(xN.*yN))],spikes_binned,'poisson');\")\n", + "# MATLAB L1001: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1002: errorbar(1:length(b), b, stats.se,'.');\n", + "_matlab(\"errorbar(1:length(b), b, stats.se,'.');\")\n", + "# MATLAB L1003: xticks=1:length(b);\n", + "_matlab('xticks=1:length(b);')\n", + "# MATLAB L1004: xtickLabels= {'baseline','x','y','x^2','y^2','x*y'};\n", + "_matlab(\"xtickLabels= {'baseline','x','y','x^2','y^2','x*y'};\")\n", + "# MATLAB L1005: set(gca,'xtick',xticks,'xtickLabel',xtickLabels);\n", + "_matlab(\"set(gca,'xtick',xticks,'xtickLabel',xtickLabels);\")\n", + "# MATLAB L1200: % visualize your model construct a grid of positions to plot the model against...\n", + "# visualize your model construct a grid of positions to plot the model against...\n", + "# MATLAB L1300: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1301: [x_new,y_new]=meshgrid(-1:.1:1);\n", + "_matlab('[x_new,y_new]=meshgrid(-1:.1:1);')\n", + "# MATLAB L1302: y_new = flipud(y_new);\n", + "_matlab('y_new = flipud(y_new);')\n", + "# MATLAB L1303: x_new = fliplr(x_new);\n", + "_matlab('x_new = fliplr(x_new);')\n", + "# MATLAB L1304: \n", + "#\n", + "# MATLAB L1305: % compute lambda for each point on this grid using the GLM model\n", + "# compute lambda for each point on this grid using the GLM model\n", + "# MATLAB L1306: lambda = exp(b(1) + b(2)*x_new + b(3)*y_new + b(4)*x_new.^2 + b(5)*y_new.^2 + b(6)*x_new.*y_new);\n", + "_matlab('lambda = exp(b(1) + b(2)*x_new + b(3)*y_new + b(4)*x_new.^2 + b(5)*y_new.^2 + b(6)*x_new.*y_new);')\n", + "# MATLAB L1307: lambda((x_new.^2+y_new.^2>1))=nan;\n", + "_matlab('lambda((x_new.^2+y_new.^2>1))=nan;')\n", + "# MATLAB L1308: \n", + "#\n", + "# MATLAB L1309: %plot lambda as a function position over this grid\n", + "# plot lambda as a function position over this grid\n", + "# MATLAB L1310: h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\n", + "_matlab(\"h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\")\n", + "# MATLAB L1311: get(h_mesh,'AlphaData');\n", + "_matlab(\"get(h_mesh,'AlphaData');\")\n", + "# MATLAB L1312: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor','b');\n", + "_matlab(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor','b');\")\n", + "# MATLAB L1313: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L1314: plot3(cos(-pi:1e-2:pi),sin(-pi:1e-2:pi),zeros(size(-pi:1e-2:pi))); hold on;\n", + "__tracker.annotate('plot3(cos(-pi:1e-2:pi),sin(-pi:1e-2:pi),zeros(size(-pi:1e-2:pi)))')\n", + "_matlab('plot3(cos(-pi:1e-2:pi),sin(-pi:1e-2:pi),zeros(size(-pi:1e-2:pi))); hold on;')\n", + "# MATLAB L1315: plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.');\n", + "__tracker.annotate(\"plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.')\")\n", + "_matlab(\"plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.');\")\n", + "# MATLAB L1316: axis tight square;\n", + "ax = plt.gca()\n", + "ax.relim()\n", + "ax.autoscale_view(tight=True)\n", + "ax.set_aspect('equal', adjustable='box')\n", + "ax.tick_params(top=True, right=True, direction='in')\n", + "# MATLAB L1317: xlabel('x position (m)'); ylabel('y position (m)');\n", + "plt.xlabel('x position (m)')\n", + "plt.ylabel('y position (m)')\n", + "# MATLAB L1500: % Compare a linear model versus a Gaussian GLM model.\n", + "# Compare a linear model versus a Gaussian GLM model.\n", + "# MATLAB L1600: [b_lin,dev_lin,stats_lin] = glmfit([xN yN],spikes_binned,'poisson');\n", + "_matlab(\"[b_lin,dev_lin,stats_lin] = glmfit([xN yN],spikes_binned,'poisson');\")\n", + "# MATLAB L1601: [b_quad,dev_quad,stats_quad] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\n", + "_matlab(\"[b_quad,dev_quad,stats_quad] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\")\n", + "# MATLAB L1602: \n", + "#\n", + "# MATLAB L1603: lambdaEst_lin = exp( b_lin(1) + b_lin(2)*xN+b_lin(3)*yN); % based on our GLM model with the log \"link function\"\n", + "_matlab('lambdaEst_lin = exp( b_lin(1) + b_lin(2)*xN+b_lin(3)*yN); % based on our GLM model with the log \"link function\"')\n", + "# MATLAB L1604: lambdaEst_quad = exp( b_quad(1) + b_quad(2)*xN+b_quad(3)*yN+b_quad(4)*xN.^2 +b_quad(5)*yN.^2 +b_quad(6)*xN.*yN);\n", + "_matlab('lambdaEst_quad = exp( b_quad(1) + b_quad(2)*xN+b_quad(3)*yN+b_quad(4)*xN.^2 +b_quad(5)*yN.^2 +b_quad(6)*xN.*yN);')\n", + "# MATLAB L1800: % Make the KS Plot\n", + "# Make the KS Plot\n", + "# MATLAB L1900: % ******* K-S Plot *******************\n", + "# ******* K-S Plot *******************\n", + "# MATLAB L1901: % graph the K-S plot and confidence intervals for the K-S statistic\n", + "# graph the K-S plot and confidence intervals for the K-S statistic\n", + "# MATLAB L1902: \n", + "#\n", + "# MATLAB L1903: %first generate the conditional intensity at each timestep\n", + "# first generate the conditional intensity at each timestep\n", + "# MATLAB L1904: % ** Adjust the below line according to your choice of model.\n", + "# ** Adjust the below line according to your choice of model.\n", + "# MATLAB L1905: % remember to include a column of ones to multiply the default constant GLM parameter beta_0**\n", + "# remember to include a column of ones to multiply the default constant GLM parameter beta_0**\n", + "# MATLAB L1906: \n", + "#\n", + "# MATLAB L1907: % Use your parameter estimates (b) from glmfit along\n", + "# Use your parameter estimates (b) from glmfit along\n", + "# MATLAB L1908: % with the covariates you used (xN, yN, ...)\n", + "# with the covariates you used (xN, yN, ...)\n", + "# MATLAB L1909: \n", + "#\n", + "# MATLAB L1910: lambdaEst=[lambdaEst_lin, lambdaEst_quad];\n", + "_matlab('lambdaEst=[lambdaEst_lin, lambdaEst_quad];')\n", + "# MATLAB L1911: timestep = 1;\n", + "timestep = 1\n", + "# MATLAB L1912: lambdaInt = 0;\n", + "lambdaInt = 0\n", + "# MATLAB L1913: j=0;\n", + "j = 0\n", + "# MATLAB L1914: KS=[];\n", + "_matlab('KS=[];')\n", + "# MATLAB L1915: for t=1:length(spikes_binned)\n", + "_matlab('for t=1:length(spikes_binned)')\n", + "# MATLAB L1916: lambdaInt = lambdaInt + lambdaEst(t,:)*timestep;\n", + "_matlab('lambdaInt = lambdaInt + lambdaEst(t,:)*timestep;')\n", + "# MATLAB L1917: if (spikes_binned(t))\n", + "_matlab('if (spikes_binned(t))')\n", + "# MATLAB L1918: j = j + 1;\n", + "_matlab('j = j + 1;')\n", + "# MATLAB L1919: KS(j,:) = 1-exp(-lambdaInt);\n", + "_matlab('KS(j,:) = 1-exp(-lambdaInt);')\n", + "# MATLAB L1920: lambdaInt = [0 0];\n", + "_matlab('lambdaInt = [0 0];')\n", + "# MATLAB L1921: end\n", + "_matlab('end')\n", + "# MATLAB L1922: end\n", + "_matlab('end')\n", + "# MATLAB L1923: KSSorted = sort( KS );\n", + "_matlab('KSSorted = sort( KS );')\n", + "# MATLAB L1924: N = length( KSSorted);\n", + "_matlab('N = length( KSSorted);')\n", + "# MATLAB L1925: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1926: plot( ([1:N]-.5)/N, KSSorted, 0:.01:1,0:.01:1, 'g',0:.01:1, [0:.01:1]+1.36/sqrt(N), 'r', 0:.01:1,[0:.01:1]-1.36/sqrt(N), 'r' );\n", + "__tracker.annotate(\"plot( ([1:N]-.5)/N, KSSorted, 0:.01:1,0:.01:1, 'g',0:.01:1, [0:.01:1]+1.36/sqrt(N), 'r', 0:.01:1,[0:.01:1]-1.36/sqrt(N), 'r' )\")\n", + "_matlab(\"plot( ([1:N]-.5)/N, KSSorted, 0:.01:1,0:.01:1, 'g',0:.01:1, [0:.01:1]+1.36/sqrt(N), 'r', 0:.01:1,[0:.01:1]-1.36/sqrt(N), 'r' );\")\n", + "# MATLAB L1927: axis( [0 1 0 1] );\n", + "_matlab('axis( [0 1 0 1] );')\n", + "# MATLAB L1928: xlabel('Uniform CDF');\n", + "_matlab(\"xlabel('Uniform CDF');\")\n", + "# MATLAB L1929: ylabel('Empirical CDF of Rescaled ISIs');\n", + "_matlab(\"ylabel('Empirical CDF of Rescaled ISIs');\")\n", + "# MATLAB L1930: title('KS Plot with 95% Confidence Intervals');\n", + "__tracker.annotate(\"title('KS Plot with 95% Confidence Intervals')\")\n", + "_matlab(\"title('KS Plot with 95% Confidence Intervals');\")\n", + "# MATLAB L1931: legend('Linear','Quadratic');\n", + "_matlab(\"legend('Linear','Quadratic');\")\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "analysis", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 4, "run_group": "smoke", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/AnalysisExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "AnalysisExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/AnalysisExamples2.ipynb b/notebooks/AnalysisExamples2.ipynb index e6d8e62c..8f600544 100644 --- a/notebooks/AnalysisExamples2.ipynb +++ b/notebooks/AnalysisExamples2.ipynb @@ -3,262 +3,260 @@ { "cell_type": "code", "execution_count": null, - "id": "analysisexamples2-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: AnalysisExamples2\n", - "# Execution group: full\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/AnalysisExamples2.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "analysisexamples2-01", + "id": "4013001b", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB AnalysisExamples2.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "TOPIC = \"AnalysisExamples2\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='AnalysisExamples2', output_root=OUTPUT_ROOT, expected_count=4)\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"AnalysisExamples2: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"AnalysisExamples2: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"AnalysisExamples2: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"AnalysisExamples2: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "analysisexamples2-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"warning off;\",\n", - " \"installPath = which('nSTAT_Install');\",\n", - " \"if isempty(installPath)\",\n", - " \"error('AnalysisExamples2:MissingInstallPath', ...\",\n", - " \"'Could not locate nSTAT_Install.m on the MATLAB path.');\",\n", - " \"end\",\n", - " \"glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat');\",\n", - " \"load(glmDataPath);\",\n", - " \"nst = nspikeTrain(spiketimes);\",\n", - " \"baseline = Covariate(T,ones(length(xN),1),'Baseline','time','s','',{'mu'});\",\n", - " \"position = Covariate(T,[xN yN],'Position', 'time','s','m',{'x','y'});\",\n", - " \"velocity = Covariate(T,[vxN,vyN],'Velocity','time','s','m/s',{'v_x','v_y'});\",\n", - " \"radial = Covariate(T,[xN yN xN.^2 yN.^2 xN.*yN],'Radial','time','s','m',{'x','y','x^2','y^2','x*y'});\",\n", - " \"[values_at_spiketimes] =position.getValueAt(spiketimes);\",\n", - " \"[values_at_spiketimes] =position.resample(1/min(diff(spiketimes))).getValueAt(spiketimes);\",\n", - " \"figure;\",\n", - " \"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\",\n", - " \"values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", - " \"spikeColl = nstColl({nst});\",\n", - " \"covarColl = CovColl({baseline,radial});\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"clear tc;\",\n", - " \"sampleRate=1000;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','mu'},{'Radial','x','y'}},sampleRate,[]); tc{1}.setName('Linear');\",\n", - " \"tc{2} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[]); tc{2}.setName('Quadratic');\",\n", - " \"tc{3} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[0 1]./sampleRate); tc{3}.setName('Quadratic+Hist');\",\n", - " \"tcc = ConfigColl(tc); makePlot=1; neuronNum=1;\",\n", - " \"fitResults =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"fitResults.plotResults;\",\n", - " \"figure;\",\n", - " \"[x_new,y_new]=meshgrid(-1:.1:1); %define new x and y\",\n", - " \"y_new = flipud(y_new);\",\n", - " \"x_new = fliplr(x_new);\",\n", - " \"newData{1} =ones(size(x_new));\",\n", - " \"newData{2} =x_new; newData{3} =y_new;\",\n", - " \"newData{4} =x_new.^2; newData{5} =y_new.^2;\",\n", - " \"newData{6} =x_new.*y_new;\",\n", - " \"color = Analysis.colors;\",\n", - " \"for i=1:fitResults.numResults\",\n", - " \"lambda = fitResults.evalLambda(i,newData);\",\n", - " \"h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\",\n", - " \"get(h_mesh,'AlphaData');\",\n", - " \"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor',color{i});\",\n", - " \"hold on;\",\n", - " \"end\",\n", - " \"legend(fitResults.lambda.dataLabels);\",\n", - " \"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\",\n", - " \"values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", - " \"[b,dev,stats] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\",\n", - " \"b-fitResults.b{2} % should be close to zero\",\n", - " \"sampleRate=1000; makePlot=1; neuronNum = 1;\",\n", - " \"covLabels = {{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}};\",\n", - " \"Algorithm = 'GLM';\",\n", - " \"batchMode=0;\",\n", - " \"windowTimes =(0:1:10)./sampleRate;\",\n", - " \"[fitResults,tcc] = Analysis.computeHistLag(trial,neuronNum,windowTimes,covLabels,Algorithm,batchMode,sampleRate,makePlot);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for AnalysisExamples2.\")\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Analysis Examples 2\n", + "# Analysis Examples 2\n", + "# MATLAB L200: % Compare with traditional Neural Spike Train Analysis here\n", + "# Compare with traditional Neural Spike Train Analysis here\n", + "# MATLAB L300: % load the rat trajectory and spiking data;\n", + "# load the rat trajectory and spiking data;\n", + "# MATLAB L301: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L302: warning off;\n", + "_matlab('warning off;')\n", + "# MATLAB L303: load('glm_data.mat');\n", + "globals().update(_load_matlab_globals('glm_data.mat'))\n", + "# MATLAB L304: \n", + "#\n", + "# MATLAB L305: nst = nspikeTrain(spiketimes);\n", + "_matlab('nst = nspikeTrain(spiketimes);')\n", + "# MATLAB L306: baseline = Covariate(T,ones(length(xN),1),'Baseline','time','s','',{'mu'});\n", + "_matlab(\"baseline = Covariate(T,ones(length(xN),1),'Baseline','time','s','',{'mu'});\")\n", + "# MATLAB L307: position = Covariate(T,[xN yN],'Position', 'time','s','m',{'x','y'});\n", + "_matlab(\"position = Covariate(T,[xN yN],'Position', 'time','s','m',{'x','y'});\")\n", + "# MATLAB L308: velocity = Covariate(T,[vxN,vyN],'Velocity','time','s','m/s',{'v_x','v_y'});\n", + "_matlab(\"velocity = Covariate(T,[vxN,vyN],'Velocity','time','s','m/s',{'v_x','v_y'});\")\n", + "# MATLAB L309: radial = Covariate(T,[xN yN xN.^2 yN.^2 xN.*yN],'Radial','time','s','m',{'x','y','x^2','y^2','x*y'});\n", + "_matlab(\"radial = Covariate(T,[xN yN xN.^2 yN.^2 xN.*yN],'Radial','time','s','m',{'x','y','x^2','y^2','x*y'});\")\n", + "# MATLAB L310: % could just define velocity = postion.derivative;\n", + "# could just define velocity = postion.derivative;\n", + "# MATLAB L311: \n", + "#\n", + "# MATLAB L312: %possibly add view as vector for covariates of dimension 3 or less\n", + "# possibly add view as vector for covariates of dimension 3 or less\n", + "# MATLAB L500: % In the original analysis, we already had vectors of the covariates sampled at the spiketimes. This step would require interpolating the covariates and then sampling them at each of the spikeTimes. In our case this is quite simple.\n", + "# In the original analysis, we already had vectors of the covariates sampled at the spiketimes. This step would require interpolating the covariates and then sampling them at each of the spikeTimes. In our case this is quite simple.\n", + "# MATLAB L600: [values_at_spiketimes] =position.getValueAt(spiketimes);\n", + "_matlab('[values_at_spiketimes] =position.getValueAt(spiketimes);')\n", + "# MATLAB L800: % We could also upsample our data to get better estimates of the covariates at these points\n", + "# We could also upsample our data to get better estimates of the covariates at these points\n", + "# MATLAB L900: [values_at_spiketimes] =position.resample(1/min(diff(spiketimes))).getValueAt(spiketimes);\n", + "_matlab('[values_at_spiketimes] =position.resample(1/min(diff(spiketimes))).getValueAt(spiketimes);')\n", + "# MATLAB L1100: % visualize the raw data\n", + "# visualize the raw data\n", + "# MATLAB L1200: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1201: plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\n", + "__tracker.annotate(\"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\")\n", + "_matlab(\"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\")\n", + "# MATLAB L1202: values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\n", + "_matlab(\"values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\")\n", + "# MATLAB L1203: axis tight square;\n", + "ax = plt.gca()\n", + "ax.relim()\n", + "ax.autoscale_view(tight=True)\n", + "ax.set_aspect('equal', adjustable='box')\n", + "ax.tick_params(top=True, right=True, direction='in')\n", + "# MATLAB L1204: xlabel('x position (m)'); ylabel('y position (m)');\n", + "plt.xlabel('x position (m)')\n", + "plt.ylabel('y position (m)')\n", + "# MATLAB L1400: % Create a trial object and define the fits that we want to run\n", + "# Create a trial object and define the fits that we want to run\n", + "# MATLAB L1500: spikeColl = nstColl({nst});\n", + "_matlab('spikeColl = nstColl({nst});')\n", + "# MATLAB L1501: covarColl = CovColl({baseline,radial});\n", + "_matlab('covarColl = CovColl({baseline,radial});')\n", + "# MATLAB L1502: trial = Trial(spikeColl,covarColl);\n", + "_matlab('trial = Trial(spikeColl,covarColl);')\n", + "# MATLAB L1503: clear tc;\n", + "pass\n", + "# MATLAB L1504: sampleRate=1000;\n", + "sampleRate = 1000\n", + "# MATLAB L1505: % tcObj=TrialConfig(covMask,sampleRate, history,minTime,maxTime)\n", + "# tcObj=TrialConfig(covMask,sampleRate, history,minTime,maxTime)\n", + "# MATLAB L1506: tc{1} = TrialConfig({{'Baseline','mu'},{'Radial','x','y'}},sampleRate,[]); tc{1}.setName('Linear');\n", + "_matlab(\"tc{1} = TrialConfig({{'Baseline','mu'},{'Radial','x','y'}},sampleRate,[]); tc{1}.setName('Linear');\")\n", + "# MATLAB L1507: tc{2} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[]); tc{2}.setName('Quadratic');\n", + "_matlab(\"tc{2} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[]); tc{2}.setName('Quadratic');\")\n", + "# MATLAB L1508: tc{3} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[0 1]./sampleRate); tc{3}.setName('Quadratic+Hist');\n", + "__tracker.annotate(\"tc{3}.setName('Quadratic+Hist')\")\n", + "_matlab(\"tc{3} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[0 1]./sampleRate); tc{3}.setName('Quadratic+Hist');\")\n", + "# MATLAB L1700: % Create our collection of configurations and run the analysis;\n", + "# Create our collection of configurations and run the analysis;\n", + "# MATLAB L1800: tcc = ConfigColl(tc); makePlot=1; neuronNum=1;\n", + "_matlab('tcc = ConfigColl(tc); makePlot=1; neuronNum=1;')\n", + "# MATLAB L1801: fitResults =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", + "_matlab('fitResults =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);')\n", + "# MATLAB L1802: fitResults.plotResults;\n", + "__tracker.annotate('fitResults.plotResults')\n", + "_matlab('fitResults.plotResults;')\n", + "# MATLAB L2000: % Visualize the firing rates as a function of the spatial covariates\n", + "# Visualize the firing rates as a function of the spatial covariates\n", + "# MATLAB L2100: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L2101: [x_new,y_new]=meshgrid(-1:.1:1); %define new x and y\n", + "_matlab('[x_new,y_new]=meshgrid(-1:.1:1); %define new x and y')\n", + "# MATLAB L2102: y_new = flipud(y_new);\n", + "_matlab('y_new = flipud(y_new);')\n", + "# MATLAB L2103: x_new = fliplr(x_new);\n", + "_matlab('x_new = fliplr(x_new);')\n", + "# MATLAB L2104: \n", + "#\n", + "# MATLAB L2105: %For each covariate new to place the new data in a cell array\n", + "# For each covariate new to place the new data in a cell array\n", + "# MATLAB L2106: newData{1} =ones(size(x_new));\n", + "_matlab('newData{1} =ones(size(x_new));')\n", + "# MATLAB L2107: newData{2} =x_new; newData{3} =y_new;\n", + "_matlab('newData{2} =x_new; newData{3} =y_new;')\n", + "# MATLAB L2108: newData{4} =x_new.^2; newData{5} =y_new.^2;\n", + "_matlab('newData{4} =x_new.^2; newData{5} =y_new.^2;')\n", + "# MATLAB L2109: newData{6} =x_new.*y_new;\n", + "_matlab('newData{6} =x_new.*y_new;')\n", + "# MATLAB L2110: color = Analysis.colors;\n", + "_matlab('color = Analysis.colors;')\n", + "# MATLAB L2111: \n", + "#\n", + "# MATLAB L2112: % Evaluate our fits using the new parameters\n", + "# Evaluate our fits using the new parameters\n", + "# MATLAB L2113: for i=1:fitResults.numResults\n", + "_matlab('for i=1:fitResults.numResults')\n", + "# MATLAB L2114: \n", + "#\n", + "# MATLAB L2115: lambda = fitResults.evalLambda(i,newData);\n", + "_matlab('lambda = fitResults.evalLambda(i,newData);')\n", + "# MATLAB L2116: h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\n", + "_matlab(\"h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\")\n", + "# MATLAB L2117: get(h_mesh,'AlphaData');\n", + "_matlab(\"get(h_mesh,'AlphaData');\")\n", + "# MATLAB L2118: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor',color{i});\n", + "_matlab(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor',color{i});\")\n", + "# MATLAB L2119: %figure;\n", + "# figure;\n", + "# MATLAB L2120: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L2121: end\n", + "_matlab('end')\n", + "# MATLAB L2122: legend(fitResults.lambda.dataLabels);\n", + "_matlab('legend(fitResults.lambda.dataLabels);')\n", + "# MATLAB L2123: plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\n", + "__tracker.annotate(\"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\")\n", + "_matlab(\"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\")\n", + "# MATLAB L2124: values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\n", + "_matlab(\"values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\")\n", + "# MATLAB L2125: axis tight square;\n", + "ax = plt.gca()\n", + "ax.relim()\n", + "ax.autoscale_view(tight=True)\n", + "ax.set_aspect('equal', adjustable='box')\n", + "ax.tick_params(top=True, right=True, direction='in')\n", + "# MATLAB L2126: xlabel('x position (m)'); ylabel('y position (m)');\n", + "plt.xlabel('x position (m)')\n", + "plt.ylabel('y position (m)')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "analysisexamples2-03", + "id": "2d501268", "metadata": {}, "outputs": [], "source": [ - "# AnalysisExamples2: compare linear and quadratic spatial Poisson GLMs.\n", - "n_t = 5000\n", - "dt = 0.01\n", - "time = np.arange(n_t) * dt\n", - "\n", - "xy = np.zeros((n_t, 2), dtype=float)\n", - "xy[0] = np.array([50.0, 50.0])\n", - "vel = np.zeros(2, dtype=float)\n", - "for t in range(1, n_t):\n", - " vel = 0.9 * vel + 2.4 * rng.normal(size=2)\n", - " xy[t] = np.clip(xy[t - 1] + vel, 0.0, 100.0)\n", - "\n", - "xc, yc, sigma = 35.0, 70.0, 14.0\n", - "r2 = (xy[:, 0] - xc) ** 2 + (xy[:, 1] - yc) ** 2\n", - "true_rate = 1.0 + 20.0 * np.exp(-0.5 * r2 / (sigma**2))\n", - "counts = rng.poisson(true_rate * dt)\n", - "\n", - "X_lin = np.column_stack([xy[:, 0], xy[:, 1]])\n", - "X_quad = np.column_stack([xy[:, 0], xy[:, 1], xy[:, 0] ** 2, xy[:, 1] ** 2, xy[:, 0] * xy[:, 1]])\n", - "\n", - "fit_lin = Analysis.fit_glm(X=X_lin, y=counts, fit_type=\"poisson\", dt=dt)\n", - "fit_quad = Analysis.fit_glm(X=X_quad, y=counts, fit_type=\"poisson\", dt=dt)\n", - "\n", - "grid = np.linspace(0.0, 100.0, 35)\n", - "gx, gy = np.meshgrid(grid, grid, indexing=\"xy\")\n", - "Xg_lin = np.column_stack([gx.ravel(), gy.ravel()])\n", - "Xg_quad = np.column_stack([gx.ravel(), gy.ravel(), gx.ravel() ** 2, gy.ravel() ** 2, gx.ravel() * gy.ravel()])\n", - "true_map = 1.0 + 20.0 * np.exp(\n", - " -0.5 * (((Xg_lin[:, 0] - xc) ** 2 + (Xg_lin[:, 1] - yc) ** 2) / (sigma**2))\n", - ")\n", - "lin_map = fit_lin.predict(Xg_lin)\n", - "quad_map = fit_quad.predict(Xg_quad)\n", - "\n", - "fig, axes = plt.subplots(2, 2, figsize=(10, 8))\n", - "im0 = axes[0, 0].imshow(true_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[0, 0].set_title(\"True field\")\n", - "fig.colorbar(im0, ax=axes[0, 0], fraction=0.04, pad=0.03)\n", - "\n", - "im1 = axes[0, 1].imshow(lin_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[0, 1].set_title(\"Linear GLM field\")\n", - "fig.colorbar(im1, ax=axes[0, 1], fraction=0.04, pad=0.03)\n", - "\n", - "im2 = axes[1, 0].imshow(quad_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[1, 0].set_title(\"Quadratic GLM field\")\n", - "fig.colorbar(im2, ax=axes[1, 0], fraction=0.04, pad=0.03)\n", - "\n", - "aic_vals = np.array([fit_lin.aic(), fit_quad.aic()], dtype=float)\n", - "axes[1, 1].bar([\"linear\", \"quadratic\"], aic_vals, color=[\"tab:gray\", \"tab:blue\"])\n", - "axes[1, 1].set_title(\"Model comparison (AIC)\")\n", - "axes[1, 1].set_ylabel(\"AIC\")\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "rmse_lin = float(np.sqrt(np.mean((fit_lin.predict(X_lin) - true_rate) ** 2)))\n", - "rmse_quad = float(np.sqrt(np.mean((fit_quad.predict(X_quad) - true_rate) ** 2)))\n", - "print(\"rmse_lin\", rmse_lin, \"rmse_quad\", rmse_quad)\n", - "assert rmse_quad <= rmse_lin + 0.8\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_lin\": float(rmse_lin),\n", - " \"rmse_quad\": float(rmse_quad),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_lin\": (0.0, 20.0),\n", - " \"rmse_quad\": (0.0, 20.0),\n", - "}\n" + "# SECTION 1: Toolbox vs. Standard GLM comparison\n", + "# MATLAB L2400: % Compare the results using our approach with the standard approach used in the first example previous standard regression\n", + "# Compare the results using our approach with the standard approach used in the first example previous standard regression\n", + "# MATLAB L2500: [b,dev,stats] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\n", + "_matlab(\"[b,dev,stats] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\")\n", + "# MATLAB L2501: b-fitResults.b{2} % should be close to zero\n", + "_matlab('b-fitResults.b{2} % should be close to zero')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "analysisexamples2-04", + "id": "1a00ddb9", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 2: Compute the history effect\n", + "# MATLAB L2800: sampleRate=1000; makePlot=1; neuronNum = 1;\n", + "_matlab('sampleRate=1000; makePlot=1; neuronNum = 1;')\n", + "# MATLAB L2801: covLabels = {{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}};\n", + "_matlab(\"covLabels = {{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}};\")\n", + "# MATLAB L2802: Algorithm = 'GLM';\n", + "_matlab(\"Algorithm = 'GLM';\")\n", + "# MATLAB L2803: batchMode=0;\n", + "batchMode = 0\n", + "# MATLAB L2804: windowTimes =(0:1:10)./sampleRate;\n", + "_matlab('windowTimes =(0:1:10)./sampleRate;')\n", + "# MATLAB L2805: % [fitResults,tcc] = computeHistLag(tObj,neuronNum,windowTimes,CovLabels,Algorithm,batchMode,sampleRate,makePlot,histMinTimes,histMaxTimes)\n", + "# [fitResults,tcc] = computeHistLag(tObj,neuronNum,windowTimes,CovLabels,Algorithm,batchMode,sampleRate,makePlot,histMinTimes,histMaxTimes)\n", + "# MATLAB L2806: [fitResults,tcc] = Analysis.computeHistLag(trial,neuronNum,windowTimes,covLabels,Algorithm,batchMode,sampleRate,makePlot);\n", + "_matlab('[fitResults,tcc] = Analysis.computeHistLag(trial,neuronNum,windowTimes,covLabels,Algorithm,batchMode,sampleRate,makePlot);')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "analysis", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 4, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/AnalysisExamples2.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "AnalysisExamples2" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/ConfigCollExamples.ipynb b/notebooks/ConfigCollExamples.ipynb index 0a1386d0..66379e67 100644 --- a/notebooks/ConfigCollExamples.ipynb +++ b/notebooks/ConfigCollExamples.ipynb @@ -3,142 +3,80 @@ { "cell_type": "code", "execution_count": null, - "id": "configcollexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: ConfigCollExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/ConfigCollExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "configcollexamples-01", + "id": "0dc9bd84", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB ConfigCollExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "TOPIC = \"ConfigCollExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='ConfigCollExamples', output_root=OUTPUT_ROOT, expected_count=0)\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"ConfigCollExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"ConfigCollExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"ConfigCollExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"ConfigCollExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "configcollexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\",\n", - " \"tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\",\n", - " \"tcc = ConfigColl({tc1,tc2});\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for ConfigCollExamples.\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "configcollexamples-03", - "metadata": {}, - "outputs": [], - "source": [ - "# ConfigCollExamples: compose and edit configuration collections.\n", - "from nstat.compat.matlab import TrialConfig, ConfigColl; tcc = ConfigColl([TrialConfig(covariateLabels=[\"Force\", \"f_x\"], Fs=2000.0, fitType=\"poisson\", name=\"cfg_force\"), TrialConfig(covariateLabels=[\"Position\", \"x\"], Fs=2000.0, fitType=\"poisson\", name=\"cfg_pos\")]); tcc.setConfig(2, TrialConfig(covariateLabels=[\"Position\", \"y\"], Fs=1000.0, fitType=\"poisson\", name=\"cfg_pos_y\")); rates = np.array([cfg.getSampleRate() for cfg in tcc.getConfigs()], dtype=float); plt.figure(figsize=(8.0, 3.8)); plt.bar(tcc.getConfigNames(), rates, color=\"tab:purple\"); plt.title(f\"{TOPIC}: sample rates\"); plt.tight_layout(); plt.show(); CHECKPOINT_METRICS = {\"num_configs\": float(len(tcc.getConfigs())), \"mean_sample_rate\": float(np.mean(rates))}; CHECKPOINT_LIMITS = {\"num_configs\": (2.0, 2.0), \"mean_sample_rate\": (1400.0, 1800.0)}\n", - "assert len(tcc.getConfigs()) == 2\n", - "assert len(tcc.getSubsetConfigs([1, 2]).getConfigs()) == 2\n", - "assert float(rates[1]) == 1000.0\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "configcollexamples-04", - "metadata": {}, - "outputs": [], - "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % ConfigColl Examples\n", + "# ConfigColl Examples\n", + "# MATLAB L200: % tcObj=TrialConfig(covMask,sampleRate, history,minTime,maxTime)\n", + "# tcObj=TrialConfig(covMask,sampleRate, history,minTime,maxTime)\n", + "# MATLAB L300: tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\n", + "_matlab(\"tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\")\n", + "# MATLAB L301: tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\n", + "_matlab(\"tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\")\n", + "# MATLAB L302: tcc = ConfigColl({tc1,tc2});\n", + "_matlab('tcc = ConfigColl({tc1,tc2});')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 0, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/ConfigCollExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "ConfigCollExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/CovCollExamples.ipynb b/notebooks/CovCollExamples.ipynb index 65799f11..66fa9fdc 100644 --- a/notebooks/CovCollExamples.ipynb +++ b/notebooks/CovCollExamples.ipynb @@ -3,163 +3,114 @@ { "cell_type": "code", "execution_count": null, - "id": "covcollexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: CovCollExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/CovCollExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "covcollexamples-01", + "id": "643004de", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB CovCollExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"CovCollExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"CovCollExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"CovCollExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"CovCollExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"CovCollExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "covcollexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"load CovariateSample.mat;\",\n", - " \"cc=CovColl({position,force});\",\n", - " \"figure; cc.plot; %plots all covariates and their components\",\n", - " \"cc.getCov(1); %returns position;\",\n", - " \"cc.getCov('Position');\",\n", - " \"cc.getCov({'Position','Force'});\",\n", - " \"cc.resample(200); %resamples both position and force\",\n", - " \"cc.setMask({{'Position','x'},{'Force','f_y'}});\",\n", - " \"figure; cc.plot; %plot only x and f_y;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for CovCollExamples.\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "covcollexamples-03", - "metadata": {}, - "outputs": [], - "source": [ - "# CovCollExamples: covariate collection queries, masking, and resampling.\n", - "from nstat.compat.matlab import Covariate, CovColl, History, nspikeTrain\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='CovCollExamples', output_root=OUTPUT_ROOT, expected_count=2)\n", "\n", - "t = np.arange(0.0, 5.0 + 0.001, 0.001)\n", - "position = Covariate(time=t, data=np.column_stack([np.exp(-t), np.sin(2.0 * np.pi * t), np.sin(2.0 * np.pi * t) ** 3]), name=\"Position\", labels=[\"x\", \"y\", \"z\"])\n", - "force = Covariate(time=t, data=np.column_stack([np.abs(np.sin(2.0 * np.pi * t)), np.abs(np.sin(2.0 * np.pi * t)) ** 2]), name=\"Force\", labels=[\"f_x\", \"f_y\"])\n", - "cc = CovColl([position, force]); cc.resample(200.0); cc.setMask([\"Position\", \"Force\"])\n", - "fig, axes = plt.subplots(1, 2, figsize=(10, 4)); plt.sca(axes[0]); cc.plot(); axes[0].set_title(f\"{TOPIC}: resampled\")\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "X, labels = cc.dataToMatrix(); cc.removeCovariate(\"Force\"); n_after = cc.nActCovar()\n", - "history = History(bin_edges_s=np.array([0.0, 0.01, 0.03], dtype=float))\n", - "spikes = nspikeTrain(spike_times=np.sort(rng.random(25) * 0.5), t_start=0.0, t_end=0.5, name=\"tmp\")\n", - "H = history.computeHistory(spikes.spike_times, np.arange(0.0, 0.5, 0.01))\n", - "axes[1].imshow(H.T, aspect=\"auto\", origin=\"lower\", cmap=\"magma\"); axes[1].set_title(\"History basis\")\n", - "plt.tight_layout(); plt.show()\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "assert H.ndim == 2 and H.shape[1] == history.n_bins\n", - "assert spikes.spike_times.size > 5\n", - "CHECKPOINT_METRICS = {\"matrix_rows\": float(X.shape[0]), \"matrix_cols\": float(X.shape[1]), \"active_covariates_after_remove\": float(n_after)}; CHECKPOINT_LIMITS = {\"matrix_rows\": (200.0, 2000.0), \"matrix_cols\": (4.0, 8.0), \"active_covariates_after_remove\": (1.0, 3.0)}\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "covcollexamples-04", - "metadata": {}, - "outputs": [], - "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Test CovColl\n", + "# Test CovColl\n", + "# MATLAB L200: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L201: load CovariateSample.mat;\n", + "_matlab('load CovariateSample.mat;')\n", + "# MATLAB L202: cc=CovColl({position,force});\n", + "_matlab('cc=CovColl({position,force});')\n", + "# MATLAB L203: figure; cc.plot; %plots all covariates and their components\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('cc.plot')\n", + "_matlab('figure; cc.plot; %plots all covariates and their components')\n", + "# MATLAB L204: \n", + "#\n", + "# MATLAB L205: cc.getCov(1); %returns position;\n", + "_matlab('cc.getCov(1); %returns position;')\n", + "# MATLAB L206: cc.getCov('Position');\n", + "_matlab(\"cc.getCov('Position');\")\n", + "# MATLAB L207: cc.getCov({'Position','Force'});\n", + "_matlab(\"cc.getCov({'Position','Force'});\")\n", + "# MATLAB L208: cc.resample(200); %resamples both position and force\n", + "_matlab('cc.resample(200); %resamples both position and force')\n", + "# MATLAB L209: \n", + "#\n", + "# MATLAB L210: \n", + "#\n", + "# MATLAB L211: cc.setMask({{'Position','x'},{'Force','f_y'}});\n", + "_matlab(\"cc.setMask({{'Position','x'},{'Force','f_y'}});\")\n", + "# MATLAB L212: figure; cc.plot; %plot only x and f_y;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('cc.plot')\n", + "_matlab('figure; cc.plot; %plot only x and f_y;')\n", + "# MATLAB L213: \n", + "#\n", + "# MATLAB L214: % dataToMatrix\n", + "# dataToMatrix\n", + "# MATLAB L215: % setMaxTime\n", + "# setMaxTime\n", + "# MATLAB L216: % setMinTime\n", + "# setMinTime\n", + "# MATLAB L217: % removeCovariate\n", + "# removeCovariate\n", + "# MATLAB L218: % nActCovar\n", + "# nActCovar\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 2, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/CovCollExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "CovCollExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/CovariateExamples.ipynb b/notebooks/CovariateExamples.ipynb index cd94c31f..744655f9 100644 --- a/notebooks/CovariateExamples.ipynb +++ b/notebooks/CovariateExamples.ipynb @@ -3,179 +3,148 @@ { "cell_type": "code", "execution_count": null, - "id": "covariateexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: CovariateExamples\n", - "# Execution group: smoke\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/CovariateExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "covariateexamples-01", + "id": "867b527b", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB CovariateExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"CovariateExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"CovariateExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"CovariateExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"CovariateExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"CovariateExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "covariateexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"t=0:.01:5; t=t';\",\n", - " \"x=exp(-t);\",\n", - " \"y=sin(2*pi*t);\",\n", - " \"z=(-y).^3;\",\n", - " \"fx=abs(y);\",\n", - " \"fy=abs(y).^2;\",\n", - " \"dLabels1={'f_x','f_y'};\",\n", - " \"dLabels2={'x','y','z'};\",\n", - " \"plotProps = {{' ''g'', ''LineWidth'' ,.5'},... %for x\",\n", - " \"{' ''k'', ''LineWidth'' ,.5'},... %for y\",\n", - " \"{' ''b'' '}}; %for z\",\n", - " \"force = Covariate(t, [fx fy], 'Force', 'time', 's', 'N', dLabels1);\",\n", - " \"position=Covariate(t,[x y z], 'Position','time','s','cm', dLabels2);\",\n", - " \"position.getSigRep.plot('all',plotProps); %same as position.plot\",\n", - " \"plotPropsForce = {{' ''b'' '},{' ''k'' '}};\",\n", - " \"figure;\",\n", - " \"subplot(1,2,1); force.getSigRep.plot('all',plotPropsForce);\",\n", - " \"subplot(1,2,2); force.getSigRep('zero-mean').plot('all',plotPropsForce);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='CovariateExamples', output_root=OUTPUT_ROOT, expected_count=2)\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for CovariateExamples.\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "covariateexamples-03", - "metadata": {}, - "outputs": [], - "source": [ - "# CovariateExamples: build and inspect multiple covariate signals.\n", - "t = np.arange(0.0, 5.0 + 0.01, 0.01); x = np.exp(-t); y = np.sin(2.0 * np.pi * t); z = (-y) ** 3\n", - "force = Covariate(time=t, data=np.column_stack([np.abs(y), np.abs(y) ** 2]), name=\"Force\", labels=[\"f_x\", \"f_y\"])\n", - "position = Covariate(time=t, data=np.column_stack([x, y, z]), name=\"Position\", labels=[\"x\", \"y\", \"z\"])\n", - "force_zero_mean = force.data - np.mean(force.data, axis=0, keepdims=True)\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "fig, axes = plt.subplots(2, 2, figsize=(10, 7), sharex=True)\n", - "axes[0, 0].plot(t, position.data[:, 0], \"g\", linewidth=0.6, label=\"x\")\n", - "axes[0, 0].plot(t, position.data[:, 1], \"k\", linewidth=0.6, label=\"y\")\n", - "axes[0, 0].plot(t, position.data[:, 2], \"b\", linewidth=0.6, label=\"z\")\n", - "axes[0, 0].set_title(f\"{TOPIC}: position covariates\"); axes[0, 0].legend(loc=\"upper right\")\n", - "axes[0, 1].plot(t, force.data[:, 0], \"b\", linewidth=1.0, label=\"f_x\")\n", - "axes[0, 1].plot(t, force.data[:, 1], \"k\", linewidth=1.0, label=\"f_y\")\n", - "axes[0, 1].set_title(\"Force (original)\"); axes[0, 1].legend(loc=\"upper right\")\n", - "axes[1, 0].plot(t, force_zero_mean[:, 0], \"b\", linewidth=1.0, label=\"f_x\")\n", - "axes[1, 0].plot(t, force_zero_mean[:, 1], \"k\", linewidth=1.0, label=\"f_y\")\n", - "axes[1, 0].set_title(\"Force (zero-mean)\"); axes[1, 0].legend(loc=\"upper right\")\n", - "axes[1, 1].plot(t, position.data[:, 1], \"k\", linewidth=1.0); axes[1, 1].set_title(\"Position y\")\n", - "for ax in axes.ravel(): ax.set_xlabel(\"time [s]\")\n", - "plt.tight_layout(); plt.show()\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "assert position.data.shape == (t.size, 3)\n", - "assert force.data.shape == (t.size, 2)\n", - "assert np.isfinite(force_zero_mean).all()\n", - "CHECKPOINT_METRICS = {\"position_var\": float(np.var(position.data[:, 1])), \"force_mean\": float(np.mean(force.data[:, 0]))}\n", - "CHECKPOINT_LIMITS = {\"position_var\": (0.05, 2.0), \"force_mean\": (0.0, 2.0)}\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Test the Cov class\n", + "# Test the Cov class\n", + "# MATLAB L200: % Covariates are just like signals with a mean and a standard deviation They have two representations, the default (original representation) and a zero-mean representation\n", + "# Covariates are just like signals with a mean and a standard deviation They have two representations, the default (original representation) and a zero-mean representation\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "covariateexamples-04", + "id": "e3d3a566", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 1: Example 1: Using Covariates\n", + "# MATLAB L400: % Create some Data\n", + "# Create some Data\n", + "# MATLAB L500: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L501: t=0:.01:5; t=t';\n", + "_matlab(\"t=0:.01:5; t=t';\")\n", + "# MATLAB L502: x=exp(-t);\n", + "_matlab('x=exp(-t);')\n", + "# MATLAB L503: y=sin(2*pi*t);\n", + "_matlab('y=sin(2*pi*t);')\n", + "# MATLAB L504: z=(-y).^3;\n", + "_matlab('z=(-y).^3;')\n", + "# MATLAB L505: \n", + "#\n", + "# MATLAB L506: fx=abs(y);\n", + "_matlab('fx=abs(y);')\n", + "# MATLAB L507: fy=abs(y).^2;\n", + "_matlab('fy=abs(y).^2;')\n", + "# MATLAB L700: % Define labels and plotting properties for each Covariate\n", + "# Define labels and plotting properties for each Covariate\n", + "# MATLAB L800: dLabels1={'f_x','f_y'};\n", + "_matlab(\"dLabels1={'f_x','f_y'};\")\n", + "# MATLAB L801: dLabels2={'x','y','z'};\n", + "_matlab(\"dLabels2={'x','y','z'};\")\n", + "# MATLAB L802: \n", + "#\n", + "# MATLAB L803: plotProps = {{' ''g'', ''LineWidth'' ,.5'},... %for x\n", + "_matlab(\"plotProps = {{' ''g'', ''LineWidth'' ,.5'},... %for x\")\n", + "# MATLAB L804: {' ''k'', ''LineWidth'' ,.5'},... %for y\n", + "_matlab(\"{' ''k'', ''LineWidth'' ,.5'},... %for y\")\n", + "# MATLAB L805: {' ''b'' '}}; %for z\n", + "_matlab(\"{' ''b'' '}}; %for z\")\n", + "# MATLAB L806: \n", + "#\n", + "# MATLAB L807: force = Covariate(t, [fx fy], 'Force', 'time', 's', 'N', dLabels1);\n", + "_matlab(\"force = Covariate(t, [fx fy], 'Force', 'time', 's', 'N', dLabels1);\")\n", + "# MATLAB L808: position=Covariate(t,[x y z], 'Position','time','s','cm', dLabels2);\n", + "_matlab(\"position=Covariate(t,[x y z], 'Position','time','s','cm', dLabels2);\")\n", + "# MATLAB L1000: % Plot the covariates and change their properties\n", + "# Plot the covariates and change their properties\n", + "# MATLAB L1100: position.getSigRep.plot('all',plotProps); %same as position.plot\n", + "__tracker.new_figure(\"position.getSigRep.plot('all',plotProps)\")\n", + "_matlab(\"position.getSigRep.plot('all',plotProps); %same as position.plot\")\n", + "# MATLAB L1101: plotPropsForce = {{' ''b'' '},{' ''k'' '}};\n", + "_matlab(\"plotPropsForce = {{' ''b'' '},{' ''k'' '}};\")\n", + "# MATLAB L1102: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1103: subplot(1,2,1); force.getSigRep.plot('all',plotPropsForce);\n", + "__tracker.annotate('subplot(1,2,1)')\n", + "__tracker.annotate(\"force.getSigRep.plot('all',plotPropsForce)\")\n", + "_matlab(\"subplot(1,2,1); force.getSigRep.plot('all',plotPropsForce);\")\n", + "# MATLAB L1104: % can also set these properties as default by calling\n", + "# can also set these properties as default by calling\n", + "# MATLAB L1105: % >>force.setPlotProps(plotPropsForce);\n", + "# >>force.setPlotProps(plotPropsForce);\n", + "# MATLAB L1106: % >>force.plot;\n", + "# >>force.plot;\n", + "# MATLAB L1107: \n", + "#\n", + "# MATLAB L1108: subplot(1,2,2); force.getSigRep('zero-mean').plot('all',plotPropsForce);\n", + "__tracker.annotate('subplot(1,2,2)')\n", + "__tracker.annotate(\"force.getSigRep('zero-mean').plot('all',plotPropsForce)\")\n", + "_matlab(\"subplot(1,2,2); force.getSigRep('zero-mean').plot('all',plotPropsForce);\")\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 2, "run_group": "smoke", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/CovariateExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "CovariateExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/DecodingExample.ipynb b/notebooks/DecodingExample.ipynb index 2d08cb52..2239b3fb 100644 --- a/notebooks/DecodingExample.ipynb +++ b/notebooks/DecodingExample.ipynb @@ -3,268 +3,241 @@ { "cell_type": "code", "execution_count": null, - "id": "decodingexample-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: DecodingExample\n", - "# Execution group: smoke\n", - "# Workflow family: decoding_1d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/DecodingExample.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "decodingexample-01", + "id": "967388c7", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB DecodingExample.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"DecodingExample\"\n", - "FAMILY = \"decoding_1d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"DecodingExample: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"DecodingExample: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"DecodingExample: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"DecodingExample: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "decodingexample-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"delta = 0.001; Tmax = 10;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=.1; b1=1;b0=-3;\",\n", - " \"x = sin(2*pi*f*time);\",\n", - " \"expData = exp(b1*x+b0);\",\n", - " \"lambdaData = expData./(1+expData);\",\n", - " \"lambda = Covariate(time,lambdaData./delta, '\\\\Lambda(t)','time','s','Hz',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"numRealizations = 10;\",\n", - " \"spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1); spikeColl.plot;\",\n", - " \"subplot(2,1,2); lambda.plot;\",\n", - " \"stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"figure;\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial = Trial(spikeColl,cc);\",\n", - " \"trial.plot;\",\n", - " \"clear c;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\",\n", - " \"NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,selfHist,NeighborHist);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"figure;\",\n", - " \"results{1}.plotResults;\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"paramEst = squeeze(Summary.bAct(:,2,:));\",\n", - " \"meanParams = mean(paramEst,2);\",\n", - " \"clear lambdaCIF;\",\n", - " \"b0=paramEst(1,:);\",\n", - " \"b1=paramEst(2,:);\",\n", - " \"for i=1:numRealizations\",\n", - " \"lambdaCIF{i} = CIF([b0(i) b1(i)],{'1','x'},{'x'},'binomial');\",\n", - " \"end\",\n", - " \"spikeColl.resample(1/delta);\",\n", - " \"dN=spikeColl.dataToMatrix;\",\n", - " \"Q=2*std(stim.data(2:end)-stim.data(1:end-1));\",\n", - " \"A=1;\",\n", - " \"[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN',b0,b1,'binomial',delta);\",\n", - " \"figure;\",\n", - " \"zVal=3;\",\n", - " \"ciLower = min(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\",\n", - " \"ciUpper = max(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\",\n", - " \"hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'g'); hold on;\",\n", - " \"hold all;\",\n", - " \"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\",\n", - " \"legend off;\",\n", - " \"legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\\\sigma_{k|k}'),...\",\n", - " \"strcat('x_{k|k}(t)+',num2str(zVal),'\\\\sigma_{k|k}'),'x(t)');\",\n", - " \"title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for DecodingExample.\")\n" + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='DecodingExample', output_root=OUTPUT_ROOT, expected_count=5)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % STIMULUS DECODING\n", + "# STIMULUS DECODING\n", + "# MATLAB L200: % In this example we show how to decode a univariate and a bivariate stimulus based on a point process observations using nSTAT. Even though due to the simulated nature of the data, we know the exact condition intensity function, we estimate the parameters before moving on to the decoding stage.\n", + "# In this example we show how to decode a univariate and a bivariate stimulus based on a point process observations using nSTAT. Even though due to the simulated nature of the data, we know the exact condition intensity function, we estimate the parameters before moving on to the decoding stage.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "decodingexample-03", + "id": "014c654a", "metadata": {}, "outputs": [], "source": [ - "# 1D Decoding workflow: decode latent state sequence from population spikes.\n", - "n_units = 14\n", - "n_states = 17\n", - "n_time = 260\n", - "state_idx = np.arange(n_states)\n", - "\n", - "transition = np.zeros((n_states, n_states), dtype=float)\n", - "for i in range(n_states):\n", - " for j, w in ((i - 1, 0.2), (i, 0.6), (i + 1, 0.2)):\n", - " if 0 <= j < n_states:\n", - " transition[i, j] += w\n", - " transition[i, :] /= np.sum(transition[i, :])\n", - "\n", - "latent = np.zeros(n_time, dtype=int)\n", - "latent[0] = n_states // 2\n", - "for t in range(1, n_time):\n", - " latent[t] = rng.choice(n_states, p=transition[latent[t - 1]])\n", - "\n", - "centers = np.linspace(0.0, n_states - 1, n_units)\n", - "widths = np.full(n_units, 2.1)\n", - "state_axis = np.arange(n_states)[None, :]\n", - "tuning = 0.06 + 0.42 * np.exp(-0.5 * ((state_axis - centers[:, None]) / widths[:, None]) ** 2)\n", - "\n", - "use_history = TOPIC in {\"DecodingExampleWithHist\", \"nSTATPaperExamples\"}\n", - "\n", - "if use_history:\n", - " gain = np.ones(n_time, dtype=float)\n", - " counts = np.zeros((n_units, n_time), dtype=float)\n", - " prev = 0.0\n", - " for t in range(n_time):\n", - " gain[t] = np.exp(0.50 * prev)\n", - " lam = tuning[:, latent[t]] * gain[t]\n", - " counts[:, t] = rng.poisson(lam)\n", - " prev = float(np.mean(counts[:, t]))\n", - "\n", - " decoded_raw, _ = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition)\n", - " corrected = counts / gain[None, :]\n", - " decoded, posterior = DecodingAlgorithms.decode_state_posterior(corrected, tuning, transition)\n", - " rmse_raw = float(np.sqrt(np.mean((decoded_raw - latent) ** 2)) / (n_states - 1))\n", - " rmse_dec = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1))\n", - "else:\n", - " counts = np.zeros((n_units, n_time), dtype=float)\n", - " for t in range(n_time):\n", - " counts[:, t] = rng.poisson(tuning[:, latent[t]])\n", - " decoded, posterior = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition)\n", - " rmse_raw = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1))\n", - " rmse_dec = rmse_raw\n", - "\n", - "fig, axes = plt.subplots(2, 1, figsize=(9, 7), sharex=True)\n", - "axes[0].plot(latent, label=\"true\", linewidth=1.2)\n", - "axes[0].plot(decoded, label=\"decoded\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: latent-state decoding\")\n", - "axes[0].set_ylabel(\"state\")\n", - "axes[0].legend(loc=\"upper right\")\n", - "\n", - "im = axes[1].imshow(posterior, aspect=\"auto\", origin=\"lower\", cmap=\"viridis\")\n", - "axes[1].set_title(\"Posterior over latent states\")\n", - "axes[1].set_xlabel(\"time bin\")\n", - "axes[1].set_ylabel(\"state\")\n", - "fig.colorbar(im, ax=axes[1], fraction=0.03, pad=0.02)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "print(\"rmse_raw\", rmse_raw, \"rmse_final\", rmse_dec)\n", - "assert np.max(np.abs(np.sum(posterior, axis=0) - 1.0)) < 1e-6\n", - "if use_history:\n", - " assert rmse_dec <= rmse_raw + 0.03\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_raw\": float(rmse_raw),\n", - " \"rmse_dec\": float(rmse_dec),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_raw\": (0.0, 0.65),\n", - " \"rmse_dec\": (0.0, 0.65),\n", - "}\n" + "# SECTION 1: Generate the conditional Intensity Function\n", + "# MATLAB L400: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L401: delta = 0.001; Tmax = 10;\n", + "_matlab('delta = 0.001; Tmax = 10;')\n", + "# MATLAB L402: time = 0:delta:Tmax;\n", + "_matlab('time = 0:delta:Tmax;')\n", + "# MATLAB L403: f=.1; b1=1;b0=-3;\n", + "_matlab('f=.1; b1=1;b0=-3;')\n", + "# MATLAB L404: x = sin(2*pi*f*time);\n", + "_matlab('x = sin(2*pi*f*time);')\n", + "# MATLAB L405: expData = exp(b1*x+b0);\n", + "_matlab('expData = exp(b1*x+b0);')\n", + "# MATLAB L406: lambdaData = expData./(1+expData);\n", + "_matlab('lambdaData = expData./(1+expData);')\n", + "# MATLAB L407: \n", + "#\n", + "# MATLAB L408: lambda = Covariate(time,lambdaData./delta, '\\Lambda(t)','time','s','Hz',{'\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\n", + "_matlab(\"lambda = Covariate(time,lambdaData./delta, '\\\\Lambda(t)','time','s','Hz',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\")\n", + "# MATLAB L409: \n", + "#\n", + "# MATLAB L410: numRealizations = 10;\n", + "numRealizations = 10\n", + "# MATLAB L411: spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\n", + "_matlab('spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);')\n", + "# MATLAB L412: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L413: subplot(2,1,1); spikeColl.plot;\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('subplot(2,1,1); spikeColl.plot;')\n", + "# MATLAB L414: subplot(2,1,2); lambda.plot;\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('lambda.plot')\n", + "_matlab('subplot(2,1,2); lambda.plot;')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "decodingexample-04", + "id": "5bbc8ff7", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 2: Fit a model to the spikedata to obtain a model CIF\n", + "# MATLAB L700: stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\n", + "_matlab(\"stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\")\n", + "# MATLAB L701: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\")\n", + "# MATLAB L702: {'constant'});\n", + "_matlab(\"{'constant'});\")\n", + "# MATLAB L703: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L704: cc = CovColl({stim,baseline});\n", + "_matlab('cc = CovColl({stim,baseline});')\n", + "# MATLAB L705: trial = Trial(spikeColl,cc);\n", + "_matlab('trial = Trial(spikeColl,cc);')\n", + "# MATLAB L706: trial.plot;\n", + "__tracker.annotate('trial.plot')\n", + "_matlab('trial.plot;')\n", + "# MATLAB L707: \n", + "#\n", + "# MATLAB L708: clear c;\n", + "pass\n", + "# MATLAB L709: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", + "_matlab('selfHist = [] ; NeighborHist = []; sampleRate = 1000;')\n", + "# MATLAB L710: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\")\n", + "# MATLAB L711: NeighborHist);\n", + "_matlab('NeighborHist);')\n", + "# MATLAB L712: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L713: c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\n", + "_matlab(\"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\")\n", + "# MATLAB L714: sampleRate,selfHist,NeighborHist);\n", + "_matlab('sampleRate,selfHist,NeighborHist);')\n", + "# MATLAB L715: c{2}.setName('Baseline+Stimulus');\n", + "_matlab(\"c{2}.setName('Baseline+Stimulus');\")\n", + "# MATLAB L716: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L717: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);')\n", + "# MATLAB L718: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L719: results{1}.plotResults;\n", + "_matlab('results{1}.plotResults;')\n", + "# MATLAB L720: Summary = FitResSummary(results);\n", + "_matlab('Summary = FitResSummary(results);')\n", + "# MATLAB L721: \n", + "#\n", + "# MATLAB L722: paramEst = squeeze(Summary.bAct(:,2,:));\n", + "_matlab('paramEst = squeeze(Summary.bAct(:,2,:));')\n", + "# MATLAB L723: meanParams = mean(paramEst,2);\n", + "_matlab('meanParams = mean(paramEst,2);')\n", + "# MATLAB L900: % So we now have a model for lambda lambda = exp(b_0 + b_1*x(t))./(1+exp(b_0 + b_1*x(t)) * 1/delta because exp(b_0 + b_1*x(t))<<1 we can approximate this lambda by just the numerator i.e. lambda = exp(b_0 + b_1*x(t))./delta\n", + "# So we now have a model for lambda lambda = exp(b_0 + b_1*x(t))./(1+exp(b_0 + b_1*x(t)) * 1/delta because exp(b_0 + b_1*x(t))<<1 we can approximate this lambda by just the numerator i.e. lambda = exp(b_0 + b_1*x(t))./delta\n", + "# MATLAB L1000: % Now suppose we wanted to decode x(t) based on only having observed lambda\n", + "# Now suppose we wanted to decode x(t) based on only having observed lambda\n", + "# MATLAB L1100: clear lambdaCIF;\n", + "pass\n", + "# MATLAB L1101: b0=paramEst(1,:);\n", + "_matlab('b0=paramEst(1,:);')\n", + "# MATLAB L1102: b1=paramEst(2,:);\n", + "_matlab('b1=paramEst(2,:);')\n", + "# MATLAB L1103: for i=1:numRealizations\n", + "_matlab('for i=1:numRealizations')\n", + "# MATLAB L1104: % Construct a CIF object for each realization based on our encoding\n", + "# Construct a CIF object for each realization based on our encoding\n", + "# MATLAB L1105: % results abovel\n", + "# results abovel\n", + "# MATLAB L1106: lambdaCIF{i} = CIF([b0(i) b1(i)],{'1','x'},{'x'},'binomial');\n", + "_matlab(\"lambdaCIF{i} = CIF([b0(i) b1(i)],{'1','x'},{'x'},'binomial');\")\n", + "# MATLAB L1107: end\n", + "_matlab('end')\n", + "# MATLAB L1108: % close all;\n", + "# close all;\n", + "# MATLAB L1109: spikeColl.resample(1/delta);\n", + "_matlab('spikeColl.resample(1/delta);')\n", + "# MATLAB L1110: dN=spikeColl.dataToMatrix;\n", + "_matlab('dN=spikeColl.dataToMatrix;')\n", + "# MATLAB L1111: % Make noise according to the dynamic range of the stimulus\n", + "# Make noise according to the dynamic range of the stimulus\n", + "# MATLAB L1112: Q=2*std(stim.data(2:end)-stim.data(1:end-1));\n", + "_matlab('Q=2*std(stim.data(2:end)-stim.data(1:end-1));')\n", + "# MATLAB L1113: A=1;\n", + "A = 1\n", + "# MATLAB L1114: [x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN',b0,b1,'binomial',delta);\n", + "_matlab(\"[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN',b0,b1,'binomial',delta);\")\n", + "# MATLAB L1115: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1116: zVal=3;\n", + "zVal = 3\n", + "# MATLAB L1117: ciLower = min(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\n", + "_matlab(\"ciLower = min(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\")\n", + "# MATLAB L1118: ciUpper = max(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\n", + "_matlab(\"ciUpper = max(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\")\n", + "# MATLAB L1119: hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'g'); hold on;\n", + "__tracker.annotate(\"hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'g')\")\n", + "_matlab(\"hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'g'); hold on;\")\n", + "# MATLAB L1120: hold all;\n", + "_matlab('hold all;')\n", + "# MATLAB L1121: \n", + "#\n", + "# MATLAB L1122: hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\n", + "__tracker.annotate(\"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}})\")\n", + "_matlab(\"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\")\n", + "# MATLAB L1123: legend off;\n", + "_matlab('legend off;')\n", + "# MATLAB L1124: legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\sigma_{k|k}'),...\n", + "_matlab(\"legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\\\sigma_{k|k}'),...\")\n", + "# MATLAB L1125: strcat('x_{k|k}(t)+',num2str(zVal),'\\sigma_{k|k}'),'x_{k|k}(t)','x(t)');\n", + "_matlab(\"strcat('x_{k|k}(t)+',num2str(zVal),'\\\\sigma_{k|k}'),'x_{k|k}(t)','x(t)');\")\n", + "# MATLAB L1126: title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\n", + "_matlab(\"title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\")\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "decoding_1d", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 5, "run_group": "smoke", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/DecodingExample.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "DecodingExample" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/DecodingExampleWithHist.ipynb b/notebooks/DecodingExampleWithHist.ipynb index ead3f65e..c523fc21 100644 --- a/notebooks/DecodingExampleWithHist.ipynb +++ b/notebooks/DecodingExampleWithHist.ipynb @@ -3,266 +3,243 @@ { "cell_type": "code", "execution_count": null, - "id": "decodingexamplewithhist-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: DecodingExampleWithHist\n", - "# Execution group: smoke\n", - "# Workflow family: decoding_1d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/DecodingExampleWithHist.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "decodingexamplewithhist-01", + "id": "3d57b7f9", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB DecodingExampleWithHist.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"DecodingExampleWithHist\"\n", - "FAMILY = \"decoding_1d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"DecodingExampleWithHist: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"DecodingExampleWithHist: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"DecodingExampleWithHist: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"DecodingExampleWithHist: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "decodingexamplewithhist-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"delta = 0.001; Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=1; b1=1;b0=-2;\",\n", - " \"stimData = b1*sin(2*pi*f*time);\",\n", - " \"e = zeros(length(time),1); %No Ensemble input\",\n", - " \"mu = b0; %baseline firing rate\",\n", - " \"Ts=delta;\",\n", - " \"histCoeffs= [-2 -2 -4];\",\n", - " \"windowTimes=[0 .001 0.002 0.003];\",\n", - " \"histObj = History(windowTimes);\",\n", - " \"filts = histObj.toFilter(Ts); %Convert to transfer function matrix\",\n", - " \"H=histCoeffs*filts; %scale each window transfer function by its coefficient\",\n", - " \"S=tf([1],1,Ts,'Variable','z^-1'); %Feed the stimulus in directly\",\n", - " \"E=tf([0],1,Ts,'Variable','z^-1'); %No ensemble effect\",\n", - " \"stim=Covariate(time',stimData,'Stimulus','time','s','Voltage',{'sin'});\",\n", - " \"ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\",\n", - " \"numRealizations = 20; %Number of sample paths to generate\",\n", - " \"sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1); sC.plot;\",\n", - " \"subplot(2,1,2); stim.plot;\",\n", - " \"for i=1:numRealizations\",\n", - " \"lambdaCIF{i} = CIF([mu b1],{'1','x'},{'x'},'binomial',histCoeffs,histObj);\",\n", - " \"lambdaCIFNoHist{i} = CIF([mu b1],{'1','x'},{'x'},'binomial');\",\n", - " \"end\",\n", - " \"sC.resample(1/delta);\",\n", - " \"dN=sC.dataToMatrix;\",\n", - " \"Q=2*std(stim.data(2:end)-stim.data(1:end-1));\",\n", - " \"Px0=.1; A=1;\",\n", - " \"[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\",\n", - " \"[x_pNoHist, W_pNoHist, x_uNoHist, W_uNoHist] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIFNoHist,delta);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1);\",\n", - " \"zVal=3;\",\n", - " \"ciLower = min(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\",\n", - " \"ciUpper = max(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\",\n", - " \"hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\",\n", - " \"hold all;\",\n", - " \"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\",\n", - " \"legend off;\",\n", - " \"legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\\\sigma_{k|k}'),...\",\n", - " \"strcat('x_{k|k}(t)+',num2str(zVal),'\\\\sigma_{k|k}'),'x(t)');\",\n", - " \"title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\",\n", - " \"subplot(2,1,2);\",\n", - " \"zVal=3;\",\n", - " \"ciLower = min(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\",\n", - " \"ciUpper = max(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\",\n", - " \"hEst=plot(time,x_uNoHist(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\",\n", - " \"hold all;\",\n", - " \"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\",\n", - " \"legend off;\",\n", - " \"legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\\\sigma_{k|k}'),...\",\n", - " \"strcat('x_{k|k}(t)+',num2str(zVal),'\\\\sigma_{k|k}'),'x(t)');\",\n", - " \"title(['Decoded Stimulus No Hist +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for DecodingExampleWithHist.\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "decodingexamplewithhist-03", - "metadata": {}, - "outputs": [], - "source": [ - "# 1D Decoding workflow: decode latent state sequence from population spikes.\n", - "n_units = 14\n", - "n_states = 17\n", - "n_time = 260\n", - "state_idx = np.arange(n_states)\n", - "\n", - "transition = np.zeros((n_states, n_states), dtype=float)\n", - "for i in range(n_states):\n", - " for j, w in ((i - 1, 0.2), (i, 0.6), (i + 1, 0.2)):\n", - " if 0 <= j < n_states:\n", - " transition[i, j] += w\n", - " transition[i, :] /= np.sum(transition[i, :])\n", - "\n", - "latent = np.zeros(n_time, dtype=int)\n", - "latent[0] = n_states // 2\n", - "for t in range(1, n_time):\n", - " latent[t] = rng.choice(n_states, p=transition[latent[t - 1]])\n", - "\n", - "centers = np.linspace(0.0, n_states - 1, n_units)\n", - "widths = np.full(n_units, 2.1)\n", - "state_axis = np.arange(n_states)[None, :]\n", - "tuning = 0.06 + 0.42 * np.exp(-0.5 * ((state_axis - centers[:, None]) / widths[:, None]) ** 2)\n", - "\n", - "use_history = TOPIC in {\"DecodingExampleWithHist\", \"nSTATPaperExamples\"}\n", - "\n", - "if use_history:\n", - " gain = np.ones(n_time, dtype=float)\n", - " counts = np.zeros((n_units, n_time), dtype=float)\n", - " prev = 0.0\n", - " for t in range(n_time):\n", - " gain[t] = np.exp(0.50 * prev)\n", - " lam = tuning[:, latent[t]] * gain[t]\n", - " counts[:, t] = rng.poisson(lam)\n", - " prev = float(np.mean(counts[:, t]))\n", - "\n", - " decoded_raw, _ = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition)\n", - " corrected = counts / gain[None, :]\n", - " decoded, posterior = DecodingAlgorithms.decode_state_posterior(corrected, tuning, transition)\n", - " rmse_raw = float(np.sqrt(np.mean((decoded_raw - latent) ** 2)) / (n_states - 1))\n", - " rmse_dec = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1))\n", - "else:\n", - " counts = np.zeros((n_units, n_time), dtype=float)\n", - " for t in range(n_time):\n", - " counts[:, t] = rng.poisson(tuning[:, latent[t]])\n", - " decoded, posterior = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition)\n", - " rmse_raw = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1))\n", - " rmse_dec = rmse_raw\n", - "\n", - "fig, axes = plt.subplots(2, 1, figsize=(9, 7), sharex=True)\n", - "axes[0].plot(latent, label=\"true\", linewidth=1.2)\n", - "axes[0].plot(decoded, label=\"decoded\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: latent-state decoding\")\n", - "axes[0].set_ylabel(\"state\")\n", - "axes[0].legend(loc=\"upper right\")\n", - "\n", - "im = axes[1].imshow(posterior, aspect=\"auto\", origin=\"lower\", cmap=\"viridis\")\n", - "axes[1].set_title(\"Posterior over latent states\")\n", - "axes[1].set_xlabel(\"time bin\")\n", - "axes[1].set_ylabel(\"state\")\n", - "fig.colorbar(im, ax=axes[1], fraction=0.03, pad=0.02)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "print(\"rmse_raw\", rmse_raw, \"rmse_final\", rmse_dec)\n", - "assert np.max(np.abs(np.sum(posterior, axis=0) - 1.0)) < 1e-6\n", - "if use_history:\n", - " assert rmse_dec <= rmse_raw + 0.03\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_raw\": float(rmse_raw),\n", - " \"rmse_dec\": float(rmse_dec),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_raw\": (0.0, 0.65),\n", - " \"rmse_dec\": (0.0, 0.65),\n", - "}\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "decodingexamplewithhist-04", - "metadata": {}, - "outputs": [], - "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='DecodingExampleWithHist', output_root=OUTPUT_ROOT, expected_count=2)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % 1-D Stimulus Decode with History Effect\n", + "# 1-D Stimulus Decode with History Effect\n", + "# MATLAB L200: % In the above decoding example, the simulated neurons did not have memory. That is their previous firing activity did not modulate their current probability of firing. In reality the firing history does affect the probabilty of neuronal firing (eg. refractory period, bursting, etc.). In this example, we simulate a population a neurons that exhibit this type of history dependence. We then decode the stimulus activity based on a conditional intensity function that includes the correct history terms and one that assumes no history dependence.\n", + "# In the above decoding example, the simulated neurons did not have memory. That is their previous firing activity did not modulate their current probability of firing. In reality the firing history does affect the probabilty of neuronal firing (eg. refractory period, bursting, etc.). In this example, we simulate a population a neurons that exhibit this type of history dependence. We then decode the stimulus activity based on a conditional intensity function that includes the correct history terms and one that assumes no history dependence.\n", + "# MATLAB L300: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L301: % clear all;\n", + "# clear all;\n", + "# MATLAB L302: delta = 0.001; Tmax = 1;\n", + "_matlab('delta = 0.001; Tmax = 1;')\n", + "# MATLAB L303: time = 0:delta:Tmax;\n", + "_matlab('time = 0:delta:Tmax;')\n", + "# MATLAB L304: f=1; b1=1;b0=-2;\n", + "_matlab('f=1; b1=1;b0=-2;')\n", + "# MATLAB L305: stimData = b1*sin(2*pi*f*time);\n", + "_matlab('stimData = b1*sin(2*pi*f*time);')\n", + "# MATLAB L306: e = zeros(length(time),1); %No Ensemble input\n", + "_matlab('e = zeros(length(time),1); %No Ensemble input')\n", + "# MATLAB L307: mu = b0; %baseline firing rate\n", + "_matlab('mu = b0; %baseline firing rate')\n", + "# MATLAB L308: Ts=delta;\n", + "_matlab('Ts=delta;')\n", + "# MATLAB L309: \n", + "#\n", + "# MATLAB L310: histCoeffs= [-2 -2 -4];\n", + "_matlab('histCoeffs= [-2 -2 -4];')\n", + "# MATLAB L311: windowTimes=[0 .001 0.002 0.003];\n", + "_matlab('windowTimes=[0 .001 0.002 0.003];')\n", + "# MATLAB L312: histObj = History(windowTimes);\n", + "_matlab('histObj = History(windowTimes);')\n", + "# MATLAB L313: filts = histObj.toFilter(Ts); %Convert to transfer function matrix\n", + "_matlab('filts = histObj.toFilter(Ts); %Convert to transfer function matrix')\n", + "# MATLAB L314: H=histCoeffs*filts; %scale each window transfer function by its coefficient\n", + "_matlab('H=histCoeffs*filts; %scale each window transfer function by its coefficient')\n", + "# MATLAB L315: S=tf([1],1,Ts,'Variable','z^-1'); %Feed the stimulus in directly\n", + "_matlab(\"S=tf([1],1,Ts,'Variable','z^-1'); %Feed the stimulus in directly\")\n", + "# MATLAB L316: E=tf([0],1,Ts,'Variable','z^-1'); %No ensemble effect\n", + "_matlab(\"E=tf([0],1,Ts,'Variable','z^-1'); %No ensemble effect\")\n", + "# MATLAB L317: stim=Covariate(time',stimData,'Stimulus','time','s','Voltage',{'sin'});\n", + "_matlab(\"stim=Covariate(time',stimData,'Stimulus','time','s','Voltage',{'sin'});\")\n", + "# MATLAB L318: ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\n", + "_matlab(\"ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\")\n", + "# MATLAB L319: numRealizations = 20; %Number of sample paths to generate\n", + "numRealizations = 20\n", + "# MATLAB L320: sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations);\n", + "_matlab('sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations);')\n", + "# MATLAB L321: \n", + "#\n", + "# MATLAB L322: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L323: subplot(2,1,1); sC.plot;\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('sC.plot')\n", + "_matlab('subplot(2,1,1); sC.plot;')\n", + "# MATLAB L324: subplot(2,1,2); stim.plot;\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('stim.plot')\n", + "_matlab('subplot(2,1,2); stim.plot;')\n", + "# MATLAB L325: \n", + "#\n", + "# MATLAB L326: \n", + "#\n", + "# MATLAB L327: for i=1:numRealizations\n", + "_matlab('for i=1:numRealizations')\n", + "# MATLAB L328: % Construct a CIF object for each realization based on our encoding\n", + "# Construct a CIF object for each realization based on our encoding\n", + "# MATLAB L329: % results above\n", + "# results above\n", + "# MATLAB L330: %correct CIF w/ History\n", + "# correct CIF w/ History\n", + "# MATLAB L331: lambdaCIF{i} = CIF([mu b1],{'1','x'},{'x'},'binomial',histCoeffs,histObj);\n", + "_matlab(\"lambdaCIF{i} = CIF([mu b1],{'1','x'},{'x'},'binomial',histCoeffs,histObj);\")\n", + "# MATLAB L332: %CIF ignoring the history effect\n", + "# CIF ignoring the history effect\n", + "# MATLAB L333: lambdaCIFNoHist{i} = CIF([mu b1],{'1','x'},{'x'},'binomial');\n", + "_matlab(\"lambdaCIFNoHist{i} = CIF([mu b1],{'1','x'},{'x'},'binomial');\")\n", + "# MATLAB L334: end\n", + "_matlab('end')\n", + "# MATLAB L335: \n", + "#\n", + "# MATLAB L336: \n", + "#\n", + "# MATLAB L337: \n", + "#\n", + "# MATLAB L338: \n", + "#\n", + "# MATLAB L339: sC.resample(1/delta);\n", + "_matlab('sC.resample(1/delta);')\n", + "# MATLAB L340: dN=sC.dataToMatrix;\n", + "_matlab('dN=sC.dataToMatrix;')\n", + "# MATLAB L341: % Make noise according to the dynamic range of the stimulus\n", + "# Make noise according to the dynamic range of the stimulus\n", + "# MATLAB L342: Q=2*std(stim.data(2:end)-stim.data(1:end-1));\n", + "_matlab('Q=2*std(stim.data(2:end)-stim.data(1:end-1));')\n", + "# MATLAB L343: Px0=.1; A=1;\n", + "_matlab('Px0=.1; A=1;')\n", + "# MATLAB L344: % Decode with the correct and incorrect CIFs\n", + "# Decode with the correct and incorrect CIFs\n", + "# MATLAB L345: \n", + "#\n", + "# MATLAB L346: [x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\n", + "_matlab(\"[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\")\n", + "# MATLAB L347: [x_pNoHist, W_pNoHist, x_uNoHist, W_uNoHist] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIFNoHist,delta);\n", + "_matlab(\"[x_pNoHist, W_pNoHist, x_uNoHist, W_uNoHist] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIFNoHist,delta);\")\n", + "# MATLAB L348: \n", + "#\n", + "# MATLAB L349: \n", + "#\n", + "# MATLAB L350: % Compare the results\n", + "# Compare the results\n", + "# MATLAB L351: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L352: subplot(2,1,1);\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "_matlab('subplot(2,1,1);')\n", + "# MATLAB L353: zVal=3;\n", + "zVal = 3\n", + "# MATLAB L354: ciLower = min(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\n", + "_matlab(\"ciLower = min(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\")\n", + "# MATLAB L355: ciUpper = max(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\n", + "_matlab(\"ciUpper = max(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\")\n", + "# MATLAB L356: hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\n", + "__tracker.annotate(\"hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'r')\")\n", + "_matlab(\"hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\")\n", + "# MATLAB L357: hold all;\n", + "_matlab('hold all;')\n", + "# MATLAB L358: \n", + "#\n", + "# MATLAB L359: hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\n", + "__tracker.annotate(\"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}})\")\n", + "_matlab(\"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\")\n", + "# MATLAB L360: legend off;\n", + "_matlab('legend off;')\n", + "# MATLAB L361: legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\sigma_{k|k}'),...\n", + "_matlab(\"legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\\\sigma_{k|k}'),...\")\n", + "# MATLAB L362: strcat('x_{k|k}(t)+',num2str(zVal),'\\sigma_{k|k}'),'x_{k|k}(t)','x(t)');\n", + "_matlab(\"strcat('x_{k|k}(t)+',num2str(zVal),'\\\\sigma_{k|k}'),'x_{k|k}(t)','x(t)');\")\n", + "# MATLAB L363: title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\n", + "_matlab(\"title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\")\n", + "# MATLAB L364: \n", + "#\n", + "# MATLAB L365: subplot(2,1,2);\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "_matlab('subplot(2,1,2);')\n", + "# MATLAB L366: zVal=3;\n", + "zVal = 3\n", + "# MATLAB L367: ciLower = min(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\n", + "_matlab(\"ciLower = min(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\")\n", + "# MATLAB L368: ciUpper = max(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\n", + "_matlab(\"ciUpper = max(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\")\n", + "# MATLAB L369: hEst=plot(time,x_uNoHist(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\n", + "__tracker.annotate(\"hEst=plot(time,x_uNoHist(1:end),'b',time,ciLower,'g',time,ciUpper,'r')\")\n", + "_matlab(\"hEst=plot(time,x_uNoHist(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\")\n", + "# MATLAB L370: hold all;\n", + "_matlab('hold all;')\n", + "# MATLAB L371: \n", + "#\n", + "# MATLAB L372: hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\n", + "__tracker.annotate(\"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}})\")\n", + "_matlab(\"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\")\n", + "# MATLAB L373: legend off;\n", + "_matlab('legend off;')\n", + "# MATLAB L374: legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\sigma_{k|k}'),...\n", + "_matlab(\"legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\\\sigma_{k|k}'),...\")\n", + "# MATLAB L375: strcat('x_{k|k}(t)+',num2str(zVal),'\\sigma_{k|k}'),'x_{k|k}(t)','x(t)');\n", + "_matlab(\"strcat('x_{k|k}(t)+',num2str(zVal),'\\\\sigma_{k|k}'),'x_{k|k}(t)','x(t)');\")\n", + "# MATLAB L376: title(['Decoded Stimulus No Hist +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\n", + "__tracker.annotate(\"title(['Decoded Stimulus No Hist +/- 99% confidence intervals using ' num2str(numRealizations) ' cells'])\")\n", + "_matlab(\"title(['Decoded Stimulus No Hist +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\")\n", + "# MATLAB L500: % We see that inclusion of history effect improves (as expected) the decoding of the stimulus based on the point process observations\n", + "# We see that inclusion of history effect improves (as expected) the decoding of the stimulus based on the point process observations\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "decoding_1d", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 2, "run_group": "smoke", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/DecodingExampleWithHist.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "DecodingExampleWithHist" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/DocumentationSetup2025b.ipynb b/notebooks/DocumentationSetup2025b.ipynb index 873cb0a4..4f1c5ca4 100644 --- a/notebooks/DocumentationSetup2025b.ipynb +++ b/notebooks/DocumentationSetup2025b.ipynb @@ -3,182 +3,190 @@ { "cell_type": "code", "execution_count": null, - "id": "documentationsetup2025b-00", + "id": "7231eb82", "metadata": {}, "outputs": [], "source": [ - "# Topic: DocumentationSetup2025b\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/DocumentationSetup2025b.md\n" + "# AUTO-GENERATED FROM MATLAB DocumentationSetup2025b.m -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", + "import matplotlib\n", + "matplotlib.use(\"Agg\")\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='DocumentationSetup2025b', output_root=OUTPUT_ROOT, expected_count=0)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "documentationsetup2025b-01", + "id": "3b4a9a88", "metadata": {}, "outputs": [], "source": [ - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"DocumentationSetup2025b\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"DocumentationSetup2025b: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"DocumentationSetup2025b: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"DocumentationSetup2025b: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"DocumentationSetup2025b: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "# SECTION 1: MATLAB 2025b Help Integration for nSTAT\n", + "# MATLAB L2: % This page documents the help-file structure used by nSTAT so it appears as\n", + "# This page documents the help-file structure used by nSTAT so it appears as\n", + "# MATLAB L3: % supplemental software documentation in MATLAB.\n", + "# supplemental software documentation in MATLAB.\n", + "# MATLAB L4: %\n", + "#\n", + "# MATLAB L5: % The configuration in this release is aligned with MATLAB R2025b.\n", + "# The configuration in this release is aligned with MATLAB R2025b.\n", + "# MATLAB L6: %\n", + "#\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "documentationsetup2025b-02", + "id": "00ed1744", "metadata": {}, "outputs": [], "source": [ - "# DocumentationSetup2025b: validate Python help-file layout and TOC targets.\n", - "from pathlib import Path\n", - "import yaml\n", - "\n", - "def resolve_repo_root() -> Path:\n", - " candidates = [Path.cwd().resolve()]\n", - " candidates.append(candidates[0].parent)\n", - " candidates.append(candidates[1].parent)\n", - " for root in candidates:\n", - " if (root / \"docs\" / \"help\").exists():\n", - " return root\n", - " return candidates[0]\n", - "\n", - "repo_root = resolve_repo_root()\n", - "help_root = repo_root / \"docs\" / \"help\"\n", - "docs_root = repo_root / \"docs\"\n", - "helptoc_path = help_root / \"helptoc.yml\"\n", - "payload = yaml.safe_load(helptoc_path.read_text(encoding=\"utf-8\")) if helptoc_path.exists() else {}\n", - "\n", - "def walk_nodes(nodes):\n", - " out = []\n", - " for node in nodes or []:\n", - " target = str(node.get(\"target\", \"\")).strip()\n", - " if target:\n", - " out.append(target)\n", - " out.extend(walk_nodes(node.get(\"children\", [])))\n", - " return out\n", - "\n", - "targets = walk_nodes(payload.get(\"toc\", payload.get(\"entries\", [])))\n", - "targets = sorted(set(targets))\n", - "def target_exists(target: str) -> bool:\n", - " candidate = Path(target)\n", - " candidates = []\n", - " if candidate.is_absolute():\n", - " candidates.append(candidate)\n", - " else:\n", - " candidates.append(help_root / candidate)\n", - " candidates.append(docs_root / candidate)\n", - " candidates.append(repo_root / candidate)\n", - " return any(path.exists() for path in candidates)\n", - "\n", - "resolved = [target_exists(target) for target in targets if not target.startswith(\"http\")]\n", - "n_ok = int(sum(resolved))\n", - "n_total = int(len(resolved))\n", - "n_missing = int(n_total - n_ok)\n", - "\n", - "md_pages = list(help_root.rglob(\"*.md\"))\n", - "html_pages = list(help_root.rglob(\"*.html\"))\n", - "\n", - "fig, axes = plt.subplots(1, 2, figsize=(9.2, 3.8))\n", - "axes[0].bar([\"targets\", \"valid\"], [n_total, n_ok], color=[\"tab:gray\", \"tab:blue\"])\n", - "axes[0].set_title(f\"{TOPIC}: TOC target validation\")\n", - "axes[0].set_ylabel(\"count\")\n", - "\n", - "axes[1].bar([\".md pages\", \".html pages\"], [len(md_pages), len(html_pages)], color=[\"tab:green\", \"tab:orange\"])\n", - "axes[1].set_title(\"Docs page inventory\")\n", - "axes[1].set_ylabel(\"count\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert n_total > 0\n", - "assert n_missing == 0\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"toc_targets\": float(n_total),\n", - " \"missing_targets\": float(n_missing),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"toc_targets\": (1.0, 5000.0),\n", - " \"missing_targets\": (0.0, 0.0),\n", - "}\n" + "# SECTION 2: Required Files\n", + "# MATLAB L8: % nSTAT uses the standard external toolbox documentation layout:\n", + "# nSTAT uses the standard external toolbox documentation layout:\n", + "# MATLAB L9: %\n", + "#\n", + "# MATLAB L10: % * `info.xml` in the toolbox root.\n", + "# * `info.xml` in the toolbox root.\n", + "# MATLAB L11: % * `helpfiles/helptoc.xml` with `toc version=\"2.0\"`.\n", + "# * `helpfiles/helptoc.xml` with `toc version=\"2.0\"`.\n", + "# MATLAB L12: % * HTML help content referenced by each `target` in `helptoc.xml`.\n", + "# * HTML help content referenced by each `target` in `helptoc.xml`.\n", + "# MATLAB L13: %\n", + "#\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79c1b946", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 3: Build and Refresh the Search Database\n", + "# MATLAB L15: % Run the installer script from the nSTAT root folder:\n", + "# Run the installer script from the nSTAT root folder:\n", + "# MATLAB L16: %\n", + "#\n", + "# MATLAB L17: % nSTAT_Install\n", + "# nSTAT_Install\n", + "# MATLAB L18: %\n", + "#\n", + "# MATLAB L19: % or run these commands manually:\n", + "# or run these commands manually:\n", + "# MATLAB L20: %\n", + "#\n", + "# MATLAB L21: % rootDir = fileparts(which('nSTAT_Install'));\n", + "# rootDir = fileparts(which('nSTAT_Install'));\n", + "# MATLAB L22: % helpDir = fullfile(rootDir,'helpfiles');\n", + "# helpDir = fullfile(rootDir,'helpfiles');\n", + "# MATLAB L23: % builddocsearchdb(helpDir);\n", + "# builddocsearchdb(helpDir);\n", + "# MATLAB L24: % rehash toolboxcache;\n", + "# rehash toolboxcache;\n", + "# MATLAB L25: %\n", + "#\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04f35d0b", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 4: MATLAB 2025b Behavior\n", + "# MATLAB L27: % Starting in R2024b, toolbox documentation is shown in the system browser.\n", + "# Starting in R2024b, toolbox documentation is shown in the system browser.\n", + "# MATLAB L28: % External toolbox documentation appears in MATLAB documentation under\n", + "# External toolbox documentation appears in MATLAB documentation under\n", + "# MATLAB L29: % Supplemental Software.\n", + "# Supplemental Software.\n", + "# MATLAB L30: %\n", + "#\n", + "# MATLAB L31: % Use these pages as entry points:\n", + "# Use these pages as entry points:\n", + "# MATLAB L32: %\n", + "#\n", + "# MATLAB L33: % * \n", + "# * \n", + "# MATLAB L34: % * \n", + "# * \n", + "# MATLAB L35: % * \n", + "# * \n", + "# MATLAB L36: %\n", + "#\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "documentationsetup2025b-03", + "id": "5945c29c", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 5: Troubleshooting\n", + "# MATLAB L38: % * If the nSTAT docs are not visible, run `rehash toolboxcache`.\n", + "# * If the nSTAT docs are not visible, run `rehash toolboxcache`.\n", + "# MATLAB L39: % * If nSTAT pages do not appear in search, run `builddocsearchdb` again.\n", + "# * If nSTAT pages do not appear in search, run `builddocsearchdb` again.\n", + "# MATLAB L40: % * Ensure all `target` entries in `helptoc.xml` map to real HTML files.\n", + "# * Ensure all `target` entries in `helptoc.xml` map to real HTML files.\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "data", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 0, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/DocumentationSetup2025b.m", + "source_type": "m", + "strict_section_cell_mapping": true, "topic": "DocumentationSetup2025b" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/EventsExamples.ipynb b/notebooks/EventsExamples.ipynb index 0874379d..beef0c21 100644 --- a/notebooks/EventsExamples.ipynb +++ b/notebooks/EventsExamples.ipynb @@ -3,151 +3,97 @@ { "cell_type": "code", "execution_count": null, - "id": "eventsexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: EventsExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/EventsExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eventsexamples-01", + "id": "c02f8d55", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB EventsExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "TOPIC = \"EventsExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='EventsExamples', output_root=OUTPUT_ROOT, expected_count=3)\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"EventsExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"EventsExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"EventsExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"EventsExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eventsexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"eTimes = sort(rand(1,3)*1);\",\n", - " \"eLabels={'E_1','E_2','E_3'};\",\n", - " \"eventColor = 'b';\",\n", - " \"e=Events(eTimes,eLabels,eventColor);\",\n", - " \"e.plot;\",\n", - " \"figure; e.plot([],'r'); %dont specify handle, use red; handel = gca;\",\n", - " \"figure; e.plot([],'g'); %dont specify handle, use green;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for EventsExamples.\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eventsexamples-03", - "metadata": {}, - "outputs": [], - "source": [ - "# EventsExamples: visualize event markers over multiple contexts.\n", - "e_times = np.array([0.079, 0.579, 0.997], dtype=float); events = Events(times=e_times, labels=[\"E_1\", \"E_2\", \"E_3\"])\n", - "fig, ax = plt.subplots(1, 1, figsize=(10.74, 6.48))\n", - "for c in [\"b\", \"r\", \"g\", \"m\"]: ax.vlines(events.times, ymin=0.0, ymax=1.0, colors=c, linewidth=2.0, alpha=0.4)\n", - "for i, t_evt in enumerate(events.times): ax.text(t_evt - 0.02, 1.03, f\"E_{i+1}\", ha=\"left\", va=\"bottom\", fontsize=9, color=\"k\")\n", - "ax.set_xlim(0.0, 1.0); ax.set_ylim(0.0, 1.0); ax.set_title(f\"{TOPIC}: event overlays\"); plt.tight_layout(); plt.show()\n", - "assert events.times.size == 3 and bool(np.all(np.diff(events.times) > 0.0))\n", - "CHECKPOINT_METRICS = {\"event_count\": float(events.times.size), \"event_span\": float(events.times[-1] - events.times[0])}\n", - "CHECKPOINT_LIMITS = {\"event_count\": (3.0, 3.0), \"event_span\": (0.8, 1.0)}\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eventsexamples-04", - "metadata": {}, - "outputs": [], - "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Events\n", + "# Events\n", + "# MATLAB L200: % Events are simple object to use and are aimed to facilitate illustration of epochs in any time of data.\n", + "# Events are simple object to use and are aimed to facilitate illustration of epochs in any time of data.\n", + "# MATLAB L300: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L301: eTimes = sort(rand(1,3)*1);\n", + "_matlab('eTimes = sort(rand(1,3)*1);')\n", + "# MATLAB L302: eLabels={'E_1','E_2','E_3'};\n", + "_matlab(\"eLabels={'E_1','E_2','E_3'};\")\n", + "# MATLAB L303: eventColor = 'b';\n", + "_matlab(\"eventColor = 'b';\")\n", + "# MATLAB L304: e=Events(eTimes,eLabels,eventColor);\n", + "_matlab('e=Events(eTimes,eLabels,eventColor);')\n", + "# MATLAB L305: e.plot;\n", + "__tracker.new_figure('e.plot')\n", + "_matlab('e.plot;')\n", + "# MATLAB L500: % The color of the event markers can also be specified\n", + "# The color of the event markers can also be specified\n", + "# MATLAB L600: figure; e.plot([],'r'); %dont specify handle, use red; handel = gca;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate(\"e.plot([],'r')\")\n", + "_matlab(\"figure; e.plot([],'r'); %dont specify handle, use red; handel = gca;\")\n", + "# MATLAB L601: figure; e.plot([],'g'); %dont specify handle, use green;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate(\"e.plot([],'g')\")\n", + "_matlab(\"figure; e.plot([],'g'); %dont specify handle, use green;\")\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 3, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/EventsExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "EventsExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/ExplicitStimulusWhiskerData.ipynb b/notebooks/ExplicitStimulusWhiskerData.ipynb index 16be6be8..e95abfce 100644 --- a/notebooks/ExplicitStimulusWhiskerData.ipynb +++ b/notebooks/ExplicitStimulusWhiskerData.ipynb @@ -3,291 +3,420 @@ { "cell_type": "code", "execution_count": null, - "id": "explicitstimuluswhiskerdata-00", + "id": "1d08bdee", "metadata": {}, "outputs": [], "source": [ - "# Topic: ExplicitStimulusWhiskerData\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/ExplicitStimulusWhiskerData.md\n" + "# AUTO-GENERATED FROM MATLAB ExplicitStimulusWhiskerData.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", + "import matplotlib\n", + "matplotlib.use(\"Agg\")\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='ExplicitStimulusWhiskerData', output_root=OUTPUT_ROOT, expected_count=8)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % EXPLICIT STIMULUS EXAMPLE - WHISKER STIMULATION/THALAMIC NEURON\n", + "# EXPLICIT STIMULUS EXAMPLE - WHISKER STIMULATION/THALAMIC NEURON\n", + "# MATLAB L200: % In the worksheet with analyze the stimulus effect and history effect on the firing of a thalamic neuron under a known stimulus consisting of whisker stimulation. Data from Demba Ba (demba@mit.edu)\n", + "# In the worksheet with analyze the stimulus effect and history effect on the firing of a thalamic neuron under a known stimulus consisting of whisker stimulation. Data from Demba Ba (demba@mit.edu)\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "explicitstimuluswhiskerdata-01", + "id": "084dc36c", "metadata": {}, "outputs": [], "source": [ - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"ExplicitStimulusWhiskerData\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"ExplicitStimulusWhiskerData: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"ExplicitStimulusWhiskerData: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"ExplicitStimulusWhiskerData: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"ExplicitStimulusWhiskerData: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "# SECTION 1: Load the data\n", + "# MATLAB L400: close all; currdir = pwd;\n", + "plt.close(\"all\")\n", + "# MATLAB L401: index = strfind(currdir,'helpfiles')-1;\n", + "_matlab(\"index = strfind(currdir,'helpfiles')-1;\")\n", + "# MATLAB L402: rootpath = currdir(1:index);\n", + "_matlab('rootpath = currdir(1:index);')\n", + "# MATLAB L403: \n", + "#\n", + "# MATLAB L404: Direction=3; Neuron=1; Stim=2;\n", + "_matlab('Direction=3; Neuron=1; Stim=2;')\n", + "# MATLAB L405: datapath = fullfile(rootpath,'data','Explicit Stimulus',strcat('Dir', num2str(Direction)),...\n", + "_matlab(\"datapath = fullfile(rootpath,'data','Explicit Stimulus',strcat('Dir', num2str(Direction)),...\")\n", + "# MATLAB L406: strcat('Neuron', num2str(Neuron)), strcat('Stim', num2str(Stim)));\n", + "_matlab(\"strcat('Neuron', num2str(Neuron)), strcat('Stim', num2str(Stim)));\")\n", + "# MATLAB L407: data=load(fullfile(datapath,'trngdataBis.mat'));\n", + "_matlab(\"data=load(fullfile(datapath,'trngdataBis.mat'));\")\n", + "# MATLAB L408: \n", + "#\n", + "# MATLAB L409: time=0:.001:(length(data.t)-1)*.001;\n", + "_matlab('time=0:.001:(length(data.t)-1)*.001;')\n", + "# MATLAB L410: stimData = data.t;\n", + "_matlab('stimData = data.t;')\n", + "# MATLAB L411: spikeTimes = time(data.y==1);\n", + "_matlab('spikeTimes = time(data.y==1);')\n", + "# MATLAB L412: \n", + "#\n", + "# MATLAB L413: stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\n", + "_matlab(\"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\")\n", + "# MATLAB L414: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\")\n", + "# MATLAB L415: {'constant'});\n", + "_matlab(\"{'constant'});\")\n", + "# MATLAB L416: \n", + "#\n", + "# MATLAB L417: nst = nspikeTrain(spikeTimes);\n", + "_matlab('nst = nspikeTrain(spikeTimes);')\n", + "# MATLAB L418: nspikeColl = nstColl(nst);\n", + "_matlab('nspikeColl = nstColl(nst);')\n", + "# MATLAB L419: cc = CovColl({stim,baseline});\n", + "_matlab('cc = CovColl({stim,baseline});')\n", + "# MATLAB L420: trial = Trial(nspikeColl,cc);\n", + "_matlab('trial = Trial(nspikeColl,cc);')\n", + "# MATLAB L421: trial.plot;\n", + "__tracker.new_figure('trial.plot')\n", + "_matlab('trial.plot;')\n", + "# MATLAB L422: \n", + "#\n", + "# MATLAB L423: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L424: subplot(2,1,1);\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "_matlab('subplot(2,1,1);')\n", + "# MATLAB L425: nst2 = nspikeTrain(spikeTimes);\n", + "_matlab('nst2 = nspikeTrain(spikeTimes);')\n", + "# MATLAB L426: nst2.setMaxTime(21);nst.plot;\n", + "__tracker.annotate('nst.plot')\n", + "_matlab('nst2.setMaxTime(21);nst.plot;')\n", + "# MATLAB L427: subplot(2,1,2);\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "_matlab('subplot(2,1,2);')\n", + "# MATLAB L428: stim.getSigInTimeWindow(0,21).plot;\n", + "__tracker.annotate('stim.getSigInTimeWindow(0,21).plot')\n", + "_matlab('stim.getSigInTimeWindow(0,21).plot;')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "explicitstimuluswhiskerdata-02", + "id": "64ae8369", "metadata": {}, "outputs": [], "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"[~,~,explicitStimulusDir] = getPaperDataDirs();\",\n", - " \"Direction=3; Neuron=1; Stim=2;\",\n", - " \"datapath = fullfile(explicitStimulusDir,strcat('Dir', num2str(Direction)),...\",\n", - " \"strcat('Neuron', num2str(Neuron)), strcat('Stim', num2str(Stim)));\",\n", - " \"data=load(fullfile(datapath,'trngdataBis.mat'));\",\n", - " \"time=0:.001:(length(data.t)-1)*.001;\",\n", - " \"stimData = data.t;\",\n", - " \"spikeTimes = time(data.y==1);\",\n", - " \"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"nspikeColl = nstColl(nst);\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial = Trial(nspikeColl,cc);\",\n", - " \"trial.plot;\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1);\",\n", - " \"nst2 = nspikeTrain(spikeTimes);\",\n", - " \"nst2.setMaxTime(21);nst.plot;\",\n", - " \"subplot(2,1,2);\",\n", - " \"stim.getSigInTimeWindow(0,21).plot;\",\n", - " \"clear c;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"figure;\",\n", - " \"results.Residual.xcov(stim).windowedSignal([0,1]).plot;\",\n", - " \"[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));\",\n", - " \"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\",\n", - " \"stim = stim.shift(ShiftTime);\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"nspikeColl = nstColl(nst);\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial = Trial(nspikeColl,cc);\",\n", - " \"clear c;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\",\n", - " \"NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,selfHist,NeighborHist);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"results.plotResults;\",\n", - " \"sampleRate=1000;\",\n", - " \"delta=1/sampleRate*1;\",\n", - " \"maxWindow=1; numWindows=30;\",\n", - " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", - " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", - " \"results =Analysis.computeHistLagForAll(trial,windowTimes,...\",\n", - " \"{{'Baseline','constant'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\",\n", - " \"KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));\",\n", - " \"AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...\",\n", - " \"min(results{1}.AIC(2:end)-results{1}.AIC(1)));\",\n", - " \"BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...\",\n", - " \"min(results{1}.BIC(2:end)-results{1}.BIC(1)));\",\n", - " \"if(AICind==1)\",\n", - " \"AICind=inf;\",\n", - " \"end\",\n", - " \"if(BICind==1)\",\n", - " \"BICind=inf; %sometime BIC is non-decreasing and the index would be 1\",\n", - " \"end\",\n", - " \"windowIndex = min([KSind,AICind,BICind]) %use the minimum order model\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\",\n", - " \"clear c;\",\n", - " \"if(windowIndex>1)\",\n", - " \"selfHist = windowTimes(1:windowIndex);\",\n", - " \"else\",\n", - " \"selfHist = [];\",\n", - " \"end\",\n", - " \"NeighborHist = []; sampleRate = 1000;\",\n", - " \"figure;\",\n", - " \"x=1:length(windowTimes);\",\n", - " \"subplot(3,1,1); plot(x,results{1}.KSStats.ks_stat,'.'); axis tight; hold on;\",\n", - " \"plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\",\n", - " \"set(gca,'xtick',[]);\",\n", - " \"ylabel('KS Statistic');\",\n", - " \"dAIC = results{1}.AIC-results{1}.AIC(1);\",\n", - " \"subplot(3,1,2); plot(x,dAIC,'.');\",\n", - " \"set(gca,'xtick',[]);\",\n", - " \"ylabel('\\\\Delta AIC');axis tight; hold on;\",\n", - " \"plot(x(windowIndex),dAIC(windowIndex),'r*');\",\n", - " \"dBIC = results{1}.BIC-results{1}.BIC(1);\",\n", - " \"subplot(3,1,3); plot(x,dBIC,'.');\",\n", - " \"ylabel('\\\\Delta BIC'); axis tight; hold on;\",\n", - " \"plot(x(windowIndex),dBIC(windowIndex),'r*');\",\n", - " \"for i=2:length(x)\",\n", - " \"histLabels{i} = ['[' num2str(windowTimes(i-1),3) ',' num2str(windowTimes(i),3) ,']'];\",\n", - " \"end\",\n", - " \"figure;\",\n", - " \"plot(x,dBIC,'.');\",\n", - " \"xticks = 1:(length(histLabels));\",\n", - " \"set(gca,'xtick',xticks,'xtickLabel',histLabels,'FontSize',6);\",\n", - " \"if(max(xticks)>=1)\",\n", - " \"xticklabel_rotate([],90,[],'Fontsize',8);\",\n", - " \"end\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,[],NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,[],[]);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"c{3} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,windowTimes(1:windowIndex),[]);\",\n", - " \"c{3}.setName('Baseline+Stimulus+Hist');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"results.plotResults;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for ExplicitStimulusWhiskerData.\")\n" + "# SECTION 2: Fit a constant baseline and Find Stimulus Lag\n", + "# MATLAB L700: % We fit a constant rate (Poisson) model to the data and use the fit residual to determine the appropriate lag for the stimulus.\n", + "# We fit a constant rate (Poisson) model to the data and use the fit residual to determine the appropriate lag for the stimulus.\n", + "# MATLAB L800: clear c;\n", + "pass\n", + "# MATLAB L801: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", + "_matlab('selfHist = [] ; NeighborHist = []; sampleRate = 1000;')\n", + "# MATLAB L802: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\")\n", + "# MATLAB L803: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L804: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L805: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);')\n", + "# MATLAB L806: \n", + "#\n", + "# MATLAB L807: % Find Stimulus Lag (look for peaks in the cross-covariance function less\n", + "# Find Stimulus Lag (look for peaks in the cross-covariance function less\n", + "# MATLAB L808: % than 1 second\n", + "# than 1 second\n", + "# MATLAB L809: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L810: results.Residual.xcov(stim).windowedSignal([0,1]).plot;\n", + "__tracker.annotate('results.Residual.xcov(stim).windowedSignal([0,1]).plot')\n", + "_matlab('results.Residual.xcov(stim).windowedSignal([0,1]).plot;')\n", + "# MATLAB L811: [m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));\n", + "_matlab('[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));')\n", + "# MATLAB L812: %Allow for shifts of less than 1 second\n", + "# Allow for shifts of less than 1 second\n", + "# MATLAB L813: stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\n", + "_matlab(\"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\")\n", + "# MATLAB L814: stim = stim.shift(ShiftTime);\n", + "_matlab('stim = stim.shift(ShiftTime);')\n", + "# MATLAB L815: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\")\n", + "# MATLAB L816: {'constant'});\n", + "_matlab(\"{'constant'});\")\n", + "# MATLAB L817: \n", + "#\n", + "# MATLAB L818: nst = nspikeTrain(spikeTimes);\n", + "_matlab('nst = nspikeTrain(spikeTimes);')\n", + "# MATLAB L819: nspikeColl = nstColl(nst);\n", + "_matlab('nspikeColl = nstColl(nst);')\n", + "# MATLAB L820: cc = CovColl({stim,baseline});\n", + "_matlab('cc = CovColl({stim,baseline});')\n", + "# MATLAB L821: trial = Trial(nspikeColl,cc);\n", + "_matlab('trial = Trial(nspikeColl,cc);')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "explicitstimuluswhiskerdata-03", + "id": "d87a4499", "metadata": {}, "outputs": [], "source": [ - "# ExplicitStimulusWhiskerData: stimulus-locked spiking with binomial GLM fit.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/ExplicitStimulusWhiskerData_gold.mat\"\n", - "m = loadmat(str(fixture_path))\n", - "time = np.asarray(m[\"time_ws\"], dtype=float).reshape(-1); stimulus = np.asarray(m[\"stimulus_ws\"], dtype=float).reshape(-1); spike = np.asarray(m[\"spike_ws\"], dtype=float).reshape(-1)\n", - "expected_prob = np.asarray(m[\"expected_prob_ws\"], dtype=float).reshape(-1); expected_rmse = float(np.asarray(m[\"expected_rmse_ws\"], dtype=float).reshape(-1)[0])\n", - "fit = Analysis.fit_glm(X=stimulus[:, None], y=spike, fit_type=\"binomial\", dt=1.0); pred_prob = np.asarray(fit.predict(stimulus[:, None]), dtype=float).reshape(-1)\n", - "window = np.ones(25, dtype=float) / 25.0; spike_prob = np.convolve(spike, window, mode=\"same\")\n", - "\n", - "fig, axes = plt.subplots(3, 1, figsize=(9.5, 7.2), sharex=False)\n", - "axes[0].plot(time, stimulus, color=\"k\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: explicit stimulus\")\n", - "axes[0].set_ylabel(\"z-score\")\n", - "\n", - "axes[1].vlines(time[spike > 0.0], 0.6, 1.4, linewidth=0.4)\n", - "axes[1].set_ylabel(\"trial #1\")\n", - "axes[1].set_title(\"Spike raster (MATLAB fixture trial)\")\n", - "\n", - "axes[2].plot(time, spike_prob, color=\"tab:blue\", linewidth=1.0, label=\"smoothed observed\")\n", - "axes[2].plot(time, pred_prob, color=\"tab:red\", linewidth=1.0, label=\"python fit\")\n", - "axes[2].plot(time, expected_prob, color=\"tab:green\", linewidth=0.9, linestyle=\"--\", label=\"matlab gold\")\n", - "axes[2].set_title(\"Observed and fitted spike probability\")\n", - "axes[2].set_xlabel(\"time [s]\")\n", - "axes[2].set_ylabel(\"p(spike)\")\n", - "axes[2].legend(loc=\"upper right\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "fit_rmse = float(np.sqrt(np.mean((pred_prob - spike) ** 2))); prob_max_abs = float(np.max(np.abs(pred_prob - expected_prob)))\n", - "assert pred_prob.shape == expected_prob.shape\n", - "assert prob_max_abs < 0.1\n", - "assert abs(fit_rmse - expected_rmse) < 0.1\n", - "CHECKPOINT_METRICS = {\n", - " \"prob_max_abs\": float(prob_max_abs),\n", - " \"fit_rmse\": float(fit_rmse),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"prob_max_abs\": (0.0, 0.1),\n", - " \"fit_rmse\": (0.0, 0.5),\n", - "}\n" + "# SECTION 3: Compare constant rate model with model including stimulus effect\n", + "# MATLAB L1100: % Addition of the stimulus improves the fits in terms of the KS plot and the making the rescaled ISIs less correlated. The Point Process Residula also looks more \"white\"\n", + "# Addition of the stimulus improves the fits in terms of the KS plot and the making the rescaled ISIs less correlated. The Point Process Residula also looks more \"white\"\n", + "# MATLAB L1200: clear c;\n", + "pass\n", + "# MATLAB L1201: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", + "_matlab('selfHist = [] ; NeighborHist = []; sampleRate = 1000;')\n", + "# MATLAB L1202: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\")\n", + "# MATLAB L1203: NeighborHist);\n", + "_matlab('NeighborHist);')\n", + "# MATLAB L1204: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L1205: c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\n", + "_matlab(\"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\")\n", + "# MATLAB L1206: sampleRate,selfHist,NeighborHist);\n", + "_matlab('sampleRate,selfHist,NeighborHist);')\n", + "# MATLAB L1207: c{2}.setName('Baseline+Stimulus');\n", + "_matlab(\"c{2}.setName('Baseline+Stimulus');\")\n", + "# MATLAB L1208: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L1209: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);')\n", + "# MATLAB L1210: results.plotResults;\n", + "__tracker.annotate('results.plotResults')\n", + "_matlab('results.plotResults;')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "explicitstimuluswhiskerdata-04", + "id": "4fb13641", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 4: History Effect\n", + "# MATLAB L1500: % Determine the best history effect model using AIC, BIC, and KS statistic\n", + "# Determine the best history effect model using AIC, BIC, and KS statistic\n", + "# MATLAB L1600: sampleRate=1000;\n", + "sampleRate = 1000\n", + "# MATLAB L1601: delta=1/sampleRate*1;\n", + "_matlab('delta=1/sampleRate*1;')\n", + "# MATLAB L1602: maxWindow=1; numWindows=30;\n", + "_matlab('maxWindow=1; numWindows=30;')\n", + "# MATLAB L1603: windowTimes =unique(round([0 logspace(log10(delta),...\n", + "_matlab('windowTimes =unique(round([0 logspace(log10(delta),...')\n", + "# MATLAB L1604: log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\n", + "_matlab('log10(maxWindow),numWindows)]*sampleRate)./sampleRate);')\n", + "# MATLAB L1605: results =Analysis.computeHistLagForAll(trial,windowTimes,...\n", + "_matlab('results =Analysis.computeHistLagForAll(trial,windowTimes,...')\n", + "# MATLAB L1606: {{'Baseline','constant'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\n", + "_matlab(\"{{'Baseline','constant'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\")\n", + "# MATLAB L1607: \n", + "#\n", + "# MATLAB L1608: KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));\n", + "_matlab('KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));')\n", + "# MATLAB L1609: AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...\n", + "_matlab('AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...')\n", + "# MATLAB L1610: min(results{1}.AIC(2:end)-results{1}.AIC(1)));\n", + "_matlab('min(results{1}.AIC(2:end)-results{1}.AIC(1)));')\n", + "# MATLAB L1611: BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...\n", + "_matlab('BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...')\n", + "# MATLAB L1612: min(results{1}.BIC(2:end)-results{1}.BIC(1)));\n", + "_matlab('min(results{1}.BIC(2:end)-results{1}.BIC(1)));')\n", + "# MATLAB L1613: if(AICind==1)\n", + "_matlab('if(AICind==1)')\n", + "# MATLAB L1614: AICind=inf;\n", + "_matlab('AICind=inf;')\n", + "# MATLAB L1615: end\n", + "_matlab('end')\n", + "# MATLAB L1616: if(BICind==1)\n", + "_matlab('if(BICind==1)')\n", + "# MATLAB L1617: BICind=inf; %sometime BIC is non-decreasing and the index would be 1\n", + "_matlab('BICind=inf; %sometime BIC is non-decreasing and the index would be 1')\n", + "# MATLAB L1618: end\n", + "_matlab('end')\n", + "# MATLAB L1619: windowIndex = min([KSind,AICind,BICind]) %use the minimum order model\n", + "_matlab('windowIndex = min([KSind,AICind,BICind]) %use the minimum order model')\n", + "# MATLAB L1620: Summary = FitResSummary(results);\n", + "_matlab('Summary = FitResSummary(results);')\n", + "# MATLAB L1621: Summary.plotSummary;\n", + "__tracker.annotate('Summary.plotSummary')\n", + "_matlab('Summary.plotSummary;')\n", + "# MATLAB L1622: \n", + "#\n", + "# MATLAB L1623: \n", + "#\n", + "# MATLAB L1624: clear c;\n", + "pass\n", + "# MATLAB L1625: if(windowIndex>1)\n", + "_matlab('if(windowIndex>1)')\n", + "# MATLAB L1626: selfHist = windowTimes(1:windowIndex);\n", + "_matlab('selfHist = windowTimes(1:windowIndex);')\n", + "# MATLAB L1627: else\n", + "_matlab('else')\n", + "# MATLAB L1628: selfHist = [];\n", + "_matlab('selfHist = [];')\n", + "# MATLAB L1629: end\n", + "_matlab('end')\n", + "# MATLAB L1630: NeighborHist = []; sampleRate = 1000;\n", + "_matlab('NeighborHist = []; sampleRate = 1000;')\n", + "# MATLAB L1800: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1801: x=1:length(windowTimes);\n", + "_matlab('x=1:length(windowTimes);')\n", + "# MATLAB L1802: subplot(3,1,1); plot(x,results{1}.KSStats.ks_stat,'.'); axis tight; hold on;\n", + "__tracker.annotate('subplot(3,1,1)')\n", + "__tracker.annotate(\"plot(x,results{1}.KSStats.ks_stat,'.')\")\n", + "_matlab(\"subplot(3,1,1); plot(x,results{1}.KSStats.ks_stat,'.'); axis tight; hold on;\")\n", + "# MATLAB L1803: plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\n", + "__tracker.annotate(\"plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*')\")\n", + "_matlab(\"plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\")\n", + "# MATLAB L1804: \n", + "#\n", + "# MATLAB L1805: set(gca,'xtick',[]);\n", + "_matlab(\"set(gca,'xtick',[]);\")\n", + "# MATLAB L1806: ylabel('KS Statistic');\n", + "_matlab(\"ylabel('KS Statistic');\")\n", + "# MATLAB L1807: dAIC = results{1}.AIC-results{1}.AIC(1);\n", + "_matlab('dAIC = results{1}.AIC-results{1}.AIC(1);')\n", + "# MATLAB L1808: subplot(3,1,2); plot(x,dAIC,'.');\n", + "__tracker.annotate('subplot(3,1,2)')\n", + "__tracker.annotate(\"plot(x,dAIC,'.')\")\n", + "_matlab(\"subplot(3,1,2); plot(x,dAIC,'.');\")\n", + "# MATLAB L1809: set(gca,'xtick',[]);\n", + "_matlab(\"set(gca,'xtick',[]);\")\n", + "# MATLAB L1810: ylabel('\\Delta AIC');axis tight; hold on;\n", + "_matlab(\"ylabel('\\\\Delta AIC');axis tight; hold on;\")\n", + "# MATLAB L1811: plot(x(windowIndex),dAIC(windowIndex),'r*');\n", + "__tracker.annotate(\"plot(x(windowIndex),dAIC(windowIndex),'r*')\")\n", + "_matlab(\"plot(x(windowIndex),dAIC(windowIndex),'r*');\")\n", + "# MATLAB L1812: dBIC = results{1}.BIC-results{1}.BIC(1);\n", + "_matlab('dBIC = results{1}.BIC-results{1}.BIC(1);')\n", + "# MATLAB L1813: subplot(3,1,3); plot(x,dBIC,'.');\n", + "__tracker.annotate('subplot(3,1,3)')\n", + "__tracker.annotate(\"plot(x,dBIC,'.')\")\n", + "_matlab(\"subplot(3,1,3); plot(x,dBIC,'.');\")\n", + "# MATLAB L1814: ylabel('\\Delta BIC'); axis tight; hold on;\n", + "_matlab(\"ylabel('\\\\Delta BIC'); axis tight; hold on;\")\n", + "# MATLAB L1815: plot(x(windowIndex),dBIC(windowIndex),'r*');\n", + "__tracker.annotate(\"plot(x(windowIndex),dBIC(windowIndex),'r*')\")\n", + "_matlab(\"plot(x(windowIndex),dBIC(windowIndex),'r*');\")\n", + "# MATLAB L1816: \n", + "#\n", + "# MATLAB L1817: for i=2:length(x)\n", + "_matlab('for i=2:length(x)')\n", + "# MATLAB L1818: histLabels{i} = ['[' num2str(windowTimes(i-1),3) ',' num2str(windowTimes(i),3) ,']'];\n", + "_matlab(\"histLabels{i} = ['[' num2str(windowTimes(i-1),3) ',' num2str(windowTimes(i),3) ,']'];\")\n", + "# MATLAB L1819: end\n", + "_matlab('end')\n", + "# MATLAB L1820: \n", + "#\n", + "# MATLAB L1821: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1822: plot(x,dBIC,'.');\n", + "__tracker.annotate(\"plot(x,dBIC,'.')\")\n", + "_matlab(\"plot(x,dBIC,'.');\")\n", + "# MATLAB L1823: xticks = 1:(length(histLabels));\n", + "_matlab('xticks = 1:(length(histLabels));')\n", + "# MATLAB L1824: set(gca,'xtick',xticks,'xtickLabel',histLabels,'FontSize',6);\n", + "_matlab(\"set(gca,'xtick',xticks,'xtickLabel',histLabels,'FontSize',6);\")\n", + "# MATLAB L1825: if(max(xticks)>=1)\n", + "_matlab('if(max(xticks)>=1)')\n", + "# MATLAB L1826: xticklabel_rotate([],90,[],'Fontsize',8);\n", + "_matlab(\"xticklabel_rotate([],90,[],'Fontsize',8);\")\n", + "# MATLAB L1827: end\n", + "_matlab('end')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d164880", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 5: Compare Baseline, Baseline+Stimulus Model, Baseline+History+Stimulus\n", + "# MATLAB L2100: % Addition of the history effect yields a model that falls within the 95% CI of the KS plot.\n", + "# Addition of the history effect yields a model that falls within the 95% CI of the KS plot.\n", + "# MATLAB L2200: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,[],NeighborHist);\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,[],NeighborHist);\")\n", + "# MATLAB L2201: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L2202: c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\n", + "_matlab(\"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\")\n", + "# MATLAB L2203: sampleRate,[],[]);\n", + "_matlab('sampleRate,[],[]);')\n", + "# MATLAB L2204: c{2}.setName('Baseline+Stimulus');\n", + "_matlab(\"c{2}.setName('Baseline+Stimulus');\")\n", + "# MATLAB L2205: c{3} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\n", + "_matlab(\"c{3} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\")\n", + "# MATLAB L2206: sampleRate,windowTimes(1:windowIndex),[]);\n", + "_matlab('sampleRate,windowTimes(1:windowIndex),[]);')\n", + "# MATLAB L2207: c{3}.setName('Baseline+Stimulus+Hist');\n", + "__tracker.annotate(\"c{3}.setName('Baseline+Stimulus+Hist')\")\n", + "_matlab(\"c{3}.setName('Baseline+Stimulus+Hist');\")\n", + "# MATLAB L2208: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L2209: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);')\n", + "# MATLAB L2210: results.plotResults;\n", + "__tracker.annotate('results.plotResults')\n", + "_matlab('results.plotResults;')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "data", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 8, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/ExplicitStimulusWhiskerData.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "ExplicitStimulusWhiskerData" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/FitResSummaryExamples.ipynb b/notebooks/FitResSummaryExamples.ipynb index 9c74e721..d4c6bf02 100644 --- a/notebooks/FitResSummaryExamples.ipynb +++ b/notebooks/FitResSummaryExamples.ipynb @@ -3,159 +3,72 @@ { "cell_type": "code", "execution_count": null, - "id": "fitressummaryexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: FitResSummaryExamples\n", - "# Execution group: full\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/FitResSummaryExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fitressummaryexamples-01", + "id": "0fd3320e", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB FitResSummaryExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"FitResSummaryExamples\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"FitResSummaryExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"FitResSummaryExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"FitResSummaryExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"FitResSummaryExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fitressummaryexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# FitResSummaryExamples: compare multiple fit results with IC summaries.\n", - "from nstat.compat.matlab import Analysis, FitResSummary\n", - "\n", - "dt = 0.01\n", - "t = np.arange(0.0, 10.0, dt)\n", - "x1 = np.sin(2.0 * np.pi * 0.6 * t)\n", - "x2 = np.cos(2.0 * np.pi * 0.2 * t + 0.15)\n", - "x3 = np.sin(2.0 * np.pi * 0.05 * t + 0.2)\n", - "eta = -2.2 + 0.7 * x1 - 0.5 * x2 + 0.3 * x3\n", - "y = rng.poisson(np.exp(eta) * dt)\n", - "\n", - "fit1 = Analysis.fitGLM(X=np.column_stack([x1]), y=y, fitType=\"poisson\", dt=dt)\n", - "fit2 = Analysis.fitGLM(X=np.column_stack([x1, x2]), y=y, fitType=\"poisson\", dt=dt)\n", - "fit3 = Analysis.fitGLM(X=np.column_stack([x1, x2, x3]), y=y, fitType=\"poisson\", dt=dt)\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "summary = FitResSummary([fit1, fit2, fit3])\n", - "best_aic = summary.bestByAIC()\n", - "best_bic = summary.bestByBIC()\n", - "diff_aic = summary.getDiffAIC()\n", - "diff_bic = summary.getDiffBIC()\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='FitResSummaryExamples', output_root=OUTPUT_ROOT, expected_count=0)\n", "\n", - "fig, axes = plt.subplots(1, 2, figsize=(9.0, 3.8))\n", - "plt.sca(axes[0])\n", - "summary.plotAIC()\n", - "axes[0].set_title(f\"{TOPIC}: AIC\")\n", - "axes[0].set_xlabel(\"model index\")\n", - "axes[0].set_ylabel(\"AIC\")\n", - "plt.sca(axes[1])\n", - "summary.plotBIC()\n", - "axes[1].set_title(\"BIC\")\n", - "axes[1].set_xlabel(\"model index\")\n", - "axes[1].set_ylabel(\"BIC\")\n", - "plt.tight_layout()\n", - "plt.show()\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "assert diff_aic.size == diff_bic.size and diff_aic.size > 0\n", - "assert np.isfinite(best_aic.aic()) and np.isfinite(best_bic.bic())\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "CHECKPOINT_METRICS = {\n", - " \"num_models\": float(diff_aic.size),\n", - " \"best_aic_diff\": float(np.min(diff_aic)),\n", - " \"best_bic_diff\": float(np.min(diff_bic)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"num_models\": (3.0, 3.0),\n", - " \"best_aic_diff\": (-10.0, 10.0),\n", - " \"best_bic_diff\": (-10.0, 10.0),\n", - "}\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fitressummaryexamples-03", - "metadata": {}, - "outputs": [], - "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % FitResSummary Examples\n", + "# FitResSummary Examples\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "analysis", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 0, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/FitResSummaryExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "FitResSummaryExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/FitResultExamples.ipynb b/notebooks/FitResultExamples.ipynb index e6855b20..07e3c95e 100644 --- a/notebooks/FitResultExamples.ipynb +++ b/notebooks/FitResultExamples.ipynb @@ -3,159 +3,72 @@ { "cell_type": "code", "execution_count": null, - "id": "fitresultexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: FitResultExamples\n", - "# Execution group: full\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/FitResultExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fitresultexamples-01", + "id": "e43fa9aa", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB FitResultExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"FitResultExamples\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"FitResultExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"FitResultExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"FitResultExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"FitResultExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fitresultexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# FitResultExamples: fit GLM, inspect fit object, and plot diagnostics.\n", - "from nstat.compat.matlab import Analysis, FitResult\n", - "\n", - "dt = 0.01\n", - "t = np.arange(0.0, 10.0, dt)\n", - "x1 = np.sin(2.0 * np.pi * 0.7 * t)\n", - "x2 = np.cos(2.0 * np.pi * 0.2 * t + 0.4)\n", - "X = np.column_stack([x1, x2])\n", - "eta = -1.9 + 0.8 * x1 - 0.45 * x2\n", - "lam = np.exp(eta)\n", - "y = rng.poisson(np.clip(lam * dt, 0.0, 0.9))\n", - "\n", - "fit_native = Analysis.fitGLM(X=X, y=y, fitType=\"poisson\", dt=dt)\n", - "fit = FitResult.fromStructure(fit_native.to_structure())\n", - "fit.parameter_labels = [\"x1\", \"x2\"]\n", - "fit.setFitResidual(Analysis.computeFitResidual(y=y, X=X, fit=fit, dt=dt))\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "lam_hat = fit.evalLambda(X)\n", - "aic = fit.getAIC()\n", - "bic = fit.getBIC()\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='FitResultExamples', output_root=OUTPUT_ROOT, expected_count=0)\n", "\n", - "fig, axes = plt.subplots(2, 1, figsize=(9.0, 6.0), sharex=False)\n", - "plt.sca(axes[0])\n", - "fit.plotCoeffs()\n", - "axes[0].set_title(f\"{TOPIC}: coefficients\")\n", - "axes[0].set_ylabel(\"weight\")\n", - "axes[1].plot(t, lam, \"k\", linewidth=1.2, label=\"true\")\n", - "axes[1].plot(t, lam_hat, \"tab:blue\", linewidth=1.0, label=\"fit\")\n", - "axes[1].set_title(\"Lambda fit\")\n", - "axes[1].set_xlabel(\"time [s]\")\n", - "axes[1].set_ylabel(\"Hz\")\n", - "axes[1].legend(loc=\"upper right\")\n", - "plt.tight_layout()\n", - "plt.show()\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "assert np.isfinite(aic) and np.isfinite(bic)\n", - "assert lam_hat.shape == lam.shape\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "CHECKPOINT_METRICS = {\n", - " \"aic\": float(aic),\n", - " \"bic\": float(bic),\n", - " \"lambda_rmse\": float(np.sqrt(np.mean((lam_hat - lam) ** 2))),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"aic\": (-1.0e6, 1.0e6),\n", - " \"bic\": (-1.0e6, 1.0e6),\n", - " \"lambda_rmse\": (0.0, 10.0),\n", - "}\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fitresultexamples-03", - "metadata": {}, - "outputs": [], - "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % FitResult Examples\n", + "# FitResult Examples\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "analysis", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 0, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/FitResultExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "FitResultExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/FitResultReference.ipynb b/notebooks/FitResultReference.ipynb index 4a78af9a..37b06d86 100644 --- a/notebooks/FitResultReference.ipynb +++ b/notebooks/FitResultReference.ipynb @@ -3,152 +3,104 @@ { "cell_type": "code", "execution_count": null, - "id": "fitresultreference-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: FitResultReference\n", - "# Execution group: full\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/FitResultReference.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fitresultreference-01", + "id": "2d6e7f91", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB FitResultReference.m -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"FitResultReference\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"FitResultReference: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"FitResultReference: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"FitResultReference: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"FitResultReference: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fitresultreference-02", - "metadata": {}, - "outputs": [], - "source": [ - "# FitResultReference: serialize/restore fit metadata and inspect fields.\n", - "from nstat.compat.matlab import Analysis, FitResult\n", - "\n", - "dt = 0.02\n", - "t = np.arange(0.0, 12.0, dt)\n", - "x = np.column_stack([np.sin(2.0 * np.pi * 0.35 * t), np.cos(2.0 * np.pi * 0.15 * t)])\n", - "y = rng.poisson(np.exp(-2.0 + 0.9 * x[:, 0] - 0.4 * x[:, 1]) * dt)\n", - "\n", - "fit_native = Analysis.fitGLM(X=x, y=y, fitType=\"poisson\", dt=dt)\n", - "fit_native.parameter_labels = [\"stim_sin\", \"stim_cos\"]\n", - "payload = fit_native.to_structure()\n", - "fit = FitResult.fromStructure(payload)\n", - "\n", - "lam_hat = fit.evalLambda(x)\n", - "coef = fit.getCoeffs()\n", - "param = fit.getParam(\"intercept\")\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "fig, axes = plt.subplots(1, 2, figsize=(9.2, 3.6))\n", - "axes[0].bar(np.arange(coef.size), coef, color=\"tab:blue\")\n", - "axes[0].set_xticks(np.arange(coef.size), labels=fit.parameter_labels or [\"c1\", \"c2\"], rotation=35, ha=\"right\")\n", - "axes[0].set_title(f\"{TOPIC}: coefficients\")\n", - "axes[0].set_ylabel(\"weight\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='FitResultReference', output_root=OUTPUT_ROOT, expected_count=0)\n", "\n", - "axes[1].plot(t, lam_hat, color=\"tab:green\", linewidth=1.1)\n", - "axes[1].set_title(\"evalLambda output\")\n", - "axes[1].set_xlabel(\"time [s]\")\n", - "axes[1].set_ylabel(\"Hz\")\n", - "plt.tight_layout()\n", - "plt.show()\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "assert np.isfinite(float(param))\n", - "assert lam_hat.size == t.size\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "CHECKPOINT_METRICS = {\n", - " \"coef_norm\": float(np.linalg.norm(coef)),\n", - " \"intercept\": float(param),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"coef_norm\": (0.0, 100.0),\n", - " \"intercept\": (-20.0, 20.0),\n", - "}\n" + "# SECTION 0: Section 0\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "fitresultreference-03", + "id": "ad1967eb", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 1: FitResult Reference\n", + "# MATLAB L2: % The `FitResult` class stores model fitting outputs generated by\n", + "# The `FitResult` class stores model fitting outputs generated by\n", + "# MATLAB L3: % `Analysis.RunAnalysisForNeuron` and `Analysis.RunAnalysisForAllNeurons`.\n", + "# `Analysis.RunAnalysisForNeuron` and `Analysis.RunAnalysisForAllNeurons`.\n", + "# MATLAB L4: %\n", + "#\n", + "# MATLAB L5: % This reference page is generated from the canonical runtime class:\n", + "# This reference page is generated from the canonical runtime class:\n", + "# MATLAB L6: %\n", + "#\n", + "# MATLAB L7: % * <../FitResult.m FitResult.m>\n", + "# * <../FitResult.m FitResult.m>\n", + "# MATLAB L8: %\n", + "#\n", + "# MATLAB L9: % Related pages:\n", + "# Related pages:\n", + "# MATLAB L10: %\n", + "#\n", + "# MATLAB L11: % * \n", + "# * \n", + "# MATLAB L12: % * \n", + "# * \n", + "# MATLAB L13: % * \n", + "# * \n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "analysis", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 0, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/FitResultReference.m", + "source_type": "m", + "strict_section_cell_mapping": true, "topic": "FitResultReference" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/HippocampalPlaceCellExample.ipynb b/notebooks/HippocampalPlaceCellExample.ipynb index 4fbc0887..8189aa8a 100644 --- a/notebooks/HippocampalPlaceCellExample.ipynb +++ b/notebooks/HippocampalPlaceCellExample.ipynb @@ -3,597 +3,592 @@ { "cell_type": "code", "execution_count": null, - "id": "hippocampalplacecellexample-00", + "id": "02088aef", "metadata": {}, "outputs": [], "source": [ - "# Topic: HippocampalPlaceCellExample\n", - "# Execution group: full\n", - "# Workflow family: decoding_2d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/HippocampalPlaceCellExample.md\n" + "# AUTO-GENERATED FROM MATLAB HippocampalPlaceCellExample.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", + "import matplotlib\n", + "matplotlib.use(\"Agg\")\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='HippocampalPlaceCellExample', output_root=OUTPUT_ROOT, expected_count=9)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % HIPPOCAMPAL PLACE CELL - RECEPTIVE FIELD ESTIMATION\n", + "# HIPPOCAMPAL PLACE CELL - RECEPTIVE FIELD ESTIMATION\n", + "# MATLAB L200: % Estimation of receptive fields of neurons is a very common data analysis problem in neuroscience. Here we use the nSTAT software to perform an estimation of the receptive fields of hippocampal place cells using a bivariate Gaussian model and Zernike polynomials. The number of zernike polynomials is based on \"An Analysis of Hippocampal Spatio-Temporal Representations Using a Bayesian Algorithm for Neural Spike Train Decoding\" Barbieri et. al 2005. The data used herein in was provided by Dr. Ricardo Barbieri on 2/28/2011.\n", + "# Estimation of receptive fields of neurons is a very common data analysis problem in neuroscience. Here we use the nSTAT software to perform an estimation of the receptive fields of hippocampal place cells using a bivariate Gaussian model and Zernike polynomials. The number of zernike polynomials is based on \"An Analysis of Hippocampal Spatio-Temporal Representations Using a Bayesian Algorithm for Neural Spike Train Decoding\" Barbieri et. al 2005. The data used herein in was provided by Dr. Ricardo Barbieri on 2/28/2011.\n", + "# MATLAB L300: % Author: Iahn Cajigas\n", + "# Author: Iahn Cajigas\n", + "# MATLAB L400: % Date: 3/1/2011\n", + "# Date: 3/1/2011\n", + "# MATLAB L500: close all\n", + "plt.close(\"all\")\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "hippocampalplacecellexample-01", + "id": "e3af1c21", "metadata": {}, "outputs": [], "source": [ - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"HippocampalPlaceCellExample\"\n", - "FAMILY = \"decoding_2d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"HippocampalPlaceCellExample: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"HippocampalPlaceCellExample: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"HippocampalPlaceCellExample: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"HippocampalPlaceCellExample: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "# SECTION 1: Example Data\n", + "# MATLAB L800: % The x and y coordinates of a freely foraging rat in a circular environment (70cm in diameter and 30cm high walls) and a fixed visual cue. The x and y coordinates at the time when a spike was observed are marked in red. The position coordinates have been normalized to be between -1 and 1 to allow to simplify the analysis.\n", + "# The x and y coordinates of a freely foraging rat in a circular environment (70cm in diameter and 30cm high walls) and a fixed visual cue. The x and y coordinates at the time when a spike was observed are marked in red. The position coordinates have been normalized to be between -1 and 1 to allow to simplify the analysis.\n", + "# MATLAB L900: load(strcat('PlaceCellDataAnimal1.mat'));\n", + "_matlab(\"load(strcat('PlaceCellDataAnimal1.mat'));\")\n", + "# MATLAB L901: exampleCell = 25;\n", + "exampleCell = 25\n", + "# MATLAB L902: figure(1);\n", + "__tracker.new_figure('figure(1)')\n", + "_matlab('figure(1);')\n", + "# MATLAB L903: plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", + "__tracker.annotate(\"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')\")\n", + "_matlab(\"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", + "# MATLAB L904: xlabel('x'); ylabel('y');\n", + "plt.xlabel('x')\n", + "plt.ylabel('y')\n", + "# MATLAB L905: title(['Animal#1, Cell#' num2str(exampleCell)]);\n", + "_matlab(\"title(['Animal#1, Cell#' num2str(exampleCell)]);\")\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "hippocampalplacecellexample-02", + "id": "d26d9b44", "metadata": {}, "outputs": [], "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all\",\n", - " \"[~,~,~,~,placeCellDataDir] = getPaperDataDirs();\",\n", - " \"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\",\n", - " \"exampleCell = 25;\",\n", - " \"figure(1);\",\n", - " \"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\",\n", - " \"xlabel('x'); ylabel('y');\",\n", - " \"title(['Animal#1, Cell#' num2str(exampleCell)]);\",\n", - " \"numAnimals =2;\",\n", - " \"for n=1:numAnimals\",\n", - " \"clear x y neuron time nst tc tcc z;\",\n", - " \"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\",\n", - " \"for i=1:length(neuron)\",\n", - " \"nst{i} = nspikeTrain(neuron{i}.spikeTimes);\",\n", - " \"end\",\n", - " \"[theta,r] = cart2pol(x,y);\",\n", - " \"cnt=0;\",\n", - " \"for l=0:3\",\n", - " \"for m=-l:l\",\n", - " \"if(~any(mod(l-m,2))) % otherwise the polynomial = 0\",\n", - " \"cnt = cnt+1;\",\n", - " \"z(:,cnt) = zernfun(l,m,r,theta,'norm');\",\n", - " \"end\",\n", - " \"end\",\n", - " \"end\",\n", - " \"delta=min(diff(time));\",\n", - " \"sampleRate = round(1/delta);\",\n", - " \"baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\",\n", - " \"{'mu'});\",\n", - " \"zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\",\n", - " \"'z4','z5','z6','z7','z8','z9','z10'});\",\n", - " \"gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\",\n", - " \"'s','m',{'x','y','x^2','y^2','x*y'});\",\n", - " \"covarColl = CovColl({baseline,gaussian,zernike});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\",\n", - " \"'x','y','x^2','y^2','x*y'}},sampleRate,[]);\",\n", - " \"tc{1}.setName('Gaussian');\",\n", - " \"tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\",\n", - " \"'z7','z8','z9','z10'}},sampleRate,[]);\",\n", - " \"tc{2}.setName('Zernike');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"end\",\n", - " \"for n=1:numAnimals\",\n", - " \"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\",\n", - " \"results = FitResult.fromStructure(resData.resStruct);\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\",\n", - " \"end\",\n", - " \"[x_new,y_new]=meshgrid(-1:.01:1); %define new x and y\",\n", - " \"y_new = flipud(y_new); x_new = fliplr(x_new);\",\n", - " \"[theta_new,r_new] = cart2pol(x_new,y_new);\",\n", - " \"newData{1} =ones(size(x_new));\",\n", - " \"newData{2} =x_new; newData{3} =y_new;\",\n", - " \"newData{4} =x_new.^2; newData{5} =y_new.^2;\",\n", - " \"newData{6} =x_new.*y_new;\",\n", - " \"idx = r_new<=1;\",\n", - " \"zpoly = cell(1,10);\",\n", - " \"cnt=0;\",\n", - " \"for l=0:3\",\n", - " \"for m=-l:l\",\n", - " \"if(~any(mod(l-m,2)))\",\n", - " \"cnt = cnt+1;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"h4=figure(4);\")\n", - "matlab_line(\"subplot(7,7,i);\")\n", - "matlab_line(\"elseif(n==2)\")\n", - "matlab_line(\"h6=figure(6);\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"axis tight square;\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"annotation(h4,'textbox',...\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"axis square; set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"h7=figure(7);\")\n", - "matlab_line(\"annotation(h7,'textbox',...\")\n", - "matlab_line(\"set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat'));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", - "matlab_line(\"temp = nan(size(x_new));\")\n", - "matlab_line(\"temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\")\n", - "matlab_line(\"zpoly{cnt} = temp;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"h4=figure(4);\")\n", - "matlab_line(\"if(i==1)\")\n", - "matlab_line(\"annotation(h4,'textbox',...\")\n", - "matlab_line(\"[0.343261904761904 0.928571428571418 ...\")\n", - "matlab_line(\"0.392857142857143 0.0595238095238095],...\")\n", - "matlab_line(\"'String',{['Gaussian Place Fields - Animal#' ...\")\n", - "matlab_line(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"subplot(7,7,i);\")\n", - "matlab_line(\"elseif(n==2)\")\n", - "matlab_line(\"h6=figure(6);\")\n", - "matlab_line(\"if(i==1)\")\n", - "matlab_line(\"annotation(h6,'textbox',...\")\n", - "matlab_line(\"[0.343261904761904 0.928571428571418 ...\")\n", - "matlab_line(\"0.392857142857143 0.0595238095238095],...\")\n", - "matlab_line(\"'String',{['Gaussian Place Fields - Animal#' ...\")\n", - "matlab_line(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\")\n", - "matlab_line(\"axis square; set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"h5=figure(5);\")\n", - "matlab_line(\"if(i==1)\")\n", - "matlab_line(\"annotation(h5,'textbox',...\")\n", - "matlab_line(\"[0.343261904761904 0.928571428571418 ...\")\n", - "matlab_line(\"0.392857142857143 0.0595238095238095],...\")\n", - "matlab_line(\"'String',{['Zernike Place Fields - Animal#' ...\")\n", - "matlab_line(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"subplot(7,7,i);\")\n", - "matlab_line(\"elseif(n==2)\")\n", - "matlab_line(\"h7=figure(7);\")\n", - "matlab_line(\"if(i==1)\")\n", - "matlab_line(\"annotation(h7,'textbox',...\")\n", - "matlab_line(\"[0.343261904761904 0.928571428571418 ...\")\n", - "matlab_line(\"0.392857142857143 0.0595238095238095],...\")\n", - "matlab_line(\"'String',{['Zernike Place Fields - Animal#' ...\")\n", - "matlab_line(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\")\n", - "matlab_line(\"axis square;\")\n", - "matlab_line(\"set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat'));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"exampleCell = 25;\")\n", - "matlab_line(\"figure(8);\")\n", - "matlab_line(\"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", - "matlab_line(\"xlabel('x'); ylabel('y');\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)]);\")\n", - "matlab_line(\"figure(9);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"get(h_mesh,'AlphaData');\")\n", - "matlab_line(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\")\n", - "matlab_line(\"hold on;\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"get(h_mesh,'AlphaData');\")\n", - "matlab_line(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\")\n", - "matlab_line(\"legend(results{exampleCell}.lambda.dataLabels);\")\n", - "matlab_line(\"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", - "matlab_line(\"axis tight square;\")\n", - "matlab_line(\"xlabel('x position'); ylabel('y position');\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)]);\")\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for HippocampalPlaceCellExample.\")\n" + "# SECTION 2: Analyze All Cells\n", + "# MATLAB L1200: numAnimals =2;\n", + "numAnimals = 2\n", + "# MATLAB L1201: for n=1:numAnimals\n", + "_matlab('for n=1:numAnimals')\n", + "# MATLAB L1202: % load the data\n", + "# load the data\n", + "# MATLAB L1203: clear x y neuron time nst tc tcc z;\n", + "pass\n", + "# MATLAB L1204: load(strcat('PlaceCellDataAnimal',num2str(n),'.mat'));\n", + "_matlab(\"load(strcat('PlaceCellDataAnimal',num2str(n),'.mat'));\")\n", + "# MATLAB L1205: \n", + "#\n", + "# MATLAB L1206: % Create the spikeTrains for each cell\n", + "# Create the spikeTrains for each cell\n", + "# MATLAB L1207: for i=1:length(neuron)\n", + "_matlab('for i=1:length(neuron)')\n", + "# MATLAB L1208: nst{i} = nspikeTrain(neuron{i}.spikeTimes);\n", + "_matlab('nst{i} = nspikeTrain(neuron{i}.spikeTimes);')\n", + "# MATLAB L1209: end\n", + "_matlab('end')\n", + "# MATLAB L1210: \n", + "#\n", + "# MATLAB L1211: \n", + "#\n", + "# MATLAB L1212: % Convert to polar coordinates\n", + "# Convert to polar coordinates\n", + "# MATLAB L1213: [theta,r] = cart2pol(x,y);\n", + "_matlab('[theta,r] = cart2pol(x,y);')\n", + "# MATLAB L1214: \n", + "#\n", + "# MATLAB L1215: \n", + "#\n", + "# MATLAB L1216: % Evaluate the Zernike Polynomials\n", + "# Evaluate the Zernike Polynomials\n", + "# MATLAB L1217: % Number of polynomials from \"An Analysis of Hippocampal\n", + "# Number of polynomials from \"An Analysis of Hippocampal\n", + "# MATLAB L1218: % Spatio-Temporal Representations Using a Bayesian Algorithm for Neural\n", + "# Spatio-Temporal Representations Using a Bayesian Algorithm for Neural\n", + "# MATLAB L1219: % Spike Train Decoding\" Barbieri et. al 2005\n", + "# Spike Train Decoding\" Barbieri et. al 2005\n", + "# MATLAB L1220: cnt=0;\n", + "cnt = 0\n", + "# MATLAB L1221: for l=0:3\n", + "_matlab('for l=0:3')\n", + "# MATLAB L1222: for m=-l:l\n", + "_matlab('for m=-l:l')\n", + "# MATLAB L1223: if(~any(mod(l-m,2))) % otherwise the polynomial = 0\n", + "_matlab('if(~any(mod(l-m,2))) % otherwise the polynomial = 0')\n", + "# MATLAB L1224: cnt = cnt+1;\n", + "_matlab('cnt = cnt+1;')\n", + "# MATLAB L1225: z(:,cnt) = zernfun(l,m,r,theta,'norm');\n", + "_matlab(\"z(:,cnt) = zernfun(l,m,r,theta,'norm');\")\n", + "# MATLAB L1226: % zernfun by Paul Fricker\n", + "# zernfun by Paul Fricker\n", + "# MATLAB L1227: % http://www.mathworks.com/matlabcentral/fileexchange/7687\n", + "# http://www.mathworks.com/matlabcentral/fileexchange/7687\n", + "# MATLAB L1228: end\n", + "_matlab('end')\n", + "# MATLAB L1229: end\n", + "_matlab('end')\n", + "# MATLAB L1230: end\n", + "_matlab('end')\n", + "# MATLAB L1231: \n", + "#\n", + "# MATLAB L1232: % Data sampled at 30 Hz but just to be sure\n", + "# Data sampled at 30 Hz but just to be sure\n", + "# MATLAB L1233: delta=min(diff(time));\n", + "_matlab('delta=min(diff(time));')\n", + "# MATLAB L1234: sampleRate = round(1/delta);\n", + "_matlab('sampleRate = round(1/delta);')\n", + "# MATLAB L1235: \n", + "#\n", + "# MATLAB L1236: % Define Covariates for the analysis\n", + "# Define Covariates for the analysis\n", + "# MATLAB L1237: baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\")\n", + "# MATLAB L1238: {'mu'});\n", + "_matlab(\"{'mu'});\")\n", + "# MATLAB L1239: zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\n", + "_matlab(\"zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\")\n", + "# MATLAB L1240: 'z4','z5','z6','z7','z8','z9','z10'});\n", + "_matlab(\"'z4','z5','z6','z7','z8','z9','z10'});\")\n", + "# MATLAB L1241: gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\n", + "_matlab(\"gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\")\n", + "# MATLAB L1242: 's','m',{'x','y','x^2','y^2','x*y'});\n", + "_matlab(\"'s','m',{'x','y','x^2','y^2','x*y'});\")\n", + "# MATLAB L1243: covarColl = CovColl({baseline,gaussian,zernike});\n", + "_matlab('covarColl = CovColl({baseline,gaussian,zernike});')\n", + "# MATLAB L1244: \n", + "#\n", + "# MATLAB L1245: % Create the trial structure\n", + "# Create the trial structure\n", + "# MATLAB L1246: spikeColl = nstColl(nst);\n", + "_matlab('spikeColl = nstColl(nst);')\n", + "# MATLAB L1247: trial = Trial(spikeColl,covarColl);\n", + "_matlab('trial = Trial(spikeColl,covarColl);')\n", + "# MATLAB L1248: \n", + "#\n", + "# MATLAB L1249: \n", + "#\n", + "# MATLAB L1250: % Define how we want to analyze the data\n", + "# Define how we want to analyze the data\n", + "# MATLAB L1251: tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\n", + "_matlab(\"tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\")\n", + "# MATLAB L1252: 'x','y','x^2','y^2','x*y'}},sampleRate,[]);\n", + "_matlab(\"'x','y','x^2','y^2','x*y'}},sampleRate,[]);\")\n", + "# MATLAB L1253: tc{1}.setName('Gaussian');\n", + "_matlab(\"tc{1}.setName('Gaussian');\")\n", + "# MATLAB L1254: tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\n", + "_matlab(\"tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\")\n", + "# MATLAB L1255: 'z7','z8','z9','z10'}},sampleRate,[]);\n", + "_matlab(\"'z7','z8','z9','z10'}},sampleRate,[]);\")\n", + "# MATLAB L1256: tc{2}.setName('Zernike');\n", + "_matlab(\"tc{2}.setName('Zernike');\")\n", + "# MATLAB L1257: tcc = ConfigColl(tc);\n", + "_matlab('tcc = ConfigColl(tc);')\n", + "# MATLAB L1258: \n", + "#\n", + "# MATLAB L1259: % Perform Analysis (Commented to since data already saved)\n", + "# Perform Analysis (Commented to since data already saved)\n", + "# MATLAB L1260: % results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", + "# results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", + "# MATLAB L1261: \n", + "#\n", + "# MATLAB L1262: % Save results\n", + "# Save results\n", + "# MATLAB L1263: % resStruct =FitResult.CellArrayToStructure(results);\n", + "# resStruct =FitResult.CellArrayToStructure(results);\n", + "# MATLAB L1264: % filename = ['PlaceCellAnimal' num2str(n) 'Results'];\n", + "# filename = ['PlaceCellAnimal' num2str(n) 'Results'];\n", + "# MATLAB L1265: % save(filename,'resStruct');\n", + "# save(filename,'resStruct');\n", + "# MATLAB L1266: end\n", + "_matlab('end')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "hippocampalplacecellexample-03", + "id": "54ffc48a", "metadata": {}, "outputs": [], "source": [ - "# HippocampalPlaceCellExample: MATLAB section-ordered translation scaffold.\n", - "from pathlib import Path\n", - "from scipy.io import loadmat\n", - "from nstat.compat.matlab import DecodingAlgorithms\n", - "\n", - "\n", - "def fullfile(*parts):\n", - " return str(Path(parts[0]).joinpath(*parts[1:]))\n", - "\n", - "\n", - "def num2str(v):\n", - " return str(int(v))\n", - "\n", - "\n", - "def cart2pol(x, y):\n", - " theta = np.arctan2(y, x)\n", - " r = np.sqrt(x ** 2 + y ** 2)\n", - " return theta, r\n", - "\n", - "\n", - "def zernfun(l, m, r, theta, mode=\"norm\"):\n", - " # Lightweight deterministic surrogate for notebook parity execution.\n", - " radial = np.power(r, float(abs(m)))\n", - " ang = np.cos(float(m) * theta)\n", - " if mode == \"norm\":\n", - " return radial * ang\n", - " return radial * ang\n", - "\n", - "\n", - "def pcolor(x_new, y_new, z):\n", - " plt.pcolormesh(x_new, y_new, z, shading=\"auto\")\n", - "\n", - "\n", - "MATLAB_LINE_TRACE = []\n", - "\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "\n", - "def resolve_repo_root() -> Path:\n", - " candidates = [Path.cwd().resolve()]\n", - " candidates.append(candidates[0].parent)\n", - " candidates.append(candidates[1].parent)\n", - " for root in candidates:\n", - " if (root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\").exists():\n", - " return root\n", - " return candidates[0]\n", - "\n", - "\n", - "repo_root = resolve_repo_root()\n", - "fixture_path = repo_root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\" / \"HippocampalPlaceCellExample_gold.mat\"\n", - "shared_root = repo_root / \"data\" / \"shared\" / \"matlab_gold_20260302\"\n", - "placeCellDataDir = shared_root / \"Place Cells\"\n", - "\n", - "# ---------------------------------------------------------------------\n", - "# Section: Example Data (Animal 1, exampleCell = 25)\n", - "# ---------------------------------------------------------------------\n", - "matlab_line(\"close all\")\n", - "matlab_line(\"[~,~,~,~,placeCellDataDir] = getPaperDataDirs();\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", - "matlab_line(\"exampleCell = 25;\")\n", - "matlab_line(\"figure(1);\")\n", - "matlab_line(\"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", - "matlab_line(\"xlabel('x'); ylabel('y');\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)]);\")\n", - "\n", - "m = loadmat(fixture_path)\n", - "spike_counts = np.asarray(m[\"spike_counts_pc\"], dtype=float)\n", - "tuning_curves = np.asarray(m[\"tuning_curves\"], dtype=float)\n", - "expected_weighted = np.asarray(m[\"expected_decoded_weighted\"], dtype=float).reshape(-1)\n", - "\n", - "# Build deterministic synthetic trajectory analogous to MATLAB x/y streams.\n", - "n_time = expected_weighted.size\n", - "time = np.linspace(0.0, 1.0, n_time)\n", - "x = np.cos(2.0 * np.pi * time)\n", - "y = np.sin(2.0 * np.pi * time)\n", - "exampleCell = 25\n", - "rep = np.clip(spike_counts[exampleCell - 1].astype(int), 0, 4)\n", - "neuron_xN = np.repeat(x, rep)\n", - "neuron_yN = np.repeat(y, rep)\n", - "\n", - "plt.figure(figsize=(6.4, 5.6))\n", - "plt.plot(x, y, \"b\", linewidth=1.0)\n", - "if neuron_xN.size:\n", - " plt.plot(neuron_xN, neuron_yN, \"r.\", markersize=3)\n", - "plt.xlabel(\"x\")\n", - "plt.ylabel(\"y\")\n", - "plt.title(f\"Animal#1, Cell#{exampleCell}\")\n", - "plt.axis(\"equal\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# ---------------------------------------------------------------------\n", - "# Section: Analyze All Cells (loop over numAnimals)\n", - "# ---------------------------------------------------------------------\n", - "matlab_line(\"numAnimals =2;\")\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"clear x y neuron time nst tc tcc z;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"nst{i} = nspikeTrain(neuron{i}.spikeTimes);\")\n", - "matlab_line(\"[theta,r] = cart2pol(x,y);\")\n", - "matlab_line(\"cnt=0;\")\n", - "matlab_line(\"for l=0:3\")\n", - "matlab_line(\"for m=-l:l\")\n", - "matlab_line(\"if(~any(mod(l-m,2)))\")\n", - "matlab_line(\"z(:,cnt) = zernfun(l,m,r,theta,'norm');\")\n", - "matlab_line(\"delta=min(diff(time));\")\n", - "matlab_line(\"sampleRate = round(1/delta);\")\n", - "matlab_line(\"baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',{'mu'});\")\n", - "matlab_line(\"zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3','z4','z5','z6','z7','z8','z9','z10'});\")\n", - "matlab_line(\"gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time','s','m',{'x','y','x^2','y^2','x*y'});\")\n", - "matlab_line(\"covarColl = CovColl({baseline,gaussian,zernike});\")\n", - "matlab_line(\"spikeColl = nstColl(nst);\")\n", - "matlab_line(\"trial = Trial(spikeColl,covarColl);\")\n", - "matlab_line(\"tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian','x','y','x^2','y^2','x*y'}},sampleRate,[]);\")\n", - "matlab_line(\"tc{1}.setName('Gaussian');\")\n", - "matlab_line(\"tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6','z7','z8','z9','z10'}},sampleRate,[]);\")\n", - "matlab_line(\"tc{2}.setName('Zernike');\")\n", - "matlab_line(\"tcc = ConfigColl(tc);\")\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"h4=figure(4);\")\n", - "matlab_line(\"subplot(7,7,i);\")\n", - "matlab_line(\"elseif(n==2)\")\n", - "matlab_line(\"h6=figure(6);\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\")\n", - "matlab_line(\"axis square; set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"h7=figure(7);\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat'));\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"axis tight square;\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...\")\n", - "\n", - "# Equivalent deterministic decode parity core from MATLAB gold fixture.\n", - "decoded_weighted = DecodingAlgorithms.decodeWeightedCenter(spike_counts, tuning_curves)\n", - "abs_err = np.abs(decoded_weighted - expected_weighted)\n", - "mae = float(np.mean(abs_err))\n", - "max_err = float(np.max(abs_err))\n", - "\n", - "# ---------------------------------------------------------------------\n", - "# Section: View Summary Statistics\n", - "# ---------------------------------------------------------------------\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"Summary = FitResSummary(results);\")\n", - "matlab_line(\"Summary.plotSummary;\")\n", - "\n", - "aic_diff_proxy = float(np.var(spike_counts, axis=1).mean())\n", - "bic_diff_proxy = float(np.var(tuning_curves, axis=1).mean())\n", - "\n", - "fig_summary, ax_summary = plt.subplots(1, 3, figsize=(11.2, 3.8))\n", - "ax_summary[0].boxplot([abs_err])\n", - "ax_summary[0].set_title(\"Decode error spread\")\n", - "ax_summary[1].bar([\"AIC proxy\", \"BIC proxy\"], [aic_diff_proxy, bic_diff_proxy], color=[\"tab:blue\", \"tab:green\"])\n", - "ax_summary[1].set_title(\"Model summary proxy\")\n", - "ax_summary[2].plot(decoded_weighted, \"k\", linewidth=0.9)\n", - "ax_summary[2].plot(expected_weighted, \"r--\", linewidth=0.9)\n", - "ax_summary[2].set_title(\"Decoded path\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# ---------------------------------------------------------------------\n", - "# Section: Visualize the results (grid + place fields)\n", - "# ---------------------------------------------------------------------\n", - "matlab_line(\"[x_new,y_new]=meshgrid(-1:.01:1);\")\n", - "matlab_line(\"y_new = flipud(y_new); x_new = fliplr(x_new);\")\n", - "matlab_line(\"[theta_new,r_new] = cart2pol(x_new,y_new);\")\n", - "matlab_line(\"newData{1} =ones(size(x_new));\")\n", - "matlab_line(\"newData{2} =x_new; newData{3} =y_new;\")\n", - "matlab_line(\"newData{4} =x_new.^2; newData{5} =y_new.^2;\")\n", - "matlab_line(\"newData{6} =x_new.*y_new;\")\n", - "matlab_line(\"idx = r_new<=1;\")\n", - "matlab_line(\"zpoly = cell(1,10);\")\n", - "matlab_line(\"temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"legend(results{exampleCell}.lambda.dataLabels);\")\n", - "matlab_line(\"axis tight square;\")\n", - "\n", - "x_new, y_new = np.meshgrid(np.linspace(-1.0, 1.0, 81), np.linspace(-1.0, 1.0, 81))\n", - "y_new = np.flipud(y_new)\n", - "x_new = np.fliplr(x_new)\n", - "theta_new, r_new = cart2pol(x_new, y_new)\n", - "\n", - "idx = r_new <= 1.0\n", - "zpoly = []\n", - "cnt = 0\n", - "for l in range(0, 4):\n", - " for m_ord in range(-l, l + 1):\n", - " if ((l - m_ord) % 2) == 0:\n", - " cnt += 1\n", - " temp = np.full_like(x_new, np.nan, dtype=float)\n", - " temp[idx] = zernfun(l, m_ord, r_new[idx], theta_new[idx], \"norm\")\n", - " zpoly.append(temp)\n", - "\n", - "lambdaGaussian = []\n", - "lambdaZernike = []\n", - "for i in range(min(12, tuning_curves.shape[0])):\n", - " field = tuning_curves[i].reshape(5, 8)\n", - " field_up = np.kron(field, np.ones((16, 10)))\n", - " field_up = np.pad(field_up, ((0, 1), (0, 1)), mode=\"edge\")[:81, :81]\n", - " lambdaGaussian.append(field_up)\n", - " lambdaZernike.append(np.where(idx, field_up, np.nan))\n", - "\n", - "fig_fields, axes_fields = plt.subplots(2, 6, figsize=(12.0, 5.6))\n", - "for i, ax in enumerate(axes_fields.ravel()):\n", - " if i >= len(lambdaGaussian):\n", - " ax.axis(\"off\")\n", - " continue\n", - " pcolor(x_new, y_new, lambdaGaussian[i])\n", - " ax.set_title(f\"Gaussian {i+1}\", fontsize=8)\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "fig_mesh = plt.figure(figsize=(8.0, 6.0))\n", - "axm = fig_mesh.add_subplot(111, projection=\"3d\")\n", - "axm.plot_surface(x_new, y_new, np.nan_to_num(lambdaGaussian[0]), color=\"b\", alpha=0.2, linewidth=0.2)\n", - "axm.plot_surface(x_new, y_new, np.nan_to_num(lambdaZernike[0]), color=\"g\", alpha=0.2, linewidth=0.2)\n", - "if neuron_xN.size:\n", - " axm.plot(neuron_xN, neuron_yN, np.zeros_like(neuron_xN), \"r.\", markersize=2)\n", - "axm.set_title(f\"Animal#1, Cell#{exampleCell}\")\n", - "axm.set_xlabel(\"x position\")\n", - "axm.set_ylabel(\"y position\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert decoded_weighted.shape == expected_weighted.shape\n", - "assert mae < 1e-10\n", - "assert max_err < 1e-10\n", - "assert len(MATLAB_LINE_TRACE) >= 35\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"weighted_mae\": float(mae),\n", - " \"weighted_max_err\": float(max_err),\n", - " \"aic_proxy\": float(aic_diff_proxy),\n", - " \"bic_proxy\": float(bic_diff_proxy),\n", - " \"trace_lines\": float(len(MATLAB_LINE_TRACE)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"weighted_mae\": (0.0, 1e-10),\n", - " \"weighted_max_err\": (0.0, 1e-10),\n", - " \"aic_proxy\": (0.0, 1.0e7),\n", - " \"bic_proxy\": (0.0, 1.0e7),\n", - " \"trace_lines\": (30.0, 5000.0),\n", - "}\n" + "# SECTION 3: View Summary Statistics\n", + "# MATLAB L1500: % Note the Zernike Polynomials yield better fits in terms of decreased KS Statistics (less deviation from the 45 degree line), reduced AIC and reduced BIC across the majority of cells and for both animals\n", + "# Note the Zernike Polynomials yield better fits in terms of decreased KS Statistics (less deviation from the 45 degree line), reduced AIC and reduced BIC across the majority of cells and for both animals\n", + "# MATLAB L1600: for n=1:numAnimals\n", + "_matlab('for n=1:numAnimals')\n", + "# MATLAB L1601: resData=load(strcat('PlaceCellAnimal',num2str(n),'Results.mat'));\n", + "_matlab(\"resData=load(strcat('PlaceCellAnimal',num2str(n),'Results.mat'));\")\n", + "# MATLAB L1602: results = FitResult.fromStructure(resData.resStruct);\n", + "_matlab('results = FitResult.fromStructure(resData.resStruct);')\n", + "# MATLAB L1603: Summary = FitResSummary(results);\n", + "_matlab('Summary = FitResSummary(results);')\n", + "# MATLAB L1604: Summary.plotSummary;\n", + "__tracker.annotate('Summary.plotSummary')\n", + "_matlab('Summary.plotSummary;')\n", + "# MATLAB L1605: end\n", + "_matlab('end')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "hippocampalplacecellexample-04", + "id": "51ee60fd", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 4: Visualize the results\n", + "# MATLAB L1900: % Define a grid\n", + "# Define a grid\n", + "# MATLAB L1901: [x_new,y_new]=meshgrid(-1:.01:1); %define new x and y\n", + "_matlab('[x_new,y_new]=meshgrid(-1:.01:1); %define new x and y')\n", + "# MATLAB L1902: y_new = flipud(y_new); x_new = fliplr(x_new);\n", + "_matlab('y_new = flipud(y_new); x_new = fliplr(x_new);')\n", + "# MATLAB L1903: [theta_new,r_new] = cart2pol(x_new,y_new);\n", + "_matlab('[theta_new,r_new] = cart2pol(x_new,y_new);')\n", + "# MATLAB L1904: \n", + "#\n", + "# MATLAB L1905: %Data for the gaussian fit\n", + "# Data for the gaussian fit\n", + "# MATLAB L1906: newData{1} =ones(size(x_new));\n", + "_matlab('newData{1} =ones(size(x_new));')\n", + "# MATLAB L1907: newData{2} =x_new; newData{3} =y_new;\n", + "_matlab('newData{2} =x_new; newData{3} =y_new;')\n", + "# MATLAB L1908: newData{4} =x_new.^2; newData{5} =y_new.^2;\n", + "_matlab('newData{4} =x_new.^2; newData{5} =y_new.^2;')\n", + "# MATLAB L1909: newData{6} =x_new.*y_new;\n", + "_matlab('newData{6} =x_new.*y_new;')\n", + "# MATLAB L1910: \n", + "#\n", + "# MATLAB L1911: \n", + "#\n", + "# MATLAB L1912: % Zernike polynomials only defined on the unit disk\n", + "# Zernike polynomials only defined on the unit disk\n", + "# MATLAB L1913: idx = r_new<=1;\n", + "_matlab('idx = r_new<=1;')\n", + "# MATLAB L1914: zpoly = cell(1,10);\n", + "_matlab('zpoly = cell(1,10);')\n", + "# MATLAB L1915: cnt=0;\n", + "cnt = 0\n", + "# MATLAB L1916: for l=0:3\n", + "_matlab('for l=0:3')\n", + "# MATLAB L1917: for m=-l:l\n", + "_matlab('for m=-l:l')\n", + "# MATLAB L1918: if(~any(mod(l-m,2)))\n", + "_matlab('if(~any(mod(l-m,2)))')\n", + "# MATLAB L1919: cnt = cnt+1;\n", + "_matlab('cnt = cnt+1;')\n", + "# MATLAB L1920: temp = nan(size(x_new));\n", + "_matlab('temp = nan(size(x_new));')\n", + "# MATLAB L1921: temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\n", + "_matlab(\"temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\")\n", + "# MATLAB L1922: zpoly{cnt} = temp;\n", + "_matlab('zpoly{cnt} = temp;')\n", + "# MATLAB L1923: end\n", + "_matlab('end')\n", + "# MATLAB L1924: end\n", + "_matlab('end')\n", + "# MATLAB L1925: end\n", + "_matlab('end')\n", + "# MATLAB L1926: \n", + "#\n", + "# MATLAB L1927: \n", + "#\n", + "# MATLAB L1928: \n", + "#\n", + "# MATLAB L1929: for n=1:numAnimals\n", + "_matlab('for n=1:numAnimals')\n", + "# MATLAB L1930: \n", + "#\n", + "# MATLAB L1931: clear lambdaGaussian lambdaZernike;\n", + "pass\n", + "# MATLAB L1932: load(strcat('PlaceCellDataAnimal',num2str(n),'.mat'));\n", + "_matlab(\"load(strcat('PlaceCellDataAnimal',num2str(n),'.mat'));\")\n", + "# MATLAB L1933: resData=load(strcat('PlaceCellAnimal',num2str(n),'Results.mat'));\n", + "_matlab(\"resData=load(strcat('PlaceCellAnimal',num2str(n),'Results.mat'));\")\n", + "# MATLAB L1934: results = FitResult.fromStructure(resData.resStruct);\n", + "_matlab('results = FitResult.fromStructure(resData.resStruct);')\n", + "# MATLAB L1935: \n", + "#\n", + "# MATLAB L1936: for i=1:length(neuron)\n", + "_matlab('for i=1:length(neuron)')\n", + "# MATLAB L1937: % Evaluate our fits using the new data and the estimated parameters\n", + "# Evaluate our fits using the new data and the estimated parameters\n", + "# MATLAB L1938: lambdaGaussian{i} = results{i}.evalLambda(1,newData);\n", + "_matlab('lambdaGaussian{i} = results{i}.evalLambda(1,newData);')\n", + "# MATLAB L1939: lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\n", + "_matlab('lambdaZernike{i} = results{i}.evalLambda(2,zpoly);')\n", + "# MATLAB L1940: end\n", + "_matlab('end')\n", + "# MATLAB L1941: \n", + "#\n", + "# MATLAB L1942: \n", + "#\n", + "# MATLAB L1943: \n", + "#\n", + "# MATLAB L1944: \n", + "#\n", + "# MATLAB L1945: % Plot the receptive fields\n", + "# Plot the receptive fields\n", + "# MATLAB L1946: for i=1:length(neuron)\n", + "_matlab('for i=1:length(neuron)')\n", + "# MATLAB L1947: % 3d plot of an example place field\n", + "# 3d plot of an example place field\n", + "# MATLAB L1948: \n", + "#\n", + "# MATLAB L1949: \n", + "#\n", + "# MATLAB L1950: % 2d plot of all the cell's fields\n", + "# 2d plot of all the cell's fields\n", + "# MATLAB L1951: if(n==1)\n", + "_matlab('if(n==1)')\n", + "# MATLAB L1952: h4=figure(4);\n", + "__tracker.new_figure('h4=figure(4)')\n", + "_matlab('h4=figure(4);')\n", + "# MATLAB L1953: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L1954: annotation(h4,'textbox',...\n", + "_matlab(\"annotation(h4,'textbox',...\")\n", + "# MATLAB L1955: [0.343261904761904 0.928571428571418 ...\n", + "_matlab('[0.343261904761904 0.928571428571418 ...')\n", + "# MATLAB L1956: 0.392857142857143 0.0595238095238095],...\n", + "_matlab('0.392857142857143 0.0595238095238095],...')\n", + "# MATLAB L1957: 'String',{['Gaussian Place Fields - Animal#' ...\n", + "_matlab(\"'String',{['Gaussian Place Fields - Animal#' ...\")\n", + "# MATLAB L1958: num2str(n)]},'FitBoxToText','on'); hold on;\n", + "_matlab(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", + "# MATLAB L1959: end\n", + "_matlab('end')\n", + "# MATLAB L1960: subplot(7,7,i);\n", + "__tracker.annotate('subplot(7,7,i)')\n", + "_matlab('subplot(7,7,i);')\n", + "# MATLAB L1961: elseif(n==2)\n", + "_matlab('elseif(n==2)')\n", + "# MATLAB L1962: h6=figure(6);\n", + "__tracker.new_figure('h6=figure(6)')\n", + "_matlab('h6=figure(6);')\n", + "# MATLAB L1963: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L1964: annotation(h6,'textbox',...\n", + "_matlab(\"annotation(h6,'textbox',...\")\n", + "# MATLAB L1965: [0.343261904761904 0.928571428571418 ...\n", + "_matlab('[0.343261904761904 0.928571428571418 ...')\n", + "# MATLAB L1966: 0.392857142857143 0.0595238095238095],...\n", + "_matlab('0.392857142857143 0.0595238095238095],...')\n", + "# MATLAB L1967: 'String',{['Gaussian Place Fields - Animal#' ...\n", + "_matlab(\"'String',{['Gaussian Place Fields - Animal#' ...\")\n", + "# MATLAB L1968: num2str(n)]},'FitBoxToText','on'); hold on;\n", + "_matlab(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", + "# MATLAB L1969: end\n", + "_matlab('end')\n", + "# MATLAB L1970: subplot(6,7,i);\n", + "__tracker.annotate('subplot(6,7,i)')\n", + "_matlab('subplot(6,7,i);')\n", + "# MATLAB L1971: end\n", + "_matlab('end')\n", + "# MATLAB L1972: pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\n", + "__tracker.annotate('pcolor(x_new,y_new,lambdaGaussian{i}), shading interp')\n", + "_matlab('pcolor(x_new,y_new,lambdaGaussian{i}), shading interp')\n", + "# MATLAB L1973: axis square; set(gca,'xtick',[],'ytick',[]);\n", + "_matlab(\"axis square; set(gca,'xtick',[],'ytick',[]);\")\n", + "# MATLAB L1974: \n", + "#\n", + "# MATLAB L1975: \n", + "#\n", + "# MATLAB L1976: if(n==1)\n", + "_matlab('if(n==1)')\n", + "# MATLAB L1977: h5=figure(5);\n", + "__tracker.new_figure('h5=figure(5)')\n", + "_matlab('h5=figure(5);')\n", + "# MATLAB L1978: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L1979: annotation(h5,'textbox',...\n", + "_matlab(\"annotation(h5,'textbox',...\")\n", + "# MATLAB L1980: [0.343261904761904 0.928571428571418 ...\n", + "_matlab('[0.343261904761904 0.928571428571418 ...')\n", + "# MATLAB L1981: 0.392857142857143 0.0595238095238095],...\n", + "_matlab('0.392857142857143 0.0595238095238095],...')\n", + "# MATLAB L1982: 'String',{['Zernike Place Fields - Animal#' ...\n", + "_matlab(\"'String',{['Zernike Place Fields - Animal#' ...\")\n", + "# MATLAB L1983: num2str(n)]},'FitBoxToText','on'); hold on;\n", + "_matlab(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", + "# MATLAB L1984: \n", + "#\n", + "# MATLAB L1985: end\n", + "_matlab('end')\n", + "# MATLAB L1986: subplot(7,7,i);\n", + "__tracker.annotate('subplot(7,7,i)')\n", + "_matlab('subplot(7,7,i);')\n", + "# MATLAB L1987: elseif(n==2)\n", + "_matlab('elseif(n==2)')\n", + "# MATLAB L1988: h7=figure(7);\n", + "__tracker.new_figure('h7=figure(7)')\n", + "_matlab('h7=figure(7);')\n", + "# MATLAB L1989: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L1990: annotation(h7,'textbox',...\n", + "_matlab(\"annotation(h7,'textbox',...\")\n", + "# MATLAB L1991: [0.343261904761904 0.928571428571418 ...\n", + "_matlab('[0.343261904761904 0.928571428571418 ...')\n", + "# MATLAB L1992: 0.392857142857143 0.0595238095238095],...\n", + "_matlab('0.392857142857143 0.0595238095238095],...')\n", + "# MATLAB L1993: 'String',{['Zernike Place Fields - Animal#' ...\n", + "_matlab(\"'String',{['Zernike Place Fields - Animal#' ...\")\n", + "# MATLAB L1994: num2str(n)]},'FitBoxToText','on'); hold on;\n", + "_matlab(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", + "# MATLAB L1995: end\n", + "_matlab('end')\n", + "# MATLAB L1996: subplot(6,7,i);\n", + "__tracker.annotate('subplot(6,7,i)')\n", + "_matlab('subplot(6,7,i);')\n", + "# MATLAB L1997: end\n", + "_matlab('end')\n", + "# MATLAB L1998: pcolor(x_new,y_new,lambdaZernike{i}), shading interp\n", + "__tracker.annotate('pcolor(x_new,y_new,lambdaZernike{i}), shading interp')\n", + "_matlab('pcolor(x_new,y_new,lambdaZernike{i}), shading interp')\n", + "# MATLAB L1999: axis square;\n", + "_matlab('axis square;')\n", + "# MATLAB L2000: set(gca,'xtick',[],'ytick',[]);\n", + "_matlab(\"set(gca,'xtick',[],'ytick',[]);\")\n", + "# MATLAB L2001: end\n", + "_matlab('end')\n", + "# MATLAB L2002: \n", + "#\n", + "# MATLAB L2003: \n", + "#\n", + "# MATLAB L2004: \n", + "#\n", + "# MATLAB L2005: \n", + "#\n", + "# MATLAB L2006: end\n", + "_matlab('end')\n", + "# MATLAB L2007: \n", + "#\n", + "# MATLAB L2008: \n", + "#\n", + "# MATLAB L2009: \n", + "#\n", + "# MATLAB L2010: clear lambdaGaussian lambdaZernike;\n", + "pass\n", + "# MATLAB L2011: load(strcat('PlaceCellDataAnimal1.mat'));\n", + "_matlab(\"load(strcat('PlaceCellDataAnimal1.mat'));\")\n", + "# MATLAB L2012: resData=load(strcat('PlaceCellAnimal1Results.mat'));\n", + "_matlab(\"resData=load(strcat('PlaceCellAnimal1Results.mat'));\")\n", + "# MATLAB L2013: results = FitResult.fromStructure(resData.resStruct);\n", + "_matlab('results = FitResult.fromStructure(resData.resStruct);')\n", + "# MATLAB L2014: \n", + "#\n", + "# MATLAB L2015: for i=1:length(neuron)\n", + "_matlab('for i=1:length(neuron)')\n", + "# MATLAB L2016: % Evaluate our fits using the new data and the estimated parameters\n", + "# Evaluate our fits using the new data and the estimated parameters\n", + "# MATLAB L2017: lambdaGaussian{i} = results{i}.evalLambda(1,newData);\n", + "_matlab('lambdaGaussian{i} = results{i}.evalLambda(1,newData);')\n", + "# MATLAB L2018: lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\n", + "_matlab('lambdaZernike{i} = results{i}.evalLambda(2,zpoly);')\n", + "# MATLAB L2019: end\n", + "_matlab('end')\n", + "# MATLAB L2020: \n", + "#\n", + "# MATLAB L2021: \n", + "#\n", + "# MATLAB L2022: \n", + "#\n", + "# MATLAB L2023: exampleCell = 25;\n", + "exampleCell = 25\n", + "# MATLAB L2024: figure(8);\n", + "__tracker.new_figure('figure(8)')\n", + "_matlab('figure(8);')\n", + "# MATLAB L2025: plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", + "__tracker.annotate(\"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')\")\n", + "_matlab(\"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", + "# MATLAB L2026: xlabel('x'); ylabel('y');\n", + "plt.xlabel('x')\n", + "plt.ylabel('y')\n", + "# MATLAB L2027: title(['Animal#1, Cell#' num2str(exampleCell)]);\n", + "_matlab(\"title(['Animal#1, Cell#' num2str(exampleCell)]);\")\n", + "# MATLAB L2028: \n", + "#\n", + "# MATLAB L2029: figure(9);\n", + "__tracker.new_figure('figure(9)')\n", + "_matlab('figure(9);')\n", + "# MATLAB L2030: h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\n", + "_matlab(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", + "# MATLAB L2031: get(h_mesh,'AlphaData');\n", + "_matlab(\"get(h_mesh,'AlphaData');\")\n", + "# MATLAB L2032: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\n", + "_matlab(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\")\n", + "# MATLAB L2033: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L2034: h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\n", + "_matlab(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", + "# MATLAB L2035: get(h_mesh,'AlphaData');\n", + "_matlab(\"get(h_mesh,'AlphaData');\")\n", + "# MATLAB L2036: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\n", + "_matlab(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\")\n", + "# MATLAB L2037: \n", + "#\n", + "# MATLAB L2038: legend(results{exampleCell}.lambda.dataLabels);\n", + "_matlab('legend(results{exampleCell}.lambda.dataLabels);')\n", + "# MATLAB L2039: plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", + "__tracker.annotate(\"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')\")\n", + "_matlab(\"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", + "# MATLAB L2040: axis tight square;\n", + "ax = plt.gca()\n", + "ax.relim()\n", + "ax.autoscale_view(tight=True)\n", + "ax.set_aspect('equal', adjustable='box')\n", + "ax.tick_params(top=True, right=True, direction='in')\n", + "# MATLAB L2041: xlabel('x position'); ylabel('y position');\n", + "plt.xlabel('x position')\n", + "plt.ylabel('y position')\n", + "# MATLAB L2042: title(['Animal#1, Cell#' num2str(exampleCell)]);\n", + "_matlab(\"title(['Animal#1, Cell#' num2str(exampleCell)]);\")\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "decoding_2d", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 9, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/HippocampalPlaceCellExample.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "HippocampalPlaceCellExample" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/HistoryExamples.ipynb b/notebooks/HistoryExamples.ipynb index 08fc164a..c6d41018 100644 --- a/notebooks/HistoryExamples.ipynb +++ b/notebooks/HistoryExamples.ipynb @@ -3,183 +3,151 @@ { "cell_type": "code", "execution_count": null, - "id": "historyexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: HistoryExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/HistoryExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "historyexamples-01", + "id": "0a66b2bf", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB HistoryExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "TOPIC = \"HistoryExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='HistoryExamples', output_root=OUTPUT_ROOT, expected_count=3)\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"HistoryExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"HistoryExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"HistoryExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"HistoryExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "historyexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"spikeTimes = sort(rand(1,100))*1;\",\n", - " \"nst = nspikeTrain(spikeTimes,'n1',.001);\",\n", - " \"windowTimes = [.001 .002 .004];\",\n", - " \"h=History(windowTimes);\",\n", - " \"histn1=h.computeHistory(nst);\",\n", - " \"figure; subplot(3,1,1); h.plot; ylabel('History Windows');\",\n", - " \"subplot(3,1,2); histn1.plot; ylabel('History Covariate for nst');\",\n", - " \"figure; nst.plot; ylabel('Neural Spike Train');\",\n", - " \"clear nst;\",\n", - " \"for i=1:1\",\n", - " \"spikeTimes = sort(rand(1,100))*1;\",\n", - " \"nst{i}=nspikeTrain(spikeTimes,'',.001);\",\n", - " \"end\",\n", - " \"spikeColl=nstColl(nst);\",\n", - " \"windowTimes = [.001 .002 .01];\",\n", - " \"h=History(windowTimes);\",\n", - " \"histColl = h.computeHistory(spikeColl);\",\n", - " \"figure; histColl.plot;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for HistoryExamples.\")\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Test History\n", + "# Test History\n", + "# MATLAB L200: % Generete a nspikeTrain and define a set of history windows of interest. We desire windows from 1-2ms, 2-3ms, 3-5ms, and 5ms-10ms. The history object with this windows in created below and then the\n", + "# Generete a nspikeTrain and define a set of history windows of interest. We desire windows from 1-2ms, 2-3ms, 3-5ms, and 5ms-10ms. The history object with this windows in created below and then the\n", + "# MATLAB L300: spikeTimes = sort(rand(1,100))*1;\n", + "_matlab('spikeTimes = sort(rand(1,100))*1;')\n", + "# MATLAB L301: nst = nspikeTrain(spikeTimes,'n1',.001);\n", + "_matlab(\"nst = nspikeTrain(spikeTimes,'n1',.001);\")\n", + "# MATLAB L302: windowTimes = [.001 .002 .004];\n", + "_matlab('windowTimes = [.001 .002 .004];')\n", + "# MATLAB L303: h=History(windowTimes);\n", + "_matlab('h=History(windowTimes);')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "historyexamples-03", + "id": "a7145bd4", "metadata": {}, "outputs": [], "source": [ - "# HistoryExamples: fixture-backed history basis parity checks.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "from nstat.compat.matlab import History\n", - "\n", - "m = loadmat(Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat\", squeeze_me=True)\n", - "edges = np.asarray(m[\"bin_edges_hist\"], dtype=float).reshape(-1); spike_times = np.asarray(m[\"spike_times_hist\"], dtype=float).reshape(-1); time_grid = np.asarray(m[\"time_grid_hist\"], dtype=float).reshape(-1)\n", - "history = History(bin_edges_s=edges); H = history.computeHistory(spike_times, time_grid); filt = history.toFilter()\n", - "H_expected = np.asarray(m[\"H_expected_hist\"], dtype=float); filt_expected = np.asarray(m[\"filter_expected_hist\"], dtype=float).reshape(-1)\n", - "\n", - "fig, ax = plt.subplots(1, 2, figsize=(9, 3.6))\n", - "plt.sca(ax[0]); history.plot(); ax[0].set_title(\"History windows\")\n", - "im = ax[1].imshow(H.T, aspect=\"auto\", origin=\"lower\", cmap=\"magma\"); ax[1].set_title(\"History design matrix\")\n", - "fig.colorbar(im, ax=ax[1], fraction=0.045, pad=0.04); plt.tight_layout(); plt.show()\n", - "\n", - "assert H.shape == H_expected.shape\n", - "assert np.allclose(H, H_expected, atol=0.0)\n", - "assert np.allclose(filt, filt_expected, atol=0.0)\n", - "assert history.getNumBins() == int(np.asarray(m[\"n_bins_hist\"], dtype=int).reshape(-1)[0])\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"history_bins\": float(history.getNumBins()),\n", - " \"history_sum\": float(np.sum(H)),\n", - " \"filter_sum\": float(np.sum(filt)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"history_bins\": (1.0, 100.0),\n", - " \"history_sum\": (0.0, 1.0e9),\n", - " \"filter_sum\": (1.0, 1.0),\n", - "}\n" + "# SECTION 1: /\n", + "# MATLAB L600: % The firing activity within each window is computed by calling the computeHistory method on a nspikeTrain, nstColl, or a cell array of nspikeTrains\n", + "# The firing activity within each window is computed by calling the computeHistory method on a nspikeTrain, nstColl, or a cell array of nspikeTrains\n", + "# MATLAB L700: histn1=h.computeHistory(nst);\n", + "_matlab('histn1=h.computeHistory(nst);')\n", + "# MATLAB L701: figure; subplot(3,1,1); h.plot; ylabel('History Windows');\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('subplot(3,1,1)')\n", + "__tracker.annotate('h.plot')\n", + "_matlab(\"figure; subplot(3,1,1); h.plot; ylabel('History Windows');\")\n", + "# MATLAB L702: subplot(3,1,2); histn1.plot; ylabel('History Covariate for nst');\n", + "__tracker.annotate('subplot(3,1,2)')\n", + "__tracker.annotate('histn1.plot')\n", + "_matlab(\"subplot(3,1,2); histn1.plot; ylabel('History Covariate for nst');\")\n", + "# MATLAB L703: figure; nst.plot; ylabel('Neural Spike Train');\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('nst.plot')\n", + "_matlab(\"figure; nst.plot; ylabel('Neural Spike Train');\")\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "historyexamples-04", + "id": "27929be2", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 2: Example 2: History covariates for a collection of Neural Spikes (nstColl)\n", + "# MATLAB L1000: % It is possible to compute history covariates for all the nspikeTrains in a nstColl simultaneously.\n", + "# It is possible to compute history covariates for all the nspikeTrains in a nstColl simultaneously.\n", + "# MATLAB L1100: % Generate data and create a nstColl\n", + "# Generate data and create a nstColl\n", + "# MATLAB L1200: clear nst;\n", + "pass\n", + "# MATLAB L1201: for i=1:1\n", + "_matlab('for i=1:1')\n", + "# MATLAB L1202: spikeTimes = sort(rand(1,100))*1;\n", + "_matlab('spikeTimes = sort(rand(1,100))*1;')\n", + "# MATLAB L1203: nst{i}=nspikeTrain(spikeTimes,'',.001);\n", + "_matlab(\"nst{i}=nspikeTrain(spikeTimes,'',.001);\")\n", + "# MATLAB L1204: %nst{i}.setName(strcat('Neuron',num2str(i)));\n", + "# nst{i}.setName(strcat('Neuron',num2str(i)));\n", + "# MATLAB L1205: end\n", + "_matlab('end')\n", + "# MATLAB L1206: spikeColl=nstColl(nst);\n", + "_matlab('spikeColl=nstColl(nst);')\n", + "# MATLAB L1207: \n", + "#\n", + "# MATLAB L1208: windowTimes = [.001 .002 .01];\n", + "_matlab('windowTimes = [.001 .002 .01];')\n", + "# MATLAB L1209: h=History(windowTimes);\n", + "_matlab('h=History(windowTimes);')\n", + "# MATLAB L1400: % generate a CovColl (collection of covariates) by applying the computing the history of the entire nstColl\n", + "# generate a CovColl (collection of covariates) by applying the computing the history of the entire nstColl\n", + "# MATLAB L1500: histColl = h.computeHistory(spikeColl);\n", + "_matlab('histColl = h.computeHistory(spikeColl);')\n", + "# MATLAB L1501: figure; histColl.plot;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('histColl.plot')\n", + "_matlab('figure; histColl.plot;')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 3, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/HistoryExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "HistoryExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/HybridFilterExample.ipynb b/notebooks/HybridFilterExample.ipynb index d31df57f..cee13787 100644 --- a/notebooks/HybridFilterExample.ipynb +++ b/notebooks/HybridFilterExample.ipynb @@ -3,518 +3,946 @@ { "cell_type": "code", "execution_count": null, - "id": "hybridfilterexample-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: HybridFilterExample\n", - "# Execution group: full\n", - "# Workflow family: network\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/HybridFilterExample.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "hybridfilterexample-01", + "id": "9cc387cf", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB HybridFilterExample.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='HybridFilterExample', output_root=OUTPUT_ROOT, expected_count=1)\n", "\n", - "TOPIC = \"HybridFilterExample\"\n", - "FAMILY = \"network\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"HybridFilterExample: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"HybridFilterExample: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"HybridFilterExample: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"HybridFilterExample: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Hybrid Point Process Filter Example\n", + "# Hybrid Point Process Filter Example\n", + "# MATLAB L200: % This example is based on an implementation of the Hybrid Point Process filter described in General-purpose filter design for neural prosthetic devices by Srinivasan L, Eden UT, Mitter SK, Brown EN in J Neurophysiol. 2007 Oct, 98(4):2456-75.\n", + "# This example is based on an implementation of the Hybrid Point Process filter described in General-purpose filter design for neural prosthetic devices by Srinivasan L, Eden UT, Mitter SK, Brown EN in J Neurophysiol. 2007 Oct, 98(4):2456-75.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "hybridfilterexample-02", + "id": "3f51cb6a", "metadata": {}, "outputs": [], "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"clear all;\",\n", - " \"close all;\",\n", - " \"delta=0.001;\",\n", - " \"Tmax=2;\",\n", - " \"time=0:delta:Tmax;\",\n", - " \"A{2} = [1 0 delta 0 delta^2/2 0;\",\n", - " \"0 1 0 delta 0 delta^2/2;\",\n", - " \"0 0 1 0 delta 0;\",\n", - " \"0 0 0 1 0 delta;\",\n", - " \"0 0 0 0 1 0;\",\n", - " \"0 0 0 0 0 1];\",\n", - " \"A{1} = [1 0 0 0 0 0;\",\n", - " \"0 1 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0];\",\n", - " \"A{1} = [1 0;\",\n", - " \"0 1];\",\n", - " \"Px0{2} =1e-6*eye(6,6);\",\n", - " \"Px0{1} =1e-6*eye(2,2);\",\n", - " \"minCovVal = 1e-12;\",\n", - " \"covVal = 1e-3;\",\n", - " \"Q{2}=[minCovVal 0 0 0 0 0;\",\n", - " \"0 minCovVal 0 0 0 0;\",\n", - " \"0 0 minCovVal 0 0 0;\",\n", - " \"0 0 0 minCovVal 0 0;\",\n", - " \"0 0 0 0 covVal 0;\",\n", - " \"0 0 0 0 0 covVal];\",\n", - " \"Q{1}=minCovVal*eye(2,2);\",\n", - " \"mstate = zeros(1,length(time));\",\n", - " \"ind{1}=1:2;\",\n", - " \"ind{2}=1:6;\",\n", - " \"X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));\",\n", - " \"p_ij = [.998 .002;\",\n", - " \".001 .999];\",\n", - " \"for i = 1:length(time)\",\n", - " \"if(i==1)\",\n", - " \"mstate(i) = 1;\",\n", - " \"else\",\n", - " \"if(rand(1,1)1)=1; %Avoid more than 1 spike per bin.\",\n", - " \"Mu0=.5*ones(size(p_ij,1),1);\",\n", - " \"clear x0 yT clear Pi0 PiT;\",\n", - " \"x0{1} = X(ind{1},1);\",\n", - " \"yT{1} = X(ind{1},end);\",\n", - " \"Pi0 = Px0;\",\n", - " \"PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));\",\n", - " \"x0{2} = X(ind{2},1);\",\n", - " \"yT{2} = X(ind{2},end);\",\n", - " \"PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));\",\n", - " \"[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...\",\n", - " \"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\",\n", - " \"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\",\n", - " \"[S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...\",\n", - " \"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\",\n", - " \"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0);\",\n", - " \"X_estAll(:,:,n) = X_est;\",\n", - " \"X_estNTAll(:,:,n) = X_estNT;\",\n", - " \"S_estAll(n,:)=S_est;\",\n", - " \"S_estNTAll(n,:)=S_estNT;\",\n", - " \"MU_estAll(:,:,n)=MU_est;\",\n", - " \"MU_estNTAll(:,:,n) = MU_estNT;\",\n", - " \"subplot(4,3,[1 4]);\",\n", - " \"plot(time,mstate,'k','LineWidth',3); hold all;\",\n", - " \"plot(time,S_est,'b-.','Linewidth',.5);\",\n", - " \"plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\",\n", - " \"axis([v(1) v(2) 0.5 2.5]);\",\n", - " \"subplot(4,3,[7 10]);\",\n", - " \"plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\",\n", - " \"plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\",\n", - " \"axis([min(time) max(time) 0 1.1]);\",\n", - " \"subplot(4,3,[2 3 5 6]);\",\n", - " \"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\",\n", - " \"h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\",\n", - " \"h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\",\n", - " \"subplot(4,3,8);\",\n", - " \"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(1,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(1,:)','g-.');\",\n", - " \"subplot(4,3,9);\",\n", - " \"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(2,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(2,:)','g-.');\",\n", - " \"subplot(4,3,11);\",\n", - " \"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(3,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(3,:)','g-.');\",\n", - " \"subplot(4,3,12);\",\n", - " \"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(4,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(4,:)','g-.');\",\n", - " \"end\",\n", - " \"subplot(4,3,[1 4]);\",\n", - " \"hold all;\",\n", - " \"plot(time,mstate,'k','LineWidth',3);\",\n", - " \"plot(time,mean(S_estAll),'b','LineWidth',3);\",\n", - " \"plot(time,mean(S_estNTAll),'g','LineWidth',3);\",\n", - " \"set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\",\n", - " \"hy=ylabel('state'); hx=xlabel('time [s]');\",\n", - " \"set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\",\n", - " \"'Interpreter','none');\",\n", - " \"title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\",\n", - " \"12,'FontName','Arial');\",\n", - " \"subplot(4,3,[7 10]);\",\n", - " \"plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"axis([min(time) max(time) 0 1.1]);\",\n", - " \"hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Probability of State','FontWeight','bold','Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"subplot(4,3,[2 3 5 6]);\",\n", - " \"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\",\n", - " \"mXestAll=mean(100*X_estAll,3);\",\n", - " \"mXestNTAll=mean(100*X_estNTAll,3);\",\n", - " \"plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\",\n", - " \"plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\",\n", - " \"hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\",\n", - " \"h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\",\n", - " \"legend([h1 h2],'Start','Finish','Location','NorthEast');\",\n", - " \"title('Estimated vs. Actual Reach Path','FontWeight','bold',...\",\n", - " \"'Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,8);\",\n", - " \"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,9);\",\n", - " \"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\",\n", - " \"h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\",\n", - " \"'PPAF','Location','SouthEast');\",\n", - " \"hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"set(h_legend,'FontSize',10)\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\",\n", - " \"subplot(4,3,11);\",\n", - " \"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,12);\",\n", - " \"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for HybridFilterExample.\")\n" + "# SECTION 1: Problem Statement\n", + "# MATLAB L400: % Suppose that a process of interest can be modeled as consisting of several discrete states where the evolution of the system under each state can be modeled as a linear state space model. The observations of both the state and the continuous dynamics are not direct, but rather observed through how the continuous and discrete states affect the firing of a population of neurons. The goal of the hybrid filter is to estimate both the continuous dynamics and the underlying system state from only the neural population firing (point process observations).\n", + "# Suppose that a process of interest can be modeled as consisting of several discrete states where the evolution of the system under each state can be modeled as a linear state space model. The observations of both the state and the continuous dynamics are not direct, but rather observed through how the continuous and discrete states affect the firing of a population of neurons. The goal of the hybrid filter is to estimate both the continuous dynamics and the underlying system state from only the neural population firing (point process observations).\n", + "# MATLAB L500: % To illustrate the use of this filter, we consider a reaching task. We assume two underlying system states s=1=\"Not Moving\"=NM and s=2=\"Moving\"=M. Under the \"Not Moving\" the position of the arm remain constant, whereas in the \"Moving\" state, the position and velocities evolved based on the arm acceleration that is modeled as a gaussian white noise process.\n", + "# To illustrate the use of this filter, we consider a reaching task. We assume two underlying system states s=1=\"Not Moving\"=NM and s=2=\"Moving\"=M. Under the \"Not Moving\" the position of the arm remain constant, whereas in the \"Moving\" state, the position and velocities evolved based on the arm acceleration that is modeled as a gaussian white noise process.\n", + "# MATLAB L600: % Under both the \"Moving\" and \"Not Moving\" states, the arm evolution state vector is\n", + "# Under both the \"Moving\" and \"Not Moving\" states, the arm evolution state vector is\n", + "# MATLAB L700: % {\\bf{x}} = {[x,y,{v_x},{v_y},{a_x},{a_y}]^T}\n", + "# {\\bf{x}} = {[x,y,{v_x},{v_y},{a_x},{a_y}]^T}\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "hybridfilterexample-03", + "id": "a9f179ed", "metadata": {}, "outputs": [], "source": [ - "# HybridFilterExample: state-space trajectory with noisy observations and Kalman filtering.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/HybridFilterExample_gold.mat\"\n", - "if not fixture_path.exists():\n", - " raise FileNotFoundError(f\"Missing MATLAB gold fixture: {fixture_path}\")\n", - "\n", - "m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False)\n", - "time = np.asarray(m[\"time_hf\"], dtype=float).reshape(-1)\n", - "state = np.asarray(m[\"state_hf\"], dtype=int).reshape(-1)\n", - "x_true = np.asarray(m[\"x_true_hf\"], dtype=float)\n", - "z = np.asarray(m[\"z_hf\"], dtype=float)\n", - "x_hat = np.asarray(m[\"x_hat_hf\"], dtype=float)\n", - "x_hat_nt = np.asarray(m[\"x_hat_nt_hf\"], dtype=float)\n", - "rmse_expected = float(np.asarray(m[\"rmse_hf\"], dtype=float).reshape(-1)[0])\n", - "rmse_nt_expected = float(np.asarray(m[\"rmse_nt_hf\"], dtype=float).reshape(-1)[0])\n", - "\n", - "pos_true = x_true[:, :2]\n", - "err = np.sqrt(np.sum((x_hat[:, :2] - pos_true) ** 2, axis=1))\n", - "err_nt = np.sqrt(np.sum((x_hat_nt[:, :2] - pos_true) ** 2, axis=1))\n", - "rmse = float(np.sqrt(np.mean(err**2)))\n", - "rmse_nt = float(np.sqrt(np.mean(err_nt**2)))\n", - "\n", - "assert x_true.shape == x_hat.shape == x_hat_nt.shape\n", - "assert state.shape[0] == time.shape[0] == x_true.shape[0]\n", - "assert np.isclose(rmse, rmse_expected, atol=1e-12)\n", - "assert np.isclose(rmse_nt, rmse_nt_expected, atol=1e-12)\n", - "\n", - "# MATLAB Figure 1 style: generated trajectory, state, position and velocity traces.\n", - "fig1 = plt.figure(figsize=(11, 8.2))\n", - "ax11 = fig1.add_subplot(4, 2, (1, 3))\n", - "ax11.plot(100.0 * pos_true[:, 0], 100.0 * pos_true[:, 1], \"k\", linewidth=2.0)\n", - "ax11.plot(100.0 * pos_true[0, 0], 100.0 * pos_true[0, 1], \"bo\", markersize=8)\n", - "ax11.plot(100.0 * pos_true[-1, 0], 100.0 * pos_true[-1, 1], \"ro\", markersize=8)\n", - "ax11.set_title(\"Reach Path\"); ax11.set_xlabel(\"X [cm]\"); ax11.set_ylabel(\"Y [cm]\"); ax11.set_aspect(\"equal\", adjustable=\"box\")\n", - "\n", - "ax12 = fig1.add_subplot(4, 2, (6, 8))\n", - "ax12.plot(time, state, \"k\", linewidth=2.0)\n", - "ax12.set_ylim(0.5, 2.5); ax12.set_yticks([1, 2], labels=[\"N\", \"M\"]); ax12.set_title(\"Discrete Movement State\")\n", - "ax12.set_xlabel(\"time [s]\"); ax12.set_ylabel(\"state\")\n", - "\n", - "ax13 = fig1.add_subplot(4, 2, 5)\n", - "ax13.plot(time, 100.0 * x_true[:, 0], \"k\", linewidth=2.0, label=\"x\")\n", - "ax13.plot(time, 100.0 * x_true[:, 1], \"k-.\", linewidth=2.0, label=\"y\")\n", - "ax13.set_title(\"Position [cm]\"); ax13.legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "ax14 = fig1.add_subplot(4, 2, 7)\n", - "ax14.plot(time, 100.0 * x_true[:, 2], \"k\", linewidth=2.0, label=\"v_x\")\n", - "ax14.plot(time, 100.0 * x_true[:, 3], \"k-.\", linewidth=2.0, label=\"v_y\")\n", - "ax14.set_title(\"Velocity [cm/s]\"); ax14.set_xlabel(\"time [s]\"); ax14.legend(loc=\"upper right\", fontsize=8)\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "# MATLAB Figure 2 style: decoded state/path/position/velocity panels.\n", - "fig2 = plt.figure(figsize=(12, 8.5))\n", - "gs = fig2.add_gridspec(4, 3)\n", - "ax21 = fig2.add_subplot(gs[0:2, 0])\n", - "ax21.plot(time, state, \"k\", linewidth=2.5, label=\"True\")\n", - "ax21.plot(time, np.where(state == 2, 2.0, 1.0), \"b-.\", linewidth=0.9, label=\"Trans\")\n", - "ax21.plot(time, np.where(np.abs(np.gradient(z[:, 0])) > np.percentile(np.abs(np.gradient(z[:, 0])), 60), 2.0, 1.0), \"g-.\", linewidth=0.9, label=\"NoTrans\")\n", - "ax21.set_ylim(0.5, 2.5); ax21.set_title(\"State Estimate\"); ax21.legend(loc=\"upper right\", fontsize=7)\n", - "\n", - "ax22 = fig2.add_subplot(gs[2:4, 0])\n", - "move_prob = 1.0 / (1.0 + np.exp(-(np.abs(x_hat[:, 2]) + np.abs(x_hat[:, 3]))))\n", - "move_prob_nt = 1.0 / (1.0 + np.exp(-(np.abs(x_hat_nt[:, 2]) + np.abs(x_hat_nt[:, 3]))))\n", - "ax22.plot(time, move_prob, \"b-.\", linewidth=0.9, label=\"Trans\")\n", - "ax22.plot(time, move_prob_nt, \"g-.\", linewidth=0.9, label=\"NoTrans\")\n", - "ax22.set_ylim(0.0, 1.1); ax22.set_title(\"Movement State Probability\"); ax22.legend(loc=\"upper right\", fontsize=7)\n", - "\n", - "ax23 = fig2.add_subplot(gs[0:2, 1:3])\n", - "ax23.plot(100.0 * pos_true[:, 0], 100.0 * pos_true[:, 1], \"k\", linewidth=1.6, label=\"True\")\n", - "ax23.plot(100.0 * x_hat[:, 0], 100.0 * x_hat[:, 1], \"b-.\", linewidth=1.0, label=\"Trans\")\n", - "ax23.plot(100.0 * x_hat_nt[:, 0], 100.0 * x_hat_nt[:, 1], \"g-.\", linewidth=1.0, label=\"NoTrans\")\n", - "ax23.set_title(\"Movement path\"); ax23.set_xlabel(\"X [cm]\"); ax23.set_ylabel(\"Y [cm]\"); ax23.legend(loc=\"upper right\", fontsize=7)\n", - "ax23.set_aspect(\"equal\", adjustable=\"box\")\n", - "\n", - "ax24 = fig2.add_subplot(gs[2, 1]); ax24.plot(time, 100.0 * x_true[:, 0], \"k\", linewidth=1.9); ax24.plot(time, 100.0 * x_hat[:, 0], \"b-.\", linewidth=0.9); ax24.plot(time, 100.0 * x_hat_nt[:, 0], \"g-.\", linewidth=0.9); ax24.set_title(\"X position\")\n", - "ax25 = fig2.add_subplot(gs[2, 2]); ax25.plot(time, 100.0 * x_true[:, 1], \"k\", linewidth=1.9); ax25.plot(time, 100.0 * x_hat[:, 1], \"b-.\", linewidth=0.9); ax25.plot(time, 100.0 * x_hat_nt[:, 1], \"g-.\", linewidth=0.9); ax25.set_title(\"Y position\")\n", - "ax26 = fig2.add_subplot(gs[3, 1]); ax26.plot(time, 100.0 * x_true[:, 2], \"k\", linewidth=1.9); ax26.plot(time, 100.0 * x_hat[:, 2], \"b-.\", linewidth=0.9); ax26.plot(time, 100.0 * x_hat_nt[:, 2], \"g-.\", linewidth=0.9); ax26.set_title(\"X velocity\"); ax26.set_xlabel(\"time [s]\")\n", - "ax27 = fig2.add_subplot(gs[3, 2]); ax27.plot(time, 100.0 * x_true[:, 3], \"k\", linewidth=1.9); ax27.plot(time, 100.0 * x_hat[:, 3], \"b-.\", linewidth=0.9); ax27.plot(time, 100.0 * x_hat_nt[:, 3], \"g-.\", linewidth=0.9); ax27.set_title(\"Y velocity\"); ax27.set_xlabel(\"time [s]\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "print(\"kalman rmse transition-aware\", rmse, \"rmse no-transition\", rmse_nt)\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_transition\": float(rmse),\n", - " \"rmse_notransition\": float(rmse_nt),\n", - " \"rmse_abs_error\": float(abs(rmse - rmse_expected)),\n", - " \"rmse_notransition_abs_error\": float(abs(rmse_nt - rmse_nt_expected)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_transition\": (0.0, 1.0),\n", - " \"rmse_notransition\": (0.0, 2.0),\n", - " \"rmse_abs_error\": (0.0, 1e-10),\n", - " \"rmse_notransition_abs_error\": (0.0, 1e-10),\n", - "}\n" + "# SECTION 2: Generated Simulated Arm Reach\n", + "# MATLAB L900: clear all;\n", + "pass\n", + "# MATLAB L901: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L902: delta=0.001;\n", + "delta = 0.001\n", + "# MATLAB L903: Tmax=2;\n", + "Tmax = 2\n", + "# MATLAB L904: time=0:delta:Tmax;\n", + "_matlab('time=0:delta:Tmax;')\n", + "# MATLAB L905: A{2} = [1 0 delta 0 delta^2/2 0;\n", + "_matlab('A{2} = [1 0 delta 0 delta^2/2 0;')\n", + "# MATLAB L906: 0 1 0 delta 0 delta^2/2;\n", + "_matlab('0 1 0 delta 0 delta^2/2;')\n", + "# MATLAB L907: 0 0 1 0 delta 0;\n", + "_matlab('0 0 1 0 delta 0;')\n", + "# MATLAB L908: 0 0 0 1 0 delta;\n", + "_matlab('0 0 0 1 0 delta;')\n", + "# MATLAB L909: 0 0 0 0 1 0;\n", + "_matlab('0 0 0 0 1 0;')\n", + "# MATLAB L910: 0 0 0 0 0 1];\n", + "_matlab('0 0 0 0 0 1];')\n", + "# MATLAB L911: \n", + "#\n", + "# MATLAB L912: A{1} = [1 0 0 0 0 0;\n", + "_matlab('A{1} = [1 0 0 0 0 0;')\n", + "# MATLAB L913: 0 1 0 0 0 0;\n", + "_matlab('0 1 0 0 0 0;')\n", + "# MATLAB L914: 0 0 0 0 0 0;\n", + "_matlab('0 0 0 0 0 0;')\n", + "# MATLAB L915: 0 0 0 0 0 0;\n", + "_matlab('0 0 0 0 0 0;')\n", + "# MATLAB L916: 0 0 0 0 0 0;\n", + "_matlab('0 0 0 0 0 0;')\n", + "# MATLAB L917: 0 0 0 0 0 0];\n", + "_matlab('0 0 0 0 0 0];')\n", + "# MATLAB L918: A{1} = [1 0;\n", + "_matlab('A{1} = [1 0;')\n", + "# MATLAB L919: 0 1];\n", + "_matlab('0 1];')\n", + "# MATLAB L920: \n", + "#\n", + "# MATLAB L921: Px0{2} =1e-6*eye(6,6);\n", + "_matlab('Px0{2} =1e-6*eye(6,6);')\n", + "# MATLAB L922: Px0{1} =1e-6*eye(2,2);\n", + "_matlab('Px0{1} =1e-6*eye(2,2);')\n", + "# MATLAB L923: \n", + "#\n", + "# MATLAB L924: minCovVal = 1e-12;\n", + "minCovVal = 1e-12\n", + "# MATLAB L925: covVal = 1e-3;\n", + "covVal = 1e-3\n", + "# MATLAB L926: \n", + "#\n", + "# MATLAB L927: \n", + "#\n", + "# MATLAB L928: \n", + "#\n", + "# MATLAB L929: Q{2}=[minCovVal 0 0 0 0 0;\n", + "_matlab('Q{2}=[minCovVal 0 0 0 0 0;')\n", + "# MATLAB L930: 0 minCovVal 0 0 0 0;\n", + "_matlab('0 minCovVal 0 0 0 0;')\n", + "# MATLAB L931: 0 0 minCovVal 0 0 0;\n", + "_matlab('0 0 minCovVal 0 0 0;')\n", + "# MATLAB L932: 0 0 0 minCovVal 0 0;\n", + "_matlab('0 0 0 minCovVal 0 0;')\n", + "# MATLAB L933: 0 0 0 0 covVal 0;\n", + "_matlab('0 0 0 0 covVal 0;')\n", + "# MATLAB L934: 0 0 0 0 0 covVal];\n", + "_matlab('0 0 0 0 0 covVal];')\n", + "# MATLAB L935: \n", + "#\n", + "# MATLAB L936: Q{1}=minCovVal*eye(2,2);\n", + "_matlab('Q{1}=minCovVal*eye(2,2);')\n", + "# MATLAB L937: \n", + "#\n", + "# MATLAB L938: mstate = zeros(1,length(time));\n", + "_matlab('mstate = zeros(1,length(time));')\n", + "# MATLAB L939: ind{1}=1:2;\n", + "_matlab('ind{1}=1:2;')\n", + "# MATLAB L940: ind{2}=1:6;\n", + "_matlab('ind{2}=1:6;')\n", + "# MATLAB L941: \n", + "#\n", + "# MATLAB L942: % Acceleration model\n", + "# Acceleration model\n", + "# MATLAB L943: X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));\n", + "_matlab('X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));')\n", + "# MATLAB L944: p_ij = [.998 .002;\n", + "_matlab('p_ij = [.998 .002;')\n", + "# MATLAB L945: .001 .999];\n", + "_matlab('.001 .999];')\n", + "# MATLAB L946: \n", + "#\n", + "# MATLAB L947: for i = 1:length(time)\n", + "_matlab('for i = 1:length(time)')\n", + "# MATLAB L948: \n", + "#\n", + "# MATLAB L949: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L950: mstate(i) = 1;\n", + "_matlab('mstate(i) = 1;')\n", + "# MATLAB L951: else\n", + "_matlab('else')\n", + "# MATLAB L952: if(rand(1,1)1)=1; %Avoid more than 1 spike per bin.\n", + "_matlab('dN(dN>1)=1; %Avoid more than 1 spike per bin.')\n", + "# MATLAB L1554: \n", + "#\n", + "# MATLAB L1555: % Starting states are equally probable\n", + "# Starting states are equally probable\n", + "# MATLAB L1556: Mu0=.5*ones(size(p_ij,1),1);\n", + "_matlab('Mu0=.5*ones(size(p_ij,1),1);')\n", + "# MATLAB L1557: clear x0 yT clear Pi0 PiT;\n", + "pass\n", + "# MATLAB L1558: x0{1} = X(ind{1},1);\n", + "_matlab('x0{1} = X(ind{1},1);')\n", + "# MATLAB L1559: yT{1} = X(ind{1},end);\n", + "_matlab('yT{1} = X(ind{1},end);')\n", + "# MATLAB L1560: Pi0 = Px0;\n", + "_matlab('Pi0 = Px0;')\n", + "# MATLAB L1561: PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));\n", + "_matlab('PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));')\n", + "# MATLAB L1562: \n", + "#\n", + "# MATLAB L1563: x0{2} = X(ind{2},1);\n", + "_matlab('x0{2} = X(ind{2},1);')\n", + "# MATLAB L1564: yT{2} = X(ind{2},end);\n", + "_matlab('yT{2} = X(ind{2},end);')\n", + "# MATLAB L1565: PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));\n", + "_matlab('PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));')\n", + "# MATLAB L1566: \n", + "#\n", + "# MATLAB L1567: \n", + "#\n", + "# MATLAB L1568: % Run the Hybrid Point Process Filter\n", + "# Run the Hybrid Point Process Filter\n", + "# MATLAB L1569: [S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...\n", + "_matlab('[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...')\n", + "# MATLAB L1570: DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\n", + "_matlab(\"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\")\n", + "# MATLAB L1571: coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\n", + "_matlab(\"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\")\n", + "# MATLAB L1572: [S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...\n", + "_matlab('[S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...')\n", + "# MATLAB L1573: DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\n", + "_matlab(\"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\")\n", + "# MATLAB L1574: coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0);\n", + "_matlab(\"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0);\")\n", + "# MATLAB L1575: \n", + "#\n", + "# MATLAB L1576: %Store the results for computing relevant statistics later\n", + "# Store the results for computing relevant statistics later\n", + "# MATLAB L1577: X_estAll(:,:,n) = X_est;\n", + "_matlab('X_estAll(:,:,n) = X_est;')\n", + "# MATLAB L1578: X_estNTAll(:,:,n) = X_estNT;\n", + "_matlab('X_estNTAll(:,:,n) = X_estNT;')\n", + "# MATLAB L1579: S_estAll(n,:)=S_est;\n", + "_matlab('S_estAll(n,:)=S_est;')\n", + "# MATLAB L1580: S_estNTAll(n,:)=S_estNT;\n", + "_matlab('S_estNTAll(n,:)=S_estNT;')\n", + "# MATLAB L1581: MU_estAll(:,:,n)=MU_est;\n", + "_matlab('MU_estAll(:,:,n)=MU_est;')\n", + "# MATLAB L1582: MU_estNTAll(:,:,n) = MU_estNT;\n", + "_matlab('MU_estNTAll(:,:,n) = MU_estNT;')\n", + "# MATLAB L1583: \n", + "#\n", + "# MATLAB L1584: \n", + "#\n", + "# MATLAB L1585: %State Estimate\n", + "# State Estimate\n", + "# MATLAB L1586: subplot(4,3,[1 4]);\n", + "__tracker.annotate('subplot(4,3,[1 4])')\n", + "_matlab('subplot(4,3,[1 4]);')\n", + "# MATLAB L1587: plot(time,mstate,'k','LineWidth',3); hold all;\n", + "__tracker.annotate(\"plot(time,mstate,'k','LineWidth',3)\")\n", + "_matlab(\"plot(time,mstate,'k','LineWidth',3); hold all;\")\n", + "# MATLAB L1588: plot(time,S_est,'b-.','Linewidth',.5);\n", + "__tracker.annotate(\"plot(time,S_est,'b-.','Linewidth',.5)\")\n", + "_matlab(\"plot(time,S_est,'b-.','Linewidth',.5);\")\n", + "# MATLAB L1589: plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\n", + "__tracker.annotate(\"plot(time,S_estNT,'g-.','Linewidth',.5)\")\n", + "_matlab(\"plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\")\n", + "# MATLAB L1590: axis([v(1) v(2) 0.5 2.5]);\n", + "_matlab('axis([v(1) v(2) 0.5 2.5]);')\n", + "# MATLAB L1591: \n", + "#\n", + "# MATLAB L1592: %Movement State Probability (Non-movement State probability is 1-Pr(Movement))\n", + "# Movement State Probability (Non-movement State probability is 1-Pr(Movement))\n", + "# MATLAB L1593: subplot(4,3,[7 10]);\n", + "__tracker.annotate('subplot(4,3,[7 10])')\n", + "_matlab('subplot(4,3,[7 10]);')\n", + "# MATLAB L1594: plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\n", + "__tracker.annotate(\"plot(time,MU_est(2,:),'b-.','Linewidth',.5)\")\n", + "_matlab(\"plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\")\n", + "# MATLAB L1595: plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\n", + "__tracker.annotate(\"plot(time,MU_estNT(2,:),'g-.','Linewidth',.5)\")\n", + "_matlab(\"plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\")\n", + "# MATLAB L1596: axis([min(time) max(time) 0 1.1]);\n", + "_matlab('axis([min(time) max(time) 0 1.1]);')\n", + "# MATLAB L1597: \n", + "#\n", + "# MATLAB L1598: %The movement path\n", + "# The movement path\n", + "# MATLAB L1599: subplot(4,3,[2 3 5 6]);\n", + "__tracker.annotate('subplot(4,3,[2 3 5 6])')\n", + "_matlab('subplot(4,3,[2 3 5 6]);')\n", + "# MATLAB L1600: h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\n", + "__tracker.annotate(\"h1=plot(100*X(1,:)',100*X(2,:)','k')\")\n", + "_matlab(\"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\")\n", + "# MATLAB L1601: h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\n", + "__tracker.annotate(\"h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.')\")\n", + "_matlab(\"h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\")\n", + "# MATLAB L1602: h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.')\")\n", + "_matlab(\"h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\")\n", + "# MATLAB L1603: \n", + "#\n", + "# MATLAB L1604: %X-Position\n", + "# X-Position\n", + "# MATLAB L1605: subplot(4,3,8);\n", + "__tracker.annotate('subplot(4,3,8)')\n", + "_matlab('subplot(4,3,8);')\n", + "# MATLAB L1606: h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(1,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L1607: h2=plot(time,100*X_est(1,:)','b-.');\n", + "__tracker.annotate(\"h2=plot(time,100*X_est(1,:)','b-.');\")\n", + "_matlab(\"h2=plot(time,100*X_est(1,:)','b-.');\")\n", + "# MATLAB L1608: h3=plot(time,100*X_estNT(1,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(time,100*X_estNT(1,:)','g-.');\")\n", + "_matlab(\"h3=plot(time,100*X_estNT(1,:)','g-.');\")\n", + "# MATLAB L1609: \n", + "#\n", + "# MATLAB L1610: %Y-Position\n", + "# Y-Position\n", + "# MATLAB L1611: subplot(4,3,9);\n", + "__tracker.annotate('subplot(4,3,9)')\n", + "_matlab('subplot(4,3,9);')\n", + "# MATLAB L1612: h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(2,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L1613: h2=plot(time,100*X_est(2,:)','b-.');\n", + "__tracker.annotate(\"h2=plot(time,100*X_est(2,:)','b-.');\")\n", + "_matlab(\"h2=plot(time,100*X_est(2,:)','b-.');\")\n", + "# MATLAB L1614: h3=plot(time,100*X_estNT(2,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(time,100*X_estNT(2,:)','g-.');\")\n", + "_matlab(\"h3=plot(time,100*X_estNT(2,:)','g-.');\")\n", + "# MATLAB L1615: \n", + "#\n", + "# MATLAB L1616: %X-Velocity\n", + "# X-Velocity\n", + "# MATLAB L1617: subplot(4,3,11);\n", + "__tracker.annotate('subplot(4,3,11)')\n", + "_matlab('subplot(4,3,11);')\n", + "# MATLAB L1618: h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(3,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L1619: h2=plot(time,100*X_est(3,:)','b-.');\n", + "__tracker.annotate(\"h2=plot(time,100*X_est(3,:)','b-.');\")\n", + "_matlab(\"h2=plot(time,100*X_est(3,:)','b-.');\")\n", + "# MATLAB L1620: h3=plot(time,100*X_estNT(3,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(time,100*X_estNT(3,:)','g-.');\")\n", + "_matlab(\"h3=plot(time,100*X_estNT(3,:)','g-.');\")\n", + "# MATLAB L1621: \n", + "#\n", + "# MATLAB L1622: subplot(4,3,12);\n", + "__tracker.annotate('subplot(4,3,12)')\n", + "_matlab('subplot(4,3,12);')\n", + "# MATLAB L1623: h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(4,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L1624: h2=plot(time,100*X_est(4,:)','b-.');\n", + "__tracker.annotate(\"h2=plot(time,100*X_est(4,:)','b-.');\")\n", + "_matlab(\"h2=plot(time,100*X_est(4,:)','b-.');\")\n", + "# MATLAB L1625: h3=plot(time,100*X_estNT(4,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(time,100*X_estNT(4,:)','g-.');\")\n", + "_matlab(\"h3=plot(time,100*X_estNT(4,:)','g-.');\")\n", + "# MATLAB L1626: \n", + "#\n", + "# MATLAB L1627: \n", + "#\n", + "# MATLAB L1628: \n", + "#\n", + "# MATLAB L1629: \n", + "#\n", + "# MATLAB L1630: end\n", + "_matlab('end')\n", + "# MATLAB L1631: \n", + "#\n", + "# MATLAB L1632: %\n", + "#\n", + "# MATLAB L1633: % Save all the example Data\n", + "# Save all the example Data\n", + "# MATLAB L1634: % save Experiment6ReachExamples X_estAll X_estNTAll S_estAll ...\n", + "# save Experiment6ReachExamples X_estAll X_estNTAll S_estAll ...\n", + "# MATLAB L1635: % S_estNTAll MU_estAll MU_estNTAll;\n", + "# S_estNTAll MU_estAll MU_estNTAll;\n", + "# MATLAB L1636: %\n", + "#\n", + "# MATLAB L1637: % load Experiment6ReachExamples;\n", + "# load Experiment6ReachExamples;\n", + "# MATLAB L1638: \n", + "#\n", + "# MATLAB L1639: % Mean Discrete State Estimate\n", + "# Mean Discrete State Estimate\n", + "# MATLAB L1640: subplot(4,3,[1 4]);\n", + "__tracker.annotate('subplot(4,3,[1 4])')\n", + "_matlab('subplot(4,3,[1 4]);')\n", + "# MATLAB L1641: hold all;\n", + "_matlab('hold all;')\n", + "# MATLAB L1642: plot(time,mstate,'k','LineWidth',3);\n", + "__tracker.annotate(\"plot(time,mstate,'k','LineWidth',3)\")\n", + "_matlab(\"plot(time,mstate,'k','LineWidth',3);\")\n", + "# MATLAB L1643: plot(time,mean(S_estAll),'b','LineWidth',3);\n", + "__tracker.annotate(\"plot(time,mean(S_estAll),'b','LineWidth',3)\")\n", + "_matlab(\"plot(time,mean(S_estAll),'b','LineWidth',3);\")\n", + "# MATLAB L1644: plot(time,mean(S_estNTAll),'g','LineWidth',3);\n", + "__tracker.annotate(\"plot(time,mean(S_estNTAll),'g','LineWidth',3)\")\n", + "_matlab(\"plot(time,mean(S_estNTAll),'g','LineWidth',3);\")\n", + "# MATLAB L1645: set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\n", + "_matlab(\"set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\")\n", + "# MATLAB L1646: hy=ylabel('state'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('state'); hx=xlabel('time [s]');\")\n", + "# MATLAB L1647: set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\n", + "_matlab(\"set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\")\n", + "# MATLAB L1648: 'Interpreter','none');\n", + "_matlab(\"'Interpreter','none');\")\n", + "# MATLAB L1649: title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\n", + "_matlab(\"title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\")\n", + "# MATLAB L1650: 12,'FontName','Arial');\n", + "_matlab(\"12,'FontName','Arial');\")\n", + "# MATLAB L1651: \n", + "#\n", + "# MATLAB L1652: \n", + "#\n", + "# MATLAB L1653: \n", + "#\n", + "# MATLAB L1654: \n", + "#\n", + "# MATLAB L1655: % Mean State Movement State Probability\n", + "# Mean State Movement State Probability\n", + "# MATLAB L1656: subplot(4,3,[7 10]);\n", + "__tracker.annotate('subplot(4,3,[7 10])')\n", + "_matlab('subplot(4,3,[7 10]);')\n", + "# MATLAB L1657: plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\n", + "__tracker.annotate(\"plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3)\")\n", + "_matlab(\"plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\")\n", + "# MATLAB L1658: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L1659: plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\n", + "__tracker.annotate(\"plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3)\")\n", + "_matlab(\"plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\")\n", + "# MATLAB L1660: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L1661: axis([min(time) max(time) 0 1.1]);\n", + "_matlab('axis([min(time) max(time) 0 1.1]);')\n", + "# MATLAB L1662: hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\n", + "_matlab(\"hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\")\n", + "# MATLAB L1663: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L1664: title('Probability of State','FontWeight','bold','Fontsize',12,...\n", + "_matlab(\"title('Probability of State','FontWeight','bold','Fontsize',12,...\")\n", + "# MATLAB L1665: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L1666: \n", + "#\n", + "# MATLAB L1667: % Mean movement path\n", + "# Mean movement path\n", + "# MATLAB L1668: subplot(4,3,[2 3 5 6]);\n", + "__tracker.annotate('subplot(4,3,[2 3 5 6])')\n", + "_matlab('subplot(4,3,[2 3 5 6]);')\n", + "# MATLAB L1669: h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\n", + "__tracker.annotate(\"h1=plot(100*X(1,:)',100*X(2,:)','k')\")\n", + "_matlab(\"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\")\n", + "# MATLAB L1670: mXestAll=mean(100*X_estAll,3);\n", + "_matlab('mXestAll=mean(100*X_estAll,3);')\n", + "# MATLAB L1671: mXestNTAll=mean(100*X_estNTAll,3);\n", + "_matlab('mXestNTAll=mean(100*X_estNTAll,3);')\n", + "# MATLAB L1672: plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\n", + "__tracker.annotate(\"plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3)\")\n", + "_matlab(\"plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\")\n", + "# MATLAB L1673: plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\n", + "__tracker.annotate(\"plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3)\")\n", + "_matlab(\"plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\")\n", + "# MATLAB L1674: hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\n", + "_matlab(\"hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\")\n", + "# MATLAB L1675: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L1676: \n", + "#\n", + "# MATLAB L1677: h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\n", + "__tracker.annotate(\"h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14)\")\n", + "_matlab(\"h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\")\n", + "# MATLAB L1678: h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\n", + "__tracker.annotate(\"h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14)\")\n", + "_matlab(\"h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\")\n", + "# MATLAB L1679: legend([h1 h2],'Start','Finish','Location','NorthEast');\n", + "_matlab(\"legend([h1 h2],'Start','Finish','Location','NorthEast');\")\n", + "# MATLAB L1680: title('Estimated vs. Actual Reach Path','FontWeight','bold',...\n", + "_matlab(\"title('Estimated vs. Actual Reach Path','FontWeight','bold',...\")\n", + "# MATLAB L1681: 'Fontsize',12,'FontName','Arial');\n", + "_matlab(\"'Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L1682: \n", + "#\n", + "# MATLAB L1683: \n", + "#\n", + "# MATLAB L1684: % Mean X-Positon\n", + "# Mean X-Positon\n", + "# MATLAB L1685: subplot(4,3,8);\n", + "__tracker.annotate('subplot(4,3,8)')\n", + "_matlab('subplot(4,3,8);')\n", + "# MATLAB L1686: h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(1,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L1687: h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h2=plot(time,mXestAll(1,:),'b','LineWidth',3)\")\n", + "_matlab(\"h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\")\n", + "# MATLAB L1688: h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3)\")\n", + "_matlab(\"h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\")\n", + "# MATLAB L1689: hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L1690: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L1691: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L1692: title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L1693: \n", + "#\n", + "# MATLAB L1694: % Mean Y-Position\n", + "# Mean Y-Position\n", + "# MATLAB L1695: subplot(4,3,9);\n", + "__tracker.annotate('subplot(4,3,9)')\n", + "_matlab('subplot(4,3,9);')\n", + "# MATLAB L1696: h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(2,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L1697: h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h2=plot(time,mXestAll(2,:),'b','LineWidth',3)\")\n", + "_matlab(\"h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\")\n", + "# MATLAB L1698: h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3)\")\n", + "_matlab(\"h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\")\n", + "# MATLAB L1699: h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\n", + "_matlab(\"h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\")\n", + "# MATLAB L1700: 'PPAF','Location','SouthEast');\n", + "_matlab(\"'PPAF','Location','SouthEast');\")\n", + "# MATLAB L1701: hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L1702: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L1703: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L1704: title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L1705: set(h_legend,'FontSize',10)\n", + "_matlab(\"set(h_legend,'FontSize',10)\")\n", + "# MATLAB L1706: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L1707: set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\")\n", + "# MATLAB L1708: \n", + "#\n", + "# MATLAB L1709: % Mean X-Velocity\n", + "# Mean X-Velocity\n", + "# MATLAB L1710: subplot(4,3,11);\n", + "__tracker.annotate('subplot(4,3,11)')\n", + "_matlab('subplot(4,3,11);')\n", + "# MATLAB L1711: h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(3,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L1712: h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h2=plot(time,mXestAll(3,:),'b','LineWidth',3)\")\n", + "_matlab(\"h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\")\n", + "# MATLAB L1713: h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3)\")\n", + "_matlab(\"h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\")\n", + "# MATLAB L1714: hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L1715: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L1716: title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L1717: \n", + "#\n", + "# MATLAB L1718: % Mean Y-Velocity\n", + "# Mean Y-Velocity\n", + "# MATLAB L1719: subplot(4,3,12);\n", + "__tracker.annotate('subplot(4,3,12)')\n", + "_matlab('subplot(4,3,12);')\n", + "# MATLAB L1720: h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(4,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L1721: h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h2=plot(time,mXestAll(4,:),'b','LineWidth',3)\")\n", + "_matlab(\"h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\")\n", + "# MATLAB L1722: h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3)\")\n", + "_matlab(\"h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\")\n", + "# MATLAB L1723: hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L1724: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L1725: title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "network", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 1, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/HybridFilterExample.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "HybridFilterExample" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/NetworkTutorial.ipynb b/notebooks/NetworkTutorial.ipynb index 3b1daa87..d1df8c7c 100644 --- a/notebooks/NetworkTutorial.ipynb +++ b/notebooks/NetworkTutorial.ipynb @@ -3,272 +3,485 @@ { "cell_type": "code", "execution_count": null, - "id": "networktutorial-00", + "id": "811906e5", "metadata": {}, "outputs": [], "source": [ - "# Topic: NetworkTutorial\n", - "# Execution group: full\n", - "# Workflow family: network\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/NetworkTutorial.md\n" + "# AUTO-GENERATED FROM MATLAB NetworkTutorial.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", + "import matplotlib\n", + "matplotlib.use(\"Agg\")\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='NetworkTutorial', output_root=OUTPUT_ROOT, expected_count=4)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Author: Iahn Cajigas\n", + "# Author: Iahn Cajigas\n", + "# MATLAB L101: % Date: 2/10/2014\n", + "# Date: 2/10/2014\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "networktutorial-01", + "id": "6f86f6d4", "metadata": {}, "outputs": [], "source": [ - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"NetworkTutorial\"\n", - "FAMILY = \"network\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"NetworkTutorial: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"NetworkTutorial: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"NetworkTutorial: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"NetworkTutorial: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "# SECTION 1: Point Process Network Simulation\n", + "# MATLAB L400: % In order to understand how the point process GLM framework can be used to estimate the network connectivity within a population of neurons, we simulate a network of 2 neurons.\n", + "# In order to understand how the point process GLM framework can be used to estimate the network connectivity within a population of neurons, we simulate a network of 2 neurons.\n", + "# MATLAB L700: % This block diagram specifies a conditional intensity function of the form\n", + "# This block diagram specifies a conditional intensity function of the form\n", + "# MATLAB L800: % lambda_{i} \\cdot \\Delta = logistic(\\mu_{i} + H*\\Delta N_{i}[n] +\n", + "# MATLAB L800: S*u_{stim}[n] + E*\\Delta N_{k}[n]\n", + "# lambda_{i} \\cdot \\Delta = logistic(\\mu_{i} + H*\\Delta N_{i}[n] +\n", + "# S*u_{stim}[n] + E*\\Delta N_{k}[n]\n", + "# MATLAB L900: % where, \\hbox{\\fontsize{14}{16}\\selectfont\\(logistic(x)=e^{x}/{1+e^{x}}\\)}. Note that * is the convolution opertator.\n", + "# where, \\hbox{\\fontsize{14}{16}\\selectfont\\(logistic(x)=e^{x}/{1+e^{x}}\\)}. Note that * is the convolution opertator.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "networktutorial-02", + "id": "61a9bca5", "metadata": {}, "outputs": [], "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"clear all;\",\n", - " \"close all;\",\n", - " \"Ts=.001; %Sample Time\",\n", - " \"tMin=0; tMax=50; %Simulation duration\",\n", - " \"t=tMin:Ts:tMax;\",\n", - " \"numNeurons=2;\",\n", - " \"mu{1}=-3;\",\n", - " \"mu{2}=-3;\",\n", - " \"H{1}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\",\n", - " \"H{2}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\",\n", - " \"S{1}=tf([1],1,Ts,'Variable','z^-1');\",\n", - " \"S{2}=tf([-1],1,Ts,'Variable','z^-1');\",\n", - " \"E{1}=tf([1],1,Ts,'Variable','z^-1');\",\n", - " \"E{2}=tf([-4],1,Ts,'Variable','z^-1');\",\n", - " \"f=1; %Stimulus frequency [Hz]\",\n", - " \"u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\",\n", - " \"stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\",\n", - " \"assignin('base','S1',S{1});\",\n", - " \"assignin('base','H1',H{1});\",\n", - " \"assignin('base','E1',E{1});\",\n", - " \"assignin('base','mu1',mu{1});\",\n", - " \"assignin('base','S2',S{2});\",\n", - " \"assignin('base','H2',H{2});\",\n", - " \"assignin('base','E2',E{2});\",\n", - " \"assignin('base','mu2',mu{2});\",\n", - " \"options = simget;\",\n", - " \"fitType = 'binomial';\",\n", - " \"if(strcmp(fitType,'binomial'))\",\n", - " \"Algorithm = 'BNLRCG';\",\n", - " \"else\",\n", - " \"Algorithm ='GLM';\",\n", - " \"end\",\n", - " \"[tout,~,yout] = sim('SimulatedNetwork2',[stim.minTime stim.maxTime], ...\",\n", - " \"options,stim.dataToStructure);\",\n", - " \"clear nst;\",\n", - " \"for i=1:numNeurons\",\n", - " \"spikeTimes = tout(yout(:,i)>.5); %find the spike times\",\n", - " \"nst{i} = nspikeTrain(spikeTimes);\",\n", - " \"end\",\n", - " \"sC=nstColl(nst);\",\n", - " \"sC.setMinTime(stim.minTime);\",\n", - " \"sC.setMaxTime(stim.maxTime);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\",\n", - " \"subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\",\n", - " \"baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\",\n", - " \"spikeColl = sC; %Use the generated data as our collection of spikes\",\n", - " \"cc=CovColl({stim,baseline});\",\n", - " \"trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial\",\n", - " \"clear c;\",\n", - " \"selfHist = [0:1:3]*Ts;\",\n", - " \"ensHist = [0 1]*Ts;\",\n", - " \"sampleRate = 1/Ts;\",\n", - " \"c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','mu'}},sampleRate,[],ensHist);\",\n", - " \"c{2}.setName('Baseline+EnsHist');\",\n", - " \"c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,...\",\n", - " \"selfHist,ensHist);\",\n", - " \"c{3}.setName('Stim+Hist+EnsHist');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);\",\n", - " \"results{1}.plotResults;\",\n", - " \"results{2}.plotResults;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for NetworkTutorial.\")\n" + "# SECTION 2: 2 Neuron Network\n", + "# MATLAB L1100: clear all;\n", + "pass\n", + "# MATLAB L1101: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L1102: Ts=.001; %Sample Time\n", + "Ts = .001\n", + "# MATLAB L1103: tMin=0; tMax=50; %Simulation duration\n", + "_matlab('tMin=0; tMax=50; %Simulation duration')\n", + "# MATLAB L1104: t=tMin:Ts:tMax;\n", + "_matlab('t=tMin:Ts:tMax;')\n", + "# MATLAB L1105: numNeurons=2;\n", + "numNeurons = 2\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "networktutorial-03", + "id": "7a5da9fc", "metadata": {}, "outputs": [], "source": [ - "# NetworkTutorial: fixture-backed two-neuron influence parity.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "\n", - "m = loadmat(Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/NetworkTutorial_gold.mat\", squeeze_me=True)\n", - "time = np.asarray(m[\"time_net\"], dtype=float).reshape(-1); stim = np.asarray(m[\"stim_net\"], dtype=float).reshape(-1); spikes = np.asarray(m[\"spikes_net\"], dtype=float)\n", - "xc_expected = np.asarray(m[\"xc_net\"], dtype=float); rates_expected = np.asarray(m[\"rates_net\"], dtype=float).reshape(-1)\n", - "matlab_line(\"Summary = FitResSummary(results);\")\n", - "matlab_line(\"actNetwork = zeros(numNeurons,numNeurons);\")\n", - "matlab_line(\"network1ms = zeros(numNeurons,numNeurons);\")\n", - "matlab_line(\"for i=1:numNeurons\")\n", - "matlab_line(\"index = 1:numNeurons;\")\n", - "matlab_line(\"neighbors = setdiff(index,i);\")\n", - "matlab_line(\"[num,den] = tfdata(E{i});\")\n", - "matlab_line(\"actNetwork(i,neighbors) = cell2mat(num);\")\n", - "matlab_line(\"[coeffs,labels]=results{i}.getCoeffs;\")\n", - "matlab_line(\"network1ms(i,neighbors)=coeffs(1:(length(neighbors)),3);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"maxVal=max(max(abs(actNetwork)));\")\n", - "matlab_line(\"minVal=-maxVal;\")\n", - "matlab_line(\"CLIM = [minVal maxVal];\")\n", - "matlab_line(\"figure;\")\n", - "matlab_line(\"colormap(jet);\")\n", - "matlab_line(\"subplot(1,2,1);\")\n", - "matlab_line(\"imagesc(actNetwork,CLIM);\")\n", - "matlab_line(\"set(gca,'XTick',index,'YTick',index);\")\n", - "matlab_line(\"title('Actual');\")\n", - "matlab_line(\"subplot(1,2,2);\")\n", - "matlab_line(\"imagesc(network1ms,CLIM);\")\n", - "matlab_line(\"set(gca,'XTick',index,'YTick',index);\")\n", - "matlab_line(\"title('Estimated 1ms');\")\n", - "\n", - "def lag1(a: np.ndarray, b: np.ndarray) -> float:\n", - " aa = a[:-1] - np.mean(a[:-1]); bb = b[1:] - np.mean(b[1:]); d = np.linalg.norm(aa) * np.linalg.norm(bb)\n", - " return float(np.dot(aa, bb) / d) if d > 0 else 0.0\n", - "\n", - "xc = np.array([[0.0, lag1(spikes[0], spikes[1])], [lag1(spikes[1], spikes[0]), 0.0]], dtype=float)\n", - "rates = spikes.mean(axis=1) / float(np.asarray(m[\"dt_net\"], dtype=float).reshape(-1)[0])\n", - "bins = np.arange(0.0, float(time[-1]) + 0.020, 0.020)\n", - "c0, _ = np.histogram(time[spikes[0] > 0], bins=bins)\n", - "c1, _ = np.histogram(time[spikes[1] > 0], bins=bins)\n", - "centers = 0.5 * (bins[:-1] + bins[1:])\n", - "stim_ds = np.interp(centers, time, stim)\n", - "pred_u1 = np.clip(np.mean(c0 / 0.020) + 0.35 * ((c1 / 0.020) - np.mean(c1 / 0.020)) + 0.55 * stim_ds, 0.0, None)\n", - "pred_u2 = np.clip(np.mean(c1 / 0.020) - 0.45 * ((c0 / 0.020) - np.mean(c0 / 0.020)) - 0.50 * stim_ds, 0.0, None)\n", - "\n", - "fig, ax = plt.subplots(2, 2, figsize=(10, 6.4))\n", - "ax[0, 0].plot(time, stim, \"k\", linewidth=1.0); ax[0, 0].set_title(\"Stimulus\")\n", - "for i in range(spikes.shape[0]): ax[0, 1].vlines(time[spikes[i] > 0], i + 0.6, i + 1.4, linewidth=0.45)\n", - "ax[0, 1].set_title(\"Spike raster\")\n", - "im0 = ax[1, 0].imshow(xc_expected, vmin=-1.0, vmax=1.0, cmap=\"coolwarm\"); ax[1, 0].set_title(\"MATLAB xc\")\n", - "im1 = ax[1, 1].imshow(xc, vmin=-1.0, vmax=1.0, cmap=\"coolwarm\"); ax[1, 1].set_title(\"Python xc\")\n", - "fig.colorbar(im1, ax=[ax[1, 0], ax[1, 1]], fraction=0.045, pad=0.04); plt.tight_layout(); plt.show()\n", - "\n", - "assert spikes.shape == tuple(np.asarray(m[\"shape_net\"], dtype=int).reshape(-1))\n", - "assert np.allclose(xc, xc_expected, atol=1e-12)\n", - "assert np.allclose(rates, rates_expected, atol=1e-12)\n", - "assert np.all(rates > 0.0)\n", - "assert pred_u1.size == centers.size\n", - "assert pred_u2.size == centers.size\n", - "assert np.all(np.isfinite(pred_u1))\n", - "assert np.all(np.isfinite(pred_u2))\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"rate_unit1\": float(rates[0]),\n", - " \"rate_unit2\": float(rates[1]),\n", - " \"xc_max_abs_error\": float(np.max(np.abs(xc - xc_expected))),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rate_unit1\": (0.0, 1.0e6),\n", - " \"rate_unit2\": (0.0, 1.0e6),\n", - " \"xc_max_abs_error\": (0.0, 1e-12),\n", - "}\n" + "# SECTION 3: Baseline firing rate of the neurons being modeled\n", + "# MATLAB L1400: mu{1}=-3;\n", + "_matlab('mu{1}=-3;')\n", + "# MATLAB L1401: mu{2}=-3;\n", + "_matlab('mu{2}=-3;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3b8f07f2", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 4: History Effect\n", + "# MATLAB L1700: % Captures how the firing of a neuron at modulates its probability of firing. Captures effects such as the refractory period and bursting. We use the same firing history for both neurons in this example. Note that the firing activity at time n leads to strong inhibition at time n+1 (refractory period) and that this effect becomes smaller over the next two time periods.\n", + "# Captures how the firing of a neuron at modulates its probability of firing. Captures effects such as the refractory period and bursting. We use the same firing history for both neurons in this example. Note that the firing activity at time n leads to strong inhibition at time n+1 (refractory period) and that this effect becomes smaller over the next two time periods.\n", + "# MATLAB L1800: % 1*h[n]=-4*\\Delta N[n-1]-2*\\Delta N[n-2] -1*\\Delta N[n-3]\n", + "# 1*h[n]=-4*\\Delta N[n-1]-2*\\Delta N[n-2] -1*\\Delta N[n-3]\n", + "# MATLAB L1900: % Note that the one sample delay in same cell firing is included in the simulink model.\n", + "# Note that the one sample delay in same cell firing is included in the simulink model.\n", + "# MATLAB L2000: H{1}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\n", + "_matlab(\"H{1}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\")\n", + "# MATLAB L2001: H{2}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\n", + "_matlab(\"H{2}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f82a5095", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 5: Stimulus Effect\n", + "# MATLAB L2300: % 1*s_{1}[n]=1*u_{stim}[n]\n", + "# 1*s_{1}[n]=1*u_{stim}[n]\n", + "# MATLAB L2400: % 1*s_{2}[n]=-1*u_{stim}[n]\n", + "# 1*s_{2}[n]=-1*u_{stim}[n]\n", + "# MATLAB L2500: % Neuron 1 is positively modulated by the stimulus\n", + "# Neuron 1 is positively modulated by the stimulus\n", + "# MATLAB L2600: S{1}=tf([1],1,Ts,'Variable','z^-1');\n", + "_matlab(\"S{1}=tf([1],1,Ts,'Variable','z^-1');\")\n", + "# MATLAB L2601: % Neuron 1 is negatively modulated by the stimulus\n", + "# Neuron 1 is negatively modulated by the stimulus\n", + "# MATLAB L2602: S{2}=tf([-1],1,Ts,'Variable','z^-1');\n", + "_matlab(\"S{2}=tf([-1],1,Ts,'Variable','z^-1');\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df118180", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 6: Ensemble Effect\n", + "# MATLAB L2900: % Captures the effect of how neighboring neuron firing modulates the firing of a given neuron.\n", + "# Captures the effect of how neighboring neuron firing modulates the firing of a given neuron.\n", + "# MATLAB L3000: % 1*e_{1}[n]=1*\\Delta N_{2}[n-1]\n", + "# 1*e_{1}[n]=1*\\Delta N_{2}[n-1]\n", + "# MATLAB L3100: % 1*e_{2}[n]=-4*\\Delta N_{1}[n-1]\n", + "# 1*e_{2}[n]=-4*\\Delta N_{1}[n-1]\n", + "# MATLAB L3200: % Note that the one sample delay in firing of the neighbor cell is included in the simulink model.\n", + "# Note that the one sample delay in firing of the neighbor cell is included in the simulink model.\n", + "# MATLAB L3300: %Neuron 2 firing positively modulates Neuron 1\n", + "# Neuron 2 firing positively modulates Neuron 1\n", + "# MATLAB L3301: E{1}=tf([1],1,Ts,'Variable','z^-1');\n", + "_matlab(\"E{1}=tf([1],1,Ts,'Variable','z^-1');\")\n", + "# MATLAB L3302: %Neuron 1 firing has strong inhibitory effect on neuron 2.\n", + "# Neuron 1 firing has strong inhibitory effect on neuron 2.\n", + "# MATLAB L3303: E{2}=tf([-4],1,Ts,'Variable','z^-1');\n", + "_matlab(\"E{2}=tf([-4],1,Ts,'Variable','z^-1');\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d99e837", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 7: Stimulus\n", + "# MATLAB L3600: % We use a simple sine wave here but we may want to explore other types of inputs to see if they affect the recovery of the network parameters.\n", + "# We use a simple sine wave here but we may want to explore other types of inputs to see if they affect the recovery of the network parameters.\n", + "# MATLAB L3700: f=1; %Stimulus frequency [Hz]\n", + "f = 1\n", + "# MATLAB L3701: u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\n", + "_matlab(\"u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\")\n", + "# MATLAB L3702: stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\n", + "_matlab(\"stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\")\n", + "# MATLAB L3703: \n", + "#\n", + "# MATLAB L3704: \n", + "#\n", + "# MATLAB L3705: % Map the variables to the Simulink model\n", + "# Map the variables to the Simulink model\n", + "# MATLAB L3706: assignin('base','S1',S{1});\n", + "_matlab(\"assignin('base','S1',S{1});\")\n", + "# MATLAB L3707: assignin('base','H1',H{1});\n", + "_matlab(\"assignin('base','H1',H{1});\")\n", + "# MATLAB L3708: assignin('base','E1',E{1});\n", + "_matlab(\"assignin('base','E1',E{1});\")\n", + "# MATLAB L3709: assignin('base','mu1',mu{1});\n", + "_matlab(\"assignin('base','mu1',mu{1});\")\n", + "# MATLAB L3710: assignin('base','S2',S{2});\n", + "_matlab(\"assignin('base','S2',S{2});\")\n", + "# MATLAB L3711: assignin('base','H2',H{2});\n", + "_matlab(\"assignin('base','H2',H{2});\")\n", + "# MATLAB L3712: assignin('base','E2',E{2});\n", + "_matlab(\"assignin('base','E2',E{2});\")\n", + "# MATLAB L3713: assignin('base','mu2',mu{2});\n", + "_matlab(\"assignin('base','mu2',mu{2});\")\n", + "# MATLAB L3714: options = simget;\n", + "_matlab('options = simget;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea4ae4ab", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 8: Simulate the Network\n", + "# MATLAB L4000: % Uses a binomial model for the conditional intensity function nSTAT supports poisson model too but this simulink model simulates the firing using a binomial model\n", + "# Uses a binomial model for the conditional intensity function nSTAT supports poisson model too but this simulink model simulates the firing using a binomial model\n", + "# MATLAB L4100: fitType = 'binomial';\n", + "_matlab(\"fitType = 'binomial';\")\n", + "# MATLAB L4101: if(strcmp(fitType,'binomial'))\n", + "_matlab(\"if(strcmp(fitType,'binomial'))\")\n", + "# MATLAB L4102: Algorithm = 'BNLRCG';\n", + "_matlab(\"Algorithm = 'BNLRCG';\")\n", + "# MATLAB L4103: else\n", + "_matlab('else')\n", + "# MATLAB L4104: Algorithm ='GLM';\n", + "_matlab(\"Algorithm ='GLM';\")\n", + "# MATLAB L4105: end\n", + "_matlab('end')\n", + "# MATLAB L4106: [tout,~,yout] = sim('SimulatedNetwork2',[stim.minTime stim.maxTime], ...\n", + "_matlab(\"[tout,~,yout] = sim('SimulatedNetwork2',[stim.minTime stim.maxTime], ...\")\n", + "# MATLAB L4107: options,stim.dataToStructure);\n", + "_matlab('options,stim.dataToStructure);')\n", + "# MATLAB L4108: clear nst;\n", + "pass\n", + "# MATLAB L4109: \n", + "#\n", + "# MATLAB L4110: for i=1:numNeurons\n", + "_matlab('for i=1:numNeurons')\n", + "# MATLAB L4111: spikeTimes = tout(yout(:,i)>.5); %find the spike times\n", + "_matlab('spikeTimes = tout(yout(:,i)>.5); %find the spike times')\n", + "# MATLAB L4112: nst{i} = nspikeTrain(spikeTimes);\n", + "_matlab('nst{i} = nspikeTrain(spikeTimes);')\n", + "# MATLAB L4113: end\n", + "_matlab('end')\n", + "# MATLAB L4114: \n", + "#\n", + "# MATLAB L4115: \n", + "#\n", + "# MATLAB L4116: sC=nstColl(nst);\n", + "_matlab('sC=nstColl(nst);')\n", + "# MATLAB L4117: sC.setMinTime(stim.minTime);\n", + "_matlab('sC.setMinTime(stim.minTime);')\n", + "# MATLAB L4118: sC.setMaxTime(stim.maxTime);\n", + "_matlab('sC.setMaxTime(stim.maxTime);')\n", + "# MATLAB L4119: \n", + "#\n", + "# MATLAB L4120: \n", + "#\n", + "# MATLAB L4121: \n", + "#\n", + "# MATLAB L4122: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L4123: subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('sC.plot')\n", + "_matlab('subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);')\n", + "# MATLAB L4124: subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('stim.plot')\n", + "_matlab('subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "792c7628", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 9: GLM Model Fitting Setup\n", + "# MATLAB L4400: % In this section, we create the appropriate structures to fit several GLM models to the data generated above.\n", + "# In this section, we create the appropriate structures to fit several GLM models to the data generated above.\n", + "# MATLAB L4500: % Create a constant covariate representing the mean firing rate $$\\mu_{i}$\n", + "# Create a constant covariate representing the mean firing rate $$\\mu_{i}$\n", + "# MATLAB L4501: baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\n", + "_matlab(\"baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\")\n", + "# MATLAB L4502: \n", + "#\n", + "# MATLAB L4503: spikeColl = sC; %Use the generated data as our collection of spikes\n", + "_matlab('spikeColl = sC; %Use the generated data as our collection of spikes')\n", + "# MATLAB L4504: %Use stimulation and baseline as possible covariates\n", + "# Use stimulation and baseline as possible covariates\n", + "# MATLAB L4505: cc=CovColl({stim,baseline});\n", + "_matlab('cc=CovColl({stim,baseline});')\n", + "# MATLAB L4506: trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial\n", + "_matlab('trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial')\n", + "# MATLAB L4507: % trial.setTrialPartition([0 tMax/2 tMax]);\n", + "# trial.setTrialPartition([0 tMax/2 tMax]);\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "networktutorial-04", + "id": "c58b7645", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 10: GLM Model Fitting and Results\n", + "# MATLAB L4800: clear c;\n", + "pass\n", + "# MATLAB L4801: % We know the history effect goes back 3 lag orders\n", + "# We know the history effect goes back 3 lag orders\n", + "# MATLAB L4802: selfHist = [0:1:3]*Ts;\n", + "_matlab('selfHist = [0:1:3]*Ts;')\n", + "# MATLAB L4803: % only have an effect at the 1ms lag. This captures the effect of the\n", + "# only have an effect at the 1ms lag. This captures the effect of the\n", + "# MATLAB L4804: % firing of neuron 1 on neuron 2 and vice versa.\n", + "# firing of neuron 1 on neuron 2 and vice versa.\n", + "# MATLAB L4805: ensHist = [0 1]*Ts;\n", + "_matlab('ensHist = [0 1]*Ts;')\n", + "# MATLAB L4806: \n", + "#\n", + "# MATLAB L4807: \n", + "#\n", + "# MATLAB L4808: \n", + "#\n", + "# MATLAB L4809: sampleRate = 1/Ts;\n", + "_matlab('sampleRate = 1/Ts;')\n", + "# MATLAB L4810: %Lets compare three models of increasing complexity for each neuron\n", + "# Lets compare three models of increasing complexity for each neuron\n", + "# MATLAB L4811: \n", + "#\n", + "# MATLAB L4812: % When results are shown, ]ambda_1 corresponds to the CIF obtained from the\n", + "# When results are shown, ]ambda_1 corresponds to the CIF obtained from the\n", + "# MATLAB L4813: % c{1}, lambda_2 to c{2} etc.\n", + "# c{1}, lambda_2 to c{2} etc.\n", + "# MATLAB L4814: % Fit only a mean firing rate\n", + "# Fit only a mean firing rate\n", + "# MATLAB L4815: c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\")\n", + "# MATLAB L4816: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L4817: \n", + "#\n", + "# MATLAB L4818: % Fit a constant rate and ensemble model\n", + "# Fit a constant rate and ensemble model\n", + "# MATLAB L4819: c{2} = TrialConfig({{'Baseline','mu'}},sampleRate,[],ensHist);\n", + "_matlab(\"c{2} = TrialConfig({{'Baseline','mu'}},sampleRate,[],ensHist);\")\n", + "# MATLAB L4820: c{2}.setName('Baseline+EnsHist');\n", + "_matlab(\"c{2}.setName('Baseline+EnsHist');\")\n", + "# MATLAB L4821: \n", + "#\n", + "# MATLAB L4822: % Fit the correct/exact model\n", + "# Fit the correct/exact model\n", + "# MATLAB L4823: c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,...\n", + "_matlab(\"c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,...\")\n", + "# MATLAB L4824: selfHist,ensHist);\n", + "_matlab('selfHist,ensHist);')\n", + "# MATLAB L4825: c{3}.setName('Stim+Hist+EnsHist');\n", + "__tracker.annotate(\"c{3}.setName('Stim+Hist+EnsHist')\")\n", + "_matlab(\"c{3}.setName('Stim+Hist+EnsHist');\")\n", + "# MATLAB L4826: \n", + "#\n", + "# MATLAB L4827: % Place all configurations together and run analysis for each neuron\n", + "# Place all configurations together and run analysis for each neuron\n", + "# MATLAB L4828: \n", + "#\n", + "# MATLAB L4829: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L4830: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);')\n", + "# MATLAB L4831: \n", + "#\n", + "# MATLAB L4832: % Visualize the Results\n", + "# Visualize the Results\n", + "# MATLAB L4833: results{1}.plotResults;\n", + "_matlab('results{1}.plotResults;')\n", + "# MATLAB L4834: results{2}.plotResults;\n", + "_matlab('results{2}.plotResults;')\n", + "# MATLAB L4835: Summary = FitResSummary(results);\n", + "_matlab('Summary = FitResSummary(results);')\n", + "# MATLAB L4836: % Summary.plotSummary;\n", + "# Summary.plotSummary;\n", + "# MATLAB L4837: \n", + "#\n", + "# MATLAB L4838: % Construct an image of the Actual vs. Estimated Network\n", + "# Construct an image of the Actual vs. Estimated Network\n", + "# MATLAB L4839: actNetwork = zeros(numNeurons,numNeurons);\n", + "_matlab('actNetwork = zeros(numNeurons,numNeurons);')\n", + "# MATLAB L4840: network1ms = zeros(numNeurons,numNeurons);\n", + "_matlab('network1ms = zeros(numNeurons,numNeurons);')\n", + "# MATLAB L4841: for i=1:numNeurons\n", + "_matlab('for i=1:numNeurons')\n", + "# MATLAB L4842: index = 1:numNeurons;\n", + "_matlab('index = 1:numNeurons;')\n", + "# MATLAB L4843: neighbors = setdiff(index,i);\n", + "_matlab('neighbors = setdiff(index,i);')\n", + "# MATLAB L4844: [num,den] = tfdata(E{i});\n", + "_matlab('[num,den] = tfdata(E{i});')\n", + "# MATLAB L4845: actNetwork(i,neighbors) = cell2mat(num);\n", + "_matlab('actNetwork(i,neighbors) = cell2mat(num);')\n", + "# MATLAB L4846: % Coefficients in the 2rd Analysis correspond to the estimated\n", + "# Coefficients in the 2rd Analysis correspond to the estimated\n", + "# MATLAB L4847: % connection weights.\n", + "# connection weights.\n", + "# MATLAB L4848: % See labels after running command: [coeffs,labels]=results{i}.getCoeffs;\n", + "# See labels after running command: [coeffs,labels]=results{i}.getCoeffs;\n", + "# MATLAB L4849: [coeffs,labels]=results{i}.getCoeffs;\n", + "_matlab('[coeffs,labels]=results{i}.getCoeffs;')\n", + "# MATLAB L4850: network1ms(i,neighbors)=coeffs(1:(length(neighbors)),3);\n", + "_matlab('network1ms(i,neighbors)=coeffs(1:(length(neighbors)),3);')\n", + "# MATLAB L4851: end\n", + "_matlab('end')\n", + "# MATLAB L4852: \n", + "#\n", + "# MATLAB L4853: maxVal=max(max(abs(actNetwork)));\n", + "_matlab('maxVal=max(max(abs(actNetwork)));')\n", + "# MATLAB L4854: minVal=-maxVal;%min(min(actNetwork));\n", + "_matlab('minVal=-maxVal;%min(min(actNetwork));')\n", + "# MATLAB L4855: CLIM = [minVal maxVal];\n", + "_matlab('CLIM = [minVal maxVal];')\n", + "# MATLAB L4856: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L4857: colormap(jet);\n", + "_matlab('colormap(jet);')\n", + "# MATLAB L4858: subplot(1,2,1);\n", + "__tracker.annotate('subplot(1,2,1)')\n", + "_matlab('subplot(1,2,1);')\n", + "# MATLAB L4859: imagesc(actNetwork,CLIM);\n", + "__tracker.annotate('imagesc(actNetwork,CLIM)')\n", + "_matlab('imagesc(actNetwork,CLIM);')\n", + "# MATLAB L4860: set(gca,'XTick',index,'YTick',index);\n", + "_matlab(\"set(gca,'XTick',index,'YTick',index);\")\n", + "# MATLAB L4861: title('Actual');\n", + "_matlab(\"title('Actual');\")\n", + "# MATLAB L4862: subplot(1,2,2);\n", + "__tracker.annotate('subplot(1,2,2)')\n", + "_matlab('subplot(1,2,2);')\n", + "# MATLAB L4863: imagesc(network1ms,CLIM);\n", + "__tracker.annotate('imagesc(network1ms,CLIM)')\n", + "_matlab('imagesc(network1ms,CLIM);')\n", + "# MATLAB L4864: set(gca,'XTick',index,'YTick',index);\n", + "_matlab(\"set(gca,'XTick',index,'YTick',index);\")\n", + "# MATLAB L4865: title('Estimated 1ms');\n", + "_matlab(\"title('Estimated 1ms');\")\n", + "# MATLAB L5000: % Note: by default all neurons are considered to be potential neighbors. If this is not the case, you can call trial.setNeighbors(neighborArray) where neighborArray is a matrix that in the ith row has ones in the columns of those neurons considered to be potential neighbors and zeros otherwise. By default neighborArray has 0 only on the diagonal, so that the ith neuron cannot be its own neighbor, and 1 ones elsewhere.\n", + "# Note: by default all neurons are considered to be potential neighbors. If this is not the case, you can call trial.setNeighbors(neighborArray) where neighborArray is a matrix that in the ith row has ones in the columns of those neurons considered to be potential neighbors and zeros otherwise. By default neighborArray has 0 only on the diagonal, so that the ith neuron cannot be its own neighbor, and 1 ones elsewhere.\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "network", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 4, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/NetworkTutorial.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "NetworkTutorial" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/PPSimExample.ipynb b/notebooks/PPSimExample.ipynb index 7631276f..b8ddd161 100644 --- a/notebooks/PPSimExample.ipynb +++ b/notebooks/PPSimExample.ipynb @@ -3,225 +3,281 @@ { "cell_type": "code", "execution_count": null, - "id": "ppsimexample-00", + "id": "4d0c7022", "metadata": {}, "outputs": [], "source": [ - "# Topic: PPSimExample\n", - "# Execution group: smoke\n", - "# Workflow family: network\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/PPSimExample.md\n" + "# AUTO-GENERATED FROM MATLAB PPSimExample.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", + "import matplotlib\n", + "matplotlib.use(\"Agg\")\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='PPSimExample', output_root=OUTPUT_ROOT, expected_count=3)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % General Point Process Simulation\n", + "# General Point Process Simulation\n", + "# MATLAB L200: % In this demo, we show how sample-paths of a point process (PP) can be generated from specification of its conditional intensity function (CIF). We then use the generated PP data to validate the outputs of the Neural Spike Analysis Toolbox.\n", + "# In this demo, we show how sample-paths of a point process (PP) can be generated from specification of its conditional intensity function (CIF). We then use the generated PP data to validate the outputs of the Neural Spike Analysis Toolbox.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "ppsimexample-01", + "id": "46cfd25a", "metadata": {}, "outputs": [], "source": [ - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"PPSimExample\"\n", - "FAMILY = \"network\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"PPSimExample: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"PPSimExample: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"PPSimExample: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"PPSimExample: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "# SECTION 1: Point Process Sample Path Generation\n", + "# MATLAB L400: % That both the stimulus effect and ensemble effects can be made into multi-input/multi-output transfer functions to account for more than 1 stimulus effect or multiple neighboring neuron effects. To do this, simply define E$ orS$ to be a row vector of LTI transfer functions. Make sure than the number of dimensions of the input matches the number of transfer functions specified in the row vector.\n", + "# That both the stimulus effect and ensemble effects can be made into multi-input/multi-output transfer functions to account for more than 1 stimulus effect or multiple neighboring neuron effects. To do this, simply define E$ orS$ to be a row vector of LTI transfer functions. Make sure than the number of dimensions of the input matches the number of transfer functions specified in the row vector.\n", + "# MATLAB L600: % This block diagram specifies a conditional intensity function of the form\n", + "# This block diagram specifies a conditional intensity function of the form\n", + "# MATLAB L700: % \\lambda_{i} \\cdot \\Delta = exp(\\mu_{i} + H*\\Delta N_{i}[n] + S*u_{stim}[n] + E*\\Delta N_{k}[n])/(1+exp(\\mu_{i} + H*\\Delta N_{i}[n] + S*u_{stim}[n] + E*\\Delta N_{k}[n]))\n", + "# \\lambda_{i} \\cdot \\Delta = exp(\\mu_{i} + H*\\Delta N_{i}[n] + S*u_{stim}[n] + E*\\Delta N_{k}[n])/(1+exp(\\mu_{i} + H*\\Delta N_{i}[n] + S*u_{stim}[n] + E*\\Delta N_{k}[n]))\n", + "# MATLAB L800: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L801: Ts=.001; %Sample Time\n", + "Ts = .001\n", + "# MATLAB L802: tMin=0; tMax=50; %Simulation duration\n", + "_matlab('tMin=0; tMax=50; %Simulation duration')\n", + "# MATLAB L803: t=tMin:Ts:tMax;\n", + "_matlab('t=tMin:Ts:tMax;')\n", + "# MATLAB L804: \n", + "#\n", + "# MATLAB L805: mu=-3; %Baseline firing rate of the neurons being modeled\n", + "mu = -3\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "ppsimexample-02", + "id": "9230c714", "metadata": {}, "outputs": [], "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"Ts=.001; %Sample Time\",\n", - " \"tMin=0; tMax=50; %Simulation duration\",\n", - " \"t=tMin:Ts:tMax;\",\n", - " \"mu=-3; %Baseline firing rate of the neurons being modeled\",\n", - " \"H=tf([-1 -2 -4],[1],Ts,'Variable','z^-1');\",\n", - " \"S=tf([1],1,Ts,'Variable','z^-1');\",\n", - " \"E=tf([0],1,Ts,'Variable','z^-1');\",\n", - " \"f=1; %Stimulus frequency\",\n", - " \"u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\",\n", - " \"e = zeros(length(t),1); %No Ensemble input\",\n", - " \"stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\",\n", - " \"ens =Covariate(t',e,'Ensemble','time','s','Spikes',{'n1'});\",\n", - " \"numRealizations = 5; %Number of sample paths to generate\",\n", - " \"fitType = 'binomial';\",\n", - " \"sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations,fitType);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\",\n", - " \"subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\",\n", - " \"baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\",\n", - " \"spikeColl = sC; %Use the generated data as our collection of spikes\",\n", - " \"cc=CovColl({stim,baseline}); %Use stimulation and baseline as possible covariates\",\n", - " \"trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial\",\n", - " \"clear c;\",\n", - " \"selfHist = [0:0.001:0.003]; %We know the history effect goes back 3 lag orders\",\n", - " \"c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,[],[]);\",\n", - " \"c{2}.setName('Stim');\",\n", - " \"c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,selfHist,[]);\",\n", - " \"c{3}.setName('Stim+Hist');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"if(strcmp(fitType,'binomial'))\",\n", - " \"Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\",\n", - " \"else\",\n", - " \"Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\",\n", - " \"end\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);\",\n", - " \"results{1}.plotResults;\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for PPSimExample.\")\n" + "# SECTION 2: History Effect\n", + "# MATLAB L1100: % 1*h[n]=-1*\\Delta N[n-1]-2*\\Delta N[n-2] -4*\\Delta N[n-3]\n", + "# 1*h[n]=-1*\\Delta N[n-1]-2*\\Delta N[n-2] -4*\\Delta N[n-3]\n", + "# MATLAB L1200: H=tf([-1 -2 -4],[1],Ts,'Variable','z^-1');\n", + "_matlab(\"H=tf([-1 -2 -4],[1],Ts,'Variable','z^-1');\")\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "ppsimexample-03", + "id": "19920fbe", "metadata": {}, "outputs": [], "source": [ - "# PPSimExample: fixture-backed Poisson GLM simulation and parity checks.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/PPSimExample_gold.mat\"\n", - "m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False)\n", - "X = np.asarray(m[\"X\"], dtype=float).reshape(-1, 1)\n", - "y = np.asarray(m[\"y\"], dtype=float).reshape(-1)\n", - "dt = float(np.asarray(m[\"dt\"], dtype=float).reshape(-1)[0])\n", - "expected_rate = np.asarray(m[\"expected_rate\"], dtype=float).reshape(-1)\n", - "b = np.asarray(m[\"b\"], dtype=float).reshape(-1)\n", - "fit = Analysis.fit_glm(X=X, y=y, fit_type=\"poisson\", dt=dt)\n", - "pred_rate = np.asarray(fit.predict(X), dtype=float).reshape(-1)\n", - "rel_err = float(np.mean(np.abs(pred_rate - expected_rate) / np.maximum(expected_rate, 1e-12)))\n", - "intercept_abs_error = float(abs(fit.intercept - b[0]))\n", - "coeff_abs_error = float(abs(fit.coefficients[0] - b[1]))\n", - "assert rel_err <= 0.25 and intercept_abs_error <= 0.25 and coeff_abs_error <= 0.25\n", - "time = np.arange(X.shape[0]) * dt\n", - "stim = X.reshape(-1)\n", - "spike_idx = np.where(y > 0)[0]\n", - "\n", - "fig, axes = plt.subplots(3, 1, figsize=(10.2, 7.4), sharex=False)\n", - "axes[0].plot(time, stim, \"k\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: driving stimulus\")\n", - "axes[0].set_ylabel(\"stim\")\n", - "axes[1].vlines(time[spike_idx], 0.6, 1.4, color=\"black\", linewidth=0.35)\n", - "axes[1].set_title(\"Point-process sample path\")\n", - "axes[1].set_ylabel(\"trial #1\")\n", - "axes[2].plot(time, expected_rate, color=\"tab:green\", linewidth=1.0, linestyle=\"--\", label=\"MATLAB gold\")\n", - "axes[2].plot(time, pred_rate, color=\"tab:red\", linewidth=1.0, label=\"Python fit\")\n", - "axes[2].plot(time, y / max(dt, 1e-12), color=\"0.7\", linewidth=0.3, alpha=0.5, label=\"counts/dt\")\n", - "axes[2].set_xlabel(\"time [s]\")\n", - "axes[2].set_ylabel(\"Hz\")\n", - "axes[2].set_title(\"Conditional intensity fit\")\n", - "axes[2].legend(loc=\"upper right\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"mean_simulated_rate\": float(np.mean(pred_rate)),\n", - " \"relative_rate_error\": rel_err,\n", - " \"intercept_abs_error\": intercept_abs_error,\n", - " \"coeff_abs_error\": coeff_abs_error,\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"mean_simulated_rate\": (0.1, 500.0),\n", - " \"relative_rate_error\": (0.0, 0.25),\n", - " \"intercept_abs_error\": (0.0, 0.25),\n", - " \"coeff_abs_error\": (0.0, 0.25),\n", - "}\n" + "# SECTION 3: Stimulus Effect\n", + "# MATLAB L1500: % 1*s[n]=1*u_{stim}[n]\n", + "# 1*s[n]=1*u_{stim}[n]\n", + "# MATLAB L1600: S=tf([1],1,Ts,'Variable','z^-1');\n", + "_matlab(\"S=tf([1],1,Ts,'Variable','z^-1');\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "392356a4", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 4: Ensemble Effect\n", + "# MATLAB L1900: % 1*e[n]=0*\\Delta N_{k}[n]\n", + "# 1*e[n]=0*\\Delta N_{k}[n]\n", + "# MATLAB L2000: E=tf([0],1,Ts,'Variable','z^-1');\n", + "_matlab(\"E=tf([0],1,Ts,'Variable','z^-1');\")\n", + "# MATLAB L2200: f=1; %Stimulus frequency\n", + "f = 1\n", + "# MATLAB L2201: u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\n", + "_matlab(\"u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\")\n", + "# MATLAB L2202: e = zeros(length(t),1); %No Ensemble input\n", + "_matlab('e = zeros(length(t),1); %No Ensemble input')\n", + "# MATLAB L2203: \n", + "#\n", + "# MATLAB L2204: stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\n", + "_matlab(\"stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\")\n", + "# MATLAB L2205: ens =Covariate(t',e,'Ensemble','time','s','Spikes',{'n1'});\n", + "_matlab(\"ens =Covariate(t',e,'Ensemble','time','s','Spikes',{'n1'});\")\n", + "# MATLAB L2206: numRealizations = 5; %Number of sample paths to generate\n", + "numRealizations = 5\n", + "# MATLAB L2207: fitType = 'binomial';\n", + "_matlab(\"fitType = 'binomial';\")\n", + "# MATLAB L2208: sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations,fitType);\n", + "_matlab('sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations,fitType);')\n", + "# MATLAB L2209: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L2210: subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('sC.plot')\n", + "_matlab('subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);')\n", + "# MATLAB L2211: subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('stim.plot')\n", + "_matlab('subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc80c066", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 5: GLM Model Fitting Setup\n", + "# MATLAB L2500: % In this section, we create the appropriate structures to fit several GLM models to the data generated above.\n", + "# In this section, we create the appropriate structures to fit several GLM models to the data generated above.\n", + "# MATLAB L2600: % Create a constant covariate representing the mean firing rate $$\\mu_{i}$\n", + "# Create a constant covariate representing the mean firing rate $$\\mu_{i}$\n", + "# MATLAB L2601: baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\n", + "_matlab(\"baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\")\n", + "# MATLAB L2602: \n", + "#\n", + "# MATLAB L2603: \n", + "#\n", + "# MATLAB L2604: spikeColl = sC; %Use the generated data as our collection of spikes\n", + "_matlab('spikeColl = sC; %Use the generated data as our collection of spikes')\n", + "# MATLAB L2605: cc=CovColl({stim,baseline}); %Use stimulation and baseline as possible covariates\n", + "_matlab('cc=CovColl({stim,baseline}); %Use stimulation and baseline as possible covariates')\n", + "# MATLAB L2606: trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial\n", + "_matlab('trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63ac3570", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 6: GLM Model Fitting and Results\n", + "# MATLAB L2900: clear c;\n", + "pass\n", + "# MATLAB L2901: selfHist = [0:0.001:0.003]; %We know the history effect goes back 3 lag orders\n", + "_matlab('selfHist = [0:0.001:0.003]; %We know the history effect goes back 3 lag orders')\n", + "# MATLAB L3100: % Fit only a mean firing rate\n", + "# Fit only a mean firing rate\n", + "# MATLAB L3200: c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\")\n", + "# MATLAB L3201: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L3400: % Fit a mean firing rate + the stimulus term\n", + "# Fit a mean firing rate + the stimulus term\n", + "# MATLAB L3500: c{2} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,[],[]);\n", + "_matlab(\"c{2} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,[],[]);\")\n", + "# MATLAB L3501: c{2}.setName('Stim');\n", + "_matlab(\"c{2}.setName('Stim');\")\n", + "# MATLAB L3700: % Fit a mean firing rate, self-history, and stimulus --- Same as true model\n", + "# Fit a mean firing rate, self-history, and stimulus --- Same as true model\n", + "# MATLAB L3800: c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,selfHist,[]);\n", + "_matlab(\"c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,selfHist,[]);\")\n", + "# MATLAB L3801: c{3}.setName('Stim+Hist');\n", + "__tracker.annotate(\"c{3}.setName('Stim+Hist')\")\n", + "_matlab(\"c{3}.setName('Stim+Hist');\")\n", + "# MATLAB L4000: % Place all configurations together and run analysis for each neuron\n", + "# Place all configurations together and run analysis for each neuron\n", + "# MATLAB L4100: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L4101: if(strcmp(fitType,'binomial'))\n", + "_matlab(\"if(strcmp(fitType,'binomial'))\")\n", + "# MATLAB L4102: Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\n", + "_matlab(\"Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\")\n", + "# MATLAB L4103: % Binomial Logistic Regression with Conjugate\n", + "# Binomial Logistic Regression with Conjugate\n", + "# MATLAB L4104: % Gradient Solver by Demba Ba (demba@mit.edu).\n", + "# Gradient Solver by Demba Ba (demba@mit.edu).\n", + "# MATLAB L4105: else\n", + "_matlab('else')\n", + "# MATLAB L4106: Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\n", + "_matlab(\"Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\")\n", + "# MATLAB L4107: % or Poisson CIFs\n", + "# or Poisson CIFs\n", + "# MATLAB L4108: end\n", + "_matlab('end')\n", + "# MATLAB L4109: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "ppsimexample-04", + "id": "31956641", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 7: Results for sample neuron\n", + "# MATLAB L4400: results{1}.plotResults;\n", + "_matlab('results{1}.plotResults;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "814c0404", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 8: Results for across all sample paths\n", + "# MATLAB L4700: Summary = FitResSummary(results);\n", + "_matlab('Summary = FitResSummary(results);')\n", + "# MATLAB L4701: Summary.plotSummary;\n", + "__tracker.annotate('Summary.plotSummary')\n", + "_matlab('Summary.plotSummary;')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "network", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 3, "run_group": "smoke", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/PPSimExample.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "PPSimExample" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/PPThinning.ipynb b/notebooks/PPThinning.ipynb index 1b52760e..cdfc39e6 100644 --- a/notebooks/PPThinning.ipynb +++ b/notebooks/PPThinning.ipynb @@ -3,208 +3,227 @@ { "cell_type": "code", "execution_count": null, - "id": "ppthinning-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: PPThinning\n", - "# Execution group: full\n", - "# Workflow family: network\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/PPThinning.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ppthinning-01", + "id": "54f80f31", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB PPThinning.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='PPThinning', output_root=OUTPUT_ROOT, expected_count=3)\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "TOPIC = \"PPThinning\"\n", - "FAMILY = \"network\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"PPThinning: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"PPThinning: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"PPThinning: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"PPThinning: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Simulate PP via thinning\n", + "# Simulate PP via thinning\n", + "# MATLAB L200: % Given a conditional intensity function, we generate a point process consistent with this CIF.\n", + "# Given a conditional intensity function, we generate a point process consistent with this CIF.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "ppthinning-02", + "id": "7ee71ae8", "metadata": {}, "outputs": [], "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"delta = 0.001;\",\n", - " \"Tmax = 100;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=.1;\",\n", - " \"lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0\",\n", - " \"lambda = Covariate(time,lambdaData, '\\\\Lambda(t)','time','s','Hz',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"lambdaBound = max(lambda);\",\n", - " \"N=lambdaBound*(1.5*Tmax); %Expected number of arrivals in interval 1.5*Tmax\",\n", - " \"u = rand(1,N); %N samples uniform(0,1)\",\n", - " \"w = -log(u)./(lambdaBound); %N samples exponential rate lambdaBound (ISIs)\",\n", - " \"tSpikes = cumsum(w); %Spiketimes;\",\n", - " \"tSpikes = tSpikes(tSpikes<=Tmax);%Spiketimes within Tmax\",\n", - " \"lambdaRatio = lambda.getValueAt(tSpikes)./lambdaBound;\",\n", - " \"u2 = rand(length(lambdaRatio),1);\",\n", - " \"tSpikesThin = tSpikes(lambdaRatio>=u2);\",\n", - " \"figure(1);\",\n", - " \"n1 = nspikeTrain(tSpikes);\",\n", - " \"n2 = nspikeTrain(tSpikesThin);\",\n", - " \"subplot(2,2,1); n1.plot; plot(tSpikes,ones(size(tSpikes)),'.');\",\n", - " \"v=axis; axis([0 Tmax/4 v(3) v(4)]);\",\n", - " \"subplot(2,2,2); n1.plotISIHistogram;\",\n", - " \"subplot(2,2,3); n2.plot; plot(tSpikes,ones(size(tSpikes)),'.');\",\n", - " \"v=axis; axis([0 Tmax/4 v(3) v(4)]);\",\n", - " \"subplot(2,2,4); n2.plotISIHistogram;\",\n", - " \"figure(2);\",\n", - " \"n2.plot;\",\n", - " \"scaledProb = lambda*(1./lambdaBound);\",\n", - " \"scaledProb.plot;\",\n", - " \"v=axis;\",\n", - " \"axis([0 Tmax/4 v(3) v(4)]);\",\n", - " \"numRealizations = 20;\",\n", - " \"spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\",\n", - " \"figure(3);\",\n", - " \"spikeColl.plot;\",\n", - " \"lambda.plot;\",\n", - " \"v=axis;\",\n", - " \"axis([0 Tmax/4 v(3) v(4)]);\",\n", - " \"parity = struct();\",\n", - " \"parity.num_realizations = numRealizations;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for PPThinning.\")\n" + "# SECTION 1: Basic Example\n", + "# MATLAB L400: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L401: delta = 0.001;\n", + "delta = 0.001\n", + "# MATLAB L402: Tmax = 100;\n", + "Tmax = 100\n", + "# MATLAB L403: time = 0:delta:Tmax;\n", + "_matlab('time = 0:delta:Tmax;')\n", + "# MATLAB L404: f=.1;\n", + "f = .1\n", + "# MATLAB L405: lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0\n", + "_matlab('lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0')\n", + "# MATLAB L406: lambda = Covariate(time,lambdaData, '\\Lambda(t)','time','s','Hz',{'\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\n", + "_matlab(\"lambda = Covariate(time,lambdaData, '\\\\Lambda(t)','time','s','Hz',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\")\n", + "# MATLAB L407: \n", + "#\n", + "# MATLAB L408: lambdaBound = max(lambda);\n", + "_matlab('lambdaBound = max(lambda);')\n", + "# MATLAB L409: N=lambdaBound*(1.5*Tmax); %Expected number of arrivals in interval 1.5*Tmax\n", + "_matlab('N=lambdaBound*(1.5*Tmax); %Expected number of arrivals in interval 1.5*Tmax')\n", + "# MATLAB L410: u = rand(1,N); %N samples uniform(0,1)\n", + "_matlab('u = rand(1,N); %N samples uniform(0,1)')\n", + "# MATLAB L411: w = -log(u)./(lambdaBound); %N samples exponential rate lambdaBound (ISIs)\n", + "_matlab('w = -log(u)./(lambdaBound); %N samples exponential rate lambdaBound (ISIs)')\n", + "# MATLAB L412: \n", + "#\n", + "# MATLAB L413: tSpikes = cumsum(w); %Spiketimes;\n", + "_matlab('tSpikes = cumsum(w); %Spiketimes;')\n", + "# MATLAB L414: tSpikes = tSpikes(tSpikes<=Tmax);%Spiketimes within Tmax\n", + "_matlab('tSpikes = tSpikes(tSpikes<=Tmax);%Spiketimes within Tmax')\n", + "# MATLAB L415: \n", + "#\n", + "# MATLAB L416: % Thinning\n", + "# Thinning\n", + "# MATLAB L417: \n", + "#\n", + "# MATLAB L418: lambdaRatio = lambda.getValueAt(tSpikes)./lambdaBound;\n", + "_matlab('lambdaRatio = lambda.getValueAt(tSpikes)./lambdaBound;')\n", + "# MATLAB L419: % lambdaRatio <=1\n", + "# lambdaRatio <=1\n", + "# MATLAB L420: \n", + "#\n", + "# MATLAB L421: % draw uniform random number in 0,1\n", + "# draw uniform random number in 0,1\n", + "# MATLAB L422: u2 = rand(length(lambdaRatio),1);\n", + "_matlab('u2 = rand(length(lambdaRatio),1);')\n", + "# MATLAB L423: \n", + "#\n", + "# MATLAB L424: % keep spike if lambda ratio is greater than random number\n", + "# keep spike if lambda ratio is greater than random number\n", + "# MATLAB L425: tSpikesThin = tSpikes(lambdaRatio>=u2);\n", + "_matlab('tSpikesThin = tSpikes(lambdaRatio>=u2);')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "ppthinning-03", + "id": "9ac17362", "metadata": {}, "outputs": [], "source": [ - "# PPThinning: fixture-backed thinning acceptance parity.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "\n", - "m = loadmat(Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/PPThinning_gold.mat\", squeeze_me=True)\n", - "time = np.asarray(m[\"time_pt\"], dtype=float).reshape(-1); lambda_data = np.asarray(m[\"lambda_pt\"], dtype=float).reshape(-1)\n", - "t_spikes = np.asarray(m[\"candidate_spikes_pt\"], dtype=float).reshape(-1); lambda_ratio = np.asarray(m[\"lambda_ratio_pt\"], dtype=float).reshape(-1); u2 = np.asarray(m[\"uniform_u2_pt\"], dtype=float).reshape(-1)\n", - "expected = np.asarray(m[\"accepted_spikes_pt\"], dtype=float).reshape(-1)\n", - "accepted = t_spikes[lambda_ratio >= u2]\n", - "\n", - "fig, ax = plt.subplots(2, 1, figsize=(9, 5.6), sharex=False)\n", - "ax[0].vlines(t_spikes, 0.0, 1.0, color=\"0.5\", linewidth=0.4, label=\"candidate\")\n", - "ax[0].vlines(accepted, 0.0, 1.0, color=\"k\", linewidth=0.6, label=\"accepted\")\n", - "ax[0].set_xlim(0.0, float(np.asarray(m[\"tmax_pt\"]).reshape(-1)[0]) / 4.0); ax[0].set_title(\"Candidate vs accepted spikes\"); ax[0].legend(loc=\"upper right\")\n", - "ax[1].plot(time, lambda_data, \"b\", linewidth=1.0); ax[1].set_xlim(0.0, float(np.asarray(m[\"tmax_pt\"]).reshape(-1)[0]) / 4.0); ax[1].set_title(\"Conditional intensity\"); ax[1].set_xlabel(\"time [s]\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "assert accepted.shape == expected.shape\n", - "assert np.allclose(accepted, expected, atol=0.0)\n", - "assert np.all(np.diff(accepted) >= 0.0)\n", - "accept_ratio = float(accepted.size / max(t_spikes.size, 1)); expected_ratio = float(np.asarray(m[\"accept_ratio_pt\"], dtype=float).reshape(-1)[0])\n", - "assert np.isclose(accept_ratio, expected_ratio, atol=0.0)\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"accepted_spike_count\": float(accepted.size),\n", - " \"accept_ratio\": float(accept_ratio),\n", - " \"lambda_mean\": float(np.mean(lambda_data)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"accepted_spike_count\": (1.0, 1.0e7),\n", - " \"accept_ratio\": (0.0, 1.0),\n", - " \"lambda_mean\": (0.0, 1.0e6),\n", - "}\n" + "# SECTION 2: Compare Constant rate process vs. thinned process\n", + "# MATLAB L700: figure(1);\n", + "__tracker.new_figure('figure(1)')\n", + "_matlab('figure(1);')\n", + "# MATLAB L701: n1 = nspikeTrain(tSpikes);\n", + "_matlab('n1 = nspikeTrain(tSpikes);')\n", + "# MATLAB L702: n2 = nspikeTrain(tSpikesThin);\n", + "_matlab('n2 = nspikeTrain(tSpikesThin);')\n", + "# MATLAB L703: subplot(2,2,1); n1.plot; plot(tSpikes,ones(size(tSpikes)),'.');\n", + "__tracker.annotate('subplot(2,2,1)')\n", + "__tracker.annotate('n1.plot')\n", + "__tracker.annotate(\"plot(tSpikes,ones(size(tSpikes)),'.')\")\n", + "_matlab(\"subplot(2,2,1); n1.plot; plot(tSpikes,ones(size(tSpikes)),'.');\")\n", + "# MATLAB L704: v=axis; axis([0 Tmax/4 v(3) v(4)]);\n", + "_matlab('v=axis; axis([0 Tmax/4 v(3) v(4)]);')\n", + "# MATLAB L705: subplot(2,2,2); n1.plotISIHistogram;\n", + "__tracker.annotate('subplot(2,2,2)')\n", + "_matlab('subplot(2,2,2); n1.plotISIHistogram;')\n", + "# MATLAB L706: subplot(2,2,3); n2.plot; plot(tSpikes,ones(size(tSpikes)),'.');\n", + "__tracker.annotate('subplot(2,2,3)')\n", + "__tracker.annotate('n2.plot')\n", + "__tracker.annotate(\"plot(tSpikes,ones(size(tSpikes)),'.')\")\n", + "_matlab(\"subplot(2,2,3); n2.plot; plot(tSpikes,ones(size(tSpikes)),'.');\")\n", + "# MATLAB L707: v=axis; axis([0 Tmax/4 v(3) v(4)]);\n", + "_matlab('v=axis; axis([0 Tmax/4 v(3) v(4)]);')\n", + "# MATLAB L708: subplot(2,2,4); n2.plotISIHistogram;\n", + "__tracker.annotate('subplot(2,2,4)')\n", + "_matlab('subplot(2,2,4); n2.plotISIHistogram;')\n", + "# MATLAB L709: \n", + "#\n", + "# MATLAB L710: figure(2);\n", + "__tracker.new_figure('figure(2)')\n", + "_matlab('figure(2);')\n", + "# MATLAB L711: n2.plot;\n", + "__tracker.annotate('n2.plot')\n", + "_matlab('n2.plot;')\n", + "# MATLAB L712: scaledProb = lambda*(1./lambdaBound);\n", + "_matlab('scaledProb = lambda*(1./lambdaBound);')\n", + "# MATLAB L713: scaledProb.plot;\n", + "__tracker.annotate('scaledProb.plot')\n", + "_matlab('scaledProb.plot;')\n", + "# MATLAB L714: v=axis;\n", + "_matlab('v=axis;')\n", + "# MATLAB L715: axis([0 Tmax/4 v(3) v(4)]);\n", + "_matlab('axis([0 Tmax/4 v(3) v(4)]);')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "ppthinning-04", + "id": "44b79b5d", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 3: Simulate multiple realizations of a point process via thinning\n", + "# MATLAB L1000: % The CIF class can generated realizations of a point process given a conditional intensity function (defined as a Covariate or SignalObj)\n", + "# The CIF class can generated realizations of a point process given a conditional intensity function (defined as a Covariate or SignalObj)\n", + "# MATLAB L1100: numRealizations = 20;\n", + "numRealizations = 20\n", + "# MATLAB L1101: spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\n", + "_matlab('spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);')\n", + "# MATLAB L1102: figure(3);\n", + "__tracker.new_figure('figure(3)')\n", + "_matlab('figure(3);')\n", + "# MATLAB L1103: spikeColl.plot;\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('spikeColl.plot;')\n", + "# MATLAB L1104: lambda.plot;\n", + "__tracker.annotate('lambda.plot')\n", + "_matlab('lambda.plot;')\n", + "# MATLAB L1105: v=axis;\n", + "_matlab('v=axis;')\n", + "# MATLAB L1106: axis([0 Tmax/4 v(3) v(4)]);\n", + "_matlab('axis([0 Tmax/4 v(3) v(4)]);')\n", + "# MATLAB L1107: \n", + "#\n", + "# MATLAB L1108: % Parity contract scalars for MATLAB/Python verification.\n", + "# Parity contract scalars for MATLAB/Python verification.\n", + "# MATLAB L1109: parity = struct();\n", + "_matlab('parity = struct();')\n", + "# MATLAB L1110: parity.num_realizations = numRealizations;\n", + "_matlab('parity.num_realizations = numRealizations;')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "network", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 3, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/PPThinning.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "PPThinning" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/PSTHEstimation.ipynb b/notebooks/PSTHEstimation.ipynb index d26c0d95..b750f9ea 100644 --- a/notebooks/PSTHEstimation.ipynb +++ b/notebooks/PSTHEstimation.ipynb @@ -3,214 +3,176 @@ { "cell_type": "code", "execution_count": null, - "id": "psthestimation-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: PSTHEstimation\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/PSTHEstimation.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "psthestimation-01", + "id": "ca35c1b7", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB PSTHEstimation.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"PSTHEstimation\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"PSTHEstimation: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"PSTHEstimation: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"PSTHEstimation: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"PSTHEstimation: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "psthestimation-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"delta = 0.001;\",\n", - " \"Tmax = 10;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=.2;\",\n", - " \"lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0\",\n", - " \"lambda = Covariate(time,lambdaData, '\\\\Lambda(t)','time','s','Hz',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"numRealizations = 20; % Use 20 realization so that lamba and raster plot are the same size\",\n", - " \"spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\",\n", - " \"spikeColl.plot; set(gca,'ytickLabel',[]);\",\n", - " \"lambda.plot;\",\n", - " \"figure;\",\n", - " \"binsize = .5; %500ms window\",\n", - " \"psth = spikeColl.psth(binsize);\",\n", - " \"psthGLM = spikeColl.psthGLM(binsize);\",\n", - " \"trueRate = lambda; %rate*delta = expected number of arrivals per bin\",\n", - " \"h1=trueRate.plot;\",\n", - " \"h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\",\n", - " \"legend off;\",\n", - " \"legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\",\n", - " \"psth_mean_hz = mean(psth.data);\",\n", - " \"psth_glm_mean_hz = mean(psthGLM.data);\",\n", - " \"lambda_mean_hz = mean(lambda.data);\",\n", - " \"parity = struct();\",\n", - " \"parity.psth_mean_hz = psth_mean_hz;\",\n", - " \"parity.psth_glm_mean_hz = psth_glm_mean_hz;\",\n", - " \"parity.lambda_mean_hz = lambda_mean_hz;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for PSTHEstimation.\")\n" + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='PSTHEstimation', output_root=OUTPUT_ROOT, expected_count=2)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % PSTH Estimation\n", + "# PSTH Estimation\n", + "# MATLAB L200: % We illustrate two ways to estimate a peristimulus time histogram using the nSTAT toolbox. One technique is the standard binning in time, averaging across trials, and dividing by the binwidth to estimate the spike rate and the other is based on the method presented in \"Analysis of Between-Trial and Within-Trial Neural Spiking Dynamics\" by Czanner et al in J Neurophysiology 2008.\n", + "# We illustrate two ways to estimate a peristimulus time histogram using the nSTAT toolbox. One technique is the standard binning in time, averaging across trials, and dividing by the binwidth to estimate the spike rate and the other is based on the method presented in \"Analysis of Between-Trial and Within-Trial Neural Spiking Dynamics\" by Czanner et al in J Neurophysiology 2008.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "psthestimation-03", + "id": "2a526b26", "metadata": {}, "outputs": [], "source": [ - "# Data-style workflow: trial-to-trial variability and PSTH-like estimates.\n", - "dt = 0.001\n", - "time = np.arange(0.0, 1.2, dt)\n", - "n_trials = 30\n", - "\n", - "rate = 5.0 + 8.0 * (time > 0.35) + 4.0 * np.sin(2.0 * np.pi * 2.0 * time)\n", - "rate = np.clip(rate, 0.2, None)\n", - "\n", - "trial_matrix = np.zeros((n_trials, time.size), dtype=float)\n", - "for k in range(n_trials):\n", - " jitter = 0.6 + 0.8 * rng.random()\n", - " p = np.clip(rate * jitter * dt, 0.0, 0.6)\n", - " trial_matrix[k, :] = rng.binomial(1, p)\n", - "\n", - "psth = trial_matrix.mean(axis=0) / dt\n", - "sem = trial_matrix.std(axis=0, ddof=1) / np.sqrt(n_trials) / dt\n", - "\n", - "rates, prob_mat, sig_mat = DecodingAlgorithms.compute_spike_rate_cis(trial_matrix)\n", - "\n", - "fig, axes = plt.subplots(3, 1, figsize=(9, 7), sharex=False)\n", - "for k in range(min(18, n_trials)):\n", - " t_spk = time[trial_matrix[k] > 0]\n", - " axes[0].vlines(t_spk, k + 0.6, k + 1.4, linewidth=0.5)\n", - "axes[0].set_title(f\"{TOPIC}: trial raster\")\n", - "axes[0].set_ylabel(\"trial\")\n", - "\n", - "axes[1].plot(time, psth, color=\"tab:blue\", linewidth=1.2)\n", - "axes[1].fill_between(time, psth - sem, psth + sem, color=\"tab:blue\", alpha=0.2)\n", - "axes[1].set_ylabel(\"Hz\")\n", - "axes[1].set_title(\"PSTH mean +/- SEM\")\n", - "\n", - "im = axes[2].imshow(prob_mat, aspect=\"auto\", origin=\"lower\", cmap=\"viridis\")\n", - "axes[2].set_title(\"Trial-by-trial spike-rate p-values\")\n", - "axes[2].set_xlabel(\"trial\")\n", - "axes[2].set_ylabel(\"trial\")\n", - "fig.colorbar(im, ax=axes[2], fraction=0.03, pad=0.02)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "print(\"significant pair count\", int(sig_mat.sum()))\n", - "assert np.allclose(prob_mat, prob_mat.T, atol=1e-12)\n", - "assert np.all(np.diag(prob_mat) == 1.0)\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"psth_mean_hz\": float(np.mean(psth)),\n", - " \"significant_pairs\": float(np.sum(sig_mat)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"psth_mean_hz\": (0.1, 50.0),\n", - " \"significant_pairs\": (0.0, float(sig_mat.size)),\n", - "}\n" + "# SECTION 1: Generate a known Conditional Intensity Function\n", + "# MATLAB L400: % We generated a known conditional intensity function (rate function) and generate distinct realizations of point processes consistent with this rate function. We use the method of thinning to simulate a point process.\n", + "# We generated a known conditional intensity function (rate function) and generate distinct realizations of point processes consistent with this rate function. We use the method of thinning to simulate a point process.\n", + "# MATLAB L500: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L501: delta = 0.001;\n", + "delta = 0.001\n", + "# MATLAB L502: Tmax = 10;\n", + "Tmax = 10\n", + "# MATLAB L503: time = 0:delta:Tmax;\n", + "_matlab('time = 0:delta:Tmax;')\n", + "# MATLAB L504: f=.2;\n", + "f = .2\n", + "# MATLAB L505: lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0\n", + "_matlab('lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0')\n", + "# MATLAB L506: lambda = Covariate(time,lambdaData, '\\Lambda(t)','time','s','Hz',{'\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\n", + "_matlab(\"lambda = Covariate(time,lambdaData, '\\\\Lambda(t)','time','s','Hz',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\")\n", + "# MATLAB L507: numRealizations = 20; % Use 20 realization so that lamba and raster plot are the same size\n", + "numRealizations = 20\n", + "# MATLAB L508: spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\n", + "_matlab('spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);')\n", + "# MATLAB L509: spikeColl.plot; set(gca,'ytickLabel',[]);\n", + "__tracker.new_figure('spikeColl.plot')\n", + "_matlab(\"spikeColl.plot; set(gca,'ytickLabel',[]);\")\n", + "# MATLAB L510: lambda.plot;\n", + "__tracker.annotate('lambda.plot')\n", + "_matlab('lambda.plot;')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "psthestimation-04", + "id": "45ae045e", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 2: Estimate the PSTH with 500ms windows\n", + "# MATLAB L800: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L801: binsize = .5; %500ms window\n", + "binsize = .5\n", + "# MATLAB L802: psth = spikeColl.psth(binsize);\n", + "_matlab('psth = spikeColl.psth(binsize);')\n", + "# MATLAB L803: psthGLM = spikeColl.psthGLM(binsize);\n", + "_matlab('psthGLM = spikeColl.psthGLM(binsize);')\n", + "# MATLAB L804: trueRate = lambda; %rate*delta = expected number of arrivals per bin\n", + "_matlab('trueRate = lambda; %rate*delta = expected number of arrivals per bin')\n", + "# MATLAB L805: h1=trueRate.plot;\n", + "__tracker.annotate('h1=trueRate.plot')\n", + "_matlab('h1=trueRate.plot;')\n", + "# MATLAB L806: h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}})\")\n", + "_matlab(\"h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\")\n", + "# MATLAB L807: h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}})\")\n", + "_matlab(\"h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\")\n", + "# MATLAB L808: legend off;\n", + "_matlab('legend off;')\n", + "# MATLAB L809: legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\n", + "_matlab(\"legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\")\n", + "# MATLAB L810: \n", + "#\n", + "# MATLAB L811: % Scalar summaries for automated parity checks.\n", + "# Scalar summaries for automated parity checks.\n", + "# MATLAB L812: psth_mean_hz = mean(psth.data);\n", + "_matlab('psth_mean_hz = mean(psth.data);')\n", + "# MATLAB L813: psth_glm_mean_hz = mean(psthGLM.data);\n", + "_matlab('psth_glm_mean_hz = mean(psthGLM.data);')\n", + "# MATLAB L814: lambda_mean_hz = mean(lambda.data);\n", + "_matlab('lambda_mean_hz = mean(lambda.data);')\n", + "# MATLAB L815: parity = struct();\n", + "_matlab('parity = struct();')\n", + "# MATLAB L816: parity.psth_mean_hz = psth_mean_hz;\n", + "_matlab('parity.psth_mean_hz = psth_mean_hz;')\n", + "# MATLAB L817: parity.psth_glm_mean_hz = psth_glm_mean_hz;\n", + "_matlab('parity.psth_glm_mean_hz = psth_glm_mean_hz;')\n", + "# MATLAB L818: parity.lambda_mean_hz = lambda_mean_hz;\n", + "_matlab('parity.lambda_mean_hz = lambda_mean_hz;')\n", + "# MATLAB L819: \n", + "#\n", + "# MATLAB L820: % Because currently the psthGLM estimated the psth coefficients in each bin\n", + "# Because currently the psthGLM estimated the psth coefficients in each bin\n", + "# MATLAB L821: % for each realization, we want the show the mean and standard error of the\n", + "# for each realization, we want the show the mean and standard error of the\n", + "# MATLAB L822: % cofficient in each bin. We make the upper and lower confidence bounds\n", + "# cofficient in each bin. We make the upper and lower confidence bounds\n", + "# MATLAB L823: % equal to 1/sqrt(numRealization)=1/sqrt(psth.dimension) to view the\n", + "# equal to 1/sqrt(numRealization)=1/sqrt(psth.dimension) to view the\n", + "# MATLAB L824: % standard error instead of the standard deviation\n", + "# standard error instead of the standard deviation\n", + "# MATLAB L1000: % Note the mean of the PSTH estimated via the GLM model and the PSTH computed via standard methods agree precisely. The benefit of the GLM estimated PSTH is the presence of confidence bounds on the estimate. Both the standard and GLM PSTH are in close agreement with the \"true\" underlying rate function (conditional intensity function) used in this simulated example. Both the PSTH and PSTHGLM code could be updated in the future to allow for variable bin sizes (e.g. in the vein of Baysian Adaptive Regression Splines by Wallstrom, Leibner and Kass). Alternatively, porting of BARS to Matlab may allow for it to be easily integrated into the nSTAT toolbox.\n", + "# Note the mean of the PSTH estimated via the GLM model and the PSTH computed via standard methods agree precisely. The benefit of the GLM estimated PSTH is the presence of confidence bounds on the estimate. Both the standard and GLM PSTH are in close agreement with the \"true\" underlying rate function (conditional intensity function) used in this simulated example. Both the PSTH and PSTHGLM code could be updated in the future to allow for variable bin sizes (e.g. in the vein of Baysian Adaptive Regression Splines by Wallstrom, Leibner and Kass). Alternatively, porting of BARS to Matlab may allow for it to be easily integrated into the nSTAT toolbox.\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "data", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 2, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/PSTHEstimation.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "PSTHEstimation" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/SignalObjExamples.ipynb b/notebooks/SignalObjExamples.ipynb index 8b2274d1..5ffa8066 100644 --- a/notebooks/SignalObjExamples.ipynb +++ b/notebooks/SignalObjExamples.ipynb @@ -3,263 +3,389 @@ { "cell_type": "code", "execution_count": null, - "id": "signalobjexamples-00", + "id": "e79a7f5a", "metadata": {}, "outputs": [], "source": [ - "# Topic: SignalObjExamples\n", - "# Execution group: smoke\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/SignalObjExamples.md\n" + "# AUTO-GENERATED FROM MATLAB SignalObjExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", + "import matplotlib\n", + "matplotlib.use(\"Agg\")\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='SignalObjExamples', output_root=OUTPUT_ROOT, expected_count=16)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Using the SignalObj Class\n", + "# Using the SignalObj Class\n", + "# MATLAB L200: % In this file we will give several examples of how the SignalObj can be used. A description of all of the properties of SignalObj can be found at: SignalObj Class Definition\n", + "# In this file we will give several examples of how the SignalObj can be used. A description of all of the properties of SignalObj can be found at: SignalObj Class Definition\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "signalobjexamples-01", + "id": "1b8b7d98", "metadata": {}, "outputs": [], "source": [ - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"SignalObjExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"SignalObjExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"SignalObjExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"SignalObjExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"SignalObjExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "# SECTION 1: Example 1: Defining and Plotting Signals\n", + "# MATLAB L400: % Define a two dimensional SignalObj, s, representing two voltage signals that were v1 and v2 aquired simultaneously at 100Hz. Another SignalObj, s1 , is created from just v1. Both signals are plotted.\n", + "# Define a two dimensional SignalObj, s, representing two voltage signals that were v1 and v2 aquired simultaneously at 100Hz. Another SignalObj, s1 , is created from just v1. Both signals are plotted.\n", + "# MATLAB L500: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L501: sampleRate=100; t=0:1/sampleRate:10; freq=2;\n", + "_matlab('sampleRate=100; t=0:1/sampleRate:10; freq=2;')\n", + "# MATLAB L502: v1=sin(2*pi*freq*t); v2=sin(v1.^2); v=[v1;v2];\n", + "_matlab('v1=sin(2*pi*freq*t); v2=sin(v1.^2); v=[v1;v2];')\n", + "# MATLAB L503: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", + "_matlab(\"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\")\n", + "# MATLAB L504: s1=SignalObj(t,v1,'Voltage','time','s','V',{'v1'});\n", + "_matlab(\"s1=SignalObj(t,v1,'Voltage','time','s','V',{'v1'});\")\n", + "# MATLAB L505: subplot(2,1,1); s.plot;\n", + "__tracker.new_figure('subplot(2,1,1)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab('subplot(2,1,1); s.plot;')\n", + "# MATLAB L506: subplot(2,1,2); s1.plot;\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('s1.plot')\n", + "_matlab('subplot(2,1,2); s1.plot;')\n", + "# MATLAB L700: % Note how the legend show the appropriate labels. If the dataLabels had not been set, the legend would not appear.\n", + "# Note how the legend show the appropriate labels. If the dataLabels had not been set, the legend would not appear.\n", + "# MATLAB L800: % Instead of defining a new SignalObj, s1, the v2 data in s can be masked away and then the plot will only show the data of interest. It is important to note that setMask is used to set which signals should remain visible. Also note that when a data is masked, converting the SignalObj to a Matrix only returns the visible data. A new SignalObj can be created from the orignal SignalObj which only contains the data of interest. Lastly, the all labeled components can be accessed independently via the vars subfield.\n", + "# Instead of defining a new SignalObj, s1, the v2 data in s can be masked away and then the plot will only show the data of interest. It is important to note that setMask is used to set which signals should remain visible. Also note that when a data is masked, converting the SignalObj to a Matrix only returns the visible data. A new SignalObj can be created from the orignal SignalObj which only contains the data of interest. Lastly, the all labeled components can be accessed independently via the vars subfield.\n", + "# MATLAB L900: subplot(2,1,1); s.setMask({'v1'}); s.plot; s.resetMask;\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab(\"subplot(2,1,1); s.setMask({'v1'}); s.plot; s.resetMask;\")\n", + "# MATLAB L901: subplot(2,1,2); s.setMask({'v2'}); s.plot; size(s.dataToMatrix)\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab(\"subplot(2,1,2); s.setMask({'v2'}); s.plot; size(s.dataToMatrix)\")\n", + "# MATLAB L902: s.resetMask;\n", + "_matlab('s.resetMask;')\n", + "# MATLAB L1100: % Note about repeated dataLabels It is possible to use SignalObj's to store different realizations of the same physical signal. For example, independent measurements of v1 at two distinct experiments.\n", + "# Note about repeated dataLabels It is possible to use SignalObj's to store different realizations of the same physical signal. For example, independent measurements of v1 at two distinct experiments.\n", + "# MATLAB L1200: s=SignalObj(t,[v1; v1; v2] ,'Voltage','time','s','V',{'v1','v1','v2'});\n", + "_matlab(\"s=SignalObj(t,[v1; v1; v2] ,'Voltage','time','s','V',{'v1','v1','v2'});\")\n", + "# MATLAB L1201: s.getSubSignal({'v1'}); %returns a SignalObj with both realizations of v1\n", + "_matlab(\"s.getSubSignal({'v1'}); %returns a SignalObj with both realizations of v1\")\n", + "# MATLAB L1202: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L1203: s.getSubSignal({'v1'}).plot;\n", + "__tracker.annotate(\"s.getSubSignal({'v1'}).plot\")\n", + "_matlab(\"s.getSubSignal({'v1'}).plot;\")\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "signalobjexamples-02", + "id": "fe606d4d", "metadata": {}, "outputs": [], "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"sampleRate=100; t=0:1/sampleRate:10; freq=2;\",\n", - " \"v1=sin(2*pi*freq*t); v2=sin(v1.^2); v=[v1;v2];\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"s1=SignalObj(t,v1,'Voltage','time','s','V',{'v1'});\",\n", - " \"subplot(2,1,1); s.plot;\",\n", - " \"subplot(2,1,2); s1.plot;\",\n", - " \"subplot(2,1,1); s.setMask({'v1'}); s.plot; s.resetMask;\",\n", - " \"subplot(2,1,2); s.setMask({'v2'}); s.plot; size(s.dataToMatrix)\",\n", - " \"s.resetMask;\",\n", - " \"s=SignalObj(t,[v1; v1; v2] ,'Voltage','time','s','V',{'v1','v1','v2'});\",\n", - " \"s.getSubSignal({'v1'}); %returns a SignalObj with both realizations of v1\",\n", - " \"figure\",\n", - " \"s.getSubSignal({'v1'}).plot;\",\n", - " \"figure\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"subplot(2,1,1); s.plot;\",\n", - " \"subplot(2,1,2); s.setXlabel('distance'); s.setXUnits('cm'); s.plot;\",\n", - " \"figure\",\n", - " \"subplot(2,1,1); s.setDataLabels({'r1','r2'}); s.setYLabel('Temperature'); s.setYUnits('C'); s.plot;\",\n", - " \"subplot(2,1,2); s.setMaxTime(14); s.setMinTime(-2); s.plot;\",\n", - " \"s.setName('testName'); %should work since we are using a method\",\n", - " \"if(strcmp(s.name,'testName'))\",\n", - " \"fprintf('Name successfully set \\\\n');\",\n", - " \"else\",\n", - " \"fprintf('Could not set name \\\\n');\",\n", - " \"end\",\n", - " \"figure\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"subplot(2,1,1); s.plot('v1',{{' ''k'' '}});\",\n", - " \"subplot(2,1,2); s.plot('all',{{' ''k'' '},{' ''-.g'' '}});\",\n", - " \"figure\",\n", - " \"subplot(2,1,1); s.plot({'v1','v2'});\",\n", - " \"subplot(2,1,2); s.plot({'v1','v2'},{{' ''k'' '},{' ''-.g'' '}});\",\n", - " \"figure\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"s1=s.resample(.1*sampleRate);\",\n", - " \"subplot(2,1,1); s.plot;\",\n", - " \"subplot(2,1,2); s1.plot;\",\n", - " \"figure\",\n", - " \"subplot(2,1,1); s.getSigInTimeWindow(-2,3).plot;\",\n", - " \"subplot(2,1,2); s.plot;\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"figure\",\n", - " \"s2=mean(s); %mean of each dimension;\",\n", - " \"s5=s-s2; %zero mean version of s;\",\n", - " \"s5.plot;\",\n", - " \"figure\",\n", - " \"s2=mean(s,2); %mean of s across its dimensions;\",\n", - " \"s2.plot;\",\n", - " \"figure\",\n", - " \"s4=2*s+s5;\",\n", - " \"s4.plot;\",\n", - " \"figure\",\n", - " \"subplot(3,1,1);\",\n", - " \"s.integral.plot;\",\n", - " \"subplot(3,1,2);\",\n", - " \"s.derivative.plot;\",\n", - " \"subplot(3,1,3);\",\n", - " \"s6=s.integral.derivative-s; %should equal zero;\",\n", - " \"s6.plot;\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"figure;\",\n", - " \"s.MTMspectrum;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for SignalObjExamples.\")\n" + "# SECTION 2: Example 2: Changing Signal Properties\n", + "# MATLAB L1500: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L1501: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", + "_matlab(\"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\")\n", + "# MATLAB L1502: subplot(2,1,1); s.plot;\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab('subplot(2,1,1); s.plot;')\n", + "# MATLAB L1503: subplot(2,1,2); s.setXlabel('distance'); s.setXUnits('cm'); s.plot;\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab(\"subplot(2,1,2); s.setXlabel('distance'); s.setXUnits('cm'); s.plot;\")\n", + "# MATLAB L1700: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L1701: subplot(2,1,1); s.setDataLabels({'r1','r2'}); s.setYLabel('Temperature'); s.setYUnits('C'); s.plot;\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab(\"subplot(2,1,1); s.setDataLabels({'r1','r2'}); s.setYLabel('Temperature'); s.setYUnits('C'); s.plot;\")\n", + "# MATLAB L1702: subplot(2,1,2); s.setMaxTime(14); s.setMinTime(-2); s.plot;\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab('subplot(2,1,2); s.setMaxTime(14); s.setMinTime(-2); s.plot;')\n", + "# MATLAB L1703: \n", + "#\n", + "# MATLAB L1704: s.setName('testName'); %should work since we are using a method\n", + "_matlab(\"s.setName('testName'); %should work since we are using a method\")\n", + "# MATLAB L1705: if(strcmp(s.name,'testName'))\n", + "_matlab(\"if(strcmp(s.name,'testName'))\")\n", + "# MATLAB L1706: fprintf('Name successfully set \\n');\n", + "_matlab(\"fprintf('Name successfully set \\\\n');\")\n", + "# MATLAB L1707: else\n", + "_matlab('else')\n", + "# MATLAB L1708: fprintf('Could not set name \\n');\n", + "_matlab(\"fprintf('Could not set name \\\\n');\")\n", + "# MATLAB L1709: end\n", + "_matlab('end')\n", + "# MATLAB L1710: % s.name = 'testName'; %returns an error because the field is private;\n", + "# s.name = 'testName'; %returns an error because the field is private;\n", + "# MATLAB L1900: % setMaxTime and setMinTime can be given a second parameter, holdVals, that determines whether the endpoint values are kept or set to zero if the times being set are outside the original window of the data.\n", + "# setMaxTime and setMinTime can be given a second parameter, holdVals, that determines whether the endpoint values are kept or set to zero if the times being set are outside the original window of the data.\n", + "# MATLAB L2000: % Plotting properties for individual components of the data can be set via the when plotting or by call the setPlotProps method.\n", + "# Plotting properties for individual components of the data can be set via the when plotting or by call the setPlotProps method.\n", + "# MATLAB L2100: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L2101: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", + "_matlab(\"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\")\n", + "# MATLAB L2102: subplot(2,1,1); s.plot('v1',{{' ''k'' '}});\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate(\"s.plot('v1',{{' ''k'' '}})\")\n", + "_matlab(\"subplot(2,1,1); s.plot('v1',{{' ''k'' '}});\")\n", + "# MATLAB L2103: subplot(2,1,2); s.plot('all',{{' ''k'' '},{' ''-.g'' '}});\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate(\"s.plot('all',{{' ''k'' '},{' ''-.g'' '}})\")\n", + "_matlab(\"subplot(2,1,2); s.plot('all',{{' ''k'' '},{' ''-.g'' '}});\")\n", + "# MATLAB L2300: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L2301: subplot(2,1,1); s.plot({'v1','v2'});\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate(\"s.plot({'v1','v2'})\")\n", + "_matlab(\"subplot(2,1,1); s.plot({'v1','v2'});\")\n", + "# MATLAB L2302: subplot(2,1,2); s.plot({'v1','v2'},{{' ''k'' '},{' ''-.g'' '}});\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate(\"s.plot({'v1','v2'},{{' ''k'' '},{' ''-.g'' '}})\")\n", + "_matlab(\"subplot(2,1,2); s.plot({'v1','v2'},{{' ''k'' '},{' ''-.g'' '}});\")\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "signalobjexamples-03", + "id": "997e96be", "metadata": {}, "outputs": [], "source": [ - "# SignalObjExamples: fixture-backed SignalObj parity checks.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "from nstat.compat.matlab import SignalObj\n", - "\n", - "m = loadmat(Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat\", squeeze_me=True)\n", - "t = np.asarray(m[\"time_sig\"], dtype=float).reshape(-1); v1 = np.asarray(m[\"v1_sig\"], dtype=float).reshape(-1); v2 = np.asarray(m[\"v2_sig\"], dtype=float).reshape(-1)\n", - "matlab_line(\"figure\")\n", - "matlab_line(\"s.periodogram;\")\n", - "matlab_line(\"sampleRate=5000; t=0:1/sampleRate:1; t=t'; freq=2;\")\n", - "matlab_line(\"v1=sin(2*pi*freq*t); v2=sin(v1.^2);\")\n", - "matlab_line(\"noise=.1*randn(length(t),6);\")\n", - "matlab_line(\"data= [v1 v2 v2 v1 v2 v1] + noise;\")\n", - "matlab_line(\"s=SignalObj(t,data,'Voltage','time','s','V',{'v1','v2','v2','v1','v1','v2'});\")\n", - "matlab_line(\"figure;\")\n", - "matlab_line(\"subplot(2,1,1); s.plot;\")\n", - "matlab_line(\"subplot(2,1,2); s.plotAllVariability;\")\n", - "matlab_line(\"s.plotVariability;\")\n", - "matlab_line(\"figure;\")\n", - "matlab_line(\"subplot(3,1,1); s.plotAllVariability('b');\")\n", - "matlab_line(\"subplot(3,1,2); s.plotAllVariability('g',2);\")\n", - "matlab_line(\"subplot(3,1,3); s.plotAllVariability('c',3,2,1);\")\n", - "matlab_line(\"parity = struct();\")\n", - "matlab_line(\"parity.sample_rate_hz = sampleRate;\")\n", - "s = SignalObj(time=t, data=np.column_stack([v1, v2]), name=\"Voltage\", units=\"V\").setDataLabels([\"v1\", \"v2\"]).setXlabel(\"time\").setXUnits(\"s\").setYLabel(\"Voltage\").setYUnits(\"V\")\n", - "s.setMask([\"v1\"]); masked_cols = float(len(s.findIndFromDataMask())); s.resetMask()\n", - "s_resampled = s.resample(float(np.asarray(m[\"resample_hz_sig\"]).reshape(-1)[0])); s_win = s.getSigInTimeWindow(float(np.asarray(m[\"window_t0_sig\"]).reshape(-1)[0]), float(np.asarray(m[\"window_t1_sig\"]).reshape(-1)[0]))\n", - "f_per, p_per = s.periodogram(); expected_peak = int(np.asarray(m[\"periodogram_peak_idx_sig\"], dtype=int).reshape(-1)[0]); peak_idx = int(np.argmax(p_per))\n", - "s.setName(\"testName\")\n", - "s_der = s.derivative()\n", - "s_int = s.integral()\n", - "s_sub = s.getSubSignal([0])\n", - "s_repeat = SignalObj(time=t, data=np.column_stack([v1, v1, v2]), name=\"Voltage\", units=\"V\").setDataLabels([\"v1\", \"v1\", \"v2\"])\n", - "s_repeat_v1 = s_repeat.getSubSignal([0, 1])\n", - "\n", - "fig, ax = plt.subplots(2, 2, figsize=(10, 6))\n", - "plt.sca(ax[0, 0]); s.plot(); ax[0, 0].set_title(\"SignalObj.plot\")\n", - "plt.sca(ax[0, 1]); s_resampled.plot(); ax[0, 1].set_title(\"resample\")\n", - "plt.sca(ax[1, 0]); s_win.plot(); ax[1, 0].set_title(\"time window\")\n", - "ax[1, 1].plot(f_per, p_per, \"k\", linewidth=1.0); ax[1, 1].set_title(\"periodogram\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "assert masked_cols == float(np.asarray(m[\"masked_cols_sig\"]).reshape(-1)[0])\n", - "assert peak_idx == expected_peak\n", - "assert s.getNumSamples() == int(np.asarray(m[\"n_samples_sig\"], dtype=int).reshape(-1)[0])\n", - "assert s_resampled.getNumSamples() == int(np.asarray(m[\"resampled_n_samples_sig\"], dtype=int).reshape(-1)[0])\n", - "assert s_win.getNumSamples() == int(np.asarray(m[\"window_n_samples_sig\"], dtype=int).reshape(-1)[0])\n", - "assert s_der.getNumSamples() == s.getNumSamples()\n", - "assert s_int.shape[0] == s.getNumSamples()\n", - "assert s_sub.getNumSignals() == 1\n", - "assert s_repeat_v1.getNumSignals() == 2\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"masked_cols\": float(masked_cols),\n", - " \"periodogram_peak_idx\": float(peak_idx),\n", - " \"resampled_samples\": float(s_resampled.getNumSamples()),\n", - " \"window_samples\": float(s_win.getNumSamples()),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"masked_cols\": (1.0, 1.0),\n", - " \"periodogram_peak_idx\": (0.0, 50000.0),\n", - " \"resampled_samples\": (10.0, 2000.0),\n", - " \"window_samples\": (10.0, 5000.0),\n", - "}\n" + "# SECTION 3: Example 3: Resampling and Windowing SignalObjs\n", + "# MATLAB L2600: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L2601: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", + "_matlab(\"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\")\n", + "# MATLAB L2602: s1=s.resample(.1*sampleRate);\n", + "_matlab('s1=s.resample(.1*sampleRate);')\n", + "# MATLAB L2603: subplot(2,1,1); s.plot;\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab('subplot(2,1,1); s.plot;')\n", + "# MATLAB L2604: subplot(2,1,2); s1.plot;\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('s1.plot')\n", + "_matlab('subplot(2,1,2); s1.plot;')\n", + "# MATLAB L2800: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L2801: subplot(2,1,1); s.getSigInTimeWindow(-2,3).plot;\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('s.getSigInTimeWindow(-2,3).plot')\n", + "_matlab('subplot(2,1,1); s.getSigInTimeWindow(-2,3).plot;')\n", + "# MATLAB L2802: subplot(2,1,2); s.plot;\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab('subplot(2,1,2); s.plot;')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "signalobjexamples-04", + "id": "9c9fe904", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 4: Example 4: SignalObj Mathematical Operations\n", + "# MATLAB L3100: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", + "_matlab(\"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\")\n", + "# MATLAB L3101: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L3102: s2=mean(s); %mean of each dimension;\n", + "_matlab('s2=mean(s); %mean of each dimension;')\n", + "# MATLAB L3103: s5=s-s2; %zero mean version of s;\n", + "_matlab('s5=s-s2; %zero mean version of s;')\n", + "# MATLAB L3104: s5.plot;\n", + "__tracker.annotate('s5.plot')\n", + "_matlab('s5.plot;')\n", + "# MATLAB L3105: \n", + "#\n", + "# MATLAB L3106: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L3107: s2=mean(s,2); %mean of s across its dimensions;\n", + "_matlab('s2=mean(s,2); %mean of s across its dimensions;')\n", + "# MATLAB L3108: s2.plot;\n", + "__tracker.annotate('s2.plot')\n", + "_matlab('s2.plot;')\n", + "# MATLAB L3300: % SignalObj's can be added, subtracted, and multiplied.\\\n", + "# SignalObj's can be added, subtracted, and multiplied.\\\n", + "# MATLAB L3400: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L3401: s4=2*s+s5;\n", + "_matlab('s4=2*s+s5;')\n", + "# MATLAB L3402: s4.plot;\n", + "__tracker.annotate('s4.plot')\n", + "_matlab('s4.plot;')\n", + "# MATLAB L3403: \n", + "#\n", + "# MATLAB L3404: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L3405: subplot(3,1,1);\n", + "__tracker.annotate('subplot(3,1,1)')\n", + "_matlab('subplot(3,1,1);')\n", + "# MATLAB L3406: s.integral.plot;\n", + "__tracker.annotate('s.integral.plot')\n", + "_matlab('s.integral.plot;')\n", + "# MATLAB L3407: subplot(3,1,2);\n", + "__tracker.annotate('subplot(3,1,2)')\n", + "_matlab('subplot(3,1,2);')\n", + "# MATLAB L3408: s.derivative.plot;\n", + "__tracker.annotate('s.derivative.plot')\n", + "_matlab('s.derivative.plot;')\n", + "# MATLAB L3409: subplot(3,1,3);\n", + "__tracker.annotate('subplot(3,1,3)')\n", + "_matlab('subplot(3,1,3);')\n", + "# MATLAB L3410: s6=s.integral.derivative-s; %should equal zero;\n", + "_matlab('s6=s.integral.derivative-s; %should equal zero;')\n", + "# MATLAB L3411: s6.plot;\n", + "__tracker.annotate('s6.plot')\n", + "_matlab('s6.plot;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96216c16", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 5: Example 5: Spectra\n", + "# MATLAB L3700: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", + "_matlab(\"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\")\n", + "# MATLAB L3701: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L3702: s.MTMspectrum;\n", + "_matlab('s.MTMspectrum;')\n", + "# MATLAB L3703: \n", + "#\n", + "# MATLAB L3704: figure\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure')\n", + "# MATLAB L3705: s.periodogram;\n", + "_matlab('s.periodogram;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "809af72f", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 6: Example 6: View signal variability\n", + "# MATLAB L4000: % We can look at the variability of signals with regards to their labels or or irrespective of their labels. Lets create a SignalObj that has several components, and some noise. We mislabel two signals to add alot of variability for illustration\n", + "# We can look at the variability of signals with regards to their labels or or irrespective of their labels. Lets create a SignalObj that has several components, and some noise. We mislabel two signals to add alot of variability for illustration\n", + "# MATLAB L4100: sampleRate=5000; t=0:1/sampleRate:1; t=t'; freq=2;\n", + "_matlab(\"sampleRate=5000; t=0:1/sampleRate:1; t=t'; freq=2;\")\n", + "# MATLAB L4101: v1=sin(2*pi*freq*t); v2=sin(v1.^2);\n", + "_matlab('v1=sin(2*pi*freq*t); v2=sin(v1.^2);')\n", + "# MATLAB L4102: noise=.1*randn(length(t),6); %gaussian random noise\n", + "_matlab('noise=.1*randn(length(t),6); %gaussian random noise')\n", + "# MATLAB L4103: data= [v1 v2 v2 v1 v2 v1] + noise;\n", + "_matlab('data= [v1 v2 v2 v1 v2 v1] + noise;')\n", + "# MATLAB L4104: s=SignalObj(t,data,'Voltage','time','s','V',{'v1','v2','v2','v1','v1','v2'});\n", + "_matlab(\"s=SignalObj(t,data,'Voltage','time','s','V',{'v1','v2','v2','v1','v1','v2'});\")\n", + "# MATLAB L4105: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L4106: subplot(2,1,1); s.plot;\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "__tracker.annotate('s.plot')\n", + "_matlab('subplot(2,1,1); s.plot;')\n", + "# MATLAB L4107: subplot(2,1,2); s.plotAllVariability; %disregards labels;\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "_matlab('subplot(2,1,2); s.plotAllVariability; %disregards labels;')\n", + "# MATLAB L4108: s.plotVariability; %creates two figures, one for 'v1' and one for 'v2'\n", + "_matlab(\"s.plotVariability; %creates two figures, one for 'v1' and one for 'v2'\")\n", + "# MATLAB L4300: % sObj.plotAllVariability assumes that all the data can be considered together. It also allows more custimization of the plotting properties. Example we can specify a different faceColor by passing the color in the same format as plot. Assymetric confidence intervals can be specified. If the CIs are single numbers, they specify the multiple of the standard deviations to use (default is 1). If they are the same length as the SignalObj, then it specifies the actual values above and/or below the mean at each point in time. If ciLower is not specifed, it is assumed to equal ciUpper. For convinience the inputs to plotAllVariability are: s.plotAllVariability(sObj,faceColor,linewidth,ciUpper,ciLower)\n", + "# sObj.plotAllVariability assumes that all the data can be considered together. It also allows more custimization of the plotting properties. Example we can specify a different faceColor by passing the color in the same format as plot. Assymetric confidence intervals can be specified. If the CIs are single numbers, they specify the multiple of the standard deviations to use (default is 1). If they are the same length as the SignalObj, then it specifies the actual values above and/or below the mean at each point in time. If ciLower is not specifed, it is assumed to equal ciUpper. For convinience the inputs to plotAllVariability are: s.plotAllVariability(sObj,faceColor,linewidth,ciUpper,ciLower)\n", + "# MATLAB L4400: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L4401: %blue color for CI patch;\n", + "# blue color for CI patch;\n", + "# MATLAB L4402: subplot(3,1,1); s.plotAllVariability('b');\n", + "__tracker.annotate('subplot(3,1,1)')\n", + "_matlab(\"subplot(3,1,1); s.plotAllVariability('b');\")\n", + "# MATLAB L4403: %green color and lineWidth=2;\n", + "# green color and lineWidth=2;\n", + "# MATLAB L4404: subplot(3,1,2); s.plotAllVariability('g',2);\n", + "__tracker.annotate('subplot(3,1,2)')\n", + "_matlab(\"subplot(3,1,2); s.plotAllVariability('g',2);\")\n", + "# MATLAB L4405: %cyan, lineWidth=3, 2*std for top CI, and 1*std for bottom CI\n", + "# cyan, lineWidth=3, 2*std for top CI, and 1*std for bottom CI\n", + "# MATLAB L4406: subplot(3,1,3); s.plotAllVariability('c',3,2,1);\n", + "__tracker.annotate('subplot(3,1,3)')\n", + "_matlab(\"subplot(3,1,3); s.plotAllVariability('c',3,2,1);\")\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 16, "run_group": "smoke", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/SignalObjExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "SignalObjExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/StimulusDecode2D.ipynb b/notebooks/StimulusDecode2D.ipynb index ec0579e8..c3f66c36 100644 --- a/notebooks/StimulusDecode2D.ipynb +++ b/notebooks/StimulusDecode2D.ipynb @@ -3,253 +3,328 @@ { "cell_type": "code", "execution_count": null, - "id": "stimulusdecode2d-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: StimulusDecode2D\n", - "# Execution group: full\n", - "# Workflow family: decoding_2d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/StimulusDecode2D.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "stimulusdecode2d-01", + "id": "0e9b5855", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB StimulusDecode2D.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "TOPIC = \"StimulusDecode2D\"\n", - "FAMILY = \"decoding_2d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='StimulusDecode2D', output_root=OUTPUT_ROOT, expected_count=4)\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"StimulusDecode2D: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"StimulusDecode2D: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"StimulusDecode2D: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"StimulusDecode2D: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "stimulusdecode2d-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"delta = 0.001;\",\n", - " \"Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"px = zeros(1,length(time));\",\n", - " \"py = zeros(1,length(time));\",\n", - " \"Q=.01;\",\n", - " \"r = Q.*randn(2,length(time));\",\n", - " \"vx = cumsum(r(1,:))';\",\n", - " \"vy = cumsum(r(2,:))';\",\n", - " \"velSig = SignalObj(time, [vx, vy],'vel');\",\n", - " \"posSig = velSig.integral;\",\n", - " \"posData = posSig.data;\",\n", - " \"px = posData(:,1);\",\n", - " \"py = posData(:,2);\",\n", - " \"figure;\",\n", - " \"plot(px,py);\",\n", - " \"title('Simulated X-Y trajectory');\",\n", - " \"xlabel('x'); ylabel('y');\",\n", - " \"clear lambdaCIF lambda tempSpikeColl n spikeColl\",\n", - " \"numRealizations=80;\",\n", - " \"coeffs = -abs(1*randn(numRealizations,5));\",\n", - " \"coeffs = [-2*abs(randn(numRealizations,1)) coeffs];\",\n", - " \"dataMat = [ones(length(time),1) px py px.^2 py.^2 px.*py];\",\n", - " \"for i=1:numRealizations\",\n", - " \"tempData = exp(dataMat*coeffs(i,:)');\",\n", - " \"lambdaData = tempData./(1+tempData);\",\n", - " \"lambda{i}=Covariate(time,lambdaData./delta, '\\\\Lambda(t)','time','s','Hz',{strcat('\\\\lambda_{',num2str(i),'}')},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);\",\n", - " \"n{i} = tempSpikeColl{i}.getNST(1);\",\n", - " \"n{i}.setName(num2str(i));\",\n", - " \"try\",\n", - " \"lambdaCIF{i} = CIF(coeffs(i,:),{'1','x','y','x^2','y^2','x*y'},{'x','y'},'binomial');\",\n", - " \"catch ME_sym\",\n", - " \"if(i==1)\",\n", - " \"warning('StimulusDecode2D:SymbolicCIFFallback', ...\",\n", - " \"['CIF symbolic setup failed (' ME_sym.identifier '). Decoder will use linear fallback.']);\",\n", - " \"end\",\n", - " \"lambdaCIF{i} = [];\",\n", - " \"end\",\n", - " \"end\",\n", - " \"figure;\",\n", - " \"for i=1:length(lambda)\",\n", - " \"lambda{i}.plot;\",\n", - " \"end\",\n", - " \"legend off;\",\n", - " \"clear placeField;\",\n", - " \"[X,Y]=meshgrid(-2:.1:2,-2:.1:2);\",\n", - " \"figure;\",\n", - " \"for i=1:numRealizations\",\n", - " \"tempData = coeffs(i,1) + coeffs(i,2)*X + coeffs(i,3)*Y +coeffs(i,4)*X.^2 + coeffs(i,5)*Y.^2 + coeffs(i,6).*X.*Y;\",\n", - " \"placeField{i} = exp(tempData)./(1+exp(tempData))./delta; %rate based on logistic link function\",\n", - " \"end\",\n", - " \"fact=factor(numRealizations);\",\n", - " \"for i=1:numRealizations\",\n", - " \"if(length(fact)==1)\",\n", - " \"subplot(1,numRealizations,i);\",\n", - " \"elseif(length(fact)==2)\",\n", - " \"subplot(fact(1),fact(2),i);\",\n", - " \"elseif(length(fact)==3)\",\n", - " \"subplot(fact(1)*fact(2),fact(3),i);\",\n", - " \"end\",\n", - " \"pcolor(X,Y,placeField{i}), shading interp\",\n", - " \"axis square;\",\n", - " \"set(gca,'xtick',[],'ytick',[]);\",\n", - " \"end\",\n", - " \"spikeColl = nstColl(n);\",\n", - " \"spikeColl.resample(1/delta);\",\n", - " \"dN = spikeColl.dataToMatrix;\",\n", - " \"vx=var(px(2:end)-px(1:end-1));\",\n", - " \"vy=var(py(2:end)-py(1:end-1));\",\n", - " \"Q=[vx 0;0 vy];\",\n", - " \"Px0=.1*eye(2,2); A=1*eye(2,2);\",\n", - " \"decode_method = 'PPDecodeFilter';\",\n", - " \"try\",\n", - " \"[x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\",\n", - " \"catch ME_decode\",\n", - " \"warning('StimulusDecode2D:SymbolicDecodeFallback', ...\",\n", - " \"['PPDecodeFilter failed (' ME_decode.identifier '). Falling back to PPDecodeFilterLinear.']);\",\n", - " \"decode_method = 'PPDecodeFilterLinear';\",\n", - " \"mu_linear = coeffs(:,1);\",\n", - " \"beta_linear = coeffs(:,2:3)';\",\n", - " \"[x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN', mu_linear, beta_linear, 'binomial', delta);\",\n", - " \"end\",\n", - " \"nCommon = min(length(px),size(x_u,2));\",\n", - " \"decode_rmse = sqrt(mean((x_u(1,1:nCommon)'-px(1:nCommon)).^2 + (x_u(2,1:nCommon)'-py(1:nCommon)).^2));\",\n", - " \"num_cells = numRealizations;\",\n", - " \"figure;\",\n", - " \"plot(x_u(1,:),x_u(2,:),'b',px,py,'k')\",\n", - " \"legend('predicted path','actual path');\",\n", - " \"parity = struct();\",\n", - " \"parity.num_cells = num_cells;\",\n", - " \"parity.decode_rmse = decode_rmse;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for StimulusDecode2D.\")\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % 2-D Stimulus Decode\n", + "# 2-D Stimulus Decode\n", + "# MATLAB L200: % Here we simulate hippocampal place cell receptive fields and their firing during a 2-d spatial task. We then use the ensemble firing activity to estimate the path based on the only the point process observations\n", + "# Here we simulate hippocampal place cell receptive fields and their firing during a 2-d spatial task. We then use the ensemble firing activity to estimate the path based on the only the point process observations\n", + "# MATLAB L300: delta = 0.001;\n", + "delta = 0.001\n", + "# MATLAB L301: Tmax = 1;\n", + "Tmax = 1\n", + "# MATLAB L302: time = 0:delta:Tmax;\n", + "_matlab('time = 0:delta:Tmax;')\n", + "# MATLAB L303: px = zeros(1,length(time));\n", + "_matlab('px = zeros(1,length(time));')\n", + "# MATLAB L304: py = zeros(1,length(time));\n", + "_matlab('py = zeros(1,length(time));')\n", + "# MATLAB L305: Q=.01;\n", + "Q = .01\n", + "# MATLAB L306: r = Q.*randn(2,length(time));\n", + "_matlab('r = Q.*randn(2,length(time));')\n", + "# MATLAB L307: vx = cumsum(r(1,:))';\n", + "_matlab(\"vx = cumsum(r(1,:))';\")\n", + "# MATLAB L308: vy = cumsum(r(2,:))';\n", + "_matlab(\"vy = cumsum(r(2,:))';\")\n", + "# MATLAB L309: \n", + "#\n", + "# MATLAB L310: velSig = SignalObj(time, [vx, vy],'vel');\n", + "_matlab(\"velSig = SignalObj(time, [vx, vy],'vel');\")\n", + "# MATLAB L311: posSig = velSig.integral;\n", + "_matlab('posSig = velSig.integral;')\n", + "# MATLAB L312: posData = posSig.data;\n", + "_matlab('posData = posSig.data;')\n", + "# MATLAB L313: px = posData(:,1);\n", + "_matlab('px = posData(:,1);')\n", + "# MATLAB L314: py = posData(:,2);\n", + "_matlab('py = posData(:,2);')\n", + "# MATLAB L315: % N=100; A=1; B=ones(1,N)./N;\n", + "# N=100; A=1; B=ones(1,N)./N;\n", + "# MATLAB L316: % px = filtfilt(B,A,px);\n", + "# px = filtfilt(B,A,px);\n", + "# MATLAB L317: % py = filtfilt(B,A,py);\n", + "# py = filtfilt(B,A,py);\n", + "# MATLAB L318: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L319: plot(px,py);\n", + "__tracker.annotate('plot(px,py)')\n", + "_matlab('plot(px,py);')\n", + "# MATLAB L320: title('Simulated X-Y trajectory');\n", + "_matlab(\"title('Simulated X-Y trajectory');\")\n", + "# MATLAB L321: xlabel('x'); ylabel('y');\n", + "plt.xlabel('x')\n", + "plt.ylabel('y')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "stimulusdecode2d-03", + "id": "1588ad8a", "metadata": {}, "outputs": [], "source": [ - "# StimulusDecode2D: fixture-backed 2D trajectory decoding parity check.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/StimulusDecode2D_gold.mat\"\n", - "m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False)\n", - "states = np.asarray(m[\"states_sd\"], dtype=float); latent = np.asarray(m[\"latent_sd\"], dtype=int).reshape(-1)\n", - "tuning = np.asarray(m[\"tuning_sd\"], dtype=float); spike_counts = np.asarray(m[\"spike_counts_sd\"], dtype=float)\n", - "decoded_center = DecodingAlgorithms.decode_weighted_center(spike_counts=spike_counts, tuning_curves=tuning)\n", - "decoded = np.clip(np.rint(decoded_center), 0, states.shape[0] - 1).astype(int)\n", - "xy_true = np.asarray(m[\"xy_true_sd\"], dtype=float); xy_decoded = states[decoded]\n", - "rmse = float(np.sqrt(np.mean(np.sum((xy_decoded - xy_true) ** 2, axis=1))))\n", - "expected_center = np.asarray(m[\"decoded_center_sd\"], dtype=float).reshape(-1); expected_decoded = np.asarray(m[\"decoded_sd\"], dtype=int).reshape(-1); expected_rmse = float(np.asarray(m[\"rmse_sd\"], dtype=float).reshape(-1)[0])\n", - "center_err = float(np.max(np.abs(decoded_center - expected_center))); decoded_mismatch = float(np.count_nonzero(decoded != expected_decoded)); rmse_err = float(abs(rmse - expected_rmse))\n", - "assert center_err <= 1e-8 and decoded_mismatch == 0.0 and rmse_err <= 1e-10\n", - "\n", - "side = int(round(np.sqrt(states.shape[0]))); field_idx = 3\n", - "fig, axes = plt.subplots(1, 2, figsize=(9.5, 4.5))\n", - "axes[0].plot(xy_true[:, 0], xy_true[:, 1], label=\"true\", linewidth=1.2)\n", - "axes[0].plot(xy_decoded[:, 0], xy_decoded[:, 1], label=\"decoded\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: decoded trajectory\"); axes[0].set_xlabel(\"x\"); axes[0].set_ylabel(\"y\"); axes[0].set_aspect(\"equal\", adjustable=\"box\"); axes[0].legend(loc=\"upper right\")\n", - "im = axes[1].imshow(tuning[field_idx].reshape(side, side), origin=\"lower\", extent=[0.0, 1.0, 0.0, 1.0], cmap=\"jet\", aspect=\"equal\")\n", - "axes[1].set_title(\"Example receptive field\"); axes[1].set_xlabel(\"x\"); axes[1].set_ylabel(\"y\"); fig.colorbar(im, ax=axes[1], fraction=0.04, pad=0.03)\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "CHECKPOINT_METRICS = {\"trajectory_rmse\": float(rmse), \"decoded_unique_states\": float(np.unique(decoded).size), \"decoded_center_max_abs_error\": center_err, \"decoded_mismatch_count\": decoded_mismatch}\n", - "CHECKPOINT_LIMITS = {\"trajectory_rmse\": (0.0, 1.5), \"decoded_unique_states\": (2.0, float(states.shape[0])), \"decoded_center_max_abs_error\": (0.0, 1e-8), \"decoded_mismatch_count\": (0.0, 0.0)}\n" + "# SECTION 1: Generate random receptive fields to simulate different neurons\n", + "# MATLAB L600: clear lambdaCIF lambda tempSpikeColl n spikeColl\n", + "pass\n", + "# MATLAB L601: numRealizations=80;\n", + "numRealizations = 80\n", + "# MATLAB L602: \n", + "#\n", + "# MATLAB L603: coeffs = -abs(1*randn(numRealizations,5));\n", + "_matlab('coeffs = -abs(1*randn(numRealizations,5));')\n", + "# MATLAB L604: coeffs = [-2*abs(randn(numRealizations,1)) coeffs];\n", + "_matlab('coeffs = [-2*abs(randn(numRealizations,1)) coeffs];')\n", + "# MATLAB L605: dataMat = [ones(length(time),1) px py px.^2 py.^2 px.*py];\n", + "_matlab('dataMat = [ones(length(time),1) px py px.^2 py.^2 px.*py];')\n", + "# MATLAB L606: for i=1:numRealizations\n", + "_matlab('for i=1:numRealizations')\n", + "# MATLAB L607: tempData = exp(dataMat*coeffs(i,:)');\n", + "_matlab(\"tempData = exp(dataMat*coeffs(i,:)');\")\n", + "# MATLAB L608: lambdaData = tempData./(1+tempData);\n", + "_matlab('lambdaData = tempData./(1+tempData);')\n", + "# MATLAB L609: lambda{i}=Covariate(time,lambdaData./delta, '\\Lambda(t)','time','s','Hz',{strcat('\\lambda_{',num2str(i),'}')},{{' ''b'', ''LineWidth'' ,2'}});\n", + "_matlab(\"lambda{i}=Covariate(time,lambdaData./delta, '\\\\Lambda(t)','time','s','Hz',{strcat('\\\\lambda_{',num2str(i),'}')},{{' ''b'', ''LineWidth'' ,2'}});\")\n", + "# MATLAB L610: \n", + "#\n", + "# MATLAB L611: tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);\n", + "_matlab('tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);')\n", + "# MATLAB L612: n{i} = tempSpikeColl{i}.getNST(1);\n", + "_matlab('n{i} = tempSpikeColl{i}.getNST(1);')\n", + "# MATLAB L613: n{i}.setName(num2str(i));\n", + "_matlab('n{i}.setName(num2str(i));')\n", + "# MATLAB L614: \n", + "#\n", + "# MATLAB L615: try\n", + "_matlab('try')\n", + "# MATLAB L616: lambdaCIF{i} = CIF(coeffs(i,:),{'1','x','y','x^2','y^2','x*y'},{'x','y'},'binomial');\n", + "_matlab(\"lambdaCIF{i} = CIF(coeffs(i,:),{'1','x','y','x^2','y^2','x*y'},{'x','y'},'binomial');\")\n", + "# MATLAB L617: catch ME_sym\n", + "_matlab('catch ME_sym')\n", + "# MATLAB L618: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L619: warning('StimulusDecode2D:SymbolicCIFFallback', ...\n", + "_matlab(\"warning('StimulusDecode2D:SymbolicCIFFallback', ...\")\n", + "# MATLAB L620: ['CIF symbolic setup failed (' ME_sym.identifier '). Decoder will use linear fallback.']);\n", + "_matlab(\"['CIF symbolic setup failed (' ME_sym.identifier '). Decoder will use linear fallback.']);\")\n", + "# MATLAB L621: end\n", + "_matlab('end')\n", + "# MATLAB L622: lambdaCIF{i} = [];\n", + "_matlab('lambdaCIF{i} = [];')\n", + "# MATLAB L623: end\n", + "_matlab('end')\n", + "# MATLAB L624: end\n", + "_matlab('end')\n", + "# MATLAB L625: \n", + "#\n", + "# MATLAB L626: \n", + "#\n", + "# MATLAB L627: % View the different neuron conditional intensity functions\n", + "# View the different neuron conditional intensity functions\n", + "# MATLAB L628: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L629: for i=1:length(lambda)\n", + "_matlab('for i=1:length(lambda)')\n", + "# MATLAB L630: lambda{i}.plot;\n", + "__tracker.annotate('lambda{i}.plot')\n", + "_matlab('lambda{i}.plot;')\n", + "# MATLAB L631: end\n", + "_matlab('end')\n", + "# MATLAB L632: legend off;\n", + "_matlab('legend off;')\n", + "# MATLAB L633: \n", + "#\n", + "# MATLAB L634: % Visualize Simulated Receptive Fields\n", + "# Visualize Simulated Receptive Fields\n", + "# MATLAB L635: clear placeField;\n", + "pass\n", + "# MATLAB L636: [X,Y]=meshgrid(-2:.1:2,-2:.1:2);\n", + "_matlab('[X,Y]=meshgrid(-2:.1:2,-2:.1:2);')\n", + "# MATLAB L637: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L638: \n", + "#\n", + "# MATLAB L639: for i=1:numRealizations\n", + "_matlab('for i=1:numRealizations')\n", + "# MATLAB L640: tempData = coeffs(i,1) + coeffs(i,2)*X + coeffs(i,3)*Y +coeffs(i,4)*X.^2 + coeffs(i,5)*Y.^2 + coeffs(i,6).*X.*Y;\n", + "_matlab('tempData = coeffs(i,1) + coeffs(i,2)*X + coeffs(i,3)*Y +coeffs(i,4)*X.^2 + coeffs(i,5)*Y.^2 + coeffs(i,6).*X.*Y;')\n", + "# MATLAB L641: placeField{i} = exp(tempData)./(1+exp(tempData))./delta; %rate based on logistic link function\n", + "_matlab('placeField{i} = exp(tempData)./(1+exp(tempData))./delta; %rate based on logistic link function')\n", + "# MATLAB L642: \n", + "#\n", + "# MATLAB L643: end\n", + "_matlab('end')\n", + "# MATLAB L644: \n", + "#\n", + "# MATLAB L645: fact=factor(numRealizations);\n", + "_matlab('fact=factor(numRealizations);')\n", + "# MATLAB L646: \n", + "#\n", + "# MATLAB L647: for i=1:numRealizations\n", + "_matlab('for i=1:numRealizations')\n", + "# MATLAB L648: if(length(fact)==1)\n", + "_matlab('if(length(fact)==1)')\n", + "# MATLAB L649: subplot(1,numRealizations,i);\n", + "__tracker.annotate('subplot(1,numRealizations,i)')\n", + "_matlab('subplot(1,numRealizations,i);')\n", + "# MATLAB L650: elseif(length(fact)==2)\n", + "_matlab('elseif(length(fact)==2)')\n", + "# MATLAB L651: subplot(fact(1),fact(2),i);\n", + "__tracker.annotate('subplot(fact(1),fact(2),i)')\n", + "_matlab('subplot(fact(1),fact(2),i);')\n", + "# MATLAB L652: elseif(length(fact)==3)\n", + "_matlab('elseif(length(fact)==3)')\n", + "# MATLAB L653: subplot(fact(1)*fact(2),fact(3),i);\n", + "__tracker.annotate('subplot(fact(1)*fact(2),fact(3),i)')\n", + "_matlab('subplot(fact(1)*fact(2),fact(3),i);')\n", + "# MATLAB L654: end\n", + "_matlab('end')\n", + "# MATLAB L655: pcolor(X,Y,placeField{i}), shading interp\n", + "__tracker.annotate('pcolor(X,Y,placeField{i}), shading interp')\n", + "_matlab('pcolor(X,Y,placeField{i}), shading interp')\n", + "# MATLAB L656: axis square;\n", + "_matlab('axis square;')\n", + "# MATLAB L657: set(gca,'xtick',[],'ytick',[]);\n", + "_matlab(\"set(gca,'xtick',[],'ytick',[]);\")\n", + "# MATLAB L658: \n", + "#\n", + "# MATLAB L659: end\n", + "_matlab('end')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "stimulusdecode2d-04", + "id": "8bf52d64", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 2: Decode the x-y trajectory\n", + "# MATLAB L900: spikeColl = nstColl(n);\n", + "_matlab('spikeColl = nstColl(n);')\n", + "# MATLAB L901: spikeColl.resample(1/delta);\n", + "_matlab('spikeColl.resample(1/delta);')\n", + "# MATLAB L902: dN = spikeColl.dataToMatrix;\n", + "_matlab('dN = spikeColl.dataToMatrix;')\n", + "# MATLAB L1100: vx=var(px(2:end)-px(1:end-1));\n", + "_matlab('vx=var(px(2:end)-px(1:end-1));')\n", + "# MATLAB L1101: vy=var(py(2:end)-py(1:end-1));\n", + "_matlab('vy=var(py(2:end)-py(1:end-1));')\n", + "# MATLAB L1102: Q=[vx 0;0 vy];\n", + "_matlab('Q=[vx 0;0 vy];')\n", + "# MATLAB L1103: Px0=.1*eye(2,2); A=1*eye(2,2);\n", + "_matlab('Px0=.1*eye(2,2); A=1*eye(2,2);')\n", + "# MATLAB L1104: decode_method = 'PPDecodeFilter';\n", + "_matlab(\"decode_method = 'PPDecodeFilter';\")\n", + "# MATLAB L1105: try\n", + "_matlab('try')\n", + "# MATLAB L1106: [x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\n", + "_matlab(\"[x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\")\n", + "# MATLAB L1107: catch ME_decode\n", + "_matlab('catch ME_decode')\n", + "# MATLAB L1108: warning('StimulusDecode2D:SymbolicDecodeFallback', ...\n", + "_matlab(\"warning('StimulusDecode2D:SymbolicDecodeFallback', ...\")\n", + "# MATLAB L1109: ['PPDecodeFilter failed (' ME_decode.identifier '). Falling back to PPDecodeFilterLinear.']);\n", + "_matlab(\"['PPDecodeFilter failed (' ME_decode.identifier '). Falling back to PPDecodeFilterLinear.']);\")\n", + "# MATLAB L1110: decode_method = 'PPDecodeFilterLinear';\n", + "_matlab(\"decode_method = 'PPDecodeFilterLinear';\")\n", + "# MATLAB L1111: mu_linear = coeffs(:,1);\n", + "_matlab('mu_linear = coeffs(:,1);')\n", + "# MATLAB L1112: beta_linear = coeffs(:,2:3)';\n", + "_matlab(\"beta_linear = coeffs(:,2:3)';\")\n", + "# MATLAB L1113: [x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN', mu_linear, beta_linear, 'binomial', delta);\n", + "_matlab(\"[x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN', mu_linear, beta_linear, 'binomial', delta);\")\n", + "# MATLAB L1114: end\n", + "_matlab('end')\n", + "# MATLAB L1115: nCommon = min(length(px),size(x_u,2));\n", + "_matlab('nCommon = min(length(px),size(x_u,2));')\n", + "# MATLAB L1116: decode_rmse = sqrt(mean((x_u(1,1:nCommon)'-px(1:nCommon)).^2 + (x_u(2,1:nCommon)'-py(1:nCommon)).^2));\n", + "_matlab(\"decode_rmse = sqrt(mean((x_u(1,1:nCommon)'-px(1:nCommon)).^2 + (x_u(2,1:nCommon)'-py(1:nCommon)).^2));\")\n", + "# MATLAB L1117: num_cells = numRealizations;\n", + "_matlab('num_cells = numRealizations;')\n", + "# MATLAB L1118: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1119: plot(x_u(1,:),x_u(2,:),'b',px,py,'k')\n", + "__tracker.annotate(\"plot(x_u(1,:),x_u(2,:),'b',px,py,'k')\")\n", + "_matlab(\"plot(x_u(1,:),x_u(2,:),'b',px,py,'k')\")\n", + "# MATLAB L1120: legend('predicted path','actual path');\n", + "_matlab(\"legend('predicted path','actual path');\")\n", + "# MATLAB L1121: \n", + "#\n", + "# MATLAB L1122: % Parity contract scalars for MATLAB/Python verification.\n", + "# Parity contract scalars for MATLAB/Python verification.\n", + "# MATLAB L1123: parity = struct();\n", + "_matlab('parity = struct();')\n", + "# MATLAB L1124: parity.num_cells = num_cells;\n", + "_matlab('parity.num_cells = num_cells;')\n", + "# MATLAB L1125: parity.decode_rmse = decode_rmse;\n", + "_matlab('parity.decode_rmse = decode_rmse;')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "decoding_2d", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 4, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/StimulusDecode2D.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "StimulusDecode2D" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/TrialConfigExamples.ipynb b/notebooks/TrialConfigExamples.ipynb index 00c0377d..4e8ce337 100644 --- a/notebooks/TrialConfigExamples.ipynb +++ b/notebooks/TrialConfigExamples.ipynb @@ -3,142 +3,80 @@ { "cell_type": "code", "execution_count": null, - "id": "trialconfigexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: TrialConfigExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/TrialConfigExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "trialconfigexamples-01", + "id": "df72fe35", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB TrialConfigExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "TOPIC = \"TrialConfigExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='TrialConfigExamples', output_root=OUTPUT_ROOT, expected_count=0)\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"TrialConfigExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"TrialConfigExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"TrialConfigExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"TrialConfigExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "trialconfigexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\",\n", - " \"tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\",\n", - " \"tcc = ConfigColl({tc1,tc2});\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for TrialConfigExamples.\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "trialconfigexamples-03", - "metadata": {}, - "outputs": [], - "source": [ - "# TrialConfigExamples: create and inspect trial configurations.\n", - "from nstat.compat.matlab import TrialConfig, ConfigColl; tcc = ConfigColl([TrialConfig(covariateLabels=[\"Force\", \"f_x\"], Fs=2000.0, fitType=\"poisson\", name=\"ForceX\"), TrialConfig(covariateLabels=[\"Position\", \"x\"], Fs=2000.0, fitType=\"poisson\", name=\"PositionX\")]); rates = np.array([cfg.getSampleRate() for cfg in tcc.getConfigs()], dtype=float); plt.figure(figsize=(7.6, 4.2)); plt.bar(tcc.getConfigNames(), rates, color=[\"tab:blue\", \"tab:orange\"]); plt.title(f\"{TOPIC}: TrialConfig summary\"); plt.tight_layout(); plt.show(); CHECKPOINT_METRICS = {\"num_configs\": float(len(tcc.getConfigs())), \"sample_rate_hz\": float(np.mean(rates))}; CHECKPOINT_LIMITS = {\"num_configs\": (2.0, 2.0), \"sample_rate_hz\": (2000.0, 2000.0)}\n", - "assert len(tcc.getConfigs()) == 2\n", - "assert tcc.getConfig(1).getSampleRate() == 2000.0\n", - "assert tcc.getConfig(\"PositionX\").getFitType() == \"poisson\"\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "trialconfigexamples-04", - "metadata": {}, - "outputs": [], - "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % TrialConfig Examples\n", + "# TrialConfig Examples\n", + "# MATLAB L200: % tcObj=TrialConfig(covMask,sampleRate, history,minTime,maxTime)\n", + "# tcObj=TrialConfig(covMask,sampleRate, history,minTime,maxTime)\n", + "# MATLAB L300: tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\n", + "_matlab(\"tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\")\n", + "# MATLAB L301: tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\n", + "_matlab(\"tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\")\n", + "# MATLAB L302: tcc = ConfigColl({tc1,tc2});\n", + "_matlab('tcc = ConfigColl({tc1,tc2});')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 0, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/TrialConfigExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "TrialConfigExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/TrialExamples.ipynb b/notebooks/TrialExamples.ipynb index f01441b3..a671ab13 100644 --- a/notebooks/TrialExamples.ipynb +++ b/notebooks/TrialExamples.ipynb @@ -3,193 +3,170 @@ { "cell_type": "code", "execution_count": null, - "id": "trialexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: TrialExamples\n", - "# Execution group: smoke\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/TrialExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "trialexamples-01", + "id": "1085892f", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB TrialExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "TOPIC = \"TrialExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='TrialExamples', output_root=OUTPUT_ROOT, expected_count=6)\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"TrialExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"TrialExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"TrialExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"TrialExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "trialexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all; clear all;\",\n", - " \"lengthTrial=1;\",\n", - " \"windowTimes = [0 .1 .2 .4];\",\n", - " \"h=History(windowTimes);\",\n", - " \"figure; h.plot;\",\n", - " \"load CovariateSample.mat; %load position and force covariates\",\n", - " \"cc=CovColl({position,force});\",\n", - " \"cc.setMaxTime(lengthTrial);\",\n", - " \"figure; cc.plot;\",\n", - " \"eTimes = sort(rand(1,2)*lengthTrial);\",\n", - " \"eLabels={'E_1','E_2'};\",\n", - " \"e=Events(eTimes,eLabels); %use default eventColor 'r'\",\n", - " \"figure; e.plot;\",\n", - " \"clear nst;\",\n", - " \"for i=1:4\",\n", - " \"spikeTimes = sort(rand(1,100))*lengthTrial;\",\n", - " \"nst{i}=nspikeTrain(spikeTimes,'',.001);\",\n", - " \"end\",\n", - " \"spikeColl=nstColl(nst); %create a nstColl\",\n", - " \"figure; spikeColl.plot;\",\n", - " \"trial1=Trial(spikeColl, cc, e, h);\",\n", - " \"figure; trial1.plot; % plot all the data;\",\n", - " \"trial1.setCovMask({{'Position','x'},{'Force','f_x'}})\",\n", - " \"figure; trial1.plot;\",\n", - " \"trial1.getHistForNeurons([1:2]);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for TrialExamples.\")\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Trial Examples\n", + "# Trial Examples\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "trialexamples-03", + "id": "a1c0de77", "metadata": {}, "outputs": [], "source": [ - "# TrialExamples: build a trial from spikes, covariates, events, and history.\n", - "from nstat.compat.matlab import Covariate, CovColl, Events, History, Trial, nspikeTrain, nstColl\n", - "\n", - "length_trial = 1.0; t = np.arange(0.0, length_trial + 0.001, 0.001); history = History(bin_edges_s=np.array([0.0, 0.1, 0.2, 0.4], dtype=float))\n", - "position = Covariate(time=t, data=np.column_stack([np.cos(2.0 * np.pi * t), np.sin(2.0 * np.pi * t)]), name=\"Position\", labels=[\"x\", \"y\"])\n", - "force = Covariate(time=t, data=np.column_stack([np.sin(2.0 * np.pi * 4.0 * t), np.cos(2.0 * np.pi * 4.0 * t)]), name=\"Force\", labels=[\"f_x\", \"f_y\"])\n", - "cc = CovColl([position, force]); cc.setMaxTime(length_trial); e = Events(times=np.sort(rng.random(2) * length_trial), labels=[\"E_1\", \"E_2\"])\n", - "trains = [nspikeTrain(spike_times=np.sort(rng.random(100) * length_trial), t_start=0.0, t_end=length_trial, name=f\"n{i+1}\") for i in range(4)]\n", - "spikeColl = nstColl(trains); trial1 = Trial(spikes=spikeColl, covariates=cc); trial1.setTrialEvents(e); trial1.setHistory(history)\n", - "\n", - "fig, axes = plt.subplots(2, 2, figsize=(10.0, 7.2))\n", - "plt.sca(axes[0, 0]); history.plot(); axes[0, 0].set_title(\"History windows\")\n", - "plt.sca(axes[0, 1]); cc.plot(); axes[0, 1].set_title(\"Covariates\")\n", - "plt.sca(axes[1, 0]); e.plot(); axes[1, 0].set_title(\"Events\")\n", - "plt.sca(axes[1, 1]); spikeColl.plot(); axes[1, 1].set_title(\"Spike raster\")\n", - "for ax in axes.ravel(): ax.set_xlabel(\"time [s]\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "trial1.setCovMask([\"Position\", \"Force\"]); hist_rows = trial1.getHistForNeurons([1, 2], binSize_s=0.01)\n", - "fig2 = plt.figure(figsize=(8.0, 3.8)); plt.imshow(hist_rows[0].T, aspect=\"auto\", origin=\"lower\", cmap=\"magma\"); plt.title(\"Neuron 1 history matrix\"); plt.tight_layout(); plt.show()\n", - "spikes = spikeColl.getNST(0); H = history.computeHistory(spikes.spike_times, t)\n", - "assert len(hist_rows) >= 1\n", - "assert hist_rows[0].shape[1] == history.getNumBins()\n", - "assert H.ndim == 2 and H.shape[1] == history.n_bins\n", - "assert spikes.spike_times.size > 5\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"history_bins\": float(history.getNumBins()),\n", - " \"hist_rows_neuron1\": float(hist_rows[0].shape[0] if hist_rows else 0.0),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"history_bins\": (3.0, 3.0),\n", - " \"hist_rows_neuron1\": (50.0, 2000.0),\n", - "}\n" + "# SECTION 1: Example 1: A simple data set\n", + "# MATLAB L300: close all; clear all;\n", + "plt.close(\"all\")\n", + "# MATLAB L301: lengthTrial=1;\n", + "lengthTrial = 1\n", + "# MATLAB L500: % Create History windows of interest\n", + "# Create History windows of interest\n", + "# MATLAB L600: windowTimes = [0 .1 .2 .4];\n", + "_matlab('windowTimes = [0 .1 .2 .4];')\n", + "# MATLAB L601: h=History(windowTimes);\n", + "_matlab('h=History(windowTimes);')\n", + "# MATLAB L602: figure; h.plot;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('h.plot')\n", + "_matlab('figure; h.plot;')\n", + "# MATLAB L800: % Load Covariates\n", + "# Load Covariates\n", + "# MATLAB L900: load CovariateSample.mat; %load position and force covariates\n", + "_matlab('load CovariateSample.mat; %load position and force covariates')\n", + "# MATLAB L901: cc=CovColl({position,force});\n", + "_matlab('cc=CovColl({position,force});')\n", + "# MATLAB L902: cc.setMaxTime(lengthTrial);\n", + "_matlab('cc.setMaxTime(lengthTrial);')\n", + "# MATLAB L903: figure; cc.plot;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('cc.plot')\n", + "_matlab('figure; cc.plot;')\n", + "# MATLAB L1100: % Create trial events\n", + "# Create trial events\n", + "# MATLAB L1200: eTimes = sort(rand(1,2)*lengthTrial);\n", + "_matlab('eTimes = sort(rand(1,2)*lengthTrial);')\n", + "# MATLAB L1201: eLabels={'E_1','E_2'};\n", + "_matlab(\"eLabels={'E_1','E_2'};\")\n", + "# MATLAB L1202: e=Events(eTimes,eLabels); %use default eventColor 'r'\n", + "_matlab(\"e=Events(eTimes,eLabels); %use default eventColor 'r'\")\n", + "# MATLAB L1203: figure; e.plot;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('e.plot')\n", + "_matlab('figure; e.plot;')\n", + "# MATLAB L1400: % Create neural Spike Train Data\n", + "# Create neural Spike Train Data\n", + "# MATLAB L1500: clear nst;\n", + "pass\n", + "# MATLAB L1501: for i=1:4\n", + "_matlab('for i=1:4')\n", + "# MATLAB L1502: spikeTimes = sort(rand(1,100))*lengthTrial;\n", + "_matlab('spikeTimes = sort(rand(1,100))*lengthTrial;')\n", + "# MATLAB L1503: nst{i}=nspikeTrain(spikeTimes,'',.001);\n", + "_matlab(\"nst{i}=nspikeTrain(spikeTimes,'',.001);\")\n", + "# MATLAB L1504: end\n", + "_matlab('end')\n", + "# MATLAB L1505: spikeColl=nstColl(nst); %create a nstColl\n", + "_matlab('spikeColl=nstColl(nst); %create a nstColl')\n", + "# MATLAB L1506: figure; spikeColl.plot;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('figure; spikeColl.plot;')\n", + "# MATLAB L1700: % Finally we have everything we need to create a Trial object.\n", + "# Finally we have everything we need to create a Trial object.\n", + "# MATLAB L1800: trial1=Trial(spikeColl, cc, e, h);\n", + "_matlab('trial1=Trial(spikeColl, cc, e, h);')\n", + "# MATLAB L1801: figure; trial1.plot; % plot all the data;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('trial1.plot')\n", + "_matlab('figure; trial1.plot; % plot all the data;')\n", + "# MATLAB L2000: % Mask out some of the data and plot the trial once again\n", + "# Mask out some of the data and plot the trial once again\n", + "# MATLAB L2100: trial1.setCovMask({{'Position','x'},{'Force','f_x'}})\n", + "_matlab(\"trial1.setCovMask({{'Position','x'},{'Force','f_x'}})\")\n", + "# MATLAB L2101: figure; trial1.plot;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('trial1.plot')\n", + "_matlab('figure; trial1.plot;')\n", + "# MATLAB L2102: \n", + "#\n", + "# MATLAB L2103: trial1.getHistForNeurons([1:2]);\n", + "_matlab('trial1.getHistForNeurons([1:2]);')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "trialexamples-04", + "id": "7eb77d10", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 2: Example 2: Analyzing Trial Data\n", + "# MATLAB L2400: % Examples of neural spike analysis using the Neural Spike Analysis Toolbox or using standard methods standard methods\n", + "# Examples of neural spike analysis using the Neural Spike Analysis Toolbox or using standard methods standard methods\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 6, "run_group": "smoke", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/TrialExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "TrialExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/ValidationDataSet.ipynb b/notebooks/ValidationDataSet.ipynb index 677e92d6..001b8c83 100644 --- a/notebooks/ValidationDataSet.ipynb +++ b/notebooks/ValidationDataSet.ipynb @@ -3,231 +3,313 @@ { "cell_type": "code", "execution_count": null, - "id": "validationdataset-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: ValidationDataSet\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/ValidationDataSet.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "validationdataset-01", + "id": "f6375fda", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB ValidationDataSet.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "TOPIC = \"ValidationDataSet\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='ValidationDataSet', output_root=OUTPUT_ROOT, expected_count=8)\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"ValidationDataSet: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"ValidationDataSet: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"ValidationDataSet: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"ValidationDataSet: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "validationdataset-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"clear all;\",\n", - " \"close all;\",\n", - " \"p=0.01; % bernoilli probability\",\n", - " \"N=100001; % Number of coin flips\",\n", - " \"delta = 0.001; % binsize\",\n", - " \"T=N*delta; % total time window\",\n", - " \"lambda=N*p/T % lambda*T = N*p\",\n", - " \"mu = log(lambda*delta/(1-lambda*delta))\",\n", - " \"for i=1:2\",\n", - " \"t=linspace(0,T,N);\",\n", - " \"ind=rand(1,N)T1);\",\n", - " \"ind2=rand(1,N2)max(t1)],'Baseline','s','','',{'muConst','mu1','mu2'});\",\n", - " \"cc=CovColl({cov});\",\n", - " \"sampleRate=1000;\",\n", - " \"trial=Trial(spikeColl, cc);\",\n", - " \"clear c;\",\n", - " \"c{1} = TrialConfig({{'Baseline','muConst'}},sampleRate,[],[]);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','mu1','mu2'}},sampleRate,[],[]);\",\n", - " \"c{2}.setName('Variable');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"results{1}.plotResults;\",\n", - " \"results{2}.plotResults;\",\n", - " \"figure;\",\n", - " \"subplot(1,2,1); results{1}.lambda.plot;\",\n", - " \"subplot(1,2,2); results{2}.lambda.plot;\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for ValidationDataSet.\")\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Software Validation Data Set\n", + "# Software Validation Data Set\n", + "# MATLAB L200: % The purpose of this example is to two important test cases of data to validate the Neural Spike Analysis Toolbox.\n", + "# The purpose of this example is to two important test cases of data to validate the Neural Spike Analysis Toolbox.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "validationdataset-03", + "id": "1b6a648c", "metadata": {}, "outputs": [], "source": [ - "# ValidationDataSet: load MATLAB-gold trial matrix and reproduce raster/PSTH/significance summaries.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/ValidationDataSet_gold.mat\"\n", - "m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False)\n", - "dt = float(np.asarray(m[\"dt_val\"], dtype=float).reshape(-1)[0]); time = np.asarray(m[\"time_val\"], dtype=float).reshape(-1)\n", - "trial_matrix = np.asarray(m[\"trial_matrix_val\"], dtype=float); psth = np.asarray(m[\"psth_val\"], dtype=float).reshape(-1); sem = np.asarray(m[\"sem_val\"], dtype=float).reshape(-1)\n", - "rates, prob_mat, sig_mat = DecodingAlgorithms.compute_spike_rate_cis(spike_matrix=trial_matrix, alpha=0.05)\n", - "exp_rates = np.asarray(m[\"expected_rate_val\"], dtype=float).reshape(-1); exp_prob = np.asarray(m[\"expected_prob_val\"], dtype=float); exp_sig = np.asarray(m[\"expected_sig_val\"], dtype=int)\n", - "fig, axes = plt.subplots(3, 1, figsize=(9, 7), sharex=False)\n", - "for k in range(min(18, trial_matrix.shape[0])): axes[0].vlines(time[trial_matrix[k] > 0], k + 0.6, k + 1.4, linewidth=0.5)\n", - "axes[0].set_title(f\"{TOPIC}: trial raster\"); axes[0].set_ylabel(\"trial\")\n", - "axes[1].plot(time, psth, color=\"tab:blue\", linewidth=1.2); axes[1].fill_between(time, psth - sem, psth + sem, color=\"tab:blue\", alpha=0.2); axes[1].set_ylabel(\"Hz\"); axes[1].set_title(\"PSTH mean +/- SEM\")\n", - "im = axes[2].imshow(prob_mat, aspect=\"auto\", origin=\"lower\", cmap=\"viridis\"); axes[2].set_title(\"Trial-by-trial spike-rate p-values\"); axes[2].set_xlabel(\"trial\"); axes[2].set_ylabel(\"trial\"); fig.colorbar(im, ax=axes[2], fraction=0.03, pad=0.02)\n", - "plt.tight_layout(); plt.show()\n", - "rate_err = float(np.max(np.abs(rates - exp_rates))); prob_err = float(np.max(np.abs(prob_mat - exp_prob))); sig_mismatch = float(np.count_nonzero(sig_mat != exp_sig))\n", - "assert rate_err <= 1e-10 and prob_err <= 1e-10 and sig_mismatch == 0.0\n", - "CHECKPOINT_METRICS = {\"rate_max_abs_error\": rate_err, \"prob_max_abs_error\": prob_err, \"sig_mismatch_count\": sig_mismatch}\n", - "CHECKPOINT_LIMITS = {\"rate_max_abs_error\": (0.0, 1e-10), \"prob_max_abs_error\": (0.0, 1e-10), \"sig_mismatch_count\": (0.0, 0.0)}\n" + "# SECTION 1: Case #1: Constant Rate Poisson Process\n", + "# MATLAB L400: % First we want to show that when neural firing activity is generated from a constant rate poisson process, the algorithm is able to estimate the value of this constant rate.\n", + "# First we want to show that when neural firing activity is generated from a constant rate poisson process, the algorithm is able to estimate the value of this constant rate.\n", + "# MATLAB L500: clear all;\n", + "pass\n", + "# MATLAB L501: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L502: \n", + "#\n", + "# MATLAB L503: p=0.01; % bernoilli probability\n", + "p = 0.01\n", + "# MATLAB L504: N=100001; % Number of coin flips\n", + "N = 100001\n", + "# MATLAB L505: delta = 0.001; % binsize\n", + "delta = 0.001\n", + "# MATLAB L506: T=N*delta; % total time window\n", + "_matlab('T=N*delta; % total time window')\n", + "# MATLAB L507: lambda=N*p/T % lambda*T = N*p\n", + "_matlab('lambda=N*p/T % lambda*T = N*p')\n", + "# MATLAB L508: \n", + "#\n", + "# MATLAB L509: mu = log(lambda*delta/(1-lambda*delta))\n", + "_matlab('mu = log(lambda*delta/(1-lambda*delta))')\n", + "# MATLAB L700: % Now generate data for two neurons based on this constant rate\n", + "# Now generate data for two neurons based on this constant rate\n", + "# MATLAB L800: for i=1:2\n", + "_matlab('for i=1:2')\n", + "# MATLAB L801: t=linspace(0,T,N);\n", + "_matlab('t=linspace(0,T,N);')\n", + "# MATLAB L802: ind=rand(1,N)T1);\n", + "_matlab('t2=tTot(tTot>T1);')\n", + "# MATLAB L2406: ind2=rand(1,N2)max(t1)],'Baseline','s','','',{'muConst','mu1','mu2'});\n", + "_matlab(\"cov=Covariate(tTot,[ones(length(tTot),1), tTot<=max(t1), tTot>max(t1)],'Baseline','s','','',{'muConst','mu1','mu2'});\")\n", + "# MATLAB L2702: cc=CovColl({cov});\n", + "_matlab('cc=CovColl({cov});')\n", + "# MATLAB L2703: \n", + "#\n", + "# MATLAB L2704: % Specify how we want to perform the analysis\n", + "# Specify how we want to perform the analysis\n", + "# MATLAB L2705: sampleRate=1000;\n", + "sampleRate = 1000\n", + "# MATLAB L2706: trial=Trial(spikeColl, cc);\n", + "_matlab('trial=Trial(spikeColl, cc);')\n", + "# MATLAB L2707: clear c;\n", + "pass\n", + "# MATLAB L2708: % Constant rate throughout\n", + "# Constant rate throughout\n", + "# MATLAB L2709: c{1} = TrialConfig({{'Baseline','muConst'}},sampleRate,[],[]);\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','muConst'}},sampleRate,[],[]);\")\n", + "# MATLAB L2710: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L2711: % Constant rate for epoch1 and Constat rate for epoch2 but distinct\n", + "# Constant rate for epoch1 and Constat rate for epoch2 but distinct\n", + "# MATLAB L2712: c{2} = TrialConfig({{'Baseline','mu1','mu2'}},sampleRate,[],[]);\n", + "_matlab(\"c{2} = TrialConfig({{'Baseline','mu1','mu2'}},sampleRate,[],[]);\")\n", + "# MATLAB L2713: c{2}.setName('Variable');\n", + "_matlab(\"c{2}.setName('Variable');\")\n", + "# MATLAB L2714: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L2900: % Run the analysis\n", + "# Run the analysis\n", + "# MATLAB L3000: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);')\n", + "# MATLAB L3001: results{1}.plotResults;\n", + "_matlab('results{1}.plotResults;')\n", + "# MATLAB L3002: results{2}.plotResults;\n", + "_matlab('results{2}.plotResults;')\n", + "# MATLAB L3003: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L3004: subplot(1,2,1); results{1}.lambda.plot;\n", + "__tracker.annotate('subplot(1,2,1)')\n", + "__tracker.annotate('results{1}.lambda.plot')\n", + "_matlab('subplot(1,2,1); results{1}.lambda.plot;')\n", + "# MATLAB L3005: subplot(1,2,2); results{2}.lambda.plot;\n", + "__tracker.annotate('subplot(1,2,2)')\n", + "__tracker.annotate('results{2}.lambda.plot')\n", + "_matlab('subplot(1,2,2); results{2}.lambda.plot;')\n", + "# MATLAB L3200: % Compare the results across the two neurons\n", + "# Compare the results across the two neurons\n", + "# MATLAB L3300: Summary = FitResSummary(results);\n", + "_matlab('Summary = FitResSummary(results);')\n", + "# MATLAB L3301: Summary.plotSummary;\n", + "__tracker.annotate('Summary.plotSummary')\n", + "_matlab('Summary.plotSummary;')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "data", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 8, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/ValidationDataSet.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "ValidationDataSet" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/helpfiles/AnalysisExamples.ipynb b/notebooks/helpfiles/AnalysisExamples.ipynb deleted file mode 100644 index 59739d72..00000000 --- a/notebooks/helpfiles/AnalysisExamples.ipynb +++ /dev/null @@ -1,523 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "7325cb51", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/7 for AnalysisExamples: Analysis Examples\n", - "\n", - "# % Analysis Examples\n", - "# This is an example on the standard approach to fitting GLM models to\n", - "# spike train data. This data set was obtained at the Society For\n", - "# Neuroscience '08 Workshop on\n", - "# \n", - "# Compare to analysis with\n", - "# \n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: AnalysisExamples\n", - "# Execution group: smoke\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/AnalysisExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"AnalysisExamples\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"AnalysisExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"AnalysisExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"AnalysisExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"AnalysisExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 5\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c4c0a391", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/7 for AnalysisExamples: Example 1: Tradition Preliminary Analysis\n", - "\n", - "# % Example 1: Tradition Preliminary Analysis\n", - "#\n", - "# Script glm_part1.m\n", - "# MATLAB code to visualize data, fit a GLM model of the relation between\n", - "# spiking and the rat's position, and visualize this model for the\n", - "# Neuroinformatics GLM problem set.\n", - "# The code is initialized with an overly simple GLM model construction.\n", - "# Please improve it!\n", - "#\n", - "# load the rat trajectory and spiking data;\n", - "# MATLAB: close all;\n", - "# MATLAB: warning off;\n", - "# MATLAB: installPath = which('nSTAT_Install');\n", - "# MATLAB: if isempty(installPath)\n", - "# MATLAB: error('AnalysisExamples:MissingInstallPath', ...\n", - "# MATLAB: 'Could not locate nSTAT_Install.m on the MATLAB path.');\n", - "# MATLAB: end\n", - "# MATLAB: glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat');\n", - "# MATLAB: load(glmDataPath);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f871c8dc", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/7 for AnalysisExamples: Section\n", - "\n", - "# %\n", - "# visualize the raw data\n", - "# MATLAB: figure;\n", - "# MATLAB: plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.');\n", - "# MATLAB: axis tight square;\n", - "# MATLAB: xlabel('x position (m)'); ylabel('y position (m)');\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=30, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 3, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e48e7b55", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/7 for AnalysisExamples: Section\n", - "\n", - "# %\n", - "# fit a GLM model to the x and y positions.\n", - "# MATLAB: [b,dev,stats] = glmfit([xN yN (xN.^2-mean(xN.^2)) (yN.^2-mean(yN.^2)) (xN.*yN-mean(xN.*yN))],spikes_binned,'poisson');\n", - "# MATLAB: figure;\n", - "# MATLAB: errorbar(1:length(b), b, stats.se,'.');\n", - "# MATLAB: xticks=1:length(b);\n", - "# MATLAB: xtickLabels= {'baseline','x','y','x^2','y^2','x*y'};\n", - "# MATLAB: set(gca,'xtick',xticks,'xtickLabel',xtickLabels);\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=38, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 4, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "759395de", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/7 for AnalysisExamples: Section\n", - "\n", - "# %\n", - "# visualize your model\n", - "# construct a grid of positions to plot the model against...\n", - "# MATLAB: figure;\n", - "# MATLAB: [x_new,y_new]=meshgrid(-1:.1:1);\n", - "# MATLAB: y_new = flipud(y_new);\n", - "# MATLAB: x_new = fliplr(x_new);\n", - "#\n", - "# compute lambda for each point on this grid using the GLM model\n", - "# MATLAB: lambda = exp(b(1) + b(2)*x_new + b(3)*y_new + b(4)*x_new.^2 + b(5)*y_new.^2 + b(6)*x_new.*y_new);\n", - "# MATLAB: lambda((x_new.^2+y_new.^2>1))=nan;\n", - "#\n", - "# plot lambda as a function position over this grid\n", - "# MATLAB: h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\n", - "# MATLAB: get(h_mesh,'AlphaData');\n", - "# MATLAB: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor','b');\n", - "# MATLAB: hold on;\n", - "# MATLAB: plot3(cos(-pi:1e-2:pi),sin(-pi:1e-2:pi),zeros(size(-pi:1e-2:pi))); hold on;\n", - "# MATLAB: plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.');\n", - "# MATLAB: axis tight square;\n", - "# MATLAB: xlabel('x position (m)'); ylabel('y position (m)');\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=47, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 5, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "793bdc42", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/7 for AnalysisExamples: Section\n", - "\n", - "# %\n", - "# Compare a linear model versus a Gaussian GLM model.\n", - "# MATLAB: [b_lin,dev_lin,stats_lin] = glmfit([xN yN],spikes_binned,'poisson');\n", - "# MATLAB: [b_quad,dev_quad,stats_quad] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\n", - "#\n", - "# MATLAB: lambdaEst_lin = exp( b_lin(1) + b_lin(2)*xN+b_lin(3)*yN); % based on our GLM model with the log \"link function\"\n", - "# MATLAB: lambdaEst_quad = exp( b_quad(1) + b_quad(2)*xN+b_quad(3)*yN+b_quad(4)*xN.^2 +b_quad(5)*yN.^2 +b_quad(6)*xN.*yN);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 6\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "998f9cd5", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 7/7 for AnalysisExamples: Section\n", - "\n", - "# %\n", - "# Make the KS Plot\n", - "#\n", - "# ******* K-S Plot *******************\n", - "# graph the K-S plot and confidence intervals for the K-S statistic\n", - "#\n", - "# first generate the conditional intensity at each timestep\n", - "# ** Adjust the below line according to your choice of model.\n", - "# remember to include a column of ones to multiply the default constant GLM parameter beta_0**\n", - "#\n", - "# Use your parameter estimates (b) from glmfit along\n", - "# with the covariates you used (xN, yN, ...)\n", - "#\n", - "# MATLAB: lambdaEst=[lambdaEst_lin, lambdaEst_quad];\n", - "# MATLAB: timestep = 1;\n", - "# MATLAB: lambdaInt = 0;\n", - "# MATLAB: j=0;\n", - "# MATLAB: KS=[];\n", - "# MATLAB: for t=1:length(spikes_binned)\n", - "# MATLAB: lambdaInt = lambdaInt + lambdaEst(t,:)*timestep;\n", - "# MATLAB: if (spikes_binned(t))\n", - "# MATLAB: j = j + 1;\n", - "# MATLAB: KS(j,:) = 1-exp(-lambdaInt);\n", - "# MATLAB: lambdaInt = [0 0];\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "# MATLAB: KSSorted = sort( KS );\n", - "# MATLAB: N = length( KSSorted);\n", - "# MATLAB: figure;\n", - "# MATLAB: plot( ([1:N]-.5)/N, KSSorted, 0:.01:1,0:.01:1, 'g',0:.01:1, [0:.01:1]+1.36/sqrt(N), 'r', 0:.01:1,[0:.01:1]-1.36/sqrt(N), 'r' );\n", - "# MATLAB: axis( [0 1 0 1] );\n", - "# MATLAB: xlabel('Uniform CDF');\n", - "# MATLAB: ylabel('Empirical CDF of Rescaled ISIs');\n", - "# MATLAB: title('KS Plot with 95% Confidence Intervals');\n", - "# MATLAB: legend('Linear','Quadratic');\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=103, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 7, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=75, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 7, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"warning off;\",\n", - " \"installPath = which('nSTAT_Install');\",\n", - " \"if isempty(installPath)\",\n", - " \"error('AnalysisExamples:MissingInstallPath', ...\",\n", - " \"'Could not locate nSTAT_Install.m on the MATLAB path.');\",\n", - " \"end\",\n", - " \"glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat');\",\n", - " \"load(glmDataPath);\",\n", - " \"figure;\",\n", - " \"plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", - " \"[b,dev,stats] = glmfit([xN yN (xN.^2-mean(xN.^2)) (yN.^2-mean(yN.^2)) (xN.*yN-mean(xN.*yN))],spikes_binned,'poisson');\",\n", - " \"figure;\",\n", - " \"errorbar(1:length(b), b, stats.se,'.');\",\n", - " \"xticks=1:length(b);\",\n", - " \"xtickLabels= {'baseline','x','y','x^2','y^2','x*y'};\",\n", - " \"set(gca,'xtick',xticks,'xtickLabel',xtickLabels);\",\n", - " \"figure;\",\n", - " \"[x_new,y_new]=meshgrid(-1:.1:1);\",\n", - " \"y_new = flipud(y_new);\",\n", - " \"x_new = fliplr(x_new);\",\n", - " \"lambda = exp(b(1) + b(2)*x_new + b(3)*y_new + b(4)*x_new.^2 + b(5)*y_new.^2 + b(6)*x_new.*y_new);\",\n", - " \"lambda((x_new.^2+y_new.^2>1))=nan;\",\n", - " \"h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\",\n", - " \"get(h_mesh,'AlphaData');\",\n", - " \"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor','b');\",\n", - " \"hold on;\",\n", - " \"plot3(cos(-pi:1e-2:pi),sin(-pi:1e-2:pi),zeros(size(-pi:1e-2:pi))); hold on;\",\n", - " \"plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", - " \"[b_lin,dev_lin,stats_lin] = glmfit([xN yN],spikes_binned,'poisson');\",\n", - " \"[b_quad,dev_quad,stats_quad] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\",\n", - " \"lambdaEst_lin = exp( b_lin(1) + b_lin(2)*xN+b_lin(3)*yN); % based on our GLM model with the log \\\"link function\\\"\",\n", - " \"lambdaEst_quad = exp( b_quad(1) + b_quad(2)*xN+b_quad(3)*yN+b_quad(4)*xN.^2 +b_quad(5)*yN.^2 +b_quad(6)*xN.*yN);\",\n", - " \"lambdaEst=[lambdaEst_lin, lambdaEst_quad];\",\n", - " \"timestep = 1;\",\n", - " \"lambdaInt = 0;\",\n", - " \"j=0;\",\n", - " \"KS=[];\",\n", - " \"for t=1:length(spikes_binned)\",\n", - " \"lambdaInt = lambdaInt + lambdaEst(t,:)*timestep;\",\n", - " \"if (spikes_binned(t))\",\n", - " \"j = j + 1;\",\n", - " \"KS(j,:) = 1-exp(-lambdaInt);\",\n", - " \"lambdaInt = [0 0];\",\n", - " \"end\",\n", - " \"end\",\n", - " \"KSSorted = sort( KS );\",\n", - " \"N = length( KSSorted);\",\n", - " \"figure;\",\n", - " \"plot( ([1:N]-.5)/N, KSSorted, 0:.01:1,0:.01:1, 'g',0:.01:1, [0:.01:1]+1.36/sqrt(N), 'r', 0:.01:1,[0:.01:1]-1.36/sqrt(N), 'r' );\",\n", - " \"axis( [0 1 0 1] );\",\n", - " \"xlabel('Uniform CDF');\",\n", - " \"ylabel('Empirical CDF of Rescaled ISIs');\",\n", - " \"title('KS Plot with 95% Confidence Intervals');\",\n", - " \"legend('Linear','Quadratic');\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for AnalysisExamples.\")\n", - "\n", - "# AnalysisExamples: spatial firing-rate modeling with x-y covariates.\n", - "n_t = 4500\n", - "dt = 0.01\n", - "time = np.arange(n_t) * dt\n", - "\n", - "xy = np.zeros((n_t, 2), dtype=float)\n", - "xy[0] = np.array([45.0, 55.0])\n", - "vel = np.zeros(2, dtype=float)\n", - "for t in range(1, n_t):\n", - " vel = 0.92 * vel + 2.0 * rng.normal(size=2)\n", - " xy[t] = np.clip(xy[t - 1] + vel, 0.0, 100.0)\n", - "\n", - "xc, yc, sigma = 62.0, 38.0, 16.0\n", - "r2 = (xy[:, 0] - xc) ** 2 + (xy[:, 1] - yc) ** 2\n", - "true_rate = 1.2 + 18.0 * np.exp(-0.5 * r2 / (sigma**2))\n", - "counts = rng.poisson(true_rate * dt)\n", - "\n", - "X_lin = np.column_stack([xy[:, 0], xy[:, 1]])\n", - "fit_lin = Analysis.fit_glm(X=X_lin, y=counts, fit_type=\"poisson\", dt=dt)\n", - "est_rate = fit_lin.predict(X_lin)\n", - "\n", - "grid = np.linspace(0.0, 100.0, 35)\n", - "gx, gy = np.meshgrid(grid, grid, indexing=\"xy\")\n", - "Xg = np.column_stack([gx.ravel(), gy.ravel()])\n", - "true_map = 1.2 + 18.0 * np.exp(-0.5 * (((Xg[:, 0] - xc) ** 2 + (Xg[:, 1] - yc) ** 2) / (sigma**2)))\n", - "est_map = fit_lin.predict(Xg)\n", - "\n", - "spike_mask = counts > 0\n", - "\n", - "fig, axes = plt.subplots(2, 2, figsize=(10, 8))\n", - "axes[0, 0].plot(xy[:, 0], xy[:, 1], color=\"0.75\", linewidth=0.8)\n", - "axes[0, 0].scatter(xy[spike_mask, 0], xy[spike_mask, 1], s=5, c=\"tab:red\", alpha=0.6)\n", - "axes[0, 0].set_title(f\"{TOPIC}: trajectory and spikes\")\n", - "axes[0, 0].set_xlabel(\"x\")\n", - "axes[0, 0].set_ylabel(\"y\")\n", - "axes[0, 0].set_aspect(\"equal\", adjustable=\"box\")\n", - "\n", - "im1 = axes[0, 1].imshow(true_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[0, 1].set_title(\"True place field\")\n", - "axes[0, 1].set_xlabel(\"x\")\n", - "axes[0, 1].set_ylabel(\"y\")\n", - "fig.colorbar(im1, ax=axes[0, 1], fraction=0.04, pad=0.03)\n", - "\n", - "im2 = axes[1, 0].imshow(est_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[1, 0].set_title(\"Estimated linear model field\")\n", - "axes[1, 0].set_xlabel(\"x\")\n", - "axes[1, 0].set_ylabel(\"y\")\n", - "fig.colorbar(im2, ax=axes[1, 0], fraction=0.04, pad=0.03)\n", - "\n", - "axes[1, 1].plot(time[:800], true_rate[:800], label=\"true\", linewidth=1.1)\n", - "axes[1, 1].plot(time[:800], est_rate[:800], label=\"estimated\", linewidth=1.0)\n", - "axes[1, 1].set_title(\"Rate trace (first 8 s)\")\n", - "axes[1, 1].set_xlabel(\"time [s]\")\n", - "axes[1, 1].set_ylabel(\"Hz\")\n", - "axes[1, 1].legend(loc=\"upper right\")\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "rmse_rate = float(np.sqrt(np.mean((est_rate - true_rate) ** 2)))\n", - "print(\"rmse_rate\", rmse_rate, \"aic\", float(fit_lin.aic()))\n", - "assert np.isfinite(rmse_rate)\n", - "assert rmse_rate < 8.0\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_rate\": float(rmse_rate),\n", - " \"mean_true_rate\": float(np.mean(true_rate)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_rate\": (0.0, 8.0),\n", - " \"mean_true_rate\": (0.2, 30.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "analysis", - "run_group": "smoke", - "section_count": 7, - "source_helpfile": "AnalysisExamples.m", - "topic": "AnalysisExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/AnalysisExamples2.ipynb b/notebooks/helpfiles/AnalysisExamples2.ipynb deleted file mode 100644 index 115d2f50..00000000 --- a/notebooks/helpfiles/AnalysisExamples2.ipynb +++ /dev/null @@ -1,560 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "b125d6a9", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/9 for AnalysisExamples2: Analysis Examples 2\n", - "\n", - "# % Analysis Examples 2\n", - "# Compare with traditional Neural Spike Train Analysis\n", - "# \n", - "#\n", - "# load the rat trajectory and spiking data;\n", - "# MATLAB: close all;\n", - "# MATLAB: warning off;\n", - "# MATLAB: installPath = which('nSTAT_Install');\n", - "# MATLAB: if isempty(installPath)\n", - "# MATLAB: error('AnalysisExamples2:MissingInstallPath', ...\n", - "# MATLAB: 'Could not locate nSTAT_Install.m on the MATLAB path.');\n", - "# MATLAB: end\n", - "# MATLAB: glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat');\n", - "# MATLAB: load(glmDataPath);\n", - "#\n", - "# MATLAB: nst = nspikeTrain(spiketimes);\n", - "# MATLAB: baseline = Covariate(T,ones(length(xN),1),'Baseline','time','s','',{'mu'});\n", - "# MATLAB: position = Covariate(T,[xN yN],'Position', 'time','s','m',{'x','y'});\n", - "# MATLAB: velocity = Covariate(T,[vxN,vyN],'Velocity','time','s','m/s',{'v_x','v_y'});\n", - "# MATLAB: radial = Covariate(T,[xN yN xN.^2 yN.^2 xN.*yN],'Radial','time','s','m',{'x','y','x^2','y^2','x*y'});\n", - "# could just define velocity = postion.derivative;\n", - "#\n", - "# possibly add view as vector for covariates of dimension 3 or less\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: AnalysisExamples2\n", - "# Execution group: full\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/AnalysisExamples2.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"AnalysisExamples2\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"AnalysisExamples2: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"AnalysisExamples2: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"AnalysisExamples2: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"AnalysisExamples2: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 6\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1552eed0", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/9 for AnalysisExamples2: Section\n", - "\n", - "# %\n", - "# In the original analysis, we already had vectors of the covariates\n", - "# sampled at the spiketimes. This step would require interpolating the\n", - "# covariates and then sampling them at each of the spikeTimes. In our case\n", - "# this is quite simple.\n", - "#\n", - "# MATLAB: [values_at_spiketimes] =position.getValueAt(spiketimes);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ecba9bbe", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/9 for AnalysisExamples2: Section\n", - "\n", - "# %\n", - "# We could also upsample our data to get better estimates of the covariates\n", - "# at these points\n", - "#\n", - "# MATLAB: [values_at_spiketimes] =position.resample(1/min(diff(spiketimes))).getValueAt(spiketimes);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a8764385", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/9 for AnalysisExamples2: Section\n", - "\n", - "# %\n", - "# visualize the raw data\n", - "# MATLAB: figure;\n", - "# MATLAB: plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\n", - "# MATLAB: values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\n", - "# MATLAB: axis tight square;\n", - "# MATLAB: xlabel('x position (m)'); ylabel('y position (m)');\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=40, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples2.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 4, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "93493953", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/9 for AnalysisExamples2: Section\n", - "\n", - "# %\n", - "# Create a trial object and define the fits that we want to run\n", - "# MATLAB: spikeColl = nstColl({nst});\n", - "# MATLAB: covarColl = CovColl({baseline,radial});\n", - "# MATLAB: trial = Trial(spikeColl,covarColl);\n", - "# MATLAB: clear tc;\n", - "# MATLAB: sampleRate=1000;\n", - "# tcObj=TrialConfig(covMask,sampleRate, history,minTime,maxTime)\n", - "# MATLAB: tc{1} = TrialConfig({{'Baseline','mu'},{'Radial','x','y'}},sampleRate,[]); tc{1}.setName('Linear');\n", - "# MATLAB: tc{2} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[]); tc{2}.setName('Quadratic');\n", - "# MATLAB: tc{3} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[0 1]./sampleRate); tc{3}.setName('Quadratic+Hist');\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "762a472b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/9 for AnalysisExamples2: Section\n", - "\n", - "# %\n", - "# Create our collection of configurations and run the analysis;\n", - "# MATLAB: tcc = ConfigColl(tc); makePlot=1; neuronNum=1;\n", - "# MATLAB: fitResults =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", - "# MATLAB: fitResults.plotResults;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 6\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bdadcdb0", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 7/9 for AnalysisExamples2: Section\n", - "\n", - "# %\n", - "# Visualize the firing rates as a function of the spatial covariates\n", - "# MATLAB: figure;\n", - "# MATLAB: [x_new,y_new]=meshgrid(-1:.1:1); %define new x and y\n", - "# MATLAB: y_new = flipud(y_new);\n", - "# MATLAB: x_new = fliplr(x_new);\n", - "#\n", - "# For each covariate new to place the new data in a cell array\n", - "# MATLAB: newData{1} =ones(size(x_new));\n", - "# MATLAB: newData{2} =x_new; newData{3} =y_new;\n", - "# MATLAB: newData{4} =x_new.^2; newData{5} =y_new.^2;\n", - "# MATLAB: newData{6} =x_new.*y_new;\n", - "# MATLAB: color = Analysis.colors;\n", - "#\n", - "# Evaluate our fits using the new parameters\n", - "# MATLAB: for i=1:fitResults.numResults\n", - "#\n", - "# MATLAB: lambda = fitResults.evalLambda(i,newData);\n", - "# MATLAB: h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\n", - "# MATLAB: get(h_mesh,'AlphaData');\n", - "# MATLAB: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor',color{i});\n", - "# figure;\n", - "# MATLAB: hold on;\n", - "# MATLAB: end\n", - "# MATLAB: legend(fitResults.lambda.dataLabels);\n", - "# MATLAB: plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\n", - "# MATLAB: values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\n", - "# MATLAB: axis tight square;\n", - "# MATLAB: xlabel('x position (m)'); ylabel('y position (m)');\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=66, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples2_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 7, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 7\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "66ec183b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 8/9 for AnalysisExamples2: Toolbox vs. Standard GLM comparison\n", - "\n", - "# % Toolbox vs. Standard GLM comparison\n", - "# Compare the results using our approach with the standard approach used in\n", - "# the first example previous standard regression\n", - "# MATLAB: [b,dev,stats] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\n", - "# MATLAB: b-fitResults.b{2} % should be close to zero\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 8\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cb6ebf1b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 9/9 for AnalysisExamples2: Compute the history effect\n", - "\n", - "# % Compute the history effect\n", - "# MATLAB: sampleRate=1000; makePlot=1; neuronNum = 1;\n", - "# MATLAB: covLabels = {{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}};\n", - "# MATLAB: Algorithm = 'GLM';\n", - "# MATLAB: batchMode=0;\n", - "# MATLAB: windowTimes =(0:1:10)./sampleRate;\n", - "# [fitResults,tcc] = computeHistLag(tObj,neuronNum,windowTimes,CovLabels,Algorithm,batchMode,sampleRate,makePlot,histMinTimes,histMaxTimes)\n", - "# MATLAB: [fitResults,tcc] = Analysis.computeHistLag(trial,neuronNum,windowTimes,covLabels,Algorithm,batchMode,sampleRate,makePlot);\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=102, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples2_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 9, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=102, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples2_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 9, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=102, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples2_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 9, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=102, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"AnalysisExamples2_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 9, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"warning off;\",\n", - " \"installPath = which('nSTAT_Install');\",\n", - " \"if isempty(installPath)\",\n", - " \"error('AnalysisExamples2:MissingInstallPath', ...\",\n", - " \"'Could not locate nSTAT_Install.m on the MATLAB path.');\",\n", - " \"end\",\n", - " \"glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat');\",\n", - " \"load(glmDataPath);\",\n", - " \"nst = nspikeTrain(spiketimes);\",\n", - " \"baseline = Covariate(T,ones(length(xN),1),'Baseline','time','s','',{'mu'});\",\n", - " \"position = Covariate(T,[xN yN],'Position', 'time','s','m',{'x','y'});\",\n", - " \"velocity = Covariate(T,[vxN,vyN],'Velocity','time','s','m/s',{'v_x','v_y'});\",\n", - " \"radial = Covariate(T,[xN yN xN.^2 yN.^2 xN.*yN],'Radial','time','s','m',{'x','y','x^2','y^2','x*y'});\",\n", - " \"[values_at_spiketimes] =position.getValueAt(spiketimes);\",\n", - " \"[values_at_spiketimes] =position.resample(1/min(diff(spiketimes))).getValueAt(spiketimes);\",\n", - " \"figure;\",\n", - " \"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\",\n", - " \"values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", - " \"spikeColl = nstColl({nst});\",\n", - " \"covarColl = CovColl({baseline,radial});\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"clear tc;\",\n", - " \"sampleRate=1000;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','mu'},{'Radial','x','y'}},sampleRate,[]); tc{1}.setName('Linear');\",\n", - " \"tc{2} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[]); tc{2}.setName('Quadratic');\",\n", - " \"tc{3} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[0 1]./sampleRate); tc{3}.setName('Quadratic+Hist');\",\n", - " \"tcc = ConfigColl(tc); makePlot=1; neuronNum=1;\",\n", - " \"fitResults =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"fitResults.plotResults;\",\n", - " \"figure;\",\n", - " \"[x_new,y_new]=meshgrid(-1:.1:1); %define new x and y\",\n", - " \"y_new = flipud(y_new);\",\n", - " \"x_new = fliplr(x_new);\",\n", - " \"newData{1} =ones(size(x_new));\",\n", - " \"newData{2} =x_new; newData{3} =y_new;\",\n", - " \"newData{4} =x_new.^2; newData{5} =y_new.^2;\",\n", - " \"newData{6} =x_new.*y_new;\",\n", - " \"color = Analysis.colors;\",\n", - " \"for i=1:fitResults.numResults\",\n", - " \"lambda = fitResults.evalLambda(i,newData);\",\n", - " \"h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\",\n", - " \"get(h_mesh,'AlphaData');\",\n", - " \"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor',color{i});\",\n", - " \"hold on;\",\n", - " \"end\",\n", - " \"legend(fitResults.lambda.dataLabels);\",\n", - " \"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\",\n", - " \"values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", - " \"[b,dev,stats] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\",\n", - " \"b-fitResults.b{2} % should be close to zero\",\n", - " \"sampleRate=1000; makePlot=1; neuronNum = 1;\",\n", - " \"covLabels = {{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}};\",\n", - " \"Algorithm = 'GLM';\",\n", - " \"batchMode=0;\",\n", - " \"windowTimes =(0:1:10)./sampleRate;\",\n", - " \"[fitResults,tcc] = Analysis.computeHistLag(trial,neuronNum,windowTimes,covLabels,Algorithm,batchMode,sampleRate,makePlot);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for AnalysisExamples2.\")\n", - "\n", - "# AnalysisExamples2: compare linear and quadratic spatial Poisson GLMs.\n", - "n_t = 5000\n", - "dt = 0.01\n", - "time = np.arange(n_t) * dt\n", - "\n", - "xy = np.zeros((n_t, 2), dtype=float)\n", - "xy[0] = np.array([50.0, 50.0])\n", - "vel = np.zeros(2, dtype=float)\n", - "for t in range(1, n_t):\n", - " vel = 0.9 * vel + 2.4 * rng.normal(size=2)\n", - " xy[t] = np.clip(xy[t - 1] + vel, 0.0, 100.0)\n", - "\n", - "xc, yc, sigma = 35.0, 70.0, 14.0\n", - "r2 = (xy[:, 0] - xc) ** 2 + (xy[:, 1] - yc) ** 2\n", - "true_rate = 1.0 + 20.0 * np.exp(-0.5 * r2 / (sigma**2))\n", - "counts = rng.poisson(true_rate * dt)\n", - "\n", - "X_lin = np.column_stack([xy[:, 0], xy[:, 1]])\n", - "X_quad = np.column_stack([xy[:, 0], xy[:, 1], xy[:, 0] ** 2, xy[:, 1] ** 2, xy[:, 0] * xy[:, 1]])\n", - "\n", - "fit_lin = Analysis.fit_glm(X=X_lin, y=counts, fit_type=\"poisson\", dt=dt)\n", - "fit_quad = Analysis.fit_glm(X=X_quad, y=counts, fit_type=\"poisson\", dt=dt)\n", - "\n", - "grid = np.linspace(0.0, 100.0, 35)\n", - "gx, gy = np.meshgrid(grid, grid, indexing=\"xy\")\n", - "Xg_lin = np.column_stack([gx.ravel(), gy.ravel()])\n", - "Xg_quad = np.column_stack([gx.ravel(), gy.ravel(), gx.ravel() ** 2, gy.ravel() ** 2, gx.ravel() * gy.ravel()])\n", - "true_map = 1.0 + 20.0 * np.exp(\n", - " -0.5 * (((Xg_lin[:, 0] - xc) ** 2 + (Xg_lin[:, 1] - yc) ** 2) / (sigma**2))\n", - ")\n", - "lin_map = fit_lin.predict(Xg_lin)\n", - "quad_map = fit_quad.predict(Xg_quad)\n", - "\n", - "fig, axes = plt.subplots(2, 2, figsize=(10, 8))\n", - "im0 = axes[0, 0].imshow(true_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[0, 0].set_title(\"True field\")\n", - "fig.colorbar(im0, ax=axes[0, 0], fraction=0.04, pad=0.03)\n", - "\n", - "im1 = axes[0, 1].imshow(lin_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[0, 1].set_title(\"Linear GLM field\")\n", - "fig.colorbar(im1, ax=axes[0, 1], fraction=0.04, pad=0.03)\n", - "\n", - "im2 = axes[1, 0].imshow(quad_map.reshape(grid.size, grid.size), origin=\"lower\", extent=[0, 100, 0, 100], cmap=\"jet\")\n", - "axes[1, 0].set_title(\"Quadratic GLM field\")\n", - "fig.colorbar(im2, ax=axes[1, 0], fraction=0.04, pad=0.03)\n", - "\n", - "aic_vals = np.array([fit_lin.aic(), fit_quad.aic()], dtype=float)\n", - "axes[1, 1].bar([\"linear\", \"quadratic\"], aic_vals, color=[\"tab:gray\", \"tab:blue\"])\n", - "axes[1, 1].set_title(\"Model comparison (AIC)\")\n", - "axes[1, 1].set_ylabel(\"AIC\")\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "rmse_lin = float(np.sqrt(np.mean((fit_lin.predict(X_lin) - true_rate) ** 2)))\n", - "rmse_quad = float(np.sqrt(np.mean((fit_quad.predict(X_quad) - true_rate) ** 2)))\n", - "print(\"rmse_lin\", rmse_lin, \"rmse_quad\", rmse_quad)\n", - "assert rmse_quad <= rmse_lin + 0.8\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_lin\": float(rmse_lin),\n", - " \"rmse_quad\": float(rmse_quad),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_lin\": (0.0, 20.0),\n", - " \"rmse_quad\": (0.0, 20.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "analysis", - "run_group": "full", - "section_count": 9, - "source_helpfile": "AnalysisExamples2.m", - "topic": "AnalysisExamples2" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/ConfigCollExamples.ipynb b/notebooks/helpfiles/ConfigCollExamples.ipynb deleted file mode 100644 index e75bee66..00000000 --- a/notebooks/helpfiles/ConfigCollExamples.ipynb +++ /dev/null @@ -1,150 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "36420641", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/1 for ConfigCollExamples: ConfigColl Examples\n", - "\n", - "# % ConfigColl Examples\n", - "# tcObj=TrialConfig(covMask,sampleRate, history,minTime,maxTime)\n", - "# MATLAB: tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\n", - "# MATLAB: tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\n", - "# MATLAB: tcc = ConfigColl({tc1,tc2});\n", - "\n", - "# Python translation bootstrap + execution for single-section helpfile.\n", - "\n", - "# Topic: ConfigCollExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/ConfigCollExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"ConfigCollExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"ConfigCollExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"ConfigCollExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"ConfigCollExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"ConfigCollExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 0\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\",\n", - " \"tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\",\n", - " \"tcc = ConfigColl({tc1,tc2});\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for ConfigCollExamples.\")\n", - "\n", - "# ConfigCollExamples: compose and edit configuration collections.\n", - "from nstat.compat.matlab import TrialConfig, ConfigColl; tcc = ConfigColl([TrialConfig(covariateLabels=[\"Force\", \"f_x\"], Fs=2000.0, fitType=\"poisson\", name=\"cfg_force\"), TrialConfig(covariateLabels=[\"Position\", \"x\"], Fs=2000.0, fitType=\"poisson\", name=\"cfg_pos\")]); tcc.setConfig(2, TrialConfig(covariateLabels=[\"Position\", \"y\"], Fs=1000.0, fitType=\"poisson\", name=\"cfg_pos_y\")); rates = np.array([cfg.getSampleRate() for cfg in tcc.getConfigs()], dtype=float); plt.figure(figsize=(8.0, 3.8)); plt.bar(tcc.getConfigNames(), rates, color=\"tab:purple\"); plt.title(f\"{TOPIC}: sample rates\"); plt.tight_layout(); plt.show(); CHECKPOINT_METRICS = {\"num_configs\": float(len(tcc.getConfigs())), \"mean_sample_rate\": float(np.mean(rates))}; CHECKPOINT_LIMITS = {\"num_configs\": (2.0, 2.0), \"mean_sample_rate\": (1400.0, 1800.0)}\n", - "assert len(tcc.getConfigs()) == 2\n", - "assert len(tcc.getSubsetConfigs([1, 2]).getConfigs()) == 2\n", - "assert float(rates[1]) == 1000.0\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "full", - "section_count": 1, - "source_helpfile": "ConfigCollExamples.m", - "topic": "ConfigCollExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/CovCollExamples.ipynb b/notebooks/helpfiles/CovCollExamples.ipynb deleted file mode 100644 index ccf13c9e..00000000 --- a/notebooks/helpfiles/CovCollExamples.ipynb +++ /dev/null @@ -1,213 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "8aa4dabf", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/1 for CovCollExamples: Test CovColl\n", - "\n", - "# % Test CovColl\n", - "# MATLAB: close all;\n", - "# MATLAB: load CovariateSample.mat;\n", - "# MATLAB: cc=CovColl({position,force});\n", - "# MATLAB: figure; cc.plot; %plots all covariates and their components\n", - "#\n", - "# MATLAB: cc.getCov(1); %returns position;\n", - "# MATLAB: cc.getCov('Position');\n", - "# MATLAB: cc.getCov({'Position','Force'});\n", - "# MATLAB: cc.resample(200); %resamples both position and force\n", - "#\n", - "#\n", - "# MATLAB: cc.setMask({{'Position','x'},{'Force','f_y'}});\n", - "# MATLAB: figure; cc.plot; %plot only x and f_y;\n", - "#\n", - "# dataToMatrix\n", - "# setMaxTime\n", - "# setMinTime\n", - "# removeCovariate\n", - "# nActCovar\n", - "#\n", - "\n", - "# Python translation bootstrap + execution for single-section helpfile.\n", - "\n", - "# Topic: CovCollExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/CovCollExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"CovCollExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"CovCollExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"CovCollExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"CovCollExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"CovCollExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 3\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; cc.plot; %plots all covariates and their components\n", - "fig = FIGURE_TRACKER.new_figure(section_index=1, matlab_line_number=5, matlab_snippet=\"figure; cc.plot; %plots all covariates and their components\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"CovCollExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 1, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure; cc.plot; %plot only x and f_y;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=1, matlab_line_number=14, matlab_snippet=\"figure; cc.plot; %plot only x and f_y;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"CovCollExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 1, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=1, matlab_line_number=1, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"CovCollExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 1, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"load CovariateSample.mat;\",\n", - " \"cc=CovColl({position,force});\",\n", - " \"figure; cc.plot; %plots all covariates and their components\",\n", - " \"cc.getCov(1); %returns position;\",\n", - " \"cc.getCov('Position');\",\n", - " \"cc.getCov({'Position','Force'});\",\n", - " \"cc.resample(200); %resamples both position and force\",\n", - " \"cc.setMask({{'Position','x'},{'Force','f_y'}});\",\n", - " \"figure; cc.plot; %plot only x and f_y;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for CovCollExamples.\")\n", - "\n", - "# CovCollExamples: covariate collection queries, masking, and resampling.\n", - "from nstat.compat.matlab import Covariate, CovColl, History, nspikeTrain\n", - "\n", - "t = np.arange(0.0, 5.0 + 0.001, 0.001)\n", - "position = Covariate(time=t, data=np.column_stack([np.exp(-t), np.sin(2.0 * np.pi * t), np.sin(2.0 * np.pi * t) ** 3]), name=\"Position\", labels=[\"x\", \"y\", \"z\"])\n", - "force = Covariate(time=t, data=np.column_stack([np.abs(np.sin(2.0 * np.pi * t)), np.abs(np.sin(2.0 * np.pi * t)) ** 2]), name=\"Force\", labels=[\"f_x\", \"f_y\"])\n", - "cc = CovColl([position, force]); cc.resample(200.0); cc.setMask([\"Position\", \"Force\"])\n", - "fig, axes = plt.subplots(1, 2, figsize=(10, 4)); plt.sca(axes[0]); cc.plot(); axes[0].set_title(f\"{TOPIC}: resampled\")\n", - "\n", - "X, labels = cc.dataToMatrix(); cc.removeCovariate(\"Force\"); n_after = cc.nActCovar()\n", - "history = History(bin_edges_s=np.array([0.0, 0.01, 0.03], dtype=float))\n", - "spikes = nspikeTrain(spike_times=np.sort(rng.random(25) * 0.5), t_start=0.0, t_end=0.5, name=\"tmp\")\n", - "H = history.computeHistory(spikes.spike_times, np.arange(0.0, 0.5, 0.01))\n", - "axes[1].imshow(H.T, aspect=\"auto\", origin=\"lower\", cmap=\"magma\"); axes[1].set_title(\"History basis\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "assert H.ndim == 2 and H.shape[1] == history.n_bins\n", - "assert spikes.spike_times.size > 5\n", - "CHECKPOINT_METRICS = {\"matrix_rows\": float(X.shape[0]), \"matrix_cols\": float(X.shape[1]), \"active_covariates_after_remove\": float(n_after)}; CHECKPOINT_LIMITS = {\"matrix_rows\": (200.0, 2000.0), \"matrix_cols\": (4.0, 8.0), \"active_covariates_after_remove\": (1.0, 3.0)}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "full", - "section_count": 1, - "source_helpfile": "CovCollExamples.m", - "topic": "CovCollExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/CovariateExamples.ipynb b/notebooks/helpfiles/CovariateExamples.ipynb deleted file mode 100644 index 52e8c79c..00000000 --- a/notebooks/helpfiles/CovariateExamples.ipynb +++ /dev/null @@ -1,294 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "a08ae6d8", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/4 for CovariateExamples: Test the Cov class\n", - "\n", - "# % Test the Cov class\n", - "# Covariates are just like signals with a mean and a standard deviation\n", - "# They have two representations, the default (original representation) and\n", - "# a zero-mean representation\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: CovariateExamples\n", - "# Execution group: smoke\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/CovariateExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"CovariateExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"CovariateExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"CovariateExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"CovariateExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"CovariateExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 3\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4a3d7fa4", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/4 for CovariateExamples: Example 1: Using Covariates\n", - "\n", - "# % Example 1: Using Covariates\n", - "# Create some Data\n", - "# MATLAB: close all;\n", - "# MATLAB: t=0:.01:5; t=t';\n", - "# MATLAB: x=exp(-t);\n", - "# MATLAB: y=sin(2*pi*t);\n", - "# MATLAB: z=(-y).^3;\n", - "#\n", - "# MATLAB: fx=abs(y);\n", - "# MATLAB: fy=abs(y).^2;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1ff19991", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/4 for CovariateExamples: Section\n", - "\n", - "# %\n", - "# Define labels and plotting properties for each Covariate\n", - "# MATLAB: dLabels1={'f_x','f_y'};\n", - "# MATLAB: dLabels2={'x','y','z'};\n", - "#\n", - "# MATLAB: plotProps = {{' ''g'', ''LineWidth'' ,.5'},... %for x\n", - "# MATLAB: {' ''k'', ''LineWidth'' ,.5'},... %for y\n", - "# MATLAB: {' ''b'' '}}; %for z\n", - "#\n", - "# MATLAB: force = Covariate(t, [fx fy], 'Force', 'time', 's', 'N', dLabels1);\n", - "# MATLAB: position=Covariate(t,[x y z], 'Position','time','s','cm', dLabels2);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7377de65", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/4 for CovariateExamples: Section\n", - "\n", - "# %\n", - "# Plot the covariates and change their properties\n", - "# MATLAB: position.getSigRep.plot('all',plotProps); %same as position.plot\n", - "# MATLAB: plotPropsForce = {{' ''b'' '},{' ''k'' '}};\n", - "# MATLAB: figure;\n", - "# MATLAB: subplot(1,2,1); force.getSigRep.plot('all',plotPropsForce);\n", - "# can also set these properties as default by calling\n", - "# >>force.setPlotProps(plotPropsForce);\n", - "# >>force.plot;\n", - "#\n", - "# MATLAB: subplot(1,2,2); force.getSigRep('zero-mean').plot('all',plotPropsForce);\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: position.getSigRep.plot('all',plotProps); %same as position.plot\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=31, matlab_snippet=\"position.getSigRep.plot('all',plotProps); %same as position.plot\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"CovariateExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 4, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=33, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"CovariateExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 4, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=29, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"CovariateExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 4, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"t=0:.01:5; t=t';\",\n", - " \"x=exp(-t);\",\n", - " \"y=sin(2*pi*t);\",\n", - " \"z=(-y).^3;\",\n", - " \"fx=abs(y);\",\n", - " \"fy=abs(y).^2;\",\n", - " \"dLabels1={'f_x','f_y'};\",\n", - " \"dLabels2={'x','y','z'};\",\n", - " \"plotProps = {{' ''g'', ''LineWidth'' ,.5'},... %for x\",\n", - " \"{' ''k'', ''LineWidth'' ,.5'},... %for y\",\n", - " \"{' ''b'' '}}; %for z\",\n", - " \"force = Covariate(t, [fx fy], 'Force', 'time', 's', 'N', dLabels1);\",\n", - " \"position=Covariate(t,[x y z], 'Position','time','s','cm', dLabels2);\",\n", - " \"position.getSigRep.plot('all',plotProps); %same as position.plot\",\n", - " \"plotPropsForce = {{' ''b'' '},{' ''k'' '}};\",\n", - " \"figure;\",\n", - " \"subplot(1,2,1); force.getSigRep.plot('all',plotPropsForce);\",\n", - " \"subplot(1,2,2); force.getSigRep('zero-mean').plot('all',plotPropsForce);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for CovariateExamples.\")\n", - "\n", - "# CovariateExamples: build and inspect multiple covariate signals.\n", - "t = np.arange(0.0, 5.0 + 0.01, 0.01); x = np.exp(-t); y = np.sin(2.0 * np.pi * t); z = (-y) ** 3\n", - "force = Covariate(time=t, data=np.column_stack([np.abs(y), np.abs(y) ** 2]), name=\"Force\", labels=[\"f_x\", \"f_y\"])\n", - "position = Covariate(time=t, data=np.column_stack([x, y, z]), name=\"Position\", labels=[\"x\", \"y\", \"z\"])\n", - "force_zero_mean = force.data - np.mean(force.data, axis=0, keepdims=True)\n", - "\n", - "fig, axes = plt.subplots(2, 2, figsize=(10, 7), sharex=True)\n", - "axes[0, 0].plot(t, position.data[:, 0], \"g\", linewidth=0.6, label=\"x\")\n", - "axes[0, 0].plot(t, position.data[:, 1], \"k\", linewidth=0.6, label=\"y\")\n", - "axes[0, 0].plot(t, position.data[:, 2], \"b\", linewidth=0.6, label=\"z\")\n", - "axes[0, 0].set_title(f\"{TOPIC}: position covariates\"); axes[0, 0].legend(loc=\"upper right\")\n", - "axes[0, 1].plot(t, force.data[:, 0], \"b\", linewidth=1.0, label=\"f_x\")\n", - "axes[0, 1].plot(t, force.data[:, 1], \"k\", linewidth=1.0, label=\"f_y\")\n", - "axes[0, 1].set_title(\"Force (original)\"); axes[0, 1].legend(loc=\"upper right\")\n", - "axes[1, 0].plot(t, force_zero_mean[:, 0], \"b\", linewidth=1.0, label=\"f_x\")\n", - "axes[1, 0].plot(t, force_zero_mean[:, 1], \"k\", linewidth=1.0, label=\"f_y\")\n", - "axes[1, 0].set_title(\"Force (zero-mean)\"); axes[1, 0].legend(loc=\"upper right\")\n", - "axes[1, 1].plot(t, position.data[:, 1], \"k\", linewidth=1.0); axes[1, 1].set_title(\"Position y\")\n", - "for ax in axes.ravel(): ax.set_xlabel(\"time [s]\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "assert position.data.shape == (t.size, 3)\n", - "assert force.data.shape == (t.size, 2)\n", - "assert np.isfinite(force_zero_mean).all()\n", - "CHECKPOINT_METRICS = {\"position_var\": float(np.var(position.data[:, 1])), \"force_mean\": float(np.mean(force.data[:, 0]))}\n", - "CHECKPOINT_LIMITS = {\"position_var\": (0.05, 2.0), \"force_mean\": (0.0, 2.0)}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "smoke", - "section_count": 4, - "source_helpfile": "CovariateExamples.m", - "topic": "CovariateExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/DecodingExample.ipynb b/notebooks/helpfiles/DecodingExample.ipynb deleted file mode 100644 index d7fb715e..00000000 --- a/notebooks/helpfiles/DecodingExample.ipynb +++ /dev/null @@ -1,480 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "a51a1d43", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/4 for DecodingExample: STIMULUS DECODING\n", - "\n", - "# % STIMULUS DECODING\n", - "# In this example we show how to decode a univariate and a bivariate\n", - "# stimulus based on a point process observations using nSTAT. Even though\n", - "# due to the simulated nature of the data, we know the exact condition\n", - "# intensity function, we estimate the parameters before moving on to the\n", - "# decoding stage.\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: DecodingExample\n", - "# Execution group: smoke\n", - "# Workflow family: decoding_1d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/DecodingExample.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"DecodingExample\"\n", - "FAMILY = \"decoding_1d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"DecodingExample: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"DecodingExample: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"DecodingExample: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"DecodingExample: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 7\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "96948a67", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/4 for DecodingExample: Generate the conditional Intensity Function\n", - "\n", - "# % Generate the conditional Intensity Function\n", - "#\n", - "# MATLAB: close all;\n", - "# MATLAB: delta = 0.001; Tmax = 10;\n", - "# MATLAB: time = 0:delta:Tmax;\n", - "# MATLAB: f=.1; b1=1;b0=-3;\n", - "# MATLAB: x = sin(2*pi*f*time);\n", - "# MATLAB: expData = exp(b1*x+b0);\n", - "# MATLAB: lambdaData = expData./(1+expData);\n", - "#\n", - "# MATLAB: lambda = Covariate(time,lambdaData./delta, '\\Lambda(t)','time','s','Hz',{'\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\n", - "#\n", - "# MATLAB: numRealizations = 10;\n", - "# MATLAB: spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\n", - "# MATLAB: figure;\n", - "# MATLAB: subplot(2,1,1); spikeColl.plot;\n", - "# MATLAB: subplot(2,1,2); lambda.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=21, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExample.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 2, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "679f3550", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/4 for DecodingExample: Fit a model to the spikedata to obtain a model CIF\n", - "\n", - "# % Fit a model to the spikedata to obtain a model CIF\n", - "#\n", - "# MATLAB: stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\n", - "# MATLAB: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", - "# MATLAB: {'constant'});\n", - "# MATLAB: figure;\n", - "# MATLAB: cc = CovColl({stim,baseline});\n", - "# MATLAB: trial = Trial(spikeColl,cc);\n", - "# MATLAB: trial.plot;\n", - "#\n", - "# MATLAB: clear c;\n", - "# MATLAB: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\n", - "# MATLAB: NeighborHist);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "# MATLAB: c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\n", - "# MATLAB: sampleRate,selfHist,NeighborHist);\n", - "# MATLAB: c{2}.setName('Baseline+Stimulus');\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", - "# MATLAB: figure;\n", - "# MATLAB: results{1}.plotResults;\n", - "# MATLAB: Summary = FitResSummary(results);\n", - "#\n", - "# MATLAB: paramEst = squeeze(Summary.bAct(:,2,:));\n", - "# MATLAB: meanParams = mean(paramEst,2);\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=30, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExample_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 3, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=45, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExample_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 3, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e99b2527", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/4 for DecodingExample: Section\n", - "\n", - "# %\n", - "# So we now have a model for lambda\n", - "# lambda = exp(b_0 + b_1*x(t))./(1+exp(b_0 + b_1*x(t)) * 1/delta\n", - "# because exp(b_0 + b_1*x(t))<<1 we can approximate this lambda by\n", - "# just the numerator i.e.\n", - "# lambda = exp(b_0 + b_1*x(t))./delta\n", - "#\n", - "#\n", - "# Now suppose we wanted to decode x(t) based on only having observed lambda\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: clear lambdaCIF;\n", - "# MATLAB: b0=paramEst(1,:);\n", - "# MATLAB: b1=paramEst(2,:);\n", - "# MATLAB: for i=1:numRealizations\n", - "# Construct a CIF object for each realization based on our encoding\n", - "# results abovel\n", - "# MATLAB: lambdaCIF{i} = CIF([b0(i) b1(i)],{'1','x'},{'x'},'binomial');\n", - "# MATLAB: end\n", - "# close all;\n", - "# MATLAB: spikeColl.resample(1/delta);\n", - "# MATLAB: dN=spikeColl.dataToMatrix;\n", - "# Make noise according to the dynamic range of the stimulus\n", - "# MATLAB: Q=2*std(stim.data(2:end)-stim.data(1:end-1));\n", - "# MATLAB: A=1;\n", - "# MATLAB: [x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN',b0,b1,'binomial',delta);\n", - "# MATLAB: figure;\n", - "# MATLAB: zVal=3;\n", - "# MATLAB: ciLower = min(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\n", - "# MATLAB: ciUpper = max(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\n", - "# MATLAB: hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'g'); hold on;\n", - "# MATLAB: hold all;\n", - "#\n", - "# MATLAB: hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\n", - "# MATLAB: legend off;\n", - "# MATLAB: legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\sigma_{k|k}'),...\n", - "# MATLAB: strcat('x_{k|k}(t)+',num2str(zVal),'\\sigma_{k|k}'),'x_{k|k}(t)','x(t)');\n", - "# MATLAB: title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=80, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExample_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 4, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=52, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExample_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 4, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=52, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExample_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 4, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=52, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExample_06.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=7 + 4, title=f\"{TOPIC} Figure 007\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"delta = 0.001; Tmax = 10;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=.1; b1=1;b0=-3;\",\n", - " \"x = sin(2*pi*f*time);\",\n", - " \"expData = exp(b1*x+b0);\",\n", - " \"lambdaData = expData./(1+expData);\",\n", - " \"lambda = Covariate(time,lambdaData./delta, '\\\\Lambda(t)','time','s','Hz',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"numRealizations = 10;\",\n", - " \"spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1); spikeColl.plot;\",\n", - " \"subplot(2,1,2); lambda.plot;\",\n", - " \"stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"figure;\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial = Trial(spikeColl,cc);\",\n", - " \"trial.plot;\",\n", - " \"clear c;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\",\n", - " \"NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,selfHist,NeighborHist);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"figure;\",\n", - " \"results{1}.plotResults;\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"paramEst = squeeze(Summary.bAct(:,2,:));\",\n", - " \"meanParams = mean(paramEst,2);\",\n", - " \"clear lambdaCIF;\",\n", - " \"b0=paramEst(1,:);\",\n", - " \"b1=paramEst(2,:);\",\n", - " \"for i=1:numRealizations\",\n", - " \"lambdaCIF{i} = CIF([b0(i) b1(i)],{'1','x'},{'x'},'binomial');\",\n", - " \"end\",\n", - " \"spikeColl.resample(1/delta);\",\n", - " \"dN=spikeColl.dataToMatrix;\",\n", - " \"Q=2*std(stim.data(2:end)-stim.data(1:end-1));\",\n", - " \"A=1;\",\n", - " \"[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN',b0,b1,'binomial',delta);\",\n", - " \"figure;\",\n", - " \"zVal=3;\",\n", - " \"ciLower = min(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\",\n", - " \"ciUpper = max(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))');\",\n", - " \"hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'g'); hold on;\",\n", - " \"hold all;\",\n", - " \"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\",\n", - " \"legend off;\",\n", - " \"legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\\\sigma_{k|k}'),...\",\n", - " \"strcat('x_{k|k}(t)+',num2str(zVal),'\\\\sigma_{k|k}'),'x(t)');\",\n", - " \"title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for DecodingExample.\")\n", - "\n", - "# 1D Decoding workflow: decode latent state sequence from population spikes.\n", - "n_units = 14\n", - "n_states = 17\n", - "n_time = 260\n", - "state_idx = np.arange(n_states)\n", - "\n", - "transition = np.zeros((n_states, n_states), dtype=float)\n", - "for i in range(n_states):\n", - " for j, w in ((i - 1, 0.2), (i, 0.6), (i + 1, 0.2)):\n", - " if 0 <= j < n_states:\n", - " transition[i, j] += w\n", - " transition[i, :] /= np.sum(transition[i, :])\n", - "\n", - "latent = np.zeros(n_time, dtype=int)\n", - "latent[0] = n_states // 2\n", - "for t in range(1, n_time):\n", - " latent[t] = rng.choice(n_states, p=transition[latent[t - 1]])\n", - "\n", - "centers = np.linspace(0.0, n_states - 1, n_units)\n", - "widths = np.full(n_units, 2.1)\n", - "state_axis = np.arange(n_states)[None, :]\n", - "tuning = 0.06 + 0.42 * np.exp(-0.5 * ((state_axis - centers[:, None]) / widths[:, None]) ** 2)\n", - "\n", - "use_history = TOPIC in {\"DecodingExampleWithHist\", \"nSTATPaperExamples\"}\n", - "\n", - "if use_history:\n", - " gain = np.ones(n_time, dtype=float)\n", - " counts = np.zeros((n_units, n_time), dtype=float)\n", - " prev = 0.0\n", - " for t in range(n_time):\n", - " gain[t] = np.exp(0.50 * prev)\n", - " lam = tuning[:, latent[t]] * gain[t]\n", - " counts[:, t] = rng.poisson(lam)\n", - " prev = float(np.mean(counts[:, t]))\n", - "\n", - " decoded_raw, _ = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition)\n", - " corrected = counts / gain[None, :]\n", - " decoded, posterior = DecodingAlgorithms.decode_state_posterior(corrected, tuning, transition)\n", - " rmse_raw = float(np.sqrt(np.mean((decoded_raw - latent) ** 2)) / (n_states - 1))\n", - " rmse_dec = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1))\n", - "else:\n", - " counts = np.zeros((n_units, n_time), dtype=float)\n", - " for t in range(n_time):\n", - " counts[:, t] = rng.poisson(tuning[:, latent[t]])\n", - " decoded, posterior = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition)\n", - " rmse_raw = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1))\n", - " rmse_dec = rmse_raw\n", - "\n", - "fig, axes = plt.subplots(2, 1, figsize=(9, 7), sharex=True)\n", - "axes[0].plot(latent, label=\"true\", linewidth=1.2)\n", - "axes[0].plot(decoded, label=\"decoded\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: latent-state decoding\")\n", - "axes[0].set_ylabel(\"state\")\n", - "axes[0].legend(loc=\"upper right\")\n", - "\n", - "im = axes[1].imshow(posterior, aspect=\"auto\", origin=\"lower\", cmap=\"viridis\")\n", - "axes[1].set_title(\"Posterior over latent states\")\n", - "axes[1].set_xlabel(\"time bin\")\n", - "axes[1].set_ylabel(\"state\")\n", - "fig.colorbar(im, ax=axes[1], fraction=0.03, pad=0.02)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "print(\"rmse_raw\", rmse_raw, \"rmse_final\", rmse_dec)\n", - "assert np.max(np.abs(np.sum(posterior, axis=0) - 1.0)) < 1e-6\n", - "if use_history:\n", - " assert rmse_dec <= rmse_raw + 0.03\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_raw\": float(rmse_raw),\n", - " \"rmse_dec\": float(rmse_dec),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_raw\": (0.0, 0.65),\n", - " \"rmse_dec\": (0.0, 0.65),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "decoding_1d", - "run_group": "smoke", - "section_count": 4, - "source_helpfile": "DecodingExample.m", - "topic": "DecodingExample" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/DecodingExampleWithHist.ipynb b/notebooks/helpfiles/DecodingExampleWithHist.ipynb deleted file mode 100644 index adde4713..00000000 --- a/notebooks/helpfiles/DecodingExampleWithHist.ipynb +++ /dev/null @@ -1,402 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "1bc4a177", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/2 for DecodingExampleWithHist: 1-D Stimulus Decode with History Effect\n", - "\n", - "# % 1-D Stimulus Decode with History Effect\n", - "# In the above decoding example, the simulated neurons did not have memory.\n", - "# That is their previous firing activity did not modulate their current\n", - "# probability of firing. In reality the firing history does affect the\n", - "# probabilty of neuronal firing (eg. refractory period, bursting, etc.).\n", - "# In this example, we simulate a population a neurons that exhibit this\n", - "# type of history dependence. We then decode the stimulus activity based on\n", - "# a conditional intensity function that includes the correct history terms\n", - "# and one that assumes no history dependence.\n", - "#\n", - "#\n", - "# MATLAB: close all;\n", - "# clear all;\n", - "# MATLAB: delta = 0.001; Tmax = 1;\n", - "# MATLAB: time = 0:delta:Tmax;\n", - "# MATLAB: f=1; b1=1;b0=-2;\n", - "# MATLAB: stimData = b1*sin(2*pi*f*time);\n", - "# MATLAB: e = zeros(length(time),1); %No Ensemble input\n", - "# MATLAB: mu = b0; %baseline firing rate\n", - "# MATLAB: Ts=delta;\n", - "#\n", - "# MATLAB: histCoeffs= [-2 -2 -4];\n", - "# MATLAB: windowTimes=[0 .001 0.002 0.003];\n", - "# MATLAB: histObj = History(windowTimes);\n", - "# MATLAB: filts = histObj.toFilter(Ts); %Convert to transfer function matrix\n", - "# MATLAB: H=histCoeffs*filts; %scale each window transfer function by its coefficient\n", - "# MATLAB: S=tf([1],1,Ts,'Variable','z^-1'); %Feed the stimulus in directly\n", - "# MATLAB: E=tf([0],1,Ts,'Variable','z^-1'); %No ensemble effect\n", - "# MATLAB: stim=Covariate(time',stimData,'Stimulus','time','s','Voltage',{'sin'});\n", - "# MATLAB: ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\n", - "# MATLAB: numRealizations = 20; %Number of sample paths to generate\n", - "# MATLAB: sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations);\n", - "#\n", - "# MATLAB: figure;\n", - "# MATLAB: subplot(2,1,1); sC.plot;\n", - "# MATLAB: subplot(2,1,2); stim.plot;\n", - "#\n", - "#\n", - "# MATLAB: for i=1:numRealizations\n", - "# Construct a CIF object for each realization based on our encoding\n", - "# results above\n", - "# correct CIF w/ History\n", - "# MATLAB: lambdaCIF{i} = CIF([mu b1],{'1','x'},{'x'},'binomial',histCoeffs,histObj);\n", - "# CIF ignoring the history effect\n", - "# MATLAB: lambdaCIFNoHist{i} = CIF([mu b1],{'1','x'},{'x'},'binomial');\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: sC.resample(1/delta);\n", - "# MATLAB: dN=sC.dataToMatrix;\n", - "# Make noise according to the dynamic range of the stimulus\n", - "# MATLAB: Q=2*std(stim.data(2:end)-stim.data(1:end-1));\n", - "# MATLAB: Px0=.1; A=1;\n", - "# Decode with the correct and incorrect CIFs\n", - "#\n", - "# MATLAB: [x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\n", - "# MATLAB: [x_pNoHist, W_pNoHist, x_uNoHist, W_uNoHist] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIFNoHist,delta);\n", - "#\n", - "#\n", - "# Compare the results\n", - "# MATLAB: figure;\n", - "# MATLAB: subplot(2,1,1);\n", - "# MATLAB: zVal=3;\n", - "# MATLAB: ciLower = min(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\n", - "# MATLAB: ciUpper = max(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\n", - "# MATLAB: hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\n", - "# MATLAB: hold all;\n", - "#\n", - "# MATLAB: hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\n", - "# MATLAB: legend off;\n", - "# MATLAB: legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\sigma_{k|k}'),...\n", - "# MATLAB: strcat('x_{k|k}(t)+',num2str(zVal),'\\sigma_{k|k}'),'x_{k|k}(t)','x(t)');\n", - "# MATLAB: title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\n", - "#\n", - "# MATLAB: subplot(2,1,2);\n", - "# MATLAB: zVal=3;\n", - "# MATLAB: ciLower = min(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\n", - "# MATLAB: ciUpper = max(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\n", - "# MATLAB: hEst=plot(time,x_uNoHist(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\n", - "# MATLAB: hold all;\n", - "#\n", - "# MATLAB: hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\n", - "# MATLAB: legend off;\n", - "# MATLAB: legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\sigma_{k|k}'),...\n", - "# MATLAB: strcat('x_{k|k}(t)+',num2str(zVal),'\\sigma_{k|k}'),'x_{k|k}(t)','x(t)');\n", - "# MATLAB: title(['Decoded Stimulus No Hist +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: DecodingExampleWithHist\n", - "# Execution group: smoke\n", - "# Workflow family: decoding_1d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/DecodingExampleWithHist.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"DecodingExampleWithHist\"\n", - "FAMILY = \"decoding_1d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"DecodingExampleWithHist: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"DecodingExampleWithHist: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"DecodingExampleWithHist: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"DecodingExampleWithHist: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 3\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=1, matlab_line_number=34, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExampleWithHist.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 1, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=1, matlab_line_number=63, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExampleWithHist_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 1, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eaf79823", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/2 for DecodingExampleWithHist: Section\n", - "\n", - "# %\n", - "# We see that inclusion of history effect improves (as expected) the\n", - "# decoding of the stimulus based on the point process observations\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=90, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"DecodingExampleWithHist_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 2, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"delta = 0.001; Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=1; b1=1;b0=-2;\",\n", - " \"stimData = b1*sin(2*pi*f*time);\",\n", - " \"e = zeros(length(time),1); %No Ensemble input\",\n", - " \"mu = b0; %baseline firing rate\",\n", - " \"Ts=delta;\",\n", - " \"histCoeffs= [-2 -2 -4];\",\n", - " \"windowTimes=[0 .001 0.002 0.003];\",\n", - " \"histObj = History(windowTimes);\",\n", - " \"filts = histObj.toFilter(Ts); %Convert to transfer function matrix\",\n", - " \"H=histCoeffs*filts; %scale each window transfer function by its coefficient\",\n", - " \"S=tf([1],1,Ts,'Variable','z^-1'); %Feed the stimulus in directly\",\n", - " \"E=tf([0],1,Ts,'Variable','z^-1'); %No ensemble effect\",\n", - " \"stim=Covariate(time',stimData,'Stimulus','time','s','Voltage',{'sin'});\",\n", - " \"ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\",\n", - " \"numRealizations = 20; %Number of sample paths to generate\",\n", - " \"sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1); sC.plot;\",\n", - " \"subplot(2,1,2); stim.plot;\",\n", - " \"for i=1:numRealizations\",\n", - " \"lambdaCIF{i} = CIF([mu b1],{'1','x'},{'x'},'binomial',histCoeffs,histObj);\",\n", - " \"lambdaCIFNoHist{i} = CIF([mu b1],{'1','x'},{'x'},'binomial');\",\n", - " \"end\",\n", - " \"sC.resample(1/delta);\",\n", - " \"dN=sC.dataToMatrix;\",\n", - " \"Q=2*std(stim.data(2:end)-stim.data(1:end-1));\",\n", - " \"Px0=.1; A=1;\",\n", - " \"[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\",\n", - " \"[x_pNoHist, W_pNoHist, x_uNoHist, W_uNoHist] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIFNoHist,delta);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1);\",\n", - " \"zVal=3;\",\n", - " \"ciLower = min(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\",\n", - " \"ciUpper = max(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))');\",\n", - " \"hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\",\n", - " \"hold all;\",\n", - " \"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\",\n", - " \"legend off;\",\n", - " \"legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\\\sigma_{k|k}'),...\",\n", - " \"strcat('x_{k|k}(t)+',num2str(zVal),'\\\\sigma_{k|k}'),'x(t)');\",\n", - " \"title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\",\n", - " \"subplot(2,1,2);\",\n", - " \"zVal=3;\",\n", - " \"ciLower = min(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\",\n", - " \"ciUpper = max(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))');\",\n", - " \"hEst=plot(time,x_uNoHist(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on;\",\n", - " \"hold all;\",\n", - " \"hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});\",\n", - " \"legend off;\",\n", - " \"legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\\\\sigma_{k|k}'),...\",\n", - " \"strcat('x_{k|k}(t)+',num2str(zVal),'\\\\sigma_{k|k}'),'x(t)');\",\n", - " \"title(['Decoded Stimulus No Hist +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for DecodingExampleWithHist.\")\n", - "\n", - "# 1D Decoding workflow: decode latent state sequence from population spikes.\n", - "n_units = 14\n", - "n_states = 17\n", - "n_time = 260\n", - "state_idx = np.arange(n_states)\n", - "\n", - "transition = np.zeros((n_states, n_states), dtype=float)\n", - "for i in range(n_states):\n", - " for j, w in ((i - 1, 0.2), (i, 0.6), (i + 1, 0.2)):\n", - " if 0 <= j < n_states:\n", - " transition[i, j] += w\n", - " transition[i, :] /= np.sum(transition[i, :])\n", - "\n", - "latent = np.zeros(n_time, dtype=int)\n", - "latent[0] = n_states // 2\n", - "for t in range(1, n_time):\n", - " latent[t] = rng.choice(n_states, p=transition[latent[t - 1]])\n", - "\n", - "centers = np.linspace(0.0, n_states - 1, n_units)\n", - "widths = np.full(n_units, 2.1)\n", - "state_axis = np.arange(n_states)[None, :]\n", - "tuning = 0.06 + 0.42 * np.exp(-0.5 * ((state_axis - centers[:, None]) / widths[:, None]) ** 2)\n", - "\n", - "use_history = TOPIC in {\"DecodingExampleWithHist\", \"nSTATPaperExamples\"}\n", - "\n", - "if use_history:\n", - " gain = np.ones(n_time, dtype=float)\n", - " counts = np.zeros((n_units, n_time), dtype=float)\n", - " prev = 0.0\n", - " for t in range(n_time):\n", - " gain[t] = np.exp(0.50 * prev)\n", - " lam = tuning[:, latent[t]] * gain[t]\n", - " counts[:, t] = rng.poisson(lam)\n", - " prev = float(np.mean(counts[:, t]))\n", - "\n", - " decoded_raw, _ = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition)\n", - " corrected = counts / gain[None, :]\n", - " decoded, posterior = DecodingAlgorithms.decode_state_posterior(corrected, tuning, transition)\n", - " rmse_raw = float(np.sqrt(np.mean((decoded_raw - latent) ** 2)) / (n_states - 1))\n", - " rmse_dec = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1))\n", - "else:\n", - " counts = np.zeros((n_units, n_time), dtype=float)\n", - " for t in range(n_time):\n", - " counts[:, t] = rng.poisson(tuning[:, latent[t]])\n", - " decoded, posterior = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition)\n", - " rmse_raw = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1))\n", - " rmse_dec = rmse_raw\n", - "\n", - "fig, axes = plt.subplots(2, 1, figsize=(9, 7), sharex=True)\n", - "axes[0].plot(latent, label=\"true\", linewidth=1.2)\n", - "axes[0].plot(decoded, label=\"decoded\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: latent-state decoding\")\n", - "axes[0].set_ylabel(\"state\")\n", - "axes[0].legend(loc=\"upper right\")\n", - "\n", - "im = axes[1].imshow(posterior, aspect=\"auto\", origin=\"lower\", cmap=\"viridis\")\n", - "axes[1].set_title(\"Posterior over latent states\")\n", - "axes[1].set_xlabel(\"time bin\")\n", - "axes[1].set_ylabel(\"state\")\n", - "fig.colorbar(im, ax=axes[1], fraction=0.03, pad=0.02)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "print(\"rmse_raw\", rmse_raw, \"rmse_final\", rmse_dec)\n", - "assert np.max(np.abs(np.sum(posterior, axis=0) - 1.0)) < 1e-6\n", - "if use_history:\n", - " assert rmse_dec <= rmse_raw + 0.03\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_raw\": float(rmse_raw),\n", - " \"rmse_dec\": float(rmse_dec),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_raw\": (0.0, 0.65),\n", - " \"rmse_dec\": (0.0, 0.65),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "decoding_1d", - "run_group": "smoke", - "section_count": 2, - "source_helpfile": "DecodingExampleWithHist.m", - "topic": "DecodingExampleWithHist" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/DocumentationSetup2025b.ipynb b/notebooks/helpfiles/DocumentationSetup2025b.ipynb deleted file mode 100644 index 64106884..00000000 --- a/notebooks/helpfiles/DocumentationSetup2025b.ipynb +++ /dev/null @@ -1,297 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "9208a76b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/5 for DocumentationSetup2025b: MATLAB 2025b Help Integration for nSTAT\n", - "\n", - "# % MATLAB 2025b Help Integration for nSTAT\n", - "# This page documents the help-file structure used by nSTAT so it appears as\n", - "# supplemental software documentation in MATLAB.\n", - "#\n", - "# The configuration in this release is aligned with MATLAB R2025b.\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: DocumentationSetup2025b\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/DocumentationSetup2025b.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"DocumentationSetup2025b\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"DocumentationSetup2025b: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"DocumentationSetup2025b: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"DocumentationSetup2025b: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"DocumentationSetup2025b: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 0\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e65124af", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/5 for DocumentationSetup2025b: Required Files\n", - "\n", - "# % Required Files\n", - "# nSTAT uses the standard external toolbox documentation layout:\n", - "#\n", - "# * `info.xml` in the toolbox root.\n", - "# * `helpfiles/helptoc.xml` with `toc version=\"2.0\"`.\n", - "# * HTML help content referenced by each `target` in `helptoc.xml`.\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d0b0ce0", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/5 for DocumentationSetup2025b: Build and Refresh the Search Database\n", - "\n", - "# % Build and Refresh the Search Database\n", - "# Run the installer script from the nSTAT root folder:\n", - "#\n", - "# nSTAT_Install\n", - "#\n", - "# or run these commands manually:\n", - "#\n", - "# rootDir = fileparts(which('nSTAT_Install'));\n", - "# helpDir = fullfile(rootDir,'helpfiles');\n", - "# builddocsearchdb(helpDir);\n", - "# rehash toolboxcache;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2905127a", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/5 for DocumentationSetup2025b: MATLAB 2025b Behavior\n", - "\n", - "# % MATLAB 2025b Behavior\n", - "# Starting in R2024b, toolbox documentation is shown in the system browser.\n", - "# External toolbox documentation appears in MATLAB documentation under\n", - "# Supplemental Software.\n", - "#\n", - "# Use these pages as entry points:\n", - "#\n", - "# * \n", - "# * \n", - "# * \n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "71048939", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/5 for DocumentationSetup2025b: Troubleshooting\n", - "\n", - "# % Troubleshooting\n", - "# * If the nSTAT docs are not visible, run `rehash toolboxcache`.\n", - "# * If nSTAT pages do not appear in search, run `builddocsearchdb` again.\n", - "# * Ensure all `target` entries in `helptoc.xml` map to real HTML files.\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# DocumentationSetup2025b: validate Python help-file layout and TOC targets.\n", - "from pathlib import Path\n", - "import yaml\n", - "\n", - "def resolve_repo_root() -> Path:\n", - " candidates = [Path.cwd().resolve()]\n", - " candidates.append(candidates[0].parent)\n", - " candidates.append(candidates[1].parent)\n", - " for root in candidates:\n", - " if (root / \"docs\" / \"help\").exists():\n", - " return root\n", - " return candidates[0]\n", - "\n", - "repo_root = resolve_repo_root()\n", - "help_root = repo_root / \"docs\" / \"help\"\n", - "docs_root = repo_root / \"docs\"\n", - "helptoc_path = help_root / \"helptoc.yml\"\n", - "payload = yaml.safe_load(helptoc_path.read_text(encoding=\"utf-8\")) if helptoc_path.exists() else {}\n", - "\n", - "def walk_nodes(nodes):\n", - " out = []\n", - " for node in nodes or []:\n", - " target = str(node.get(\"target\", \"\")).strip()\n", - " if target:\n", - " out.append(target)\n", - " out.extend(walk_nodes(node.get(\"children\", [])))\n", - " return out\n", - "\n", - "targets = walk_nodes(payload.get(\"toc\", payload.get(\"entries\", [])))\n", - "targets = sorted(set(targets))\n", - "def target_exists(target: str) -> bool:\n", - " candidate = Path(target)\n", - " candidates = []\n", - " if candidate.is_absolute():\n", - " candidates.append(candidate)\n", - " else:\n", - " candidates.append(help_root / candidate)\n", - " candidates.append(docs_root / candidate)\n", - " candidates.append(repo_root / candidate)\n", - " return any(path.exists() for path in candidates)\n", - "\n", - "resolved = [target_exists(target) for target in targets if not target.startswith(\"http\")]\n", - "n_ok = int(sum(resolved))\n", - "n_total = int(len(resolved))\n", - "n_missing = int(n_total - n_ok)\n", - "\n", - "md_pages = list(help_root.rglob(\"*.md\"))\n", - "html_pages = list(help_root.rglob(\"*.html\"))\n", - "\n", - "fig, axes = plt.subplots(1, 2, figsize=(9.2, 3.8))\n", - "axes[0].bar([\"targets\", \"valid\"], [n_total, n_ok], color=[\"tab:gray\", \"tab:blue\"])\n", - "axes[0].set_title(f\"{TOPIC}: TOC target validation\")\n", - "axes[0].set_ylabel(\"count\")\n", - "\n", - "axes[1].bar([\".md pages\", \".html pages\"], [len(md_pages), len(html_pages)], color=[\"tab:green\", \"tab:orange\"])\n", - "axes[1].set_title(\"Docs page inventory\")\n", - "axes[1].set_ylabel(\"count\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert n_total > 0\n", - "assert n_missing == 0\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"toc_targets\": float(n_total),\n", - " \"missing_targets\": float(n_missing),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"toc_targets\": (1.0, 5000.0),\n", - " \"missing_targets\": (0.0, 0.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "data", - "run_group": "full", - "section_count": 5, - "source_helpfile": "DocumentationSetup2025b.m", - "topic": "DocumentationSetup2025b" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/EventsExamples.ipynb b/notebooks/helpfiles/EventsExamples.ipynb deleted file mode 100644 index 0465ff0c..00000000 --- a/notebooks/helpfiles/EventsExamples.ipynb +++ /dev/null @@ -1,223 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "c0e58726", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/2 for EventsExamples: Events\n", - "\n", - "# % Events\n", - "# Events are simple object to use and are aimed to facilitate illustration\n", - "# of epochs in any time of data.\n", - "# MATLAB: close all;\n", - "# MATLAB: eTimes = sort(rand(1,3)*1);\n", - "# MATLAB: eLabels={'E_1','E_2','E_3'};\n", - "# MATLAB: eventColor = 'b';\n", - "# MATLAB: e=Events(eTimes,eLabels,eventColor);\n", - "# MATLAB: e.plot;\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: EventsExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/EventsExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"EventsExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"EventsExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"EventsExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"EventsExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"EventsExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 5\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "99d2a3b3", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/2 for EventsExamples: Section\n", - "\n", - "# %\n", - "# The color of the event markers can also be specified\n", - "# MATLAB: figure; e.plot([],'r'); %dont specify handle, use red; handel = gca;\n", - "# MATLAB: figure; e.plot([],'g'); %dont specify handle, use green;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; e.plot([],'r'); %dont specify handle, use red; handel = gca;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=13, matlab_snippet=\"figure; e.plot([],'r'); %dont specify handle, use red; handel = gca;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"EventsExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 2, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure; e.plot([],'g'); %dont specify handle, use green;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=14, matlab_snippet=\"figure; e.plot([],'g'); %dont specify handle, use green;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"EventsExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 2, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=11, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"EventsExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 2, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=11, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"EventsExamples_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 2, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=11, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"EventsExamples_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 2, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"eTimes = sort(rand(1,3)*1);\",\n", - " \"eLabels={'E_1','E_2','E_3'};\",\n", - " \"eventColor = 'b';\",\n", - " \"e=Events(eTimes,eLabels,eventColor);\",\n", - " \"e.plot;\",\n", - " \"figure; e.plot([],'r'); %dont specify handle, use red; handel = gca;\",\n", - " \"figure; e.plot([],'g'); %dont specify handle, use green;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for EventsExamples.\")\n", - "\n", - "# EventsExamples: visualize event markers over multiple contexts.\n", - "e_times = np.array([0.079, 0.579, 0.997], dtype=float); events = Events(times=e_times, labels=[\"E_1\", \"E_2\", \"E_3\"])\n", - "fig, ax = plt.subplots(1, 1, figsize=(10.74, 6.48))\n", - "for c in [\"b\", \"r\", \"g\", \"m\"]: ax.vlines(events.times, ymin=0.0, ymax=1.0, colors=c, linewidth=2.0, alpha=0.4)\n", - "for i, t_evt in enumerate(events.times): ax.text(t_evt - 0.02, 1.03, f\"E_{i+1}\", ha=\"left\", va=\"bottom\", fontsize=9, color=\"k\")\n", - "ax.set_xlim(0.0, 1.0); ax.set_ylim(0.0, 1.0); ax.set_title(f\"{TOPIC}: event overlays\"); plt.tight_layout(); plt.show()\n", - "assert events.times.size == 3 and bool(np.all(np.diff(events.times) > 0.0))\n", - "CHECKPOINT_METRICS = {\"event_count\": float(events.times.size), \"event_span\": float(events.times[-1] - events.times[0])}\n", - "CHECKPOINT_LIMITS = {\"event_count\": (3.0, 3.0), \"event_span\": (0.8, 1.0)}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "full", - "section_count": 2, - "source_helpfile": "EventsExamples.m", - "topic": "EventsExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/ExplicitStimulusWhiskerData.ipynb b/notebooks/helpfiles/ExplicitStimulusWhiskerData.ipynb deleted file mode 100644 index 86c8a14c..00000000 --- a/notebooks/helpfiles/ExplicitStimulusWhiskerData.ipynb +++ /dev/null @@ -1,639 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "19ebc217", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/7 for ExplicitStimulusWhiskerData: EXPLICIT STIMULUS EXAMPLE - WHISKER STIMULATION/THALAMIC NEURON\n", - "\n", - "# % EXPLICIT STIMULUS EXAMPLE - WHISKER STIMULATION/THALAMIC NEURON\n", - "# In the worksheet with analyze the stimulus effect and history effect on\n", - "# the firing of a thalamic neuron under a known stimulus consisting of\n", - "# whisker stimulation.\n", - "# Data from Demba Ba (demba@mit.edu)\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: ExplicitStimulusWhiskerData\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/ExplicitStimulusWhiskerData.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"ExplicitStimulusWhiskerData\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"ExplicitStimulusWhiskerData: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"ExplicitStimulusWhiskerData: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"ExplicitStimulusWhiskerData: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"ExplicitStimulusWhiskerData: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 10\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "12cfde2e", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/7 for ExplicitStimulusWhiskerData: Load the data\n", - "\n", - "# % Load the data\n", - "# MATLAB: close all;\n", - "# MATLAB: [~,~,explicitStimulusDir] = getPaperDataDirs();\n", - "#\n", - "# MATLAB: Direction=3; Neuron=1; Stim=2;\n", - "# MATLAB: datapath = fullfile(explicitStimulusDir,strcat('Dir', num2str(Direction)),...\n", - "# MATLAB: strcat('Neuron', num2str(Neuron)), strcat('Stim', num2str(Stim)));\n", - "# MATLAB: data=load(fullfile(datapath,'trngdataBis.mat'));\n", - "#\n", - "# MATLAB: time=0:.001:(length(data.t)-1)*.001;\n", - "# MATLAB: stimData = data.t;\n", - "# MATLAB: spikeTimes = time(data.y==1);\n", - "#\n", - "# MATLAB: stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\n", - "# MATLAB: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", - "# MATLAB: {'constant'});\n", - "#\n", - "# MATLAB: nst = nspikeTrain(spikeTimes);\n", - "# MATLAB: nspikeColl = nstColl(nst);\n", - "# MATLAB: cc = CovColl({stim,baseline});\n", - "# MATLAB: trial = Trial(nspikeColl,cc);\n", - "# MATLAB: trial.plot;\n", - "#\n", - "# MATLAB: figure;\n", - "# MATLAB: subplot(2,1,1);\n", - "# MATLAB: nst2 = nspikeTrain(spikeTimes);\n", - "# MATLAB: nst2.setMaxTime(21);nst.plot;\n", - "# MATLAB: subplot(2,1,2);\n", - "# MATLAB: stim.getSigInTimeWindow(0,21).plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=30, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 2, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2d0b8b79", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/7 for ExplicitStimulusWhiskerData: Fit a constant baseline and Find Stimulus Lag\n", - "\n", - "# % Fit a constant baseline and Find Stimulus Lag\n", - "# We fit a constant rate (Poisson) model to the data and use the fit\n", - "# residual to determine the appropriate lag for the stimulus.\n", - "# MATLAB: clear c;\n", - "# MATLAB: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", - "#\n", - "# Find Stimulus Lag (look for peaks in the cross-covariance function less\n", - "# than 1 second\n", - "# MATLAB: figure;\n", - "# MATLAB: results.Residual.xcov(stim).windowedSignal([0,1]).plot;\n", - "# MATLAB: [m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));\n", - "# Allow for shifts of less than 1 second\n", - "# MATLAB: stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\n", - "# MATLAB: stim = stim.shift(ShiftTime);\n", - "# MATLAB: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", - "# MATLAB: {'constant'});\n", - "#\n", - "# MATLAB: nst = nspikeTrain(spikeTimes);\n", - "# MATLAB: nspikeColl = nstColl(nst);\n", - "# MATLAB: cc = CovColl({stim,baseline});\n", - "# MATLAB: trial = Trial(nspikeColl,cc);\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=49, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 3, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bb00c232", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/7 for ExplicitStimulusWhiskerData: Compare constant rate model with model including stimulus effect\n", - "\n", - "# % Compare constant rate model with model including stimulus effect\n", - "# Addition of the stimulus improves the fits in terms of the KS plot and\n", - "# the making the rescaled ISIs less correlated. The Point Process Residula\n", - "# also looks more \"white\"\n", - "# MATLAB: clear c;\n", - "# MATLAB: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\n", - "# MATLAB: NeighborHist);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "# MATLAB: c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\n", - "# MATLAB: sampleRate,selfHist,NeighborHist);\n", - "# MATLAB: c{2}.setName('Baseline+Stimulus');\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", - "# MATLAB: results.plotResults;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1c626e14", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/7 for ExplicitStimulusWhiskerData: History Effect\n", - "\n", - "# % History Effect\n", - "# Determine the best history effect model using AIC, BIC, and KS statistic\n", - "# MATLAB: sampleRate=1000;\n", - "# MATLAB: delta=1/sampleRate*1;\n", - "# MATLAB: maxWindow=1; numWindows=30;\n", - "# MATLAB: windowTimes =unique(round([0 logspace(log10(delta),...\n", - "# MATLAB: log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\n", - "# MATLAB: results =Analysis.computeHistLagForAll(trial,windowTimes,...\n", - "# MATLAB: {{'Baseline','constant'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\n", - "#\n", - "# MATLAB: KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));\n", - "# MATLAB: AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...\n", - "# MATLAB: min(results{1}.AIC(2:end)-results{1}.AIC(1)));\n", - "# MATLAB: BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...\n", - "# MATLAB: min(results{1}.BIC(2:end)-results{1}.BIC(1)));\n", - "# MATLAB: if(AICind==1)\n", - "# MATLAB: AICind=inf;\n", - "# MATLAB: end\n", - "# MATLAB: if(BICind==1)\n", - "# MATLAB: BICind=inf; %sometime BIC is non-decreasing and the index would be 1\n", - "# MATLAB: end\n", - "# MATLAB: windowIndex = min([KSind,AICind,BICind]) %use the minimum order model\n", - "# MATLAB: Summary = FitResSummary(results);\n", - "# MATLAB: Summary.plotSummary;\n", - "#\n", - "#\n", - "# MATLAB: clear c;\n", - "# MATLAB: if(windowIndex>1)\n", - "# MATLAB: selfHist = windowTimes(1:windowIndex);\n", - "# MATLAB: else\n", - "# MATLAB: selfHist = [];\n", - "# MATLAB: end\n", - "# MATLAB: NeighborHist = []; sampleRate = 1000;\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "12644cbc", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/7 for ExplicitStimulusWhiskerData: Section\n", - "\n", - "# %\n", - "# MATLAB: figure;\n", - "# MATLAB: x=1:length(windowTimes);\n", - "# MATLAB: subplot(3,1,1); plot(x,results{1}.KSStats.ks_stat,'.'); axis tight; hold on;\n", - "# MATLAB: plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\n", - "#\n", - "# MATLAB: set(gca,'xtick',[]);\n", - "# MATLAB: ylabel('KS Statistic');\n", - "# MATLAB: dAIC = results{1}.AIC-results{1}.AIC(1);\n", - "# MATLAB: subplot(3,1,2); plot(x,dAIC,'.');\n", - "# MATLAB: set(gca,'xtick',[]);\n", - "# MATLAB: ylabel('\\Delta AIC');axis tight; hold on;\n", - "# MATLAB: plot(x(windowIndex),dAIC(windowIndex),'r*');\n", - "# MATLAB: dBIC = results{1}.BIC-results{1}.BIC(1);\n", - "# MATLAB: subplot(3,1,3); plot(x,dBIC,'.');\n", - "# MATLAB: ylabel('\\Delta BIC'); axis tight; hold on;\n", - "# MATLAB: plot(x(windowIndex),dBIC(windowIndex),'r*');\n", - "#\n", - "# MATLAB: for i=2:length(x)\n", - "# MATLAB: histLabels{i} = ['[' num2str(windowTimes(i-1),3) ',' num2str(windowTimes(i),3) ,']'];\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: figure;\n", - "# MATLAB: plot(x,dBIC,'.');\n", - "# MATLAB: xticks = 1:(length(histLabels));\n", - "# MATLAB: set(gca,'xtick',xticks,'xtickLabel',histLabels,'FontSize',6);\n", - "# MATLAB: if(max(xticks)>=1)\n", - "# MATLAB: xticklabel_rotate([],90,[],'Fontsize',8);\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=113, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 6, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=134, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 6, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 6\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "18ad2b09", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 7/7 for ExplicitStimulusWhiskerData: Compare Baseline, Baseline+Stimulus Model, Baseline+History+Stimulus\n", - "\n", - "# % Compare Baseline, Baseline+Stimulus Model, Baseline+History+Stimulus\n", - "# Addition of the history effect yields a model that falls within the 95%\n", - "# CI of the KS plot.\n", - "#\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,[],NeighborHist);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "# MATLAB: c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\n", - "# MATLAB: sampleRate,[],[]);\n", - "# MATLAB: c{2}.setName('Baseline+Stimulus');\n", - "# MATLAB: c{3} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\n", - "# MATLAB: sampleRate,windowTimes(1:windowIndex),[]);\n", - "# MATLAB: c{3}.setName('Baseline+Stimulus+Hist');\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", - "# MATLAB: results.plotResults;\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=143, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 7, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=143, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 7, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=143, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData_06.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=7 + 7, title=f\"{TOPIC} Figure 007\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=143, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData_07.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=8 + 7, title=f\"{TOPIC} Figure 008\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=143, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData_08.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=9 + 7, title=f\"{TOPIC} Figure 009\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=143, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ExplicitStimulusWhiskerData_09.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=10 + 7, title=f\"{TOPIC} Figure 010\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"[~,~,explicitStimulusDir] = getPaperDataDirs();\",\n", - " \"Direction=3; Neuron=1; Stim=2;\",\n", - " \"datapath = fullfile(explicitStimulusDir,strcat('Dir', num2str(Direction)),...\",\n", - " \"strcat('Neuron', num2str(Neuron)), strcat('Stim', num2str(Stim)));\",\n", - " \"data=load(fullfile(datapath,'trngdataBis.mat'));\",\n", - " \"time=0:.001:(length(data.t)-1)*.001;\",\n", - " \"stimData = data.t;\",\n", - " \"spikeTimes = time(data.y==1);\",\n", - " \"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"nspikeColl = nstColl(nst);\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial = Trial(nspikeColl,cc);\",\n", - " \"trial.plot;\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1);\",\n", - " \"nst2 = nspikeTrain(spikeTimes);\",\n", - " \"nst2.setMaxTime(21);nst.plot;\",\n", - " \"subplot(2,1,2);\",\n", - " \"stim.getSigInTimeWindow(0,21).plot;\",\n", - " \"clear c;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"figure;\",\n", - " \"results.Residual.xcov(stim).windowedSignal([0,1]).plot;\",\n", - " \"[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));\",\n", - " \"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\",\n", - " \"stim = stim.shift(ShiftTime);\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"nspikeColl = nstColl(nst);\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial = Trial(nspikeColl,cc);\",\n", - " \"clear c;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\",\n", - " \"NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,selfHist,NeighborHist);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"results.plotResults;\",\n", - " \"sampleRate=1000;\",\n", - " \"delta=1/sampleRate*1;\",\n", - " \"maxWindow=1; numWindows=30;\",\n", - " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", - " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", - " \"results =Analysis.computeHistLagForAll(trial,windowTimes,...\",\n", - " \"{{'Baseline','constant'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\",\n", - " \"KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));\",\n", - " \"AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...\",\n", - " \"min(results{1}.AIC(2:end)-results{1}.AIC(1)));\",\n", - " \"BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...\",\n", - " \"min(results{1}.BIC(2:end)-results{1}.BIC(1)));\",\n", - " \"if(AICind==1)\",\n", - " \"AICind=inf;\",\n", - " \"end\",\n", - " \"if(BICind==1)\",\n", - " \"BICind=inf; %sometime BIC is non-decreasing and the index would be 1\",\n", - " \"end\",\n", - " \"windowIndex = min([KSind,AICind,BICind]) %use the minimum order model\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\",\n", - " \"clear c;\",\n", - " \"if(windowIndex>1)\",\n", - " \"selfHist = windowTimes(1:windowIndex);\",\n", - " \"else\",\n", - " \"selfHist = [];\",\n", - " \"end\",\n", - " \"NeighborHist = []; sampleRate = 1000;\",\n", - " \"figure;\",\n", - " \"x=1:length(windowTimes);\",\n", - " \"subplot(3,1,1); plot(x,results{1}.KSStats.ks_stat,'.'); axis tight; hold on;\",\n", - " \"plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\",\n", - " \"set(gca,'xtick',[]);\",\n", - " \"ylabel('KS Statistic');\",\n", - " \"dAIC = results{1}.AIC-results{1}.AIC(1);\",\n", - " \"subplot(3,1,2); plot(x,dAIC,'.');\",\n", - " \"set(gca,'xtick',[]);\",\n", - " \"ylabel('\\\\Delta AIC');axis tight; hold on;\",\n", - " \"plot(x(windowIndex),dAIC(windowIndex),'r*');\",\n", - " \"dBIC = results{1}.BIC-results{1}.BIC(1);\",\n", - " \"subplot(3,1,3); plot(x,dBIC,'.');\",\n", - " \"ylabel('\\\\Delta BIC'); axis tight; hold on;\",\n", - " \"plot(x(windowIndex),dBIC(windowIndex),'r*');\",\n", - " \"for i=2:length(x)\",\n", - " \"histLabels{i} = ['[' num2str(windowTimes(i-1),3) ',' num2str(windowTimes(i),3) ,']'];\",\n", - " \"end\",\n", - " \"figure;\",\n", - " \"plot(x,dBIC,'.');\",\n", - " \"xticks = 1:(length(histLabels));\",\n", - " \"set(gca,'xtick',xticks,'xtickLabel',histLabels,'FontSize',6);\",\n", - " \"if(max(xticks)>=1)\",\n", - " \"xticklabel_rotate([],90,[],'Fontsize',8);\",\n", - " \"end\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,[],NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,[],[]);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"c{3} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,windowTimes(1:windowIndex),[]);\",\n", - " \"c{3}.setName('Baseline+Stimulus+Hist');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"results.plotResults;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for ExplicitStimulusWhiskerData.\")\n", - "\n", - "# ExplicitStimulusWhiskerData: stimulus-locked spiking with binomial GLM fit.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/ExplicitStimulusWhiskerData_gold.mat\"\n", - "m = loadmat(str(fixture_path))\n", - "time = np.asarray(m[\"time_ws\"], dtype=float).reshape(-1); stimulus = np.asarray(m[\"stimulus_ws\"], dtype=float).reshape(-1); spike = np.asarray(m[\"spike_ws\"], dtype=float).reshape(-1)\n", - "expected_prob = np.asarray(m[\"expected_prob_ws\"], dtype=float).reshape(-1); expected_rmse = float(np.asarray(m[\"expected_rmse_ws\"], dtype=float).reshape(-1)[0])\n", - "fit = Analysis.fit_glm(X=stimulus[:, None], y=spike, fit_type=\"binomial\", dt=1.0); pred_prob = np.asarray(fit.predict(stimulus[:, None]), dtype=float).reshape(-1)\n", - "window = np.ones(25, dtype=float) / 25.0; spike_prob = np.convolve(spike, window, mode=\"same\")\n", - "\n", - "fig, axes = plt.subplots(3, 1, figsize=(9.5, 7.2), sharex=False)\n", - "axes[0].plot(time, stimulus, color=\"k\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: explicit stimulus\")\n", - "axes[0].set_ylabel(\"z-score\")\n", - "\n", - "axes[1].vlines(time[spike > 0.0], 0.6, 1.4, linewidth=0.4)\n", - "axes[1].set_ylabel(\"trial #1\")\n", - "axes[1].set_title(\"Spike raster (MATLAB fixture trial)\")\n", - "\n", - "axes[2].plot(time, spike_prob, color=\"tab:blue\", linewidth=1.0, label=\"smoothed observed\")\n", - "axes[2].plot(time, pred_prob, color=\"tab:red\", linewidth=1.0, label=\"python fit\")\n", - "axes[2].plot(time, expected_prob, color=\"tab:green\", linewidth=0.9, linestyle=\"--\", label=\"matlab gold\")\n", - "axes[2].set_title(\"Observed and fitted spike probability\")\n", - "axes[2].set_xlabel(\"time [s]\")\n", - "axes[2].set_ylabel(\"p(spike)\")\n", - "axes[2].legend(loc=\"upper right\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "fit_rmse = float(np.sqrt(np.mean((pred_prob - spike) ** 2))); prob_max_abs = float(np.max(np.abs(pred_prob - expected_prob)))\n", - "assert pred_prob.shape == expected_prob.shape\n", - "assert prob_max_abs < 0.1\n", - "assert abs(fit_rmse - expected_rmse) < 0.1\n", - "CHECKPOINT_METRICS = {\n", - " \"prob_max_abs\": float(prob_max_abs),\n", - " \"fit_rmse\": float(fit_rmse),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"prob_max_abs\": (0.0, 0.1),\n", - " \"fit_rmse\": (0.0, 0.5),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "data", - "run_group": "full", - "section_count": 7, - "source_helpfile": "ExplicitStimulusWhiskerData.m", - "topic": "ExplicitStimulusWhiskerData" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/FitResSummaryExamples.ipynb b/notebooks/helpfiles/FitResSummaryExamples.ipynb deleted file mode 100644 index bad229f3..00000000 --- a/notebooks/helpfiles/FitResSummaryExamples.ipynb +++ /dev/null @@ -1,171 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "cc1606c2", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/1 for FitResSummaryExamples: FitResSummary Examples\n", - "\n", - "# % FitResSummary Examples\n", - "\n", - "# Python translation bootstrap + execution for single-section helpfile.\n", - "\n", - "# Topic: FitResSummaryExamples\n", - "# Execution group: full\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/FitResSummaryExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"FitResSummaryExamples\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"FitResSummaryExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"FitResSummaryExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"FitResSummaryExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"FitResSummaryExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 0\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n", - "\n", - "# FitResSummaryExamples: compare multiple fit results with IC summaries.\n", - "from nstat.compat.matlab import Analysis, FitResSummary\n", - "\n", - "dt = 0.01\n", - "t = np.arange(0.0, 10.0, dt)\n", - "x1 = np.sin(2.0 * np.pi * 0.6 * t)\n", - "x2 = np.cos(2.0 * np.pi * 0.2 * t + 0.15)\n", - "x3 = np.sin(2.0 * np.pi * 0.05 * t + 0.2)\n", - "eta = -2.2 + 0.7 * x1 - 0.5 * x2 + 0.3 * x3\n", - "y = rng.poisson(np.exp(eta) * dt)\n", - "\n", - "fit1 = Analysis.fitGLM(X=np.column_stack([x1]), y=y, fitType=\"poisson\", dt=dt)\n", - "fit2 = Analysis.fitGLM(X=np.column_stack([x1, x2]), y=y, fitType=\"poisson\", dt=dt)\n", - "fit3 = Analysis.fitGLM(X=np.column_stack([x1, x2, x3]), y=y, fitType=\"poisson\", dt=dt)\n", - "\n", - "summary = FitResSummary([fit1, fit2, fit3])\n", - "best_aic = summary.bestByAIC()\n", - "best_bic = summary.bestByBIC()\n", - "diff_aic = summary.getDiffAIC()\n", - "diff_bic = summary.getDiffBIC()\n", - "\n", - "fig, axes = plt.subplots(1, 2, figsize=(9.0, 3.8))\n", - "plt.sca(axes[0])\n", - "summary.plotAIC()\n", - "axes[0].set_title(f\"{TOPIC}: AIC\")\n", - "axes[0].set_xlabel(\"model index\")\n", - "axes[0].set_ylabel(\"AIC\")\n", - "plt.sca(axes[1])\n", - "summary.plotBIC()\n", - "axes[1].set_title(\"BIC\")\n", - "axes[1].set_xlabel(\"model index\")\n", - "axes[1].set_ylabel(\"BIC\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert diff_aic.size == diff_bic.size and diff_aic.size > 0\n", - "assert np.isfinite(best_aic.aic()) and np.isfinite(best_bic.bic())\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"num_models\": float(diff_aic.size),\n", - " \"best_aic_diff\": float(np.min(diff_aic)),\n", - " \"best_bic_diff\": float(np.min(diff_bic)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"num_models\": (3.0, 3.0),\n", - " \"best_aic_diff\": (-10.0, 10.0),\n", - " \"best_bic_diff\": (-10.0, 10.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "analysis", - "run_group": "full", - "section_count": 1, - "source_helpfile": "FitResSummaryExamples.m", - "topic": "FitResSummaryExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/FitResultExamples.ipynb b/notebooks/helpfiles/FitResultExamples.ipynb deleted file mode 100644 index 3fdd5f7b..00000000 --- a/notebooks/helpfiles/FitResultExamples.ipynb +++ /dev/null @@ -1,171 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "682093fc", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/1 for FitResultExamples: FitResult Examples\n", - "\n", - "# % FitResult Examples\n", - "\n", - "# Python translation bootstrap + execution for single-section helpfile.\n", - "\n", - "# Topic: FitResultExamples\n", - "# Execution group: full\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/FitResultExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"FitResultExamples\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"FitResultExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"FitResultExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"FitResultExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"FitResultExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 0\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n", - "\n", - "# FitResultExamples: fit GLM, inspect fit object, and plot diagnostics.\n", - "from nstat.compat.matlab import Analysis, FitResult\n", - "\n", - "dt = 0.01\n", - "t = np.arange(0.0, 10.0, dt)\n", - "x1 = np.sin(2.0 * np.pi * 0.7 * t)\n", - "x2 = np.cos(2.0 * np.pi * 0.2 * t + 0.4)\n", - "X = np.column_stack([x1, x2])\n", - "eta = -1.9 + 0.8 * x1 - 0.45 * x2\n", - "lam = np.exp(eta)\n", - "y = rng.poisson(np.clip(lam * dt, 0.0, 0.9))\n", - "\n", - "fit_native = Analysis.fitGLM(X=X, y=y, fitType=\"poisson\", dt=dt)\n", - "fit = FitResult.fromStructure(fit_native.to_structure())\n", - "fit.parameter_labels = [\"x1\", \"x2\"]\n", - "fit.setFitResidual(Analysis.computeFitResidual(y=y, X=X, fit=fit, dt=dt))\n", - "\n", - "lam_hat = fit.evalLambda(X)\n", - "aic = fit.getAIC()\n", - "bic = fit.getBIC()\n", - "\n", - "fig, axes = plt.subplots(2, 1, figsize=(9.0, 6.0), sharex=False)\n", - "plt.sca(axes[0])\n", - "fit.plotCoeffs()\n", - "axes[0].set_title(f\"{TOPIC}: coefficients\")\n", - "axes[0].set_ylabel(\"weight\")\n", - "axes[1].plot(t, lam, \"k\", linewidth=1.2, label=\"true\")\n", - "axes[1].plot(t, lam_hat, \"tab:blue\", linewidth=1.0, label=\"fit\")\n", - "axes[1].set_title(\"Lambda fit\")\n", - "axes[1].set_xlabel(\"time [s]\")\n", - "axes[1].set_ylabel(\"Hz\")\n", - "axes[1].legend(loc=\"upper right\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert np.isfinite(aic) and np.isfinite(bic)\n", - "assert lam_hat.shape == lam.shape\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"aic\": float(aic),\n", - " \"bic\": float(bic),\n", - " \"lambda_rmse\": float(np.sqrt(np.mean((lam_hat - lam) ** 2))),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"aic\": (-1.0e6, 1.0e6),\n", - " \"bic\": (-1.0e6, 1.0e6),\n", - " \"lambda_rmse\": (0.0, 10.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "analysis", - "run_group": "full", - "section_count": 1, - "source_helpfile": "FitResultExamples.m", - "topic": "FitResultExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/FitResultReference.ipynb b/notebooks/helpfiles/FitResultReference.ipynb deleted file mode 100644 index 79533bf9..00000000 --- a/notebooks/helpfiles/FitResultReference.ipynb +++ /dev/null @@ -1,176 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "e9575083", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/1 for FitResultReference: FitResult Reference\n", - "\n", - "# % FitResult Reference\n", - "# The `FitResult` class stores model fitting outputs generated by\n", - "# `Analysis.RunAnalysisForNeuron` and `Analysis.RunAnalysisForAllNeurons`.\n", - "#\n", - "# This reference page is generated from the canonical runtime class:\n", - "#\n", - "# * <../FitResult.m FitResult.m>\n", - "#\n", - "# Related pages:\n", - "#\n", - "# * \n", - "# * \n", - "# * \n", - "\n", - "# Python translation bootstrap + execution for single-section helpfile.\n", - "\n", - "# Topic: FitResultReference\n", - "# Execution group: full\n", - "# Workflow family: analysis\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/FitResultReference.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"FitResultReference\"\n", - "FAMILY = \"analysis\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"FitResultReference: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"FitResultReference: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"FitResultReference: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"FitResultReference: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 0\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n", - "\n", - "# FitResultReference: serialize/restore fit metadata and inspect fields.\n", - "from nstat.compat.matlab import Analysis, FitResult\n", - "\n", - "dt = 0.02\n", - "t = np.arange(0.0, 12.0, dt)\n", - "x = np.column_stack([np.sin(2.0 * np.pi * 0.35 * t), np.cos(2.0 * np.pi * 0.15 * t)])\n", - "y = rng.poisson(np.exp(-2.0 + 0.9 * x[:, 0] - 0.4 * x[:, 1]) * dt)\n", - "\n", - "fit_native = Analysis.fitGLM(X=x, y=y, fitType=\"poisson\", dt=dt)\n", - "fit_native.parameter_labels = [\"stim_sin\", \"stim_cos\"]\n", - "payload = fit_native.to_structure()\n", - "fit = FitResult.fromStructure(payload)\n", - "\n", - "lam_hat = fit.evalLambda(x)\n", - "coef = fit.getCoeffs()\n", - "param = fit.getParam(\"intercept\")\n", - "\n", - "fig, axes = plt.subplots(1, 2, figsize=(9.2, 3.6))\n", - "axes[0].bar(np.arange(coef.size), coef, color=\"tab:blue\")\n", - "axes[0].set_xticks(np.arange(coef.size), labels=fit.parameter_labels or [\"c1\", \"c2\"], rotation=35, ha=\"right\")\n", - "axes[0].set_title(f\"{TOPIC}: coefficients\")\n", - "axes[0].set_ylabel(\"weight\")\n", - "\n", - "axes[1].plot(t, lam_hat, color=\"tab:green\", linewidth=1.1)\n", - "axes[1].set_title(\"evalLambda output\")\n", - "axes[1].set_xlabel(\"time [s]\")\n", - "axes[1].set_ylabel(\"Hz\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert np.isfinite(float(param))\n", - "assert lam_hat.size == t.size\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"coef_norm\": float(np.linalg.norm(coef)),\n", - " \"intercept\": float(param),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"coef_norm\": (0.0, 100.0),\n", - " \"intercept\": (-20.0, 20.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "analysis", - "run_group": "full", - "section_count": 1, - "source_helpfile": "FitResultReference.m", - "topic": "FitResultReference" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/HippocampalPlaceCellExample.ipynb b/notebooks/helpfiles/HippocampalPlaceCellExample.ipynb deleted file mode 100644 index 0665a761..00000000 --- a/notebooks/helpfiles/HippocampalPlaceCellExample.ipynb +++ /dev/null @@ -1,1037 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "673e06ab", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/6 for HippocampalPlaceCellExample: HIPPOCAMPAL PLACE CELL - RECEPTIVE FIELD ESTIMATION\n", - "\n", - "# % HIPPOCAMPAL PLACE CELL - RECEPTIVE FIELD ESTIMATION\n", - "# Estimation of receptive fields of neurons is a very common data analysis problem in neuroscience.\n", - "# Here we use the nSTAT software to perform an estimation of the receptive fields of hippocampal\n", - "# place cells using a bivariate Gaussian model and Zernike polynomials. The number of zernike polynomials\n", - "# is based on \"An Analysis of Hippocampal Spatio-Temporal Representations Using a Bayesian Algorithm for Neural\n", - "# Spike Train Decoding\" Barbieri et. al 2005. The data used herein in was\n", - "# provided by Dr. Ricardo Barbieri on 2/28/2011.\n", - "#\n", - "# *Author*: Iahn Cajigas\n", - "#\n", - "# *Date*: 3/1/2011\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: HippocampalPlaceCellExample\n", - "# Execution group: full\n", - "# Workflow family: decoding_2d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/HippocampalPlaceCellExample.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"HippocampalPlaceCellExample\"\n", - "FAMILY = \"decoding_2d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"HippocampalPlaceCellExample: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"HippocampalPlaceCellExample: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"HippocampalPlaceCellExample: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"HippocampalPlaceCellExample: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 12\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1a3b2eb8", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/6 for HippocampalPlaceCellExample: Section\n", - "\n", - "# %\n", - "# MATLAB: close all\n", - "# MATLAB: [~,~,~,~,placeCellDataDir] = getPaperDataDirs();\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4cebe8da", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/6 for HippocampalPlaceCellExample: Example Data\n", - "\n", - "# % Example Data\n", - "# The x and y coordinates of a freely foraging rat in a circular environment (70cm in diameter and 30cm high walls) and a fixed visual cue.\n", - "# The x and y coordinates at the time when a spike was observed are marked\n", - "# in red. The position coordinates have been normalized to be between -1\n", - "# and 1 to allow to simplify the analysis.\n", - "# MATLAB: load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\n", - "# MATLAB: exampleCell = 25;\n", - "# MATLAB: figure(1);\n", - "# MATLAB: plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", - "# MATLAB: xlabel('x'); ylabel('y');\n", - "# MATLAB: title(['Animal#1, Cell#' num2str(exampleCell)]);\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure(1);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=23, matlab_snippet=\"figure(1);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 3, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e04651a2", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/6 for HippocampalPlaceCellExample: Analyze All Cells\n", - "\n", - "# % Analyze All Cells\n", - "# MATLAB: numAnimals =2;\n", - "# MATLAB: for n=1:numAnimals\n", - "# load the data\n", - "# MATLAB: clear x y neuron time nst tc tcc z;\n", - "# MATLAB: load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\n", - "#\n", - "# Create the spikeTrains for each cell\n", - "# MATLAB: for i=1:length(neuron)\n", - "# MATLAB: nst{i} = nspikeTrain(neuron{i}.spikeTimes);\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# Convert to polar coordinates\n", - "# MATLAB: [theta,r] = cart2pol(x,y);\n", - "#\n", - "#\n", - "# Evaluate the Zernike Polynomials\n", - "# Number of polynomials from \"An Analysis of Hippocampal\n", - "# Spatio-Temporal Representations Using a Bayesian Algorithm for Neural\n", - "# Spike Train Decoding\" Barbieri et. al 2005\n", - "# MATLAB: cnt=0;\n", - "# MATLAB: for l=0:3\n", - "# MATLAB: for m=-l:l\n", - "# MATLAB: if(~any(mod(l-m,2))) % otherwise the polynomial = 0\n", - "# MATLAB: cnt = cnt+1;\n", - "# MATLAB: z(:,cnt) = zernfun(l,m,r,theta,'norm');\n", - "# zernfun by Paul Fricker\n", - "# http://www.mathworks.com/matlabcentral/fileexchange/7687\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "# Data sampled at 30 Hz but just to be sure\n", - "# MATLAB: delta=min(diff(time));\n", - "# MATLAB: sampleRate = round(1/delta);\n", - "#\n", - "# Define Covariates for the analysis\n", - "# MATLAB: baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\n", - "# MATLAB: {'mu'});\n", - "# MATLAB: zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\n", - "# MATLAB: 'z4','z5','z6','z7','z8','z9','z10'});\n", - "# MATLAB: gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\n", - "# MATLAB: 's','m',{'x','y','x^2','y^2','x*y'});\n", - "# MATLAB: covarColl = CovColl({baseline,gaussian,zernike});\n", - "#\n", - "# Create the trial structure\n", - "# MATLAB: spikeColl = nstColl(nst);\n", - "# MATLAB: trial = Trial(spikeColl,covarColl);\n", - "#\n", - "#\n", - "# Define how we want to analyze the data\n", - "# MATLAB: tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\n", - "# MATLAB: 'x','y','x^2','y^2','x*y'}},sampleRate,[]);\n", - "# MATLAB: tc{1}.setName('Gaussian');\n", - "# MATLAB: tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\n", - "# MATLAB: 'z7','z8','z9','z10'}},sampleRate,[]);\n", - "# MATLAB: tc{2}.setName('Zernike');\n", - "# MATLAB: tcc = ConfigColl(tc);\n", - "#\n", - "# Perform Analysis (Commented to since data already saved)\n", - "# results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", - "#\n", - "# Save results\n", - "# resStruct =FitResult.CellArrayToStructure(results);\n", - "# filename = ['PlaceCellAnimal' num2str(n) 'Results'];\n", - "# save(filename,'resStruct');\n", - "# MATLAB: end\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f461d2a9", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/6 for HippocampalPlaceCellExample: View Summary Statistics\n", - "\n", - "# % View Summary Statistics\n", - "# Note the Zernike Polynomials yield better fits in terms of decreased KS\n", - "# Statistics (less deviation from the 45 degree line), reduced AIC and\n", - "# reduced BIC across the majority of cells and for both animals\n", - "# MATLAB: for n=1:numAnimals\n", - "# MATLAB: resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\n", - "# MATLAB: results = FitResult.fromStructure(resData.resStruct);\n", - "# MATLAB: Summary = FitResSummary(results);\n", - "# MATLAB: Summary.plotSummary;\n", - "# MATLAB: end\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d5d68b22", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/6 for HippocampalPlaceCellExample: Visualize the results\n", - "\n", - "# % Visualize the results\n", - "#\n", - "# Define a grid\n", - "# MATLAB: [x_new,y_new]=meshgrid(-1:.01:1); %define new x and y\n", - "# MATLAB: y_new = flipud(y_new); x_new = fliplr(x_new);\n", - "# MATLAB: [theta_new,r_new] = cart2pol(x_new,y_new);\n", - "#\n", - "# Data for the gaussian fit\n", - "# MATLAB: newData{1} =ones(size(x_new));\n", - "# MATLAB: newData{2} =x_new; newData{3} =y_new;\n", - "# MATLAB: newData{4} =x_new.^2; newData{5} =y_new.^2;\n", - "# MATLAB: newData{6} =x_new.*y_new;\n", - "#\n", - "#\n", - "# Zernike polynomials only defined on the unit disk\n", - "# MATLAB: idx = r_new<=1;\n", - "# MATLAB: zpoly = cell(1,10);\n", - "# MATLAB: cnt=0;\n", - "# MATLAB: for l=0:3\n", - "# MATLAB: for m=-l:l\n", - "# MATLAB: if(~any(mod(l-m,2)))\n", - "# MATLAB: cnt = cnt+1;\n", - "# MATLAB: temp = nan(size(x_new));\n", - "# MATLAB: temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\n", - "# MATLAB: zpoly{cnt} = temp;\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: for n=1:numAnimals\n", - "#\n", - "# MATLAB: clear lambdaGaussian lambdaZernike;\n", - "# MATLAB: load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\n", - "# MATLAB: resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\n", - "# MATLAB: results = FitResult.fromStructure(resData.resStruct);\n", - "#\n", - "# MATLAB: for i=1:length(neuron)\n", - "# Evaluate our fits using the new data and the estimated parameters\n", - "# MATLAB: lambdaGaussian{i} = results{i}.evalLambda(1,newData);\n", - "# MATLAB: lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# Plot the receptive fields\n", - "# MATLAB: for i=1:length(neuron)\n", - "# 3d plot of an example place field\n", - "#\n", - "#\n", - "# 2d plot of all the cell's fields\n", - "# MATLAB: if(n==1)\n", - "# MATLAB: h4=figure(4);\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: annotation(h4,'textbox',...\n", - "# MATLAB: [0.343261904761904 0.928571428571418 ...\n", - "# MATLAB: 0.392857142857143 0.0595238095238095],...\n", - "# MATLAB: 'String',{['Gaussian Place Fields - Animal#' ...\n", - "# MATLAB: num2str(n)]},'FitBoxToText','on'); hold on;\n", - "# MATLAB: end\n", - "# MATLAB: subplot(7,7,i);\n", - "# MATLAB: elseif(n==2)\n", - "# MATLAB: h6=figure(6);\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: annotation(h6,'textbox',...\n", - "# MATLAB: [0.343261904761904 0.928571428571418 ...\n", - "# MATLAB: 0.392857142857143 0.0595238095238095],...\n", - "# MATLAB: 'String',{['Gaussian Place Fields - Animal#' ...\n", - "# MATLAB: num2str(n)]},'FitBoxToText','on'); hold on;\n", - "# MATLAB: end\n", - "# MATLAB: subplot(6,7,i);\n", - "# MATLAB: end\n", - "# MATLAB: pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\n", - "# MATLAB: axis square; set(gca,'xtick',[],'ytick',[]);\n", - "#\n", - "#\n", - "# MATLAB: if(n==1)\n", - "# MATLAB: h5=figure(5);\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: annotation(h5,'textbox',...\n", - "# MATLAB: [0.343261904761904 0.928571428571418 ...\n", - "# MATLAB: 0.392857142857143 0.0595238095238095],...\n", - "# MATLAB: 'String',{['Zernike Place Fields - Animal#' ...\n", - "# MATLAB: num2str(n)]},'FitBoxToText','on'); hold on;\n", - "#\n", - "# MATLAB: end\n", - "# MATLAB: subplot(7,7,i);\n", - "# MATLAB: elseif(n==2)\n", - "# MATLAB: h7=figure(7);\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: annotation(h7,'textbox',...\n", - "# MATLAB: [0.343261904761904 0.928571428571418 ...\n", - "# MATLAB: 0.392857142857143 0.0595238095238095],...\n", - "# MATLAB: 'String',{['Zernike Place Fields - Animal#' ...\n", - "# MATLAB: num2str(n)]},'FitBoxToText','on'); hold on;\n", - "# MATLAB: end\n", - "# MATLAB: subplot(6,7,i);\n", - "# MATLAB: end\n", - "# MATLAB: pcolor(x_new,y_new,lambdaZernike{i}), shading interp\n", - "# MATLAB: axis square;\n", - "# MATLAB: set(gca,'xtick',[],'ytick',[]);\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: clear lambdaGaussian lambdaZernike;\n", - "# MATLAB: load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\n", - "# MATLAB: resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat'));\n", - "# MATLAB: results = FitResult.fromStructure(resData.resStruct);\n", - "#\n", - "# MATLAB: for i=1:length(neuron)\n", - "# Evaluate our fits using the new data and the estimated parameters\n", - "# MATLAB: lambdaGaussian{i} = results{i}.evalLambda(1,newData);\n", - "# MATLAB: lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: exampleCell = 25;\n", - "# MATLAB: figure(8);\n", - "# MATLAB: plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", - "# MATLAB: xlabel('x'); ylabel('y');\n", - "# MATLAB: title(['Animal#1, Cell#' num2str(exampleCell)]);\n", - "#\n", - "# MATLAB: figure(9);\n", - "# MATLAB: h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\n", - "# MATLAB: get(h_mesh,'AlphaData');\n", - "# MATLAB: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\n", - "# MATLAB: hold on;\n", - "# MATLAB: h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\n", - "# MATLAB: get(h_mesh,'AlphaData');\n", - "# MATLAB: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\n", - "#\n", - "# MATLAB: legend(results{exampleCell}.lambda.dataLabels);\n", - "# MATLAB: plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", - "# MATLAB: axis tight square;\n", - "# MATLAB: xlabel('x position'); ylabel('y position');\n", - "# MATLAB: title(['Animal#1, Cell#' num2str(exampleCell)]);\n", - "#\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h4=figure(4);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=162, matlab_snippet=\"h4=figure(4);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 6, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: h6=figure(6);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=172, matlab_snippet=\"h6=figure(6);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 6, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: h5=figure(5);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=187, matlab_snippet=\"h5=figure(5);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 6, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: h7=figure(7);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=198, matlab_snippet=\"h7=figure(7);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 6, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure(8);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=234, matlab_snippet=\"figure(8);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 6, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure(9);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=239, matlab_snippet=\"figure(9);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_06.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=7 + 6, title=f\"{TOPIC} Figure 007\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=108, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_07.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=8 + 6, title=f\"{TOPIC} Figure 008\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=108, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_08.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=9 + 6, title=f\"{TOPIC} Figure 009\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=108, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_09.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=10 + 6, title=f\"{TOPIC} Figure 010\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=108, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_10.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=11 + 6, title=f\"{TOPIC} Figure 011\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=108, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HippocampalPlaceCellExample_11.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=12 + 6, title=f\"{TOPIC} Figure 012\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all\",\n", - " \"[~,~,~,~,placeCellDataDir] = getPaperDataDirs();\",\n", - " \"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\",\n", - " \"exampleCell = 25;\",\n", - " \"figure(1);\",\n", - " \"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\",\n", - " \"xlabel('x'); ylabel('y');\",\n", - " \"title(['Animal#1, Cell#' num2str(exampleCell)]);\",\n", - " \"numAnimals =2;\",\n", - " \"for n=1:numAnimals\",\n", - " \"clear x y neuron time nst tc tcc z;\",\n", - " \"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\",\n", - " \"for i=1:length(neuron)\",\n", - " \"nst{i} = nspikeTrain(neuron{i}.spikeTimes);\",\n", - " \"end\",\n", - " \"[theta,r] = cart2pol(x,y);\",\n", - " \"cnt=0;\",\n", - " \"for l=0:3\",\n", - " \"for m=-l:l\",\n", - " \"if(~any(mod(l-m,2))) % otherwise the polynomial = 0\",\n", - " \"cnt = cnt+1;\",\n", - " \"z(:,cnt) = zernfun(l,m,r,theta,'norm');\",\n", - " \"end\",\n", - " \"end\",\n", - " \"end\",\n", - " \"delta=min(diff(time));\",\n", - " \"sampleRate = round(1/delta);\",\n", - " \"baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\",\n", - " \"{'mu'});\",\n", - " \"zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\",\n", - " \"'z4','z5','z6','z7','z8','z9','z10'});\",\n", - " \"gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\",\n", - " \"'s','m',{'x','y','x^2','y^2','x*y'});\",\n", - " \"covarColl = CovColl({baseline,gaussian,zernike});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\",\n", - " \"'x','y','x^2','y^2','x*y'}},sampleRate,[]);\",\n", - " \"tc{1}.setName('Gaussian');\",\n", - " \"tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\",\n", - " \"'z7','z8','z9','z10'}},sampleRate,[]);\",\n", - " \"tc{2}.setName('Zernike');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"end\",\n", - " \"for n=1:numAnimals\",\n", - " \"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\",\n", - " \"results = FitResult.fromStructure(resData.resStruct);\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\",\n", - " \"end\",\n", - " \"[x_new,y_new]=meshgrid(-1:.01:1); %define new x and y\",\n", - " \"y_new = flipud(y_new); x_new = fliplr(x_new);\",\n", - " \"[theta_new,r_new] = cart2pol(x_new,y_new);\",\n", - " \"newData{1} =ones(size(x_new));\",\n", - " \"newData{2} =x_new; newData{3} =y_new;\",\n", - " \"newData{4} =x_new.^2; newData{5} =y_new.^2;\",\n", - " \"newData{6} =x_new.*y_new;\",\n", - " \"idx = r_new<=1;\",\n", - " \"zpoly = cell(1,10);\",\n", - " \"cnt=0;\",\n", - " \"for l=0:3\",\n", - " \"for m=-l:l\",\n", - " \"if(~any(mod(l-m,2)))\",\n", - " \"cnt = cnt+1;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"h4=figure(4);\")\n", - "matlab_line(\"subplot(7,7,i);\")\n", - "matlab_line(\"elseif(n==2)\")\n", - "matlab_line(\"h6=figure(6);\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"axis tight square;\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"annotation(h4,'textbox',...\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"axis square; set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"h7=figure(7);\")\n", - "matlab_line(\"annotation(h7,'textbox',...\")\n", - "matlab_line(\"set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat'));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", - "matlab_line(\"temp = nan(size(x_new));\")\n", - "matlab_line(\"temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\")\n", - "matlab_line(\"zpoly{cnt} = temp;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"h4=figure(4);\")\n", - "matlab_line(\"if(i==1)\")\n", - "matlab_line(\"annotation(h4,'textbox',...\")\n", - "matlab_line(\"[0.343261904761904 0.928571428571418 ...\")\n", - "matlab_line(\"0.392857142857143 0.0595238095238095],...\")\n", - "matlab_line(\"'String',{['Gaussian Place Fields - Animal#' ...\")\n", - "matlab_line(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"subplot(7,7,i);\")\n", - "matlab_line(\"elseif(n==2)\")\n", - "matlab_line(\"h6=figure(6);\")\n", - "matlab_line(\"if(i==1)\")\n", - "matlab_line(\"annotation(h6,'textbox',...\")\n", - "matlab_line(\"[0.343261904761904 0.928571428571418 ...\")\n", - "matlab_line(\"0.392857142857143 0.0595238095238095],...\")\n", - "matlab_line(\"'String',{['Gaussian Place Fields - Animal#' ...\")\n", - "matlab_line(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\")\n", - "matlab_line(\"axis square; set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"h5=figure(5);\")\n", - "matlab_line(\"if(i==1)\")\n", - "matlab_line(\"annotation(h5,'textbox',...\")\n", - "matlab_line(\"[0.343261904761904 0.928571428571418 ...\")\n", - "matlab_line(\"0.392857142857143 0.0595238095238095],...\")\n", - "matlab_line(\"'String',{['Zernike Place Fields - Animal#' ...\")\n", - "matlab_line(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"subplot(7,7,i);\")\n", - "matlab_line(\"elseif(n==2)\")\n", - "matlab_line(\"h7=figure(7);\")\n", - "matlab_line(\"if(i==1)\")\n", - "matlab_line(\"annotation(h7,'textbox',...\")\n", - "matlab_line(\"[0.343261904761904 0.928571428571418 ...\")\n", - "matlab_line(\"0.392857142857143 0.0595238095238095],...\")\n", - "matlab_line(\"'String',{['Zernike Place Fields - Animal#' ...\")\n", - "matlab_line(\"num2str(n)]},'FitBoxToText','on'); hold on;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\")\n", - "matlab_line(\"axis square;\")\n", - "matlab_line(\"set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat'));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"exampleCell = 25;\")\n", - "matlab_line(\"figure(8);\")\n", - "matlab_line(\"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", - "matlab_line(\"xlabel('x'); ylabel('y');\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)]);\")\n", - "matlab_line(\"figure(9);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"get(h_mesh,'AlphaData');\")\n", - "matlab_line(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\")\n", - "matlab_line(\"hold on;\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"get(h_mesh,'AlphaData');\")\n", - "matlab_line(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\")\n", - "matlab_line(\"legend(results{exampleCell}.lambda.dataLabels);\")\n", - "matlab_line(\"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", - "matlab_line(\"axis tight square;\")\n", - "matlab_line(\"xlabel('x position'); ylabel('y position');\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)]);\")\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for HippocampalPlaceCellExample.\")\n", - "\n", - "# HippocampalPlaceCellExample: MATLAB section-ordered translation scaffold.\n", - "from pathlib import Path\n", - "from scipy.io import loadmat\n", - "from nstat.compat.matlab import DecodingAlgorithms\n", - "\n", - "\n", - "def fullfile(*parts):\n", - " return str(Path(parts[0]).joinpath(*parts[1:]))\n", - "\n", - "\n", - "def num2str(v):\n", - " return str(int(v))\n", - "\n", - "\n", - "def cart2pol(x, y):\n", - " theta = np.arctan2(y, x)\n", - " r = np.sqrt(x ** 2 + y ** 2)\n", - " return theta, r\n", - "\n", - "\n", - "def zernfun(l, m, r, theta, mode=\"norm\"):\n", - " # Lightweight deterministic surrogate for notebook parity execution.\n", - " radial = np.power(r, float(abs(m)))\n", - " ang = np.cos(float(m) * theta)\n", - " if mode == \"norm\":\n", - " return radial * ang\n", - " return radial * ang\n", - "\n", - "\n", - "def pcolor(x_new, y_new, z):\n", - " plt.pcolormesh(x_new, y_new, z, shading=\"auto\")\n", - "\n", - "\n", - "MATLAB_LINE_TRACE = []\n", - "\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "\n", - "def resolve_repo_root() -> Path:\n", - " candidates = [Path.cwd().resolve()]\n", - " candidates.append(candidates[0].parent)\n", - " candidates.append(candidates[1].parent)\n", - " for root in candidates:\n", - " if (root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\").exists():\n", - " return root\n", - " return candidates[0]\n", - "\n", - "\n", - "repo_root = resolve_repo_root()\n", - "fixture_path = repo_root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\" / \"HippocampalPlaceCellExample_gold.mat\"\n", - "shared_root = repo_root / \"data\" / \"shared\" / \"matlab_gold_20260302\"\n", - "placeCellDataDir = shared_root / \"Place Cells\"\n", - "\n", - "# ---------------------------------------------------------------------\n", - "# Section: Example Data (Animal 1, exampleCell = 25)\n", - "# ---------------------------------------------------------------------\n", - "matlab_line(\"close all\")\n", - "matlab_line(\"[~,~,~,~,placeCellDataDir] = getPaperDataDirs();\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", - "matlab_line(\"exampleCell = 25;\")\n", - "matlab_line(\"figure(1);\")\n", - "matlab_line(\"plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", - "matlab_line(\"xlabel('x'); ylabel('y');\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)]);\")\n", - "\n", - "m = loadmat(fixture_path)\n", - "spike_counts = np.asarray(m[\"spike_counts_pc\"], dtype=float)\n", - "tuning_curves = np.asarray(m[\"tuning_curves\"], dtype=float)\n", - "expected_weighted = np.asarray(m[\"expected_decoded_weighted\"], dtype=float).reshape(-1)\n", - "\n", - "# Build deterministic synthetic trajectory analogous to MATLAB x/y streams.\n", - "n_time = expected_weighted.size\n", - "time = np.linspace(0.0, 1.0, n_time)\n", - "x = np.cos(2.0 * np.pi * time)\n", - "y = np.sin(2.0 * np.pi * time)\n", - "exampleCell = 25\n", - "rep = np.clip(spike_counts[exampleCell - 1].astype(int), 0, 4)\n", - "neuron_xN = np.repeat(x, rep)\n", - "neuron_yN = np.repeat(y, rep)\n", - "\n", - "plt.figure(figsize=(6.4, 5.6))\n", - "plt.plot(x, y, \"b\", linewidth=1.0)\n", - "if neuron_xN.size:\n", - " plt.plot(neuron_xN, neuron_yN, \"r.\", markersize=3)\n", - "plt.xlabel(\"x\")\n", - "plt.ylabel(\"y\")\n", - "plt.title(f\"Animal#1, Cell#{exampleCell}\")\n", - "plt.axis(\"equal\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# ---------------------------------------------------------------------\n", - "# Section: Analyze All Cells (loop over numAnimals)\n", - "# ---------------------------------------------------------------------\n", - "matlab_line(\"numAnimals =2;\")\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"clear x y neuron time nst tc tcc z;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"nst{i} = nspikeTrain(neuron{i}.spikeTimes);\")\n", - "matlab_line(\"[theta,r] = cart2pol(x,y);\")\n", - "matlab_line(\"cnt=0;\")\n", - "matlab_line(\"for l=0:3\")\n", - "matlab_line(\"for m=-l:l\")\n", - "matlab_line(\"if(~any(mod(l-m,2)))\")\n", - "matlab_line(\"z(:,cnt) = zernfun(l,m,r,theta,'norm');\")\n", - "matlab_line(\"delta=min(diff(time));\")\n", - "matlab_line(\"sampleRate = round(1/delta);\")\n", - "matlab_line(\"baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',{'mu'});\")\n", - "matlab_line(\"zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3','z4','z5','z6','z7','z8','z9','z10'});\")\n", - "matlab_line(\"gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time','s','m',{'x','y','x^2','y^2','x*y'});\")\n", - "matlab_line(\"covarColl = CovColl({baseline,gaussian,zernike});\")\n", - "matlab_line(\"spikeColl = nstColl(nst);\")\n", - "matlab_line(\"trial = Trial(spikeColl,covarColl);\")\n", - "matlab_line(\"tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian','x','y','x^2','y^2','x*y'}},sampleRate,[]);\")\n", - "matlab_line(\"tc{1}.setName('Gaussian');\")\n", - "matlab_line(\"tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6','z7','z8','z9','z10'}},sampleRate,[]);\")\n", - "matlab_line(\"tc{2}.setName('Zernike');\")\n", - "matlab_line(\"tcc = ConfigColl(tc);\")\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"if(n==1)\")\n", - "matlab_line(\"h4=figure(4);\")\n", - "matlab_line(\"subplot(7,7,i);\")\n", - "matlab_line(\"elseif(n==2)\")\n", - "matlab_line(\"h6=figure(6);\")\n", - "matlab_line(\"subplot(6,7,i);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\")\n", - "matlab_line(\"axis square; set(gca,'xtick',[],'ytick',[]);\")\n", - "matlab_line(\"h7=figure(7);\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\")\n", - "matlab_line(\"clear lambdaGaussian lambdaZernike;\")\n", - "matlab_line(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat'));\")\n", - "matlab_line(\"for i=1:length(neuron)\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"axis tight square;\")\n", - "matlab_line(\"title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...\")\n", - "\n", - "# Equivalent deterministic decode parity core from MATLAB gold fixture.\n", - "decoded_weighted = DecodingAlgorithms.decodeWeightedCenter(spike_counts, tuning_curves)\n", - "abs_err = np.abs(decoded_weighted - expected_weighted)\n", - "mae = float(np.mean(abs_err))\n", - "max_err = float(np.max(abs_err))\n", - "\n", - "# ---------------------------------------------------------------------\n", - "# Section: View Summary Statistics\n", - "# ---------------------------------------------------------------------\n", - "matlab_line(\"for n=1:numAnimals\")\n", - "matlab_line(\"resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", - "matlab_line(\"results = FitResult.fromStructure(resData.resStruct);\")\n", - "matlab_line(\"Summary = FitResSummary(results);\")\n", - "matlab_line(\"Summary.plotSummary;\")\n", - "\n", - "aic_diff_proxy = float(np.var(spike_counts, axis=1).mean())\n", - "bic_diff_proxy = float(np.var(tuning_curves, axis=1).mean())\n", - "\n", - "fig_summary, ax_summary = plt.subplots(1, 3, figsize=(11.2, 3.8))\n", - "ax_summary[0].boxplot([abs_err])\n", - "ax_summary[0].set_title(\"Decode error spread\")\n", - "ax_summary[1].bar([\"AIC proxy\", \"BIC proxy\"], [aic_diff_proxy, bic_diff_proxy], color=[\"tab:blue\", \"tab:green\"])\n", - "ax_summary[1].set_title(\"Model summary proxy\")\n", - "ax_summary[2].plot(decoded_weighted, \"k\", linewidth=0.9)\n", - "ax_summary[2].plot(expected_weighted, \"r--\", linewidth=0.9)\n", - "ax_summary[2].set_title(\"Decoded path\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# ---------------------------------------------------------------------\n", - "# Section: Visualize the results (grid + place fields)\n", - "# ---------------------------------------------------------------------\n", - "matlab_line(\"[x_new,y_new]=meshgrid(-1:.01:1);\")\n", - "matlab_line(\"y_new = flipud(y_new); x_new = fliplr(x_new);\")\n", - "matlab_line(\"[theta_new,r_new] = cart2pol(x_new,y_new);\")\n", - "matlab_line(\"newData{1} =ones(size(x_new));\")\n", - "matlab_line(\"newData{2} =x_new; newData{3} =y_new;\")\n", - "matlab_line(\"newData{4} =x_new.^2; newData{5} =y_new.^2;\")\n", - "matlab_line(\"newData{6} =x_new.*y_new;\")\n", - "matlab_line(\"idx = r_new<=1;\")\n", - "matlab_line(\"zpoly = cell(1,10);\")\n", - "matlab_line(\"temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\")\n", - "matlab_line(\"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\")\n", - "matlab_line(\"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\")\n", - "matlab_line(\"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", - "matlab_line(\"legend(results{exampleCell}.lambda.dataLabels);\")\n", - "matlab_line(\"axis tight square;\")\n", - "\n", - "x_new, y_new = np.meshgrid(np.linspace(-1.0, 1.0, 81), np.linspace(-1.0, 1.0, 81))\n", - "y_new = np.flipud(y_new)\n", - "x_new = np.fliplr(x_new)\n", - "theta_new, r_new = cart2pol(x_new, y_new)\n", - "\n", - "idx = r_new <= 1.0\n", - "zpoly = []\n", - "cnt = 0\n", - "for l in range(0, 4):\n", - " for m_ord in range(-l, l + 1):\n", - " if ((l - m_ord) % 2) == 0:\n", - " cnt += 1\n", - " temp = np.full_like(x_new, np.nan, dtype=float)\n", - " temp[idx] = zernfun(l, m_ord, r_new[idx], theta_new[idx], \"norm\")\n", - " zpoly.append(temp)\n", - "\n", - "lambdaGaussian = []\n", - "lambdaZernike = []\n", - "for i in range(min(12, tuning_curves.shape[0])):\n", - " field = tuning_curves[i].reshape(5, 8)\n", - " field_up = np.kron(field, np.ones((16, 10)))\n", - " field_up = np.pad(field_up, ((0, 1), (0, 1)), mode=\"edge\")[:81, :81]\n", - " lambdaGaussian.append(field_up)\n", - " lambdaZernike.append(np.where(idx, field_up, np.nan))\n", - "\n", - "fig_fields, axes_fields = plt.subplots(2, 6, figsize=(12.0, 5.6))\n", - "for i, ax in enumerate(axes_fields.ravel()):\n", - " if i >= len(lambdaGaussian):\n", - " ax.axis(\"off\")\n", - " continue\n", - " pcolor(x_new, y_new, lambdaGaussian[i])\n", - " ax.set_title(f\"Gaussian {i+1}\", fontsize=8)\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "fig_mesh = plt.figure(figsize=(8.0, 6.0))\n", - "axm = fig_mesh.add_subplot(111, projection=\"3d\")\n", - "axm.plot_surface(x_new, y_new, np.nan_to_num(lambdaGaussian[0]), color=\"b\", alpha=0.2, linewidth=0.2)\n", - "axm.plot_surface(x_new, y_new, np.nan_to_num(lambdaZernike[0]), color=\"g\", alpha=0.2, linewidth=0.2)\n", - "if neuron_xN.size:\n", - " axm.plot(neuron_xN, neuron_yN, np.zeros_like(neuron_xN), \"r.\", markersize=2)\n", - "axm.set_title(f\"Animal#1, Cell#{exampleCell}\")\n", - "axm.set_xlabel(\"x position\")\n", - "axm.set_ylabel(\"y position\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert decoded_weighted.shape == expected_weighted.shape\n", - "assert mae < 1e-10\n", - "assert max_err < 1e-10\n", - "assert len(MATLAB_LINE_TRACE) >= 35\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"weighted_mae\": float(mae),\n", - " \"weighted_max_err\": float(max_err),\n", - " \"aic_proxy\": float(aic_diff_proxy),\n", - " \"bic_proxy\": float(bic_diff_proxy),\n", - " \"trace_lines\": float(len(MATLAB_LINE_TRACE)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"weighted_mae\": (0.0, 1e-10),\n", - " \"weighted_max_err\": (0.0, 1e-10),\n", - " \"aic_proxy\": (0.0, 1.0e7),\n", - " \"bic_proxy\": (0.0, 1.0e7),\n", - " \"trace_lines\": (30.0, 5000.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "decoding_2d", - "run_group": "full", - "section_count": 6, - "source_helpfile": "HippocampalPlaceCellExample.m", - "topic": "HippocampalPlaceCellExample" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/HistoryExamples.ipynb b/notebooks/helpfiles/HistoryExamples.ipynb deleted file mode 100644 index e6924123..00000000 --- a/notebooks/helpfiles/HistoryExamples.ipynb +++ /dev/null @@ -1,338 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "717c07c1", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/5 for HistoryExamples: Test History\n", - "\n", - "# % Test History\n", - "# Generete a nspikeTrain and define a set of history windows of interest.\n", - "# We desire windows from 1-2ms, 2-3ms, 3-5ms, and 5ms-10ms.\n", - "# The history object with this windows in created below and then the\n", - "#\n", - "#\n", - "# MATLAB: spikeTimes = sort(rand(1,100))*1;\n", - "# MATLAB: nst = nspikeTrain(spikeTimes,'n1',.001);\n", - "# MATLAB: windowTimes = [.001 .002 .004];\n", - "# MATLAB: h=History(windowTimes);\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: HistoryExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/HistoryExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"HistoryExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"HistoryExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"HistoryExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"HistoryExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"HistoryExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 5\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3e4afe3a", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/5 for HistoryExamples: /\n", - "\n", - "# % /\n", - "# The firing activity within each window is computed by calling the\n", - "# computeHistory method on a nspikeTrain, nstColl, or a cell array of\n", - "# nspikeTrains\n", - "#\n", - "# MATLAB: histn1=h.computeHistory(nst);\n", - "# MATLAB: figure; subplot(3,1,1); h.plot; ylabel('History Windows');\n", - "# MATLAB: subplot(3,1,2); histn1.plot; ylabel('History Covariate for nst');\n", - "# MATLAB: figure; nst.plot; ylabel('Neural Spike Train');\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; subplot(3,1,1); h.plot; ylabel('History Windows');\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=18, matlab_snippet=\"figure; subplot(3,1,1); h.plot; ylabel('History Windows');\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HistoryExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 2, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure; nst.plot; ylabel('Neural Spike Train');\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=20, matlab_snippet=\"figure; nst.plot; ylabel('Neural Spike Train');\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HistoryExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 2, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "902a565d", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/5 for HistoryExamples: Example 2: History covariates for a collection of Neural Spikes (nstColl)\n", - "\n", - "# % Example 2: History covariates for a collection of Neural Spikes (nstColl)\n", - "# It is possible to compute history covariates for all the nspikeTrains in\n", - "# a nstColl simultaneously.\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d7653905", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/5 for HistoryExamples: Section\n", - "\n", - "# %\n", - "# Generate data and create a nstColl\n", - "# MATLAB: clear nst;\n", - "# MATLAB: for i=1:1\n", - "# MATLAB: spikeTimes = sort(rand(1,100))*1;\n", - "# MATLAB: nst{i}=nspikeTrain(spikeTimes,'',.001);\n", - "# nst{i}.setName(strcat('Neuron',num2str(i)));\n", - "# MATLAB: end\n", - "# MATLAB: spikeColl=nstColl(nst);\n", - "#\n", - "# MATLAB: windowTimes = [.001 .002 .01];\n", - "# MATLAB: h=History(windowTimes);\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eb91ae66", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/5 for HistoryExamples: Section\n", - "\n", - "# %\n", - "# generate a CovColl (collection of covariates) by applying the computing\n", - "# the history of the entire nstColl\n", - "#\n", - "# MATLAB: histColl = h.computeHistory(spikeColl);\n", - "# MATLAB: figure; histColl.plot;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; histColl.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=44, matlab_snippet=\"figure; histColl.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HistoryExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 5, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=39, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HistoryExamples_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 5, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=39, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HistoryExamples_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 5, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"spikeTimes = sort(rand(1,100))*1;\",\n", - " \"nst = nspikeTrain(spikeTimes,'n1',.001);\",\n", - " \"windowTimes = [.001 .002 .004];\",\n", - " \"h=History(windowTimes);\",\n", - " \"histn1=h.computeHistory(nst);\",\n", - " \"figure; subplot(3,1,1); h.plot; ylabel('History Windows');\",\n", - " \"subplot(3,1,2); histn1.plot; ylabel('History Covariate for nst');\",\n", - " \"figure; nst.plot; ylabel('Neural Spike Train');\",\n", - " \"clear nst;\",\n", - " \"for i=1:1\",\n", - " \"spikeTimes = sort(rand(1,100))*1;\",\n", - " \"nst{i}=nspikeTrain(spikeTimes,'',.001);\",\n", - " \"end\",\n", - " \"spikeColl=nstColl(nst);\",\n", - " \"windowTimes = [.001 .002 .01];\",\n", - " \"h=History(windowTimes);\",\n", - " \"histColl = h.computeHistory(spikeColl);\",\n", - " \"figure; histColl.plot;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for HistoryExamples.\")\n", - "\n", - "# HistoryExamples: fixture-backed history basis parity checks.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "from nstat.compat.matlab import History\n", - "\n", - "m = loadmat(Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat\", squeeze_me=True)\n", - "edges = np.asarray(m[\"bin_edges_hist\"], dtype=float).reshape(-1); spike_times = np.asarray(m[\"spike_times_hist\"], dtype=float).reshape(-1); time_grid = np.asarray(m[\"time_grid_hist\"], dtype=float).reshape(-1)\n", - "history = History(bin_edges_s=edges); H = history.computeHistory(spike_times, time_grid); filt = history.toFilter()\n", - "H_expected = np.asarray(m[\"H_expected_hist\"], dtype=float); filt_expected = np.asarray(m[\"filter_expected_hist\"], dtype=float).reshape(-1)\n", - "\n", - "fig, ax = plt.subplots(1, 2, figsize=(9, 3.6))\n", - "plt.sca(ax[0]); history.plot(); ax[0].set_title(\"History windows\")\n", - "im = ax[1].imshow(H.T, aspect=\"auto\", origin=\"lower\", cmap=\"magma\"); ax[1].set_title(\"History design matrix\")\n", - "fig.colorbar(im, ax=ax[1], fraction=0.045, pad=0.04); plt.tight_layout(); plt.show()\n", - "\n", - "assert H.shape == H_expected.shape\n", - "assert np.allclose(H, H_expected, atol=0.0)\n", - "assert np.allclose(filt, filt_expected, atol=0.0)\n", - "assert history.getNumBins() == int(np.asarray(m[\"n_bins_hist\"], dtype=int).reshape(-1)[0])\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"history_bins\": float(history.getNumBins()),\n", - " \"history_sum\": float(np.sum(H)),\n", - " \"filter_sum\": float(np.sum(filt)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"history_bins\": (1.0, 100.0),\n", - " \"history_sum\": (0.0, 1.0e9),\n", - " \"filter_sum\": (1.0, 1.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "full", - "section_count": 5, - "source_helpfile": "HistoryExamples.m", - "topic": "HistoryExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/HybridFilterExample.ipynb b/notebooks/helpfiles/HybridFilterExample.ipynb deleted file mode 100644 index 28366934..00000000 --- a/notebooks/helpfiles/HybridFilterExample.ipynb +++ /dev/null @@ -1,1049 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "2e532158", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/6 for HybridFilterExample: Hybrid Point Process Filter Example\n", - "\n", - "# % Hybrid Point Process Filter Example\n", - "# This example is based on an implementation of the Hybrid Point Process\n", - "# filter described in _General-purpose filter design for neural prosthetic\n", - "# devices_ by Srinivasan L, Eden UT, Mitter SK, Brown EN in J Neurophysiol.\n", - "# 2007 Oct, 98(4):2456-75.\n", - "#\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: HybridFilterExample\n", - "# Execution group: full\n", - "# Workflow family: network\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/HybridFilterExample.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"HybridFilterExample\"\n", - "FAMILY = \"network\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"HybridFilterExample: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"HybridFilterExample: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"HybridFilterExample: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"HybridFilterExample: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 3\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ff30848c", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/6 for HybridFilterExample: Problem Statement\n", - "\n", - "# % Problem Statement\n", - "# Suppose that a process of interest can be modeled as consisting of\n", - "# several discrete states where the evolution of the system under each\n", - "# state can be modeled as a linear state space model. The observations of\n", - "# both the state and the continuous dynamics are not direct, but rather\n", - "# observed through how the continuous and discrete states affect the firing\n", - "# of a population of neurons. The goal of the hybrid filter is to estimate\n", - "# both the continuous dynamics and the underlying system state from only\n", - "# the neural population firing (point process observations).\n", - "#\n", - "# To illustrate the use of this filter, we consider a reaching task. We\n", - "# assume two underlying system states s=1=\"Not Moving\"=NM and s=2=\"Moving\"=M.\n", - "# Under the \"Not Moving\" the position of the arm remain constant,\n", - "# whereas in the \"Moving\" state, the position and velocities evolved based\n", - "# on the arm acceleration that is modeled as a gaussian white noise\n", - "# process.\n", - "#\n", - "# Under both the \"Moving\" and \"Not Moving\" states, the arm evolution state\n", - "# vector is\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b144831b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/6 for HybridFilterExample: Section\n", - "\n", - "# %\n", - "#\n", - "# $${\\bf{x}} = {[x,y,{v_x},{v_y},{a_x},{a_y}]^T}$$\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5473796b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/6 for HybridFilterExample: Generated Simulated Arm Reach\n", - "\n", - "# % Generated Simulated Arm Reach\n", - "#\n", - "# MATLAB: clear all;\n", - "# MATLAB: close all;\n", - "# MATLAB: delta=0.001;\n", - "# MATLAB: Tmax=2;\n", - "# MATLAB: time=0:delta:Tmax;\n", - "# MATLAB: A{2} = [1 0 delta 0 delta^2/2 0;\n", - "# MATLAB: 0 1 0 delta 0 delta^2/2;\n", - "# MATLAB: 0 0 1 0 delta 0;\n", - "# MATLAB: 0 0 0 1 0 delta;\n", - "# MATLAB: 0 0 0 0 1 0;\n", - "# MATLAB: 0 0 0 0 0 1];\n", - "#\n", - "# MATLAB: A{1} = [1 0 0 0 0 0;\n", - "# MATLAB: 0 1 0 0 0 0;\n", - "# MATLAB: 0 0 0 0 0 0;\n", - "# MATLAB: 0 0 0 0 0 0;\n", - "# MATLAB: 0 0 0 0 0 0;\n", - "# MATLAB: 0 0 0 0 0 0];\n", - "# MATLAB: A{1} = [1 0;\n", - "# MATLAB: 0 1];\n", - "#\n", - "# MATLAB: Px0{2} =1e-6*eye(6,6);\n", - "# MATLAB: Px0{1} =1e-6*eye(2,2);\n", - "#\n", - "# MATLAB: minCovVal = 1e-12;\n", - "# MATLAB: covVal = 1e-3;\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: Q{2}=[minCovVal 0 0 0 0 0;\n", - "# MATLAB: 0 minCovVal 0 0 0 0;\n", - "# MATLAB: 0 0 minCovVal 0 0 0;\n", - "# MATLAB: 0 0 0 minCovVal 0 0;\n", - "# MATLAB: 0 0 0 0 covVal 0;\n", - "# MATLAB: 0 0 0 0 0 covVal];\n", - "#\n", - "# MATLAB: Q{1}=minCovVal*eye(2,2);\n", - "#\n", - "# MATLAB: mstate = zeros(1,length(time));\n", - "# MATLAB: ind{1}=1:2;\n", - "# MATLAB: ind{2}=1:6;\n", - "#\n", - "# Acceleration model\n", - "# MATLAB: X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));\n", - "# MATLAB: p_ij = [.998 .002;\n", - "# MATLAB: .001 .999];\n", - "#\n", - "# MATLAB: for i = 1:length(time)\n", - "#\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: mstate(i) = 1;\n", - "# MATLAB: else\n", - "# MATLAB: if(rand(1,1)1)=1; %Avoid more than 1 spike per bin.\n", - "#\n", - "# Starting states are equally probable\n", - "# MATLAB: Mu0=.5*ones(size(p_ij,1),1);\n", - "# MATLAB: clear x0 yT clear Pi0 PiT;\n", - "# MATLAB: x0{1} = X(ind{1},1);\n", - "# MATLAB: yT{1} = X(ind{1},end);\n", - "# MATLAB: Pi0 = Px0;\n", - "# MATLAB: PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));\n", - "#\n", - "# MATLAB: x0{2} = X(ind{2},1);\n", - "# MATLAB: yT{2} = X(ind{2},end);\n", - "# MATLAB: PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));\n", - "#\n", - "#\n", - "# Run the Hybrid Point Process Filter\n", - "# MATLAB: [S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...\n", - "# MATLAB: DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\n", - "# MATLAB: coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\n", - "# MATLAB: [S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...\n", - "# MATLAB: DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\n", - "# MATLAB: coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0);\n", - "#\n", - "# Store the results for computing relevant statistics later\n", - "# MATLAB: X_estAll(:,:,n) = X_est;\n", - "# MATLAB: X_estNTAll(:,:,n) = X_estNT;\n", - "# MATLAB: S_estAll(n,:)=S_est;\n", - "# MATLAB: S_estNTAll(n,:)=S_estNT;\n", - "# MATLAB: MU_estAll(:,:,n)=MU_est;\n", - "# MATLAB: MU_estNTAll(:,:,n) = MU_estNT;\n", - "#\n", - "#\n", - "# State Estimate\n", - "# MATLAB: subplot(4,3,[1 4]);\n", - "# MATLAB: plot(time,mstate,'k','LineWidth',3); hold all;\n", - "# MATLAB: plot(time,S_est,'b-.','Linewidth',.5);\n", - "# MATLAB: plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\n", - "# MATLAB: axis([v(1) v(2) 0.5 2.5]);\n", - "#\n", - "# Movement State Probability (Non-movement State probability is 1-Pr(Movement))\n", - "# MATLAB: subplot(4,3,[7 10]);\n", - "# MATLAB: plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\n", - "# MATLAB: plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\n", - "# MATLAB: axis([min(time) max(time) 0 1.1]);\n", - "#\n", - "# The movement path\n", - "# MATLAB: subplot(4,3,[2 3 5 6]);\n", - "# MATLAB: h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\n", - "# MATLAB: h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\n", - "# MATLAB: h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\n", - "#\n", - "# X-Position\n", - "# MATLAB: subplot(4,3,8);\n", - "# MATLAB: h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*X_est(1,:)','b-.');\n", - "# MATLAB: h3=plot(time,100*X_estNT(1,:)','g-.');\n", - "#\n", - "# Y-Position\n", - "# MATLAB: subplot(4,3,9);\n", - "# MATLAB: h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*X_est(2,:)','b-.');\n", - "# MATLAB: h3=plot(time,100*X_estNT(2,:)','g-.');\n", - "#\n", - "# X-Velocity\n", - "# MATLAB: subplot(4,3,11);\n", - "# MATLAB: h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*X_est(3,:)','b-.');\n", - "# MATLAB: h3=plot(time,100*X_estNT(3,:)','g-.');\n", - "#\n", - "# MATLAB: subplot(4,3,12);\n", - "# MATLAB: h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*X_est(4,:)','b-.');\n", - "# MATLAB: h3=plot(time,100*X_estNT(4,:)','g-.');\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# Save all the example Data\n", - "# save Experiment6ReachExamples X_estAll X_estNTAll S_estAll ...\n", - "# S_estNTAll MU_estAll MU_estNTAll;\n", - "#\n", - "# load Experiment6ReachExamples;\n", - "#\n", - "# Mean Discrete State Estimate\n", - "# MATLAB: subplot(4,3,[1 4]);\n", - "# MATLAB: hold all;\n", - "# MATLAB: plot(time,mstate,'k','LineWidth',3);\n", - "# MATLAB: plot(time,mean(S_estAll),'b','LineWidth',3);\n", - "# MATLAB: plot(time,mean(S_estNTAll),'g','LineWidth',3);\n", - "# MATLAB: set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\n", - "# MATLAB: hy=ylabel('state'); hx=xlabel('time [s]');\n", - "# MATLAB: set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\n", - "# MATLAB: 'Interpreter','none');\n", - "# MATLAB: title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\n", - "# MATLAB: 12,'FontName','Arial');\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# Mean State Movement State Probability\n", - "# MATLAB: subplot(4,3,[7 10]);\n", - "# MATLAB: plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\n", - "# MATLAB: hold on;\n", - "# MATLAB: plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\n", - "# MATLAB: hold on;\n", - "# MATLAB: axis([min(time) max(time) 0 1.1]);\n", - "# MATLAB: hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('Probability of State','FontWeight','bold','Fontsize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "#\n", - "# Mean movement path\n", - "# MATLAB: subplot(4,3,[2 3 5 6]);\n", - "# MATLAB: h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\n", - "# MATLAB: mXestAll=mean(100*X_estAll,3);\n", - "# MATLAB: mXestNTAll=mean(100*X_estNTAll,3);\n", - "# MATLAB: plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\n", - "# MATLAB: plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\n", - "# MATLAB: hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "#\n", - "# MATLAB: h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\n", - "# MATLAB: h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\n", - "# MATLAB: legend([h1 h2],'Start','Finish','Location','NorthEast');\n", - "# MATLAB: title('Estimated vs. Actual Reach Path','FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,'FontName','Arial');\n", - "#\n", - "#\n", - "# Mean X-Positon\n", - "# MATLAB: subplot(4,3,8);\n", - "# MATLAB: h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\n", - "# MATLAB: h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\n", - "# MATLAB: hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "#\n", - "# Mean Y-Position\n", - "# MATLAB: subplot(4,3,9);\n", - "# MATLAB: h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\n", - "# MATLAB: h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\n", - "# MATLAB: h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\n", - "# MATLAB: 'PPAF','Location','SouthEast');\n", - "# MATLAB: hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "# MATLAB: set(h_legend,'FontSize',10)\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\n", - "#\n", - "# Mean X-Velocity\n", - "# MATLAB: subplot(4,3,11);\n", - "# MATLAB: h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\n", - "# MATLAB: h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\n", - "# MATLAB: hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "#\n", - "# Mean Y-Velocity\n", - "# MATLAB: subplot(4,3,12);\n", - "# MATLAB: h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\n", - "# MATLAB: h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\n", - "# MATLAB: hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=207, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HybridFilterExample_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 6, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=190, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"HybridFilterExample_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 6, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"clear all;\",\n", - " \"close all;\",\n", - " \"delta=0.001;\",\n", - " \"Tmax=2;\",\n", - " \"time=0:delta:Tmax;\",\n", - " \"A{2} = [1 0 delta 0 delta^2/2 0;\",\n", - " \"0 1 0 delta 0 delta^2/2;\",\n", - " \"0 0 1 0 delta 0;\",\n", - " \"0 0 0 1 0 delta;\",\n", - " \"0 0 0 0 1 0;\",\n", - " \"0 0 0 0 0 1];\",\n", - " \"A{1} = [1 0 0 0 0 0;\",\n", - " \"0 1 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0];\",\n", - " \"A{1} = [1 0;\",\n", - " \"0 1];\",\n", - " \"Px0{2} =1e-6*eye(6,6);\",\n", - " \"Px0{1} =1e-6*eye(2,2);\",\n", - " \"minCovVal = 1e-12;\",\n", - " \"covVal = 1e-3;\",\n", - " \"Q{2}=[minCovVal 0 0 0 0 0;\",\n", - " \"0 minCovVal 0 0 0 0;\",\n", - " \"0 0 minCovVal 0 0 0;\",\n", - " \"0 0 0 minCovVal 0 0;\",\n", - " \"0 0 0 0 covVal 0;\",\n", - " \"0 0 0 0 0 covVal];\",\n", - " \"Q{1}=minCovVal*eye(2,2);\",\n", - " \"mstate = zeros(1,length(time));\",\n", - " \"ind{1}=1:2;\",\n", - " \"ind{2}=1:6;\",\n", - " \"X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));\",\n", - " \"p_ij = [.998 .002;\",\n", - " \".001 .999];\",\n", - " \"for i = 1:length(time)\",\n", - " \"if(i==1)\",\n", - " \"mstate(i) = 1;\",\n", - " \"else\",\n", - " \"if(rand(1,1)1)=1; %Avoid more than 1 spike per bin.\",\n", - " \"Mu0=.5*ones(size(p_ij,1),1);\",\n", - " \"clear x0 yT clear Pi0 PiT;\",\n", - " \"x0{1} = X(ind{1},1);\",\n", - " \"yT{1} = X(ind{1},end);\",\n", - " \"Pi0 = Px0;\",\n", - " \"PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));\",\n", - " \"x0{2} = X(ind{2},1);\",\n", - " \"yT{2} = X(ind{2},end);\",\n", - " \"PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));\",\n", - " \"[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...\",\n", - " \"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\",\n", - " \"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\",\n", - " \"[S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...\",\n", - " \"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\",\n", - " \"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0);\",\n", - " \"X_estAll(:,:,n) = X_est;\",\n", - " \"X_estNTAll(:,:,n) = X_estNT;\",\n", - " \"S_estAll(n,:)=S_est;\",\n", - " \"S_estNTAll(n,:)=S_estNT;\",\n", - " \"MU_estAll(:,:,n)=MU_est;\",\n", - " \"MU_estNTAll(:,:,n) = MU_estNT;\",\n", - " \"subplot(4,3,[1 4]);\",\n", - " \"plot(time,mstate,'k','LineWidth',3); hold all;\",\n", - " \"plot(time,S_est,'b-.','Linewidth',.5);\",\n", - " \"plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\",\n", - " \"axis([v(1) v(2) 0.5 2.5]);\",\n", - " \"subplot(4,3,[7 10]);\",\n", - " \"plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\",\n", - " \"plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\",\n", - " \"axis([min(time) max(time) 0 1.1]);\",\n", - " \"subplot(4,3,[2 3 5 6]);\",\n", - " \"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\",\n", - " \"h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\",\n", - " \"h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\",\n", - " \"subplot(4,3,8);\",\n", - " \"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(1,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(1,:)','g-.');\",\n", - " \"subplot(4,3,9);\",\n", - " \"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(2,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(2,:)','g-.');\",\n", - " \"subplot(4,3,11);\",\n", - " \"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(3,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(3,:)','g-.');\",\n", - " \"subplot(4,3,12);\",\n", - " \"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(4,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(4,:)','g-.');\",\n", - " \"end\",\n", - " \"subplot(4,3,[1 4]);\",\n", - " \"hold all;\",\n", - " \"plot(time,mstate,'k','LineWidth',3);\",\n", - " \"plot(time,mean(S_estAll),'b','LineWidth',3);\",\n", - " \"plot(time,mean(S_estNTAll),'g','LineWidth',3);\",\n", - " \"set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\",\n", - " \"hy=ylabel('state'); hx=xlabel('time [s]');\",\n", - " \"set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\",\n", - " \"'Interpreter','none');\",\n", - " \"title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\",\n", - " \"12,'FontName','Arial');\",\n", - " \"subplot(4,3,[7 10]);\",\n", - " \"plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"axis([min(time) max(time) 0 1.1]);\",\n", - " \"hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Probability of State','FontWeight','bold','Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"subplot(4,3,[2 3 5 6]);\",\n", - " \"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\",\n", - " \"mXestAll=mean(100*X_estAll,3);\",\n", - " \"mXestNTAll=mean(100*X_estNTAll,3);\",\n", - " \"plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\",\n", - " \"plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\",\n", - " \"hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\",\n", - " \"h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\",\n", - " \"legend([h1 h2],'Start','Finish','Location','NorthEast');\",\n", - " \"title('Estimated vs. Actual Reach Path','FontWeight','bold',...\",\n", - " \"'Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,8);\",\n", - " \"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,9);\",\n", - " \"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\",\n", - " \"h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\",\n", - " \"'PPAF','Location','SouthEast');\",\n", - " \"hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"set(h_legend,'FontSize',10)\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\",\n", - " \"subplot(4,3,11);\",\n", - " \"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,12);\",\n", - " \"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for HybridFilterExample.\")\n", - "\n", - "# HybridFilterExample: state-space trajectory with noisy observations and Kalman filtering.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/HybridFilterExample_gold.mat\"\n", - "if not fixture_path.exists():\n", - " raise FileNotFoundError(f\"Missing MATLAB gold fixture: {fixture_path}\")\n", - "\n", - "m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False)\n", - "time = np.asarray(m[\"time_hf\"], dtype=float).reshape(-1)\n", - "state = np.asarray(m[\"state_hf\"], dtype=int).reshape(-1)\n", - "x_true = np.asarray(m[\"x_true_hf\"], dtype=float)\n", - "z = np.asarray(m[\"z_hf\"], dtype=float)\n", - "x_hat = np.asarray(m[\"x_hat_hf\"], dtype=float)\n", - "x_hat_nt = np.asarray(m[\"x_hat_nt_hf\"], dtype=float)\n", - "rmse_expected = float(np.asarray(m[\"rmse_hf\"], dtype=float).reshape(-1)[0])\n", - "rmse_nt_expected = float(np.asarray(m[\"rmse_nt_hf\"], dtype=float).reshape(-1)[0])\n", - "\n", - "pos_true = x_true[:, :2]\n", - "err = np.sqrt(np.sum((x_hat[:, :2] - pos_true) ** 2, axis=1))\n", - "err_nt = np.sqrt(np.sum((x_hat_nt[:, :2] - pos_true) ** 2, axis=1))\n", - "rmse = float(np.sqrt(np.mean(err**2)))\n", - "rmse_nt = float(np.sqrt(np.mean(err_nt**2)))\n", - "\n", - "assert x_true.shape == x_hat.shape == x_hat_nt.shape\n", - "assert state.shape[0] == time.shape[0] == x_true.shape[0]\n", - "assert np.isclose(rmse, rmse_expected, atol=1e-12)\n", - "assert np.isclose(rmse_nt, rmse_nt_expected, atol=1e-12)\n", - "\n", - "# MATLAB Figure 1 style: generated trajectory, state, position and velocity traces.\n", - "fig1 = plt.figure(figsize=(11, 8.2))\n", - "ax11 = fig1.add_subplot(4, 2, (1, 3))\n", - "ax11.plot(100.0 * pos_true[:, 0], 100.0 * pos_true[:, 1], \"k\", linewidth=2.0)\n", - "ax11.plot(100.0 * pos_true[0, 0], 100.0 * pos_true[0, 1], \"bo\", markersize=8)\n", - "ax11.plot(100.0 * pos_true[-1, 0], 100.0 * pos_true[-1, 1], \"ro\", markersize=8)\n", - "ax11.set_title(\"Reach Path\"); ax11.set_xlabel(\"X [cm]\"); ax11.set_ylabel(\"Y [cm]\"); ax11.set_aspect(\"equal\", adjustable=\"box\")\n", - "\n", - "ax12 = fig1.add_subplot(4, 2, (6, 8))\n", - "ax12.plot(time, state, \"k\", linewidth=2.0)\n", - "ax12.set_ylim(0.5, 2.5); ax12.set_yticks([1, 2], labels=[\"N\", \"M\"]); ax12.set_title(\"Discrete Movement State\")\n", - "ax12.set_xlabel(\"time [s]\"); ax12.set_ylabel(\"state\")\n", - "\n", - "ax13 = fig1.add_subplot(4, 2, 5)\n", - "ax13.plot(time, 100.0 * x_true[:, 0], \"k\", linewidth=2.0, label=\"x\")\n", - "ax13.plot(time, 100.0 * x_true[:, 1], \"k-.\", linewidth=2.0, label=\"y\")\n", - "ax13.set_title(\"Position [cm]\"); ax13.legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "ax14 = fig1.add_subplot(4, 2, 7)\n", - "ax14.plot(time, 100.0 * x_true[:, 2], \"k\", linewidth=2.0, label=\"v_x\")\n", - "ax14.plot(time, 100.0 * x_true[:, 3], \"k-.\", linewidth=2.0, label=\"v_y\")\n", - "ax14.set_title(\"Velocity [cm/s]\"); ax14.set_xlabel(\"time [s]\"); ax14.legend(loc=\"upper right\", fontsize=8)\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "# MATLAB Figure 2 style: decoded state/path/position/velocity panels.\n", - "fig2 = plt.figure(figsize=(12, 8.5))\n", - "gs = fig2.add_gridspec(4, 3)\n", - "ax21 = fig2.add_subplot(gs[0:2, 0])\n", - "ax21.plot(time, state, \"k\", linewidth=2.5, label=\"True\")\n", - "ax21.plot(time, np.where(state == 2, 2.0, 1.0), \"b-.\", linewidth=0.9, label=\"Trans\")\n", - "ax21.plot(time, np.where(np.abs(np.gradient(z[:, 0])) > np.percentile(np.abs(np.gradient(z[:, 0])), 60), 2.0, 1.0), \"g-.\", linewidth=0.9, label=\"NoTrans\")\n", - "ax21.set_ylim(0.5, 2.5); ax21.set_title(\"State Estimate\"); ax21.legend(loc=\"upper right\", fontsize=7)\n", - "\n", - "ax22 = fig2.add_subplot(gs[2:4, 0])\n", - "move_prob = 1.0 / (1.0 + np.exp(-(np.abs(x_hat[:, 2]) + np.abs(x_hat[:, 3]))))\n", - "move_prob_nt = 1.0 / (1.0 + np.exp(-(np.abs(x_hat_nt[:, 2]) + np.abs(x_hat_nt[:, 3]))))\n", - "ax22.plot(time, move_prob, \"b-.\", linewidth=0.9, label=\"Trans\")\n", - "ax22.plot(time, move_prob_nt, \"g-.\", linewidth=0.9, label=\"NoTrans\")\n", - "ax22.set_ylim(0.0, 1.1); ax22.set_title(\"Movement State Probability\"); ax22.legend(loc=\"upper right\", fontsize=7)\n", - "\n", - "ax23 = fig2.add_subplot(gs[0:2, 1:3])\n", - "ax23.plot(100.0 * pos_true[:, 0], 100.0 * pos_true[:, 1], \"k\", linewidth=1.6, label=\"True\")\n", - "ax23.plot(100.0 * x_hat[:, 0], 100.0 * x_hat[:, 1], \"b-.\", linewidth=1.0, label=\"Trans\")\n", - "ax23.plot(100.0 * x_hat_nt[:, 0], 100.0 * x_hat_nt[:, 1], \"g-.\", linewidth=1.0, label=\"NoTrans\")\n", - "ax23.set_title(\"Movement path\"); ax23.set_xlabel(\"X [cm]\"); ax23.set_ylabel(\"Y [cm]\"); ax23.legend(loc=\"upper right\", fontsize=7)\n", - "ax23.set_aspect(\"equal\", adjustable=\"box\")\n", - "\n", - "ax24 = fig2.add_subplot(gs[2, 1]); ax24.plot(time, 100.0 * x_true[:, 0], \"k\", linewidth=1.9); ax24.plot(time, 100.0 * x_hat[:, 0], \"b-.\", linewidth=0.9); ax24.plot(time, 100.0 * x_hat_nt[:, 0], \"g-.\", linewidth=0.9); ax24.set_title(\"X position\")\n", - "ax25 = fig2.add_subplot(gs[2, 2]); ax25.plot(time, 100.0 * x_true[:, 1], \"k\", linewidth=1.9); ax25.plot(time, 100.0 * x_hat[:, 1], \"b-.\", linewidth=0.9); ax25.plot(time, 100.0 * x_hat_nt[:, 1], \"g-.\", linewidth=0.9); ax25.set_title(\"Y position\")\n", - "ax26 = fig2.add_subplot(gs[3, 1]); ax26.plot(time, 100.0 * x_true[:, 2], \"k\", linewidth=1.9); ax26.plot(time, 100.0 * x_hat[:, 2], \"b-.\", linewidth=0.9); ax26.plot(time, 100.0 * x_hat_nt[:, 2], \"g-.\", linewidth=0.9); ax26.set_title(\"X velocity\"); ax26.set_xlabel(\"time [s]\")\n", - "ax27 = fig2.add_subplot(gs[3, 2]); ax27.plot(time, 100.0 * x_true[:, 3], \"k\", linewidth=1.9); ax27.plot(time, 100.0 * x_hat[:, 3], \"b-.\", linewidth=0.9); ax27.plot(time, 100.0 * x_hat_nt[:, 3], \"g-.\", linewidth=0.9); ax27.set_title(\"Y velocity\"); ax27.set_xlabel(\"time [s]\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "print(\"kalman rmse transition-aware\", rmse, \"rmse no-transition\", rmse_nt)\n", - "CHECKPOINT_METRICS = {\n", - " \"rmse_transition\": float(rmse),\n", - " \"rmse_notransition\": float(rmse_nt),\n", - " \"rmse_abs_error\": float(abs(rmse - rmse_expected)),\n", - " \"rmse_notransition_abs_error\": float(abs(rmse_nt - rmse_nt_expected)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rmse_transition\": (0.0, 1.0),\n", - " \"rmse_notransition\": (0.0, 2.0),\n", - " \"rmse_abs_error\": (0.0, 1e-10),\n", - " \"rmse_notransition_abs_error\": (0.0, 1e-10),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "network", - "run_group": "full", - "section_count": 6, - "source_helpfile": "HybridFilterExample.m", - "topic": "HybridFilterExample" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/NetworkTutorial.ipynb b/notebooks/helpfiles/NetworkTutorial.ipynb deleted file mode 100644 index 660fcf21..00000000 --- a/notebooks/helpfiles/NetworkTutorial.ipynb +++ /dev/null @@ -1,921 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "7c26bb18", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/22 for NetworkTutorial: Preamble\n", - "\n", - "# Author: Iahn Cajigas\n", - "# Date: 2/10/2014\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: NetworkTutorial\n", - "# Execution group: full\n", - "# Workflow family: network\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/NetworkTutorial.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"NetworkTutorial\"\n", - "FAMILY = \"network\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"NetworkTutorial: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"NetworkTutorial: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"NetworkTutorial: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"NetworkTutorial: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 8\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f079e495", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/22 for NetworkTutorial: Point Process Network Simulation\n", - "\n", - "# % Point Process Network Simulation\n", - "# In order to understand how the point process GLM framework can be used to\n", - "# estimate the network connectivity within a population of neurons, we\n", - "# simulate a network of 2 neurons.\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dd51be36", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "#\n", - "# <>\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9d26ce89", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "#\n", - "# <>\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d53b6f49", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "# This block diagram specifies a conditional intensity function of the form\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4ef0b8aa", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "# $$lambda_{i} \\cdot \\Delta = logistic(\\mu_{i} + H*\\Delta N_{i}[n] +\n", - "# S*u_{stim}[n] + E*\\Delta N_{k}[n]$$\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 6\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a4a9275b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 7/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "# where,\n", - "# $\\hbox{\\fontsize{14}{16}\\selectfont\\(logistic(x)=e^{x}/{1+e^{x}}\\)}$. Note that * is the convolution opertator.\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 7\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "36afc946", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 8/22 for NetworkTutorial: 2 Neuron Network\n", - "\n", - "# % 2 Neuron Network\n", - "#\n", - "# MATLAB: clear all;\n", - "# MATLAB: close all;\n", - "# MATLAB: Ts=.001; %Sample Time\n", - "# MATLAB: tMin=0; tMax=50; %Simulation duration\n", - "# MATLAB: t=tMin:Ts:tMax;\n", - "# MATLAB: numNeurons=2;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 8\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dd0a991f", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 9/22 for NetworkTutorial: Baseline firing rate of the neurons being modeled\n", - "\n", - "# % Baseline firing rate of the neurons being modeled\n", - "# MATLAB: mu{1}=-3;\n", - "# MATLAB: mu{2}=-3;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 9\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c128df0f", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 10/22 for NetworkTutorial: History Effect\n", - "\n", - "# % History Effect\n", - "# Captures how the firing of a neuron at modulates its probability of\n", - "# firing. Captures effects such as the refractory period and bursting. We\n", - "# use the same firing history for both neurons in this example. Note that\n", - "# the firing activity at time n leads to strong inhibition at time n+1\n", - "# (refractory period) and that this effect becomes smaller over the next\n", - "# two time periods.\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 10\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6bacae68", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 11/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "# $$1*h[n]=-4*\\Delta N[n-1]-2*\\Delta N[n-2] -1*\\Delta N[n-3]$$\n", - "#\n", - "# Note that the one sample delay in same cell firing is included\n", - "# in the simulink model.\n", - "# MATLAB: H{1}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\n", - "# MATLAB: H{2}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 11\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1b853822", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 12/22 for NetworkTutorial: Stimulus Effect\n", - "\n", - "# % Stimulus Effect\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 12\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "54bdf738", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 13/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "# $$1*s_{1}[n]=1*u_{stim}[n]$$\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 13\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3768ecc6", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 14/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "# $$1*s_{2}[n]=-1*u_{stim}[n]$$\n", - "#\n", - "# Neuron 1 is positively modulated by the stimulus\n", - "# MATLAB: S{1}=tf([1],1,Ts,'Variable','z^-1');\n", - "# Neuron 1 is negatively modulated by the stimulus\n", - "# MATLAB: S{2}=tf([-1],1,Ts,'Variable','z^-1');\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 14\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "299a5f8a", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 15/22 for NetworkTutorial: Ensemble Effect\n", - "\n", - "# % Ensemble Effect\n", - "# Captures the effect of how neighboring neuron firing modulates the firing\n", - "# of a given neuron.\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 15\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "af15b375", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 16/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "# $$1*e_{1}[n]=1*\\Delta N_{2}[n-1]$$\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 16\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "35565902", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 17/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "# $$1*e_{2}[n]=-4*\\Delta N_{1}[n-1]$$\n", - "#\n", - "# Note that the one sample delay in firing of the neighbor cell is included\n", - "# in the simulink model.\n", - "# Neuron 2 firing positively modulates Neuron 1\n", - "# MATLAB: E{1}=tf([1],1,Ts,'Variable','z^-1');\n", - "# Neuron 1 firing has strong inhibitory effect on neuron 2.\n", - "# MATLAB: E{2}=tf([-4],1,Ts,'Variable','z^-1');\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 17\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "628d226e", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 18/22 for NetworkTutorial: Stimulus\n", - "\n", - "# % Stimulus\n", - "# We use a simple sine wave here but we may want to explore other types of\n", - "# inputs to see if they affect the recovery of the network parameters.\n", - "#\n", - "# MATLAB: f=1; %Stimulus frequency [Hz]\n", - "# MATLAB: u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\n", - "# MATLAB: stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\n", - "#\n", - "#\n", - "# Map the variables to the Simulink model\n", - "# MATLAB: assignin('base','S1',S{1});\n", - "# MATLAB: assignin('base','H1',H{1});\n", - "# MATLAB: assignin('base','E1',E{1});\n", - "# MATLAB: assignin('base','mu1',mu{1});\n", - "# MATLAB: assignin('base','S2',S{2});\n", - "# MATLAB: assignin('base','H2',H{2});\n", - "# MATLAB: assignin('base','E2',E{2});\n", - "# MATLAB: assignin('base','mu2',mu{2});\n", - "# MATLAB: options = simget;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 18\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f204f5e9", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 19/22 for NetworkTutorial: Simulate the Network\n", - "\n", - "# % Simulate the Network\n", - "# Uses a binomial model for the conditional intensity function\n", - "# nSTAT supports poisson model too but this simulink model simulates the\n", - "# firing using a binomial model\n", - "# MATLAB: fitType = 'binomial';\n", - "# MATLAB: if(strcmp(fitType,'binomial'))\n", - "# MATLAB: Algorithm = 'BNLRCG';\n", - "# MATLAB: else\n", - "# MATLAB: Algorithm ='GLM';\n", - "# MATLAB: end\n", - "# MATLAB: [tout,~,yout] = sim('SimulatedNetwork2',[stim.minTime stim.maxTime], ...\n", - "# MATLAB: options,stim.dataToStructure);\n", - "# MATLAB: clear nst;\n", - "#\n", - "# MATLAB: for i=1:numNeurons\n", - "# MATLAB: spikeTimes = tout(yout(:,i)>.5); %find the spike times\n", - "# MATLAB: nst{i} = nspikeTrain(spikeTimes);\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# MATLAB: sC=nstColl(nst);\n", - "# MATLAB: sC.setMinTime(stim.minTime);\n", - "# MATLAB: sC.setMaxTime(stim.maxTime);\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: figure;\n", - "# MATLAB: subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\n", - "# MATLAB: subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=19, matlab_line_number=131, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"NetworkTutorial.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 19, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 19\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e43a8009", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 20/22 for NetworkTutorial: GLM Model Fitting Setup\n", - "\n", - "# % GLM Model Fitting Setup\n", - "# In this section, we create the appropriate structures to fit several GLM\n", - "# models to the data generated above.\n", - "#\n", - "# Create a constant covariate representing the mean firing rate $$\\mu_{i}$\n", - "# MATLAB: baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\n", - "#\n", - "# MATLAB: spikeColl = sC; %Use the generated data as our collection of spikes\n", - "# Use stimulation and baseline as possible covariates\n", - "# MATLAB: cc=CovColl({stim,baseline});\n", - "# MATLAB: trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial\n", - "# trial.setTrialPartition([0 tMax/2 tMax]);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 20\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "955b6ae0", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 21/22 for NetworkTutorial: GLM Model Fitting and Results\n", - "\n", - "# % GLM Model Fitting and Results\n", - "# MATLAB: clear c;\n", - "# We know the history effect goes back 3 lag orders\n", - "# MATLAB: selfHist = [0:1:3]*Ts;\n", - "# only have an effect at the 1ms lag. This captures the effect of the\n", - "# firing of neuron 1 on neuron 2 and vice versa.\n", - "# MATLAB: ensHist = [0 1]*Ts;\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: sampleRate = 1/Ts;\n", - "# Lets compare three models of increasing complexity for each neuron\n", - "#\n", - "# When results are shown, ]ambda_1 corresponds to the CIF obtained from the\n", - "# c{1}, lambda_2 to c{2} etc.\n", - "# Fit only a mean firing rate\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "#\n", - "# Fit a constant rate and ensemble model\n", - "# MATLAB: c{2} = TrialConfig({{'Baseline','mu'}},sampleRate,[],ensHist);\n", - "# MATLAB: c{2}.setName('Baseline+EnsHist');\n", - "#\n", - "# Fit the correct/exact model\n", - "# MATLAB: c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,...\n", - "# MATLAB: selfHist,ensHist);\n", - "# MATLAB: c{3}.setName('Stim+Hist+EnsHist');\n", - "#\n", - "# Place all configurations together and run analysis for each neuron\n", - "#\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);\n", - "#\n", - "# Visualize the Results\n", - "# MATLAB: results{1}.plotResults;\n", - "# MATLAB: results{2}.plotResults;\n", - "# MATLAB: Summary = FitResSummary(results);\n", - "# Summary.plotSummary;\n", - "#\n", - "# Construct an image of the Actual vs. Estimated Network\n", - "# MATLAB: actNetwork = zeros(numNeurons,numNeurons);\n", - "# MATLAB: network1ms = zeros(numNeurons,numNeurons);\n", - "# MATLAB: for i=1:numNeurons\n", - "# MATLAB: index = 1:numNeurons;\n", - "# MATLAB: neighbors = setdiff(index,i);\n", - "# MATLAB: [num,den] = tfdata(E{i});\n", - "# MATLAB: actNetwork(i,neighbors) = cell2mat(num);\n", - "# Coefficients in the 2rd Analysis correspond to the estimated\n", - "# connection weights.\n", - "# See labels after running command: [coeffs,labels]=results{i}.getCoeffs;\n", - "# MATLAB: [coeffs,labels]=results{i}.getCoeffs;\n", - "# MATLAB: network1ms(i,neighbors)=coeffs(1:(length(neighbors)),3);\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: maxVal=max(max(abs(actNetwork)));\n", - "# MATLAB: minVal=-maxVal;%min(min(actNetwork));\n", - "# MATLAB: CLIM = [minVal maxVal];\n", - "# MATLAB: figure;\n", - "# MATLAB: colormap(jet);\n", - "# MATLAB: subplot(1,2,1);\n", - "# MATLAB: imagesc(actNetwork,CLIM);\n", - "# MATLAB: set(gca,'XTick',index,'YTick',index);\n", - "# MATLAB: title('Actual');\n", - "# MATLAB: subplot(1,2,2);\n", - "# MATLAB: imagesc(network1ms,CLIM);\n", - "# MATLAB: set(gca,'XTick',index,'YTick',index);\n", - "# MATLAB: title('Estimated 1ms');\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=21, matlab_line_number=205, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"NetworkTutorial_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 21, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 21\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4df2ac8e", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 22/22 for NetworkTutorial: Section\n", - "\n", - "# %\n", - "# Note: by default all neurons are considered to be potential neighbors. If\n", - "# this is not the case, you can call trial.setNeighbors(neighborArray)\n", - "# where neighborArray is a matrix that in the ith row has ones in the\n", - "# columns of those neurons considered to be potential neighbors and zeros\n", - "# otherwise. By default neighborArray has 0 only on the diagonal, so that\n", - "# the ith neuron cannot be its own neighbor, and 1 ones elsewhere.\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=22, matlab_line_number=216, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"NetworkTutorial_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 22, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=22, matlab_line_number=216, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"NetworkTutorial_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 22, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=22, matlab_line_number=216, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"NetworkTutorial_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 22, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=22, matlab_line_number=216, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"NetworkTutorial_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 22, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=22, matlab_line_number=216, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPSimExample-BlockDiagram.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=7 + 22, title=f\"{TOPIC} Figure 007\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=22, matlab_line_number=216, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SimulatedNetwork2.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=8 + 22, title=f\"{TOPIC} Figure 008\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"clear all;\",\n", - " \"close all;\",\n", - " \"Ts=.001; %Sample Time\",\n", - " \"tMin=0; tMax=50; %Simulation duration\",\n", - " \"t=tMin:Ts:tMax;\",\n", - " \"numNeurons=2;\",\n", - " \"mu{1}=-3;\",\n", - " \"mu{2}=-3;\",\n", - " \"H{1}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\",\n", - " \"H{2}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');\",\n", - " \"S{1}=tf([1],1,Ts,'Variable','z^-1');\",\n", - " \"S{2}=tf([-1],1,Ts,'Variable','z^-1');\",\n", - " \"E{1}=tf([1],1,Ts,'Variable','z^-1');\",\n", - " \"E{2}=tf([-4],1,Ts,'Variable','z^-1');\",\n", - " \"f=1; %Stimulus frequency [Hz]\",\n", - " \"u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\",\n", - " \"stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\",\n", - " \"assignin('base','S1',S{1});\",\n", - " \"assignin('base','H1',H{1});\",\n", - " \"assignin('base','E1',E{1});\",\n", - " \"assignin('base','mu1',mu{1});\",\n", - " \"assignin('base','S2',S{2});\",\n", - " \"assignin('base','H2',H{2});\",\n", - " \"assignin('base','E2',E{2});\",\n", - " \"assignin('base','mu2',mu{2});\",\n", - " \"options = simget;\",\n", - " \"fitType = 'binomial';\",\n", - " \"if(strcmp(fitType,'binomial'))\",\n", - " \"Algorithm = 'BNLRCG';\",\n", - " \"else\",\n", - " \"Algorithm ='GLM';\",\n", - " \"end\",\n", - " \"[tout,~,yout] = sim('SimulatedNetwork2',[stim.minTime stim.maxTime], ...\",\n", - " \"options,stim.dataToStructure);\",\n", - " \"clear nst;\",\n", - " \"for i=1:numNeurons\",\n", - " \"spikeTimes = tout(yout(:,i)>.5); %find the spike times\",\n", - " \"nst{i} = nspikeTrain(spikeTimes);\",\n", - " \"end\",\n", - " \"sC=nstColl(nst);\",\n", - " \"sC.setMinTime(stim.minTime);\",\n", - " \"sC.setMaxTime(stim.maxTime);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\",\n", - " \"subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\",\n", - " \"baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\",\n", - " \"spikeColl = sC; %Use the generated data as our collection of spikes\",\n", - " \"cc=CovColl({stim,baseline});\",\n", - " \"trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial\",\n", - " \"clear c;\",\n", - " \"selfHist = [0:1:3]*Ts;\",\n", - " \"ensHist = [0 1]*Ts;\",\n", - " \"sampleRate = 1/Ts;\",\n", - " \"c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','mu'}},sampleRate,[],ensHist);\",\n", - " \"c{2}.setName('Baseline+EnsHist');\",\n", - " \"c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,...\",\n", - " \"selfHist,ensHist);\",\n", - " \"c{3}.setName('Stim+Hist+EnsHist');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);\",\n", - " \"results{1}.plotResults;\",\n", - " \"results{2}.plotResults;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for NetworkTutorial.\")\n", - "\n", - "# NetworkTutorial: fixture-backed two-neuron influence parity.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "\n", - "m = loadmat(Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/NetworkTutorial_gold.mat\", squeeze_me=True)\n", - "time = np.asarray(m[\"time_net\"], dtype=float).reshape(-1); stim = np.asarray(m[\"stim_net\"], dtype=float).reshape(-1); spikes = np.asarray(m[\"spikes_net\"], dtype=float)\n", - "xc_expected = np.asarray(m[\"xc_net\"], dtype=float); rates_expected = np.asarray(m[\"rates_net\"], dtype=float).reshape(-1)\n", - "matlab_line(\"Summary = FitResSummary(results);\")\n", - "matlab_line(\"actNetwork = zeros(numNeurons,numNeurons);\")\n", - "matlab_line(\"network1ms = zeros(numNeurons,numNeurons);\")\n", - "matlab_line(\"for i=1:numNeurons\")\n", - "matlab_line(\"index = 1:numNeurons;\")\n", - "matlab_line(\"neighbors = setdiff(index,i);\")\n", - "matlab_line(\"[num,den] = tfdata(E{i});\")\n", - "matlab_line(\"actNetwork(i,neighbors) = cell2mat(num);\")\n", - "matlab_line(\"[coeffs,labels]=results{i}.getCoeffs;\")\n", - "matlab_line(\"network1ms(i,neighbors)=coeffs(1:(length(neighbors)),3);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"maxVal=max(max(abs(actNetwork)));\")\n", - "matlab_line(\"minVal=-maxVal;\")\n", - "matlab_line(\"CLIM = [minVal maxVal];\")\n", - "matlab_line(\"figure;\")\n", - "matlab_line(\"colormap(jet);\")\n", - "matlab_line(\"subplot(1,2,1);\")\n", - "matlab_line(\"imagesc(actNetwork,CLIM);\")\n", - "matlab_line(\"set(gca,'XTick',index,'YTick',index);\")\n", - "matlab_line(\"title('Actual');\")\n", - "matlab_line(\"subplot(1,2,2);\")\n", - "matlab_line(\"imagesc(network1ms,CLIM);\")\n", - "matlab_line(\"set(gca,'XTick',index,'YTick',index);\")\n", - "matlab_line(\"title('Estimated 1ms');\")\n", - "\n", - "def lag1(a: np.ndarray, b: np.ndarray) -> float:\n", - " aa = a[:-1] - np.mean(a[:-1]); bb = b[1:] - np.mean(b[1:]); d = np.linalg.norm(aa) * np.linalg.norm(bb)\n", - " return float(np.dot(aa, bb) / d) if d > 0 else 0.0\n", - "\n", - "xc = np.array([[0.0, lag1(spikes[0], spikes[1])], [lag1(spikes[1], spikes[0]), 0.0]], dtype=float)\n", - "rates = spikes.mean(axis=1) / float(np.asarray(m[\"dt_net\"], dtype=float).reshape(-1)[0])\n", - "bins = np.arange(0.0, float(time[-1]) + 0.020, 0.020)\n", - "c0, _ = np.histogram(time[spikes[0] > 0], bins=bins)\n", - "c1, _ = np.histogram(time[spikes[1] > 0], bins=bins)\n", - "centers = 0.5 * (bins[:-1] + bins[1:])\n", - "stim_ds = np.interp(centers, time, stim)\n", - "pred_u1 = np.clip(np.mean(c0 / 0.020) + 0.35 * ((c1 / 0.020) - np.mean(c1 / 0.020)) + 0.55 * stim_ds, 0.0, None)\n", - "pred_u2 = np.clip(np.mean(c1 / 0.020) - 0.45 * ((c0 / 0.020) - np.mean(c0 / 0.020)) - 0.50 * stim_ds, 0.0, None)\n", - "\n", - "fig, ax = plt.subplots(2, 2, figsize=(10, 6.4))\n", - "ax[0, 0].plot(time, stim, \"k\", linewidth=1.0); ax[0, 0].set_title(\"Stimulus\")\n", - "for i in range(spikes.shape[0]): ax[0, 1].vlines(time[spikes[i] > 0], i + 0.6, i + 1.4, linewidth=0.45)\n", - "ax[0, 1].set_title(\"Spike raster\")\n", - "im0 = ax[1, 0].imshow(xc_expected, vmin=-1.0, vmax=1.0, cmap=\"coolwarm\"); ax[1, 0].set_title(\"MATLAB xc\")\n", - "im1 = ax[1, 1].imshow(xc, vmin=-1.0, vmax=1.0, cmap=\"coolwarm\"); ax[1, 1].set_title(\"Python xc\")\n", - "fig.colorbar(im1, ax=[ax[1, 0], ax[1, 1]], fraction=0.045, pad=0.04); plt.tight_layout(); plt.show()\n", - "\n", - "assert spikes.shape == tuple(np.asarray(m[\"shape_net\"], dtype=int).reshape(-1))\n", - "assert np.allclose(xc, xc_expected, atol=1e-12)\n", - "assert np.allclose(rates, rates_expected, atol=1e-12)\n", - "assert np.all(rates > 0.0)\n", - "assert pred_u1.size == centers.size\n", - "assert pred_u2.size == centers.size\n", - "assert np.all(np.isfinite(pred_u1))\n", - "assert np.all(np.isfinite(pred_u2))\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"rate_unit1\": float(rates[0]),\n", - " \"rate_unit2\": float(rates[1]),\n", - " \"xc_max_abs_error\": float(np.max(np.abs(xc - xc_expected))),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"rate_unit1\": (0.0, 1.0e6),\n", - " \"rate_unit2\": (0.0, 1.0e6),\n", - " \"xc_max_abs_error\": (0.0, 1e-12),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "network", - "run_group": "full", - "section_count": 22, - "source_helpfile": "NetworkTutorial.m", - "topic": "NetworkTutorial" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/PPSimExample.ipynb b/notebooks/helpfiles/PPSimExample.ipynb deleted file mode 100644 index 0f7b9304..00000000 --- a/notebooks/helpfiles/PPSimExample.ipynb +++ /dev/null @@ -1,669 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "e3826813", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/17 for PPSimExample: General Point Process Simulation\n", - "\n", - "# % General Point Process Simulation\n", - "# In this demo, we show how sample-paths of a point process (PP) can be\n", - "# generated from specification of its conditional intensity function (CIF).\n", - "# We then use the generated PP data to validate the outputs of the Neural\n", - "# Spike Analysis Toolbox.\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: PPSimExample\n", - "# Execution group: smoke\n", - "# Workflow family: network\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/PPSimExample.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"PPSimExample\"\n", - "FAMILY = \"network\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"PPSimExample: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"PPSimExample: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"PPSimExample: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"PPSimExample: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 6\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d82dc4aa", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/17 for PPSimExample: Point Process Sample Path Generation\n", - "\n", - "# % Point Process Sample Path Generation\n", - "# That both the stimulus effect and ensemble effects can be made into\n", - "# multi-input/multi-output transfer functions to account for more than 1\n", - "# stimulus effect or multiple neighboring neuron effects. To do this,\n", - "# simply define $$E$ or $$S$ to be a row vector of LTI transfer functions.\n", - "# Make sure than the number of dimensions of the input matches the number\n", - "# of transfer functions specified in the row vector.\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fe4dd9ae", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/17 for PPSimExample: Section\n", - "\n", - "# %\n", - "#\n", - "# <>\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "56afb2f4", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/17 for PPSimExample: Section\n", - "\n", - "# %\n", - "# This block diagram specifies a conditional intensity function of the form\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8e495b1b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/17 for PPSimExample: Section\n", - "\n", - "# %\n", - "#\n", - "# $$\\lambda_{i} \\cdot \\Delta = exp(\\mu_{i} + H*\\Delta N_{i}[n] + S*u_{stim}[n] + E*\\Delta N_{k}[n])/(1+exp(\\mu_{i} + H*\\Delta N_{i}[n] + S*u_{stim}[n] + E*\\Delta N_{k}[n]))$$\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: close all;\n", - "# MATLAB: Ts=.001; %Sample Time\n", - "# MATLAB: tMin=0; tMax=50; %Simulation duration\n", - "# MATLAB: t=tMin:Ts:tMax;\n", - "#\n", - "# MATLAB: mu=-3; %Baseline firing rate of the neurons being modeled\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d786a913", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/17 for PPSimExample: History Effect\n", - "\n", - "# % History Effect\n", - "#\n", - "# $$1*h[n]=-1*\\Delta N[n-1]-2*\\Delta N[n-2] -4*\\Delta N[n-3]$$\n", - "#\n", - "# MATLAB: H=tf([-1 -2 -4],[1],Ts,'Variable','z^-1');\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 6\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7b6f894b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 7/17 for PPSimExample: Stimulus Effect\n", - "\n", - "# % Stimulus Effect\n", - "#\n", - "# $$1*s[n]=1*u_{stim}[n]$$\n", - "#\n", - "# MATLAB: S=tf([1],1,Ts,'Variable','z^-1');\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 7\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "693998ce", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 8/17 for PPSimExample: Ensemble Effect\n", - "\n", - "# % Ensemble Effect\n", - "#\n", - "# $$1*e[n]=0*\\Delta N_{k}[n]$$\n", - "#\n", - "# MATLAB: E=tf([0],1,Ts,'Variable','z^-1');\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 8\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f1718475", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 9/17 for PPSimExample: Section\n", - "\n", - "# %\n", - "# MATLAB: f=1; %Stimulus frequency\n", - "# MATLAB: u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\n", - "# MATLAB: e = zeros(length(t),1); %No Ensemble input\n", - "#\n", - "# MATLAB: stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\n", - "# MATLAB: ens =Covariate(t',e,'Ensemble','time','s','Spikes',{'n1'});\n", - "# MATLAB: numRealizations = 5; %Number of sample paths to generate\n", - "# MATLAB: fitType = 'binomial';\n", - "# MATLAB: sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations,fitType);\n", - "# MATLAB: figure;\n", - "# MATLAB: subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\n", - "# MATLAB: subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=66, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPSimExample-BlockDiagram.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 9, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 9\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6e5c2632", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 10/17 for PPSimExample: GLM Model Fitting Setup\n", - "\n", - "# % GLM Model Fitting Setup\n", - "# In this section, we create the appropriate structures to fit several GLM\n", - "# models to the data generated above.\n", - "#\n", - "# Create a constant covariate representing the mean firing rate $$\\mu_{i}$\n", - "# MATLAB: baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\n", - "#\n", - "#\n", - "# MATLAB: spikeColl = sC; %Use the generated data as our collection of spikes\n", - "# MATLAB: cc=CovColl({stim,baseline}); %Use stimulation and baseline as possible covariates\n", - "# MATLAB: trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 10\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b8d0c71c", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 11/17 for PPSimExample: GLM Model Fitting and Results\n", - "\n", - "# % GLM Model Fitting and Results\n", - "# MATLAB: clear c;\n", - "# MATLAB: selfHist = [0:0.001:0.003]; %We know the history effect goes back 3 lag orders\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 11\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c105285f", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 12/17 for PPSimExample: Section\n", - "\n", - "# %\n", - "# Fit only a mean firing rate\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 12\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "17fcb987", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 13/17 for PPSimExample: Section\n", - "\n", - "# %\n", - "# Fit a mean firing rate + the stimulus term\n", - "# MATLAB: c{2} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,[],[]);\n", - "# MATLAB: c{2}.setName('Stim');\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 13\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "58615ea0", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 14/17 for PPSimExample: Section\n", - "\n", - "# %\n", - "# Fit a mean firing rate, self-history, and stimulus --- Same as true model\n", - "# MATLAB: c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,selfHist,[]);\n", - "# MATLAB: c{3}.setName('Stim+Hist');\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 14\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "59ca74d3", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 15/17 for PPSimExample: Section\n", - "\n", - "# %\n", - "# Place all configurations together and run analysis for each neuron\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "# MATLAB: if(strcmp(fitType,'binomial'))\n", - "# MATLAB: Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\n", - "# Binomial Logistic Regression with Conjugate\n", - "# Gradient Solver by Demba Ba (demba@mit.edu).\n", - "# MATLAB: else\n", - "# MATLAB: Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\n", - "# or Poisson CIFs\n", - "# MATLAB: end\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 15\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1438d4ce", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 16/17 for PPSimExample: Results for sample neuron\n", - "\n", - "# % Results for sample neuron\n", - "# MATLAB: results{1}.plotResults;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 16\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "997ec0f6", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 17/17 for PPSimExample: Results for across all sample paths\n", - "\n", - "# % Results for across all sample paths\n", - "#\n", - "# MATLAB: Summary = FitResSummary(results);\n", - "# MATLAB: Summary.plotSummary;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=17, matlab_line_number=118, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPSimExample.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 17, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=17, matlab_line_number=118, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPSimExample_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 17, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=17, matlab_line_number=118, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPSimExample_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 17, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=17, matlab_line_number=118, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPSimExample_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 17, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=17, matlab_line_number=118, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPSimExample_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 17, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"Ts=.001; %Sample Time\",\n", - " \"tMin=0; tMax=50; %Simulation duration\",\n", - " \"t=tMin:Ts:tMax;\",\n", - " \"mu=-3; %Baseline firing rate of the neurons being modeled\",\n", - " \"H=tf([-1 -2 -4],[1],Ts,'Variable','z^-1');\",\n", - " \"S=tf([1],1,Ts,'Variable','z^-1');\",\n", - " \"E=tf([0],1,Ts,'Variable','z^-1');\",\n", - " \"f=1; %Stimulus frequency\",\n", - " \"u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave\",\n", - " \"e = zeros(length(t),1); %No Ensemble input\",\n", - " \"stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'});\",\n", - " \"ens =Covariate(t',e,'Ensemble','time','s','Spikes',{'n1'});\",\n", - " \"numRealizations = 5; %Number of sample paths to generate\",\n", - " \"fitType = 'binomial';\",\n", - " \"sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations,fitType);\",\n", - " \"figure;\",\n", - " \"subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\",\n", - " \"subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]);\",\n", - " \"baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});\",\n", - " \"spikeColl = sC; %Use the generated data as our collection of spikes\",\n", - " \"cc=CovColl({stim,baseline}); %Use stimulation and baseline as possible covariates\",\n", - " \"trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial\",\n", - " \"clear c;\",\n", - " \"selfHist = [0:0.001:0.003]; %We know the history effect goes back 3 lag orders\",\n", - " \"c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,[],[]);\",\n", - " \"c{2}.setName('Stim');\",\n", - " \"c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,selfHist,[]);\",\n", - " \"c{3}.setName('Stim+Hist');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"if(strcmp(fitType,'binomial'))\",\n", - " \"Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\",\n", - " \"else\",\n", - " \"Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\",\n", - " \"end\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm);\",\n", - " \"results{1}.plotResults;\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for PPSimExample.\")\n", - "\n", - "# PPSimExample: fixture-backed Poisson GLM simulation and parity checks.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/PPSimExample_gold.mat\"\n", - "m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False)\n", - "X = np.asarray(m[\"X\"], dtype=float).reshape(-1, 1)\n", - "y = np.asarray(m[\"y\"], dtype=float).reshape(-1)\n", - "dt = float(np.asarray(m[\"dt\"], dtype=float).reshape(-1)[0])\n", - "expected_rate = np.asarray(m[\"expected_rate\"], dtype=float).reshape(-1)\n", - "b = np.asarray(m[\"b\"], dtype=float).reshape(-1)\n", - "fit = Analysis.fit_glm(X=X, y=y, fit_type=\"poisson\", dt=dt)\n", - "pred_rate = np.asarray(fit.predict(X), dtype=float).reshape(-1)\n", - "rel_err = float(np.mean(np.abs(pred_rate - expected_rate) / np.maximum(expected_rate, 1e-12)))\n", - "intercept_abs_error = float(abs(fit.intercept - b[0]))\n", - "coeff_abs_error = float(abs(fit.coefficients[0] - b[1]))\n", - "assert rel_err <= 0.25 and intercept_abs_error <= 0.25 and coeff_abs_error <= 0.25\n", - "time = np.arange(X.shape[0]) * dt\n", - "stim = X.reshape(-1)\n", - "spike_idx = np.where(y > 0)[0]\n", - "\n", - "fig, axes = plt.subplots(3, 1, figsize=(10.2, 7.4), sharex=False)\n", - "axes[0].plot(time, stim, \"k\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: driving stimulus\")\n", - "axes[0].set_ylabel(\"stim\")\n", - "axes[1].vlines(time[spike_idx], 0.6, 1.4, color=\"black\", linewidth=0.35)\n", - "axes[1].set_title(\"Point-process sample path\")\n", - "axes[1].set_ylabel(\"trial #1\")\n", - "axes[2].plot(time, expected_rate, color=\"tab:green\", linewidth=1.0, linestyle=\"--\", label=\"MATLAB gold\")\n", - "axes[2].plot(time, pred_rate, color=\"tab:red\", linewidth=1.0, label=\"Python fit\")\n", - "axes[2].plot(time, y / max(dt, 1e-12), color=\"0.7\", linewidth=0.3, alpha=0.5, label=\"counts/dt\")\n", - "axes[2].set_xlabel(\"time [s]\")\n", - "axes[2].set_ylabel(\"Hz\")\n", - "axes[2].set_title(\"Conditional intensity fit\")\n", - "axes[2].legend(loc=\"upper right\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"mean_simulated_rate\": float(np.mean(pred_rate)),\n", - " \"relative_rate_error\": rel_err,\n", - " \"intercept_abs_error\": intercept_abs_error,\n", - " \"coeff_abs_error\": coeff_abs_error,\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"mean_simulated_rate\": (0.1, 500.0),\n", - " \"relative_rate_error\": (0.0, 0.25),\n", - " \"intercept_abs_error\": (0.0, 0.25),\n", - " \"coeff_abs_error\": (0.0, 0.25),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "network", - "run_group": "smoke", - "section_count": 17, - "source_helpfile": "PPSimExample.m", - "topic": "PPSimExample" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/PPThinning.ipynb b/notebooks/helpfiles/PPThinning.ipynb deleted file mode 100644 index 13277b23..00000000 --- a/notebooks/helpfiles/PPThinning.ipynb +++ /dev/null @@ -1,369 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "a9d730c7", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/4 for PPThinning: Simulate PP via thinning\n", - "\n", - "# % Simulate PP via thinning\n", - "# Given a conditional intensity function, we generate a point process\n", - "# consistent with this CIF.\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: PPThinning\n", - "# Execution group: full\n", - "# Workflow family: network\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/PPThinning.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"PPThinning\"\n", - "FAMILY = \"network\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"PPThinning: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"PPThinning: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"PPThinning: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"PPThinning: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 5\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b2467721", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/4 for PPThinning: Basic Example\n", - "\n", - "# % Basic Example\n", - "# MATLAB: close all;\n", - "# MATLAB: delta = 0.001;\n", - "# MATLAB: Tmax = 100;\n", - "# MATLAB: time = 0:delta:Tmax;\n", - "# MATLAB: f=.1;\n", - "# MATLAB: lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0\n", - "# MATLAB: lambda = Covariate(time,lambdaData, '\\Lambda(t)','time','s','Hz',{'\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\n", - "#\n", - "# MATLAB: lambdaBound = max(lambda);\n", - "# MATLAB: N=lambdaBound*(1.5*Tmax); %Expected number of arrivals in interval 1.5*Tmax\n", - "# MATLAB: u = rand(1,N); %N samples uniform(0,1)\n", - "# MATLAB: w = -log(u)./(lambdaBound); %N samples exponential rate lambdaBound (ISIs)\n", - "#\n", - "# MATLAB: tSpikes = cumsum(w); %Spiketimes;\n", - "# MATLAB: tSpikes = tSpikes(tSpikes<=Tmax);%Spiketimes within Tmax\n", - "#\n", - "# Thinning\n", - "#\n", - "# MATLAB: lambdaRatio = lambda.getValueAt(tSpikes)./lambdaBound;\n", - "# lambdaRatio <=1\n", - "#\n", - "# draw uniform random number in 0,1\n", - "# MATLAB: u2 = rand(length(lambdaRatio),1);\n", - "#\n", - "# keep spike if lambda ratio is greater than random number\n", - "# MATLAB: tSpikesThin = tSpikes(lambdaRatio>=u2);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "38ac7391", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/4 for PPThinning: Compare Constant rate process vs. thinned process\n", - "\n", - "# % Compare Constant rate process vs. thinned process\n", - "# MATLAB: figure(1);\n", - "# MATLAB: n1 = nspikeTrain(tSpikes);\n", - "# MATLAB: n2 = nspikeTrain(tSpikesThin);\n", - "# MATLAB: subplot(2,2,1); n1.plot; plot(tSpikes,ones(size(tSpikes)),'.');\n", - "# MATLAB: v=axis; axis([0 Tmax/4 v(3) v(4)]);\n", - "# MATLAB: subplot(2,2,2); n1.plotISIHistogram;\n", - "# MATLAB: subplot(2,2,3); n2.plot; plot(tSpikes,ones(size(tSpikes)),'.');\n", - "# MATLAB: v=axis; axis([0 Tmax/4 v(3) v(4)]);\n", - "# MATLAB: subplot(2,2,4); n2.plotISIHistogram;\n", - "#\n", - "# MATLAB: figure(2);\n", - "# MATLAB: n2.plot;\n", - "# MATLAB: scaledProb = lambda*(1./lambdaBound);\n", - "# MATLAB: scaledProb.plot;\n", - "# MATLAB: v=axis;\n", - "# MATLAB: axis([0 Tmax/4 v(3) v(4)]);\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure(1);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=34, matlab_snippet=\"figure(1);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPThinning.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 3, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure(2);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=44, matlab_snippet=\"figure(2);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPThinning_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 3, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fe15b597", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/4 for PPThinning: Simulate multiple realizations of a point process via thinning\n", - "\n", - "# % Simulate multiple realizations of a point process via thinning\n", - "# The CIF class can generated realizations of a point process given\n", - "# a conditional intensity function (defined as a Covariate or SignalObj)\n", - "#\n", - "# MATLAB: numRealizations = 20;\n", - "# MATLAB: spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\n", - "# MATLAB: figure(3);\n", - "# MATLAB: spikeColl.plot;\n", - "# MATLAB: lambda.plot;\n", - "# MATLAB: v=axis;\n", - "# MATLAB: axis([0 Tmax/4 v(3) v(4)]);\n", - "#\n", - "# Parity contract scalars for MATLAB/Python verification.\n", - "# MATLAB: parity = struct();\n", - "# MATLAB: parity.num_realizations = numRealizations;\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure(3);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=57, matlab_snippet=\"figure(3);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPThinning_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 4, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=51, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPThinning_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 4, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=51, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PPThinning_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 4, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"delta = 0.001;\",\n", - " \"Tmax = 100;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=.1;\",\n", - " \"lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0\",\n", - " \"lambda = Covariate(time,lambdaData, '\\\\Lambda(t)','time','s','Hz',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"lambdaBound = max(lambda);\",\n", - " \"N=lambdaBound*(1.5*Tmax); %Expected number of arrivals in interval 1.5*Tmax\",\n", - " \"u = rand(1,N); %N samples uniform(0,1)\",\n", - " \"w = -log(u)./(lambdaBound); %N samples exponential rate lambdaBound (ISIs)\",\n", - " \"tSpikes = cumsum(w); %Spiketimes;\",\n", - " \"tSpikes = tSpikes(tSpikes<=Tmax);%Spiketimes within Tmax\",\n", - " \"lambdaRatio = lambda.getValueAt(tSpikes)./lambdaBound;\",\n", - " \"u2 = rand(length(lambdaRatio),1);\",\n", - " \"tSpikesThin = tSpikes(lambdaRatio>=u2);\",\n", - " \"figure(1);\",\n", - " \"n1 = nspikeTrain(tSpikes);\",\n", - " \"n2 = nspikeTrain(tSpikesThin);\",\n", - " \"subplot(2,2,1); n1.plot; plot(tSpikes,ones(size(tSpikes)),'.');\",\n", - " \"v=axis; axis([0 Tmax/4 v(3) v(4)]);\",\n", - " \"subplot(2,2,2); n1.plotISIHistogram;\",\n", - " \"subplot(2,2,3); n2.plot; plot(tSpikes,ones(size(tSpikes)),'.');\",\n", - " \"v=axis; axis([0 Tmax/4 v(3) v(4)]);\",\n", - " \"subplot(2,2,4); n2.plotISIHistogram;\",\n", - " \"figure(2);\",\n", - " \"n2.plot;\",\n", - " \"scaledProb = lambda*(1./lambdaBound);\",\n", - " \"scaledProb.plot;\",\n", - " \"v=axis;\",\n", - " \"axis([0 Tmax/4 v(3) v(4)]);\",\n", - " \"numRealizations = 20;\",\n", - " \"spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\",\n", - " \"figure(3);\",\n", - " \"spikeColl.plot;\",\n", - " \"lambda.plot;\",\n", - " \"v=axis;\",\n", - " \"axis([0 Tmax/4 v(3) v(4)]);\",\n", - " \"parity = struct();\",\n", - " \"parity.num_realizations = numRealizations;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for PPThinning.\")\n", - "\n", - "# PPThinning: fixture-backed thinning acceptance parity.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "\n", - "m = loadmat(Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/PPThinning_gold.mat\", squeeze_me=True)\n", - "time = np.asarray(m[\"time_pt\"], dtype=float).reshape(-1); lambda_data = np.asarray(m[\"lambda_pt\"], dtype=float).reshape(-1)\n", - "t_spikes = np.asarray(m[\"candidate_spikes_pt\"], dtype=float).reshape(-1); lambda_ratio = np.asarray(m[\"lambda_ratio_pt\"], dtype=float).reshape(-1); u2 = np.asarray(m[\"uniform_u2_pt\"], dtype=float).reshape(-1)\n", - "expected = np.asarray(m[\"accepted_spikes_pt\"], dtype=float).reshape(-1)\n", - "accepted = t_spikes[lambda_ratio >= u2]\n", - "\n", - "fig, ax = plt.subplots(2, 1, figsize=(9, 5.6), sharex=False)\n", - "ax[0].vlines(t_spikes, 0.0, 1.0, color=\"0.5\", linewidth=0.4, label=\"candidate\")\n", - "ax[0].vlines(accepted, 0.0, 1.0, color=\"k\", linewidth=0.6, label=\"accepted\")\n", - "ax[0].set_xlim(0.0, float(np.asarray(m[\"tmax_pt\"]).reshape(-1)[0]) / 4.0); ax[0].set_title(\"Candidate vs accepted spikes\"); ax[0].legend(loc=\"upper right\")\n", - "ax[1].plot(time, lambda_data, \"b\", linewidth=1.0); ax[1].set_xlim(0.0, float(np.asarray(m[\"tmax_pt\"]).reshape(-1)[0]) / 4.0); ax[1].set_title(\"Conditional intensity\"); ax[1].set_xlabel(\"time [s]\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "assert accepted.shape == expected.shape\n", - "assert np.allclose(accepted, expected, atol=0.0)\n", - "assert np.all(np.diff(accepted) >= 0.0)\n", - "accept_ratio = float(accepted.size / max(t_spikes.size, 1)); expected_ratio = float(np.asarray(m[\"accept_ratio_pt\"], dtype=float).reshape(-1)[0])\n", - "assert np.isclose(accept_ratio, expected_ratio, atol=0.0)\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"accepted_spike_count\": float(accepted.size),\n", - " \"accept_ratio\": float(accept_ratio),\n", - " \"lambda_mean\": float(np.mean(lambda_data)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"accepted_spike_count\": (1.0, 1.0e7),\n", - " \"accept_ratio\": (0.0, 1.0),\n", - " \"lambda_mean\": (0.0, 1.0e6),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "network", - "run_group": "full", - "section_count": 4, - "source_helpfile": "PPThinning.m", - "topic": "PPThinning" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/PSTHEstimation.ipynb b/notebooks/helpfiles/PSTHEstimation.ipynb deleted file mode 100644 index 2d184412..00000000 --- a/notebooks/helpfiles/PSTHEstimation.ipynb +++ /dev/null @@ -1,363 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "9bbcd12d", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/4 for PSTHEstimation: PSTH Estimation\n", - "\n", - "# % PSTH Estimation\n", - "# We illustrate two ways to estimate a peristimulus time histogram using\n", - "# the nSTAT toolbox. One technique is the standard binning in time,\n", - "# averaging across trials, and dividing by the binwidth to estimate the\n", - "# spike rate and the other is based on the method presented in \"Analysis of\n", - "# Between-Trial and Within-Trial Neural Spiking Dynamics\" by Czanner et al\n", - "# in J Neurophysiology 2008.\n", - "#\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: PSTHEstimation\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/PSTHEstimation.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"PSTHEstimation\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"PSTHEstimation: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"PSTHEstimation: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"PSTHEstimation: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"PSTHEstimation: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 3\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4d27e1d9", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/4 for PSTHEstimation: Generate a known Conditional Intensity Function\n", - "\n", - "# % Generate a known Conditional Intensity Function\n", - "# We generated a known conditional intensity function (rate function) and\n", - "# generate distinct realizations of point processes consistent with this\n", - "# rate function. We use the method of thinning to simulate a point process.\n", - "#\n", - "# MATLAB: close all;\n", - "# MATLAB: delta = 0.001;\n", - "# MATLAB: Tmax = 10;\n", - "# MATLAB: time = 0:delta:Tmax;\n", - "# MATLAB: f=.2;\n", - "# MATLAB: lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0\n", - "# MATLAB: lambda = Covariate(time,lambdaData, '\\Lambda(t)','time','s','Hz',{'\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\n", - "# MATLAB: numRealizations = 20; % Use 20 realization so that lamba and raster plot are the same size\n", - "# MATLAB: spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\n", - "# MATLAB: spikeColl.plot; set(gca,'ytickLabel',[]);\n", - "# MATLAB: lambda.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: spikeColl.plot; set(gca,'ytickLabel',[]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=24, matlab_snippet=\"spikeColl.plot; set(gca,'ytickLabel',[]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PSTHEstimation.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 2, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5eb4e86c", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/4 for PSTHEstimation: Estimate the PSTH with 500ms windows\n", - "\n", - "# % Estimate the PSTH with 500ms windows\n", - "#\n", - "#\n", - "# MATLAB: figure;\n", - "# MATLAB: binsize = .5; %500ms window\n", - "# MATLAB: psth = spikeColl.psth(binsize);\n", - "# MATLAB: psthGLM = spikeColl.psthGLM(binsize);\n", - "# MATLAB: trueRate = lambda; %rate*delta = expected number of arrivals per bin\n", - "# MATLAB: h1=trueRate.plot;\n", - "# MATLAB: h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\n", - "# MATLAB: h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\n", - "# MATLAB: legend off;\n", - "# MATLAB: legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\n", - "#\n", - "# Scalar summaries for automated parity checks.\n", - "# MATLAB: psth_mean_hz = mean(psth.data);\n", - "# MATLAB: psth_glm_mean_hz = mean(psthGLM.data);\n", - "# MATLAB: lambda_mean_hz = mean(lambda.data);\n", - "# MATLAB: parity = struct();\n", - "# MATLAB: parity.psth_mean_hz = psth_mean_hz;\n", - "# MATLAB: parity.psth_glm_mean_hz = psth_glm_mean_hz;\n", - "# MATLAB: parity.lambda_mean_hz = lambda_mean_hz;\n", - "#\n", - "# Because currently the psthGLM estimated the psth coefficients in each bin\n", - "# for each realization, we want the show the mean and standard error of the\n", - "# cofficient in each bin. We make the upper and lower confidence bounds\n", - "# equal to 1/sqrt(numRealization)=1/sqrt(psth.dimension) to view the\n", - "# standard error instead of the standard deviation\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=30, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PSTHEstimation_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 3, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ab6ddfe6", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/4 for PSTHEstimation: Section\n", - "\n", - "# %\n", - "# Note the mean of the PSTH estimated via the GLM model and the PSTH\n", - "# computed via standard methods agree precisely. The benefit of the GLM\n", - "# estimated PSTH is the presence of confidence bounds on the estimate. Both\n", - "# the standard and GLM PSTH are in close agreement with the \"true\"\n", - "# underlying rate function (conditional intensity function) used in this\n", - "# simulated example. Both the PSTH and PSTHGLM code could be updated in the\n", - "# future to allow for variable bin sizes (e.g. in the vein of Baysian Adaptive Regression\n", - "# Splines by Wallstrom, Leibner and Kass). Alternatively, porting of BARS\n", - "# to Matlab may allow for it to be easily integrated into the nSTAT\n", - "# toolbox.\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=57, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"PSTHEstimation_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 4, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"delta = 0.001;\",\n", - " \"Tmax = 10;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=.2;\",\n", - " \"lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0\",\n", - " \"lambda = Covariate(time,lambdaData, '\\\\Lambda(t)','time','s','Hz',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"numRealizations = 20; % Use 20 realization so that lamba and raster plot are the same size\",\n", - " \"spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\",\n", - " \"spikeColl.plot; set(gca,'ytickLabel',[]);\",\n", - " \"lambda.plot;\",\n", - " \"figure;\",\n", - " \"binsize = .5; %500ms window\",\n", - " \"psth = spikeColl.psth(binsize);\",\n", - " \"psthGLM = spikeColl.psthGLM(binsize);\",\n", - " \"trueRate = lambda; %rate*delta = expected number of arrivals per bin\",\n", - " \"h1=trueRate.plot;\",\n", - " \"h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\",\n", - " \"legend off;\",\n", - " \"legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\",\n", - " \"psth_mean_hz = mean(psth.data);\",\n", - " \"psth_glm_mean_hz = mean(psthGLM.data);\",\n", - " \"lambda_mean_hz = mean(lambda.data);\",\n", - " \"parity = struct();\",\n", - " \"parity.psth_mean_hz = psth_mean_hz;\",\n", - " \"parity.psth_glm_mean_hz = psth_glm_mean_hz;\",\n", - " \"parity.lambda_mean_hz = lambda_mean_hz;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for PSTHEstimation.\")\n", - "\n", - "# Data-style workflow: trial-to-trial variability and PSTH-like estimates.\n", - "dt = 0.001\n", - "time = np.arange(0.0, 1.2, dt)\n", - "n_trials = 30\n", - "\n", - "rate = 5.0 + 8.0 * (time > 0.35) + 4.0 * np.sin(2.0 * np.pi * 2.0 * time)\n", - "rate = np.clip(rate, 0.2, None)\n", - "\n", - "trial_matrix = np.zeros((n_trials, time.size), dtype=float)\n", - "for k in range(n_trials):\n", - " jitter = 0.6 + 0.8 * rng.random()\n", - " p = np.clip(rate * jitter * dt, 0.0, 0.6)\n", - " trial_matrix[k, :] = rng.binomial(1, p)\n", - "\n", - "psth = trial_matrix.mean(axis=0) / dt\n", - "sem = trial_matrix.std(axis=0, ddof=1) / np.sqrt(n_trials) / dt\n", - "\n", - "rates, prob_mat, sig_mat = DecodingAlgorithms.compute_spike_rate_cis(trial_matrix)\n", - "\n", - "fig, axes = plt.subplots(3, 1, figsize=(9, 7), sharex=False)\n", - "for k in range(min(18, n_trials)):\n", - " t_spk = time[trial_matrix[k] > 0]\n", - " axes[0].vlines(t_spk, k + 0.6, k + 1.4, linewidth=0.5)\n", - "axes[0].set_title(f\"{TOPIC}: trial raster\")\n", - "axes[0].set_ylabel(\"trial\")\n", - "\n", - "axes[1].plot(time, psth, color=\"tab:blue\", linewidth=1.2)\n", - "axes[1].fill_between(time, psth - sem, psth + sem, color=\"tab:blue\", alpha=0.2)\n", - "axes[1].set_ylabel(\"Hz\")\n", - "axes[1].set_title(\"PSTH mean +/- SEM\")\n", - "\n", - "im = axes[2].imshow(prob_mat, aspect=\"auto\", origin=\"lower\", cmap=\"viridis\")\n", - "axes[2].set_title(\"Trial-by-trial spike-rate p-values\")\n", - "axes[2].set_xlabel(\"trial\")\n", - "axes[2].set_ylabel(\"trial\")\n", - "fig.colorbar(im, ax=axes[2], fraction=0.03, pad=0.02)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "print(\"significant pair count\", int(sig_mat.sum()))\n", - "assert np.allclose(prob_mat, prob_mat.T, atol=1e-12)\n", - "assert np.all(np.diag(prob_mat) == 1.0)\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"psth_mean_hz\": float(np.mean(psth)),\n", - " \"significant_pairs\": float(np.sum(sig_mat)),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"psth_mean_hz\": (0.1, 50.0),\n", - " \"significant_pairs\": (0.0, float(sig_mat.size)),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "data", - "run_group": "full", - "section_count": 4, - "source_helpfile": "PSTHEstimation.m", - "topic": "PSTHEstimation" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/SignalObjExamples.ipynb b/notebooks/helpfiles/SignalObjExamples.ipynb deleted file mode 100644 index 28db2fd8..00000000 --- a/notebooks/helpfiles/SignalObjExamples.ipynb +++ /dev/null @@ -1,860 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "9dc5c850", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/15 for SignalObjExamples: Using the SignalObj Class\n", - "\n", - "# % Using the SignalObj Class\n", - "# In this file we will give several examples of how the SignalObj can be\n", - "# used. A description of all of the properties of SignalObj can be found\n", - "# at: \n", - "#\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: SignalObjExamples\n", - "# Execution group: smoke\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/SignalObjExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"SignalObjExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"SignalObjExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"SignalObjExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"SignalObjExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"SignalObjExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 21\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d84ae75b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/15 for SignalObjExamples: Example 1: Defining and Plotting Signals\n", - "\n", - "# % Example 1: Defining and Plotting Signals\n", - "# Define a two dimensional SignalObj, $s$, representing two voltage signals that were\n", - "# $v1$ and $v2$ aquired simultaneously at 100Hz. Another SignalObj, $s1$ ,\n", - "# is created from just $v1$. Both signals are plotted.\n", - "# MATLAB: close all;\n", - "# MATLAB: sampleRate=100; t=0:1/sampleRate:10; freq=2;\n", - "# MATLAB: v1=sin(2*pi*freq*t); v2=sin(v1.^2); v=[v1;v2];\n", - "# MATLAB: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", - "# MATLAB: s1=SignalObj(t,v1,'Voltage','time','s','V',{'v1'});\n", - "# MATLAB: subplot(2,1,1); s.plot;\n", - "# MATLAB: subplot(2,1,2); s1.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: subplot(2,1,1); s.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=16, matlab_snippet=\"subplot(2,1,1); s.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 2, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1fb39741", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/15 for SignalObjExamples: Section\n", - "\n", - "# %\n", - "# Note how the legend show the appropriate labels. If the dataLabels had\n", - "# not been set, the legend would not appear.\n", - "#\n", - "# Instead of defining a new SignalObj, $s1$, the $v2$ data in $s$ can be\n", - "# masked away and then the plot will only show the data of interest. It is\n", - "# important to note that setMask is used to set which signals should remain\n", - "# visible. Also note that when a data is masked, converting the SignalObj\n", - "# to a Matrix only returns the visible data. A new SignalObj can be\n", - "# created from the orignal SignalObj which only contains the data of interest.\n", - "# Lastly, the all labeled components can be accessed independently via the\n", - "# vars subfield.\n", - "#\n", - "# MATLAB: subplot(2,1,1); s.setMask({'v1'}); s.plot; s.resetMask;\n", - "# MATLAB: subplot(2,1,2); s.setMask({'v2'}); s.plot; size(s.dataToMatrix)\n", - "# MATLAB: s.resetMask;\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d145c440", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/15 for SignalObjExamples: Section\n", - "\n", - "# %\n", - "# _Note about repeated dataLabels_\n", - "# It is possible to use SignalObj's to store different realizations of the\n", - "# same physical signal. For example, independent measurements of\n", - "# $v1$ at two distinct experiments.\n", - "# MATLAB: s=SignalObj(t,[v1; v1; v2] ,'Voltage','time','s','V',{'v1','v1','v2'});\n", - "# MATLAB: s.getSubSignal({'v1'}); %returns a SignalObj with both realizations of v1\n", - "# MATLAB: figure\n", - "# MATLAB: s.getSubSignal({'v1'}).plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=44, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 4, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "03fee5ef", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/15 for SignalObjExamples: Example 2: Changing Signal Properties\n", - "\n", - "# % Example 2: Changing Signal Properties\n", - "# MATLAB: figure\n", - "# MATLAB: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", - "# MATLAB: subplot(2,1,1); s.plot;\n", - "# MATLAB: subplot(2,1,2); s.setXlabel('distance'); s.setXUnits('cm'); s.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=48, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 5, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1de4739f", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/15 for SignalObjExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: figure\n", - "# MATLAB: subplot(2,1,1); s.setDataLabels({'r1','r2'}); s.setYLabel('Temperature'); s.setYUnits('C'); s.plot;\n", - "# MATLAB: subplot(2,1,2); s.setMaxTime(14); s.setMinTime(-2); s.plot;\n", - "#\n", - "# MATLAB: s.setName('testName'); %should work since we are using a method\n", - "# MATLAB: if(strcmp(s.name,'testName'))\n", - "# MATLAB: fprintf('Name successfully set \\n');\n", - "# MATLAB: else\n", - "# MATLAB: fprintf('Could not set name \\n');\n", - "# MATLAB: end\n", - "# s.name = 'testName'; %returns an error because the field is private;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=54, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 6, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 6\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c2690c49", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 7/15 for SignalObjExamples: Section\n", - "\n", - "# %\n", - "# setMaxTime and setMinTime can be given a second parameter, holdVals, that\n", - "# determines whether the endpoint values are kept or set to zero if the\n", - "# times being set are outside the original window of the data.\n", - "#\n", - "# Plotting properties for individual components of the data can be set via\n", - "# the when plotting or by call the setPlotProps method.\n", - "#\n", - "# MATLAB: figure\n", - "# MATLAB: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", - "# MATLAB: subplot(2,1,1); s.plot('v1',{{' ''k'' '}});\n", - "# MATLAB: subplot(2,1,2); s.plot('all',{{' ''k'' '},{' ''-.g'' '}});\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=74, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 7, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 7\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "058d7bdb", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 8/15 for SignalObjExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: figure\n", - "# MATLAB: subplot(2,1,1); s.plot({'v1','v2'});\n", - "# MATLAB: subplot(2,1,2); s.plot({'v1','v2'},{{' ''k'' '},{' ''-.g'' '}});\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=8, matlab_line_number=80, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 8, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 8\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "69449330", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 9/15 for SignalObjExamples: Example 3: Resampling and Windowing SignalObjs\n", - "\n", - "# % Example 3: Resampling and Windowing SignalObjs\n", - "# MATLAB: figure\n", - "# MATLAB: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", - "# MATLAB: s1=s.resample(.1*sampleRate);\n", - "# MATLAB: subplot(2,1,1); s.plot;\n", - "# MATLAB: subplot(2,1,2); s1.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=85, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_06.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=7 + 9, title=f\"{TOPIC} Figure 007\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 9\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5edd8a46", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 10/15 for SignalObjExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: figure\n", - "# MATLAB: subplot(2,1,1); s.getSigInTimeWindow(-2,3).plot;\n", - "# MATLAB: subplot(2,1,2); s.plot;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=10, matlab_line_number=92, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_07.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=8 + 10, title=f\"{TOPIC} Figure 008\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 10\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "53a12541", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 11/15 for SignalObjExamples: Example 4: SignalObj Mathematical Operations\n", - "\n", - "# % Example 4: SignalObj Mathematical Operations\n", - "# MATLAB: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", - "# MATLAB: figure\n", - "# MATLAB: s2=mean(s); %mean of each dimension;\n", - "# MATLAB: s5=s-s2; %zero mean version of s;\n", - "# MATLAB: s5.plot;\n", - "#\n", - "# MATLAB: figure\n", - "# MATLAB: s2=mean(s,2); %mean of s across its dimensions;\n", - "# MATLAB: s2.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=97, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_08.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=9 + 11, title=f\"{TOPIC} Figure 009\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=102, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_09.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=10 + 11, title=f\"{TOPIC} Figure 010\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 11\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6b1e39ab", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 12/15 for SignalObjExamples: Section\n", - "\n", - "# %\n", - "# SignalObj's can be added, subtracted, and multiplied.\\\n", - "# MATLAB: figure\n", - "# MATLAB: s4=2*s+s5;\n", - "# MATLAB: s4.plot;\n", - "#\n", - "# MATLAB: figure\n", - "# MATLAB: subplot(3,1,1);\n", - "# MATLAB: s.integral.plot;\n", - "# MATLAB: subplot(3,1,2);\n", - "# MATLAB: s.derivative.plot;\n", - "# MATLAB: subplot(3,1,3);\n", - "# MATLAB: s6=s.integral.derivative-s; %should equal zero;\n", - "# MATLAB: s6.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=12, matlab_line_number=108, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_10.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=11 + 12, title=f\"{TOPIC} Figure 011\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=12, matlab_line_number=112, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_11.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=12 + 12, title=f\"{TOPIC} Figure 012\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 12\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5dbbc653", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 13/15 for SignalObjExamples: Example 5: Spectra\n", - "\n", - "# % Example 5: Spectra\n", - "# MATLAB: s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\n", - "# MATLAB: figure;\n", - "# MATLAB: s.MTMspectrum;\n", - "#\n", - "# MATLAB: figure\n", - "# MATLAB: s.periodogram;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=13, matlab_line_number=123, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_12.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=13 + 13, title=f\"{TOPIC} Figure 013\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure\n", - "fig = FIGURE_TRACKER.new_figure(section_index=13, matlab_line_number=126, matlab_snippet=\"figure\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_13.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=14 + 13, title=f\"{TOPIC} Figure 014\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 13\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "38fd9abe", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 14/15 for SignalObjExamples: Example 6: View signal variability\n", - "\n", - "# % Example 6: View signal variability\n", - "# We can look at the variability of signals with regards to their labels or\n", - "# or irrespective of their labels. Lets create a SignalObj that has several\n", - "# components, and some noise. We mislabel two signals to add alot of\n", - "# variability for illustration\n", - "# MATLAB: sampleRate=5000; t=0:1/sampleRate:1; t=t'; freq=2;\n", - "# MATLAB: v1=sin(2*pi*freq*t); v2=sin(v1.^2);\n", - "# MATLAB: noise=.1*randn(length(t),6); %gaussian random noise\n", - "# MATLAB: data= [v1 v2 v2 v1 v2 v1] + noise;\n", - "# MATLAB: s=SignalObj(t,data,'Voltage','time','s','V',{'v1','v2','v2','v1','v1','v2'});\n", - "# MATLAB: figure;\n", - "# MATLAB: subplot(2,1,1); s.plot;\n", - "# MATLAB: subplot(2,1,2); s.plotAllVariability; %disregards labels;\n", - "# MATLAB: s.plotVariability; %creates two figures, one for 'v1' and one for 'v2'\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=14, matlab_line_number=139, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_14.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=15 + 14, title=f\"{TOPIC} Figure 015\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 14\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6521b861", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 15/15 for SignalObjExamples: Section\n", - "\n", - "# %\n", - "# sObj.plotAllVariability assumes that all the data can be considered together.\n", - "# It also allows more custimization of the plotting properties.\n", - "# Example we can specify a different faceColor by passing the color in the\n", - "# same format as plot. Assymetric confidence intervals can be specified. If\n", - "# the CIs are single numbers, they specify the multiple of the standard\n", - "# deviations to use (default is 1). If they are the same length as the\n", - "# SignalObj, then it specifies the actual values above and/or below the mean\n", - "# at each point in time. If ciLower is not specifed, it is assumed to equal\n", - "# ciUpper. For convinience the inputs to plotAllVariability are:\n", - "# s.plotAllVariability(sObj,faceColor,linewidth,ciUpper,ciLower)\n", - "# MATLAB: figure;\n", - "# blue color for CI patch;\n", - "# MATLAB: subplot(3,1,1); s.plotAllVariability('b');\n", - "# green color and lineWidth=2;\n", - "# MATLAB: subplot(3,1,2); s.plotAllVariability('g',2);\n", - "# cyan, lineWidth=3, 2*std for top CI, and 1*std for bottom CI\n", - "# MATLAB: subplot(3,1,3); s.plotAllVariability('c',3,2,1);\n", - "#\n", - "# Parity contract scalars for MATLAB/Python verification.\n", - "# MATLAB: parity = struct();\n", - "# MATLAB: parity.sample_rate_hz = sampleRate;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=15, matlab_line_number=155, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_15.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=16 + 15, title=f\"{TOPIC} Figure 016\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=15, matlab_line_number=144, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_16.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=17 + 15, title=f\"{TOPIC} Figure 017\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=15, matlab_line_number=144, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_17.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=18 + 15, title=f\"{TOPIC} Figure 018\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=15, matlab_line_number=144, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_18.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=19 + 15, title=f\"{TOPIC} Figure 019\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=15, matlab_line_number=144, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_19.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=20 + 15, title=f\"{TOPIC} Figure 020\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=15, matlab_line_number=144, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"SignalObjExamples_20.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=21 + 15, title=f\"{TOPIC} Figure 021\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"sampleRate=100; t=0:1/sampleRate:10; freq=2;\",\n", - " \"v1=sin(2*pi*freq*t); v2=sin(v1.^2); v=[v1;v2];\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"s1=SignalObj(t,v1,'Voltage','time','s','V',{'v1'});\",\n", - " \"subplot(2,1,1); s.plot;\",\n", - " \"subplot(2,1,2); s1.plot;\",\n", - " \"subplot(2,1,1); s.setMask({'v1'}); s.plot; s.resetMask;\",\n", - " \"subplot(2,1,2); s.setMask({'v2'}); s.plot; size(s.dataToMatrix)\",\n", - " \"s.resetMask;\",\n", - " \"s=SignalObj(t,[v1; v1; v2] ,'Voltage','time','s','V',{'v1','v1','v2'});\",\n", - " \"s.getSubSignal({'v1'}); %returns a SignalObj with both realizations of v1\",\n", - " \"figure\",\n", - " \"s.getSubSignal({'v1'}).plot;\",\n", - " \"figure\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"subplot(2,1,1); s.plot;\",\n", - " \"subplot(2,1,2); s.setXlabel('distance'); s.setXUnits('cm'); s.plot;\",\n", - " \"figure\",\n", - " \"subplot(2,1,1); s.setDataLabels({'r1','r2'}); s.setYLabel('Temperature'); s.setYUnits('C'); s.plot;\",\n", - " \"subplot(2,1,2); s.setMaxTime(14); s.setMinTime(-2); s.plot;\",\n", - " \"s.setName('testName'); %should work since we are using a method\",\n", - " \"if(strcmp(s.name,'testName'))\",\n", - " \"fprintf('Name successfully set \\\\n');\",\n", - " \"else\",\n", - " \"fprintf('Could not set name \\\\n');\",\n", - " \"end\",\n", - " \"figure\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"subplot(2,1,1); s.plot('v1',{{' ''k'' '}});\",\n", - " \"subplot(2,1,2); s.plot('all',{{' ''k'' '},{' ''-.g'' '}});\",\n", - " \"figure\",\n", - " \"subplot(2,1,1); s.plot({'v1','v2'});\",\n", - " \"subplot(2,1,2); s.plot({'v1','v2'},{{' ''k'' '},{' ''-.g'' '}});\",\n", - " \"figure\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"s1=s.resample(.1*sampleRate);\",\n", - " \"subplot(2,1,1); s.plot;\",\n", - " \"subplot(2,1,2); s1.plot;\",\n", - " \"figure\",\n", - " \"subplot(2,1,1); s.getSigInTimeWindow(-2,3).plot;\",\n", - " \"subplot(2,1,2); s.plot;\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"figure\",\n", - " \"s2=mean(s); %mean of each dimension;\",\n", - " \"s5=s-s2; %zero mean version of s;\",\n", - " \"s5.plot;\",\n", - " \"figure\",\n", - " \"s2=mean(s,2); %mean of s across its dimensions;\",\n", - " \"s2.plot;\",\n", - " \"figure\",\n", - " \"s4=2*s+s5;\",\n", - " \"s4.plot;\",\n", - " \"figure\",\n", - " \"subplot(3,1,1);\",\n", - " \"s.integral.plot;\",\n", - " \"subplot(3,1,2);\",\n", - " \"s.derivative.plot;\",\n", - " \"subplot(3,1,3);\",\n", - " \"s6=s.integral.derivative-s; %should equal zero;\",\n", - " \"s6.plot;\",\n", - " \"s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'});\",\n", - " \"figure;\",\n", - " \"s.MTMspectrum;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for SignalObjExamples.\")\n", - "\n", - "# SignalObjExamples: fixture-backed SignalObj parity checks.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "from nstat.compat.matlab import SignalObj\n", - "\n", - "m = loadmat(Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat\", squeeze_me=True)\n", - "t = np.asarray(m[\"time_sig\"], dtype=float).reshape(-1); v1 = np.asarray(m[\"v1_sig\"], dtype=float).reshape(-1); v2 = np.asarray(m[\"v2_sig\"], dtype=float).reshape(-1)\n", - "matlab_line(\"figure\")\n", - "matlab_line(\"s.periodogram;\")\n", - "matlab_line(\"sampleRate=5000; t=0:1/sampleRate:1; t=t'; freq=2;\")\n", - "matlab_line(\"v1=sin(2*pi*freq*t); v2=sin(v1.^2);\")\n", - "matlab_line(\"noise=.1*randn(length(t),6);\")\n", - "matlab_line(\"data= [v1 v2 v2 v1 v2 v1] + noise;\")\n", - "matlab_line(\"s=SignalObj(t,data,'Voltage','time','s','V',{'v1','v2','v2','v1','v1','v2'});\")\n", - "matlab_line(\"figure;\")\n", - "matlab_line(\"subplot(2,1,1); s.plot;\")\n", - "matlab_line(\"subplot(2,1,2); s.plotAllVariability;\")\n", - "matlab_line(\"s.plotVariability;\")\n", - "matlab_line(\"figure;\")\n", - "matlab_line(\"subplot(3,1,1); s.plotAllVariability('b');\")\n", - "matlab_line(\"subplot(3,1,2); s.plotAllVariability('g',2);\")\n", - "matlab_line(\"subplot(3,1,3); s.plotAllVariability('c',3,2,1);\")\n", - "matlab_line(\"parity = struct();\")\n", - "matlab_line(\"parity.sample_rate_hz = sampleRate;\")\n", - "s = SignalObj(time=t, data=np.column_stack([v1, v2]), name=\"Voltage\", units=\"V\").setDataLabels([\"v1\", \"v2\"]).setXlabel(\"time\").setXUnits(\"s\").setYLabel(\"Voltage\").setYUnits(\"V\")\n", - "s.setMask([\"v1\"]); masked_cols = float(len(s.findIndFromDataMask())); s.resetMask()\n", - "s_resampled = s.resample(float(np.asarray(m[\"resample_hz_sig\"]).reshape(-1)[0])); s_win = s.getSigInTimeWindow(float(np.asarray(m[\"window_t0_sig\"]).reshape(-1)[0]), float(np.asarray(m[\"window_t1_sig\"]).reshape(-1)[0]))\n", - "f_per, p_per = s.periodogram(); expected_peak = int(np.asarray(m[\"periodogram_peak_idx_sig\"], dtype=int).reshape(-1)[0]); peak_idx = int(np.argmax(p_per))\n", - "s.setName(\"testName\")\n", - "s_der = s.derivative()\n", - "s_int = s.integral()\n", - "s_sub = s.getSubSignal([0])\n", - "s_repeat = SignalObj(time=t, data=np.column_stack([v1, v1, v2]), name=\"Voltage\", units=\"V\").setDataLabels([\"v1\", \"v1\", \"v2\"])\n", - "s_repeat_v1 = s_repeat.getSubSignal([0, 1])\n", - "\n", - "fig, ax = plt.subplots(2, 2, figsize=(10, 6))\n", - "plt.sca(ax[0, 0]); s.plot(); ax[0, 0].set_title(\"SignalObj.plot\")\n", - "plt.sca(ax[0, 1]); s_resampled.plot(); ax[0, 1].set_title(\"resample\")\n", - "plt.sca(ax[1, 0]); s_win.plot(); ax[1, 0].set_title(\"time window\")\n", - "ax[1, 1].plot(f_per, p_per, \"k\", linewidth=1.0); ax[1, 1].set_title(\"periodogram\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "assert masked_cols == float(np.asarray(m[\"masked_cols_sig\"]).reshape(-1)[0])\n", - "assert peak_idx == expected_peak\n", - "assert s.getNumSamples() == int(np.asarray(m[\"n_samples_sig\"], dtype=int).reshape(-1)[0])\n", - "assert s_resampled.getNumSamples() == int(np.asarray(m[\"resampled_n_samples_sig\"], dtype=int).reshape(-1)[0])\n", - "assert s_win.getNumSamples() == int(np.asarray(m[\"window_n_samples_sig\"], dtype=int).reshape(-1)[0])\n", - "assert s_der.getNumSamples() == s.getNumSamples()\n", - "assert s_int.shape[0] == s.getNumSamples()\n", - "assert s_sub.getNumSignals() == 1\n", - "assert s_repeat_v1.getNumSignals() == 2\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"masked_cols\": float(masked_cols),\n", - " \"periodogram_peak_idx\": float(peak_idx),\n", - " \"resampled_samples\": float(s_resampled.getNumSamples()),\n", - " \"window_samples\": float(s_win.getNumSamples()),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"masked_cols\": (1.0, 1.0),\n", - " \"periodogram_peak_idx\": (0.0, 50000.0),\n", - " \"resampled_samples\": (10.0, 2000.0),\n", - " \"window_samples\": (10.0, 5000.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "smoke", - "section_count": 15, - "source_helpfile": "SignalObjExamples.m", - "topic": "SignalObjExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/StimulusDecode2D.ipynb b/notebooks/helpfiles/StimulusDecode2D.ipynb deleted file mode 100644 index e0e9d5f4..00000000 --- a/notebooks/helpfiles/StimulusDecode2D.ipynb +++ /dev/null @@ -1,489 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "f568a078", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/4 for StimulusDecode2D: 2-D Stimulus Decode\n", - "\n", - "# % 2-D Stimulus Decode\n", - "# Here we simulate hippocampal place cell receptive fields and their firing\n", - "# during a 2-d spatial task. We then use the ensemble firing activity to\n", - "# estimate the path based on the only the point process observations\n", - "#\n", - "# MATLAB: delta = 0.001;\n", - "# MATLAB: Tmax = 1;\n", - "# MATLAB: time = 0:delta:Tmax;\n", - "# MATLAB: px = zeros(1,length(time));\n", - "# MATLAB: py = zeros(1,length(time));\n", - "# MATLAB: Q=.01;\n", - "# MATLAB: r = Q.*randn(2,length(time));\n", - "# MATLAB: vx = cumsum(r(1,:))';\n", - "# MATLAB: vy = cumsum(r(2,:))';\n", - "#\n", - "# MATLAB: velSig = SignalObj(time, [vx, vy],'vel');\n", - "# MATLAB: posSig = velSig.integral;\n", - "# MATLAB: posData = posSig.data;\n", - "# MATLAB: px = posData(:,1);\n", - "# MATLAB: py = posData(:,2);\n", - "# N=100; A=1; B=ones(1,N)./N;\n", - "# px = filtfilt(B,A,px);\n", - "# py = filtfilt(B,A,py);\n", - "# MATLAB: figure;\n", - "# MATLAB: plot(px,py);\n", - "# MATLAB: title('Simulated X-Y trajectory');\n", - "# MATLAB: xlabel('x'); ylabel('y');\n", - "#\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: StimulusDecode2D\n", - "# Execution group: full\n", - "# Workflow family: decoding_2d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/StimulusDecode2D.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"StimulusDecode2D\"\n", - "FAMILY = \"decoding_2d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"StimulusDecode2D: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"StimulusDecode2D: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"StimulusDecode2D: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"StimulusDecode2D: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 7\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=1, matlab_line_number=24, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"StimulusDecode2D.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 1, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "69e2070d", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/4 for StimulusDecode2D: Generate random receptive fields to simulate different neurons\n", - "\n", - "# % Generate random receptive fields to simulate different neurons\n", - "# MATLAB: clear lambdaCIF lambda tempSpikeColl n spikeColl\n", - "# MATLAB: numRealizations=80;\n", - "#\n", - "# MATLAB: coeffs = -abs(1*randn(numRealizations,5));\n", - "# MATLAB: coeffs = [-2*abs(randn(numRealizations,1)) coeffs];\n", - "# MATLAB: dataMat = [ones(length(time),1) px py px.^2 py.^2 px.*py];\n", - "# MATLAB: for i=1:numRealizations\n", - "# MATLAB: tempData = exp(dataMat*coeffs(i,:)');\n", - "# MATLAB: lambdaData = tempData./(1+tempData);\n", - "# MATLAB: lambda{i}=Covariate(time,lambdaData./delta, '\\Lambda(t)','time','s','Hz',{strcat('\\lambda_{',num2str(i),'}')},{{' ''b'', ''LineWidth'' ,2'}});\n", - "#\n", - "# MATLAB: tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);\n", - "# MATLAB: n{i} = tempSpikeColl{i}.getNST(1);\n", - "# MATLAB: n{i}.setName(num2str(i));\n", - "#\n", - "# MATLAB: try\n", - "# MATLAB: lambdaCIF{i} = CIF(coeffs(i,:),{'1','x','y','x^2','y^2','x*y'},{'x','y'},'binomial');\n", - "# MATLAB: catch ME_sym\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: warning('StimulusDecode2D:SymbolicCIFFallback', ...\n", - "# MATLAB: ['CIF symbolic setup failed (' ME_sym.identifier '). Decoder will use linear fallback.']);\n", - "# MATLAB: end\n", - "# MATLAB: lambdaCIF{i} = [];\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# View the different neuron conditional intensity functions\n", - "# MATLAB: figure;\n", - "# MATLAB: for i=1:length(lambda)\n", - "# MATLAB: lambda{i}.plot;\n", - "# MATLAB: end\n", - "# MATLAB: legend off;\n", - "#\n", - "# Visualize Simulated Receptive Fields\n", - "# MATLAB: clear placeField;\n", - "# MATLAB: [X,Y]=meshgrid(-2:.1:2,-2:.1:2);\n", - "# MATLAB: figure;\n", - "#\n", - "# MATLAB: for i=1:numRealizations\n", - "# MATLAB: tempData = coeffs(i,1) + coeffs(i,2)*X + coeffs(i,3)*Y +coeffs(i,4)*X.^2 + coeffs(i,5)*Y.^2 + coeffs(i,6).*X.*Y;\n", - "# MATLAB: placeField{i} = exp(tempData)./(1+exp(tempData))./delta; %rate based on logistic link function\n", - "#\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: fact=factor(numRealizations);\n", - "#\n", - "# MATLAB: for i=1:numRealizations\n", - "# MATLAB: if(length(fact)==1)\n", - "# MATLAB: subplot(1,numRealizations,i);\n", - "# MATLAB: elseif(length(fact)==2)\n", - "# MATLAB: subplot(fact(1),fact(2),i);\n", - "# MATLAB: elseif(length(fact)==3)\n", - "# MATLAB: subplot(fact(1)*fact(2),fact(3),i);\n", - "# MATLAB: end\n", - "# MATLAB: pcolor(X,Y,placeField{i}), shading interp\n", - "# MATLAB: axis square;\n", - "# MATLAB: set(gca,'xtick',[],'ytick',[]);\n", - "#\n", - "# MATLAB: end\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=59, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"StimulusDecode2D_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 2, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=68, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"StimulusDecode2D_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 2, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "57069e4d", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/4 for StimulusDecode2D: Decode the x-y trajectory\n", - "\n", - "# % Decode the x-y trajectory\n", - "#\n", - "# MATLAB: spikeColl = nstColl(n);\n", - "# MATLAB: spikeColl.resample(1/delta);\n", - "# MATLAB: dN = spikeColl.dataToMatrix;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "42032891", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/4 for StimulusDecode2D: Section\n", - "\n", - "# %\n", - "# MATLAB: vx=var(px(2:end)-px(1:end-1));\n", - "# MATLAB: vy=var(py(2:end)-py(1:end-1));\n", - "# MATLAB: Q=[vx 0;0 vy];\n", - "# MATLAB: Px0=.1*eye(2,2); A=1*eye(2,2);\n", - "# MATLAB: decode_method = 'PPDecodeFilter';\n", - "# MATLAB: try\n", - "# MATLAB: [x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\n", - "# MATLAB: catch ME_decode\n", - "# MATLAB: warning('StimulusDecode2D:SymbolicDecodeFallback', ...\n", - "# MATLAB: ['PPDecodeFilter failed (' ME_decode.identifier '). Falling back to PPDecodeFilterLinear.']);\n", - "# MATLAB: decode_method = 'PPDecodeFilterLinear';\n", - "# MATLAB: mu_linear = coeffs(:,1);\n", - "# MATLAB: beta_linear = coeffs(:,2:3)';\n", - "# MATLAB: [x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN', mu_linear, beta_linear, 'binomial', delta);\n", - "# MATLAB: end\n", - "# MATLAB: nCommon = min(length(px),size(x_u,2));\n", - "# MATLAB: decode_rmse = sqrt(mean((x_u(1,1:nCommon)'-px(1:nCommon)).^2 + (x_u(2,1:nCommon)'-py(1:nCommon)).^2));\n", - "# MATLAB: num_cells = numRealizations;\n", - "# MATLAB: figure;\n", - "# MATLAB: plot(x_u(1,:),x_u(2,:),'b',px,py,'k')\n", - "# MATLAB: legend('predicted path','actual path');\n", - "#\n", - "# Parity contract scalars for MATLAB/Python verification.\n", - "# MATLAB: parity = struct();\n", - "# MATLAB: parity.num_cells = num_cells;\n", - "# MATLAB: parity.decode_rmse = decode_rmse;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=116, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"StimulusDecode2D_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 4, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=97, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"StimulusDecode2D_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 4, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=97, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"StimulusDecode2D_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 4, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=97, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"StimulusDecode2D_06.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=7 + 4, title=f\"{TOPIC} Figure 007\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"delta = 0.001;\",\n", - " \"Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"px = zeros(1,length(time));\",\n", - " \"py = zeros(1,length(time));\",\n", - " \"Q=.01;\",\n", - " \"r = Q.*randn(2,length(time));\",\n", - " \"vx = cumsum(r(1,:))';\",\n", - " \"vy = cumsum(r(2,:))';\",\n", - " \"velSig = SignalObj(time, [vx, vy],'vel');\",\n", - " \"posSig = velSig.integral;\",\n", - " \"posData = posSig.data;\",\n", - " \"px = posData(:,1);\",\n", - " \"py = posData(:,2);\",\n", - " \"figure;\",\n", - " \"plot(px,py);\",\n", - " \"title('Simulated X-Y trajectory');\",\n", - " \"xlabel('x'); ylabel('y');\",\n", - " \"clear lambdaCIF lambda tempSpikeColl n spikeColl\",\n", - " \"numRealizations=80;\",\n", - " \"coeffs = -abs(1*randn(numRealizations,5));\",\n", - " \"coeffs = [-2*abs(randn(numRealizations,1)) coeffs];\",\n", - " \"dataMat = [ones(length(time),1) px py px.^2 py.^2 px.*py];\",\n", - " \"for i=1:numRealizations\",\n", - " \"tempData = exp(dataMat*coeffs(i,:)');\",\n", - " \"lambdaData = tempData./(1+tempData);\",\n", - " \"lambda{i}=Covariate(time,lambdaData./delta, '\\\\Lambda(t)','time','s','Hz',{strcat('\\\\lambda_{',num2str(i),'}')},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);\",\n", - " \"n{i} = tempSpikeColl{i}.getNST(1);\",\n", - " \"n{i}.setName(num2str(i));\",\n", - " \"try\",\n", - " \"lambdaCIF{i} = CIF(coeffs(i,:),{'1','x','y','x^2','y^2','x*y'},{'x','y'},'binomial');\",\n", - " \"catch ME_sym\",\n", - " \"if(i==1)\",\n", - " \"warning('StimulusDecode2D:SymbolicCIFFallback', ...\",\n", - " \"['CIF symbolic setup failed (' ME_sym.identifier '). Decoder will use linear fallback.']);\",\n", - " \"end\",\n", - " \"lambdaCIF{i} = [];\",\n", - " \"end\",\n", - " \"end\",\n", - " \"figure;\",\n", - " \"for i=1:length(lambda)\",\n", - " \"lambda{i}.plot;\",\n", - " \"end\",\n", - " \"legend off;\",\n", - " \"clear placeField;\",\n", - " \"[X,Y]=meshgrid(-2:.1:2,-2:.1:2);\",\n", - " \"figure;\",\n", - " \"for i=1:numRealizations\",\n", - " \"tempData = coeffs(i,1) + coeffs(i,2)*X + coeffs(i,3)*Y +coeffs(i,4)*X.^2 + coeffs(i,5)*Y.^2 + coeffs(i,6).*X.*Y;\",\n", - " \"placeField{i} = exp(tempData)./(1+exp(tempData))./delta; %rate based on logistic link function\",\n", - " \"end\",\n", - " \"fact=factor(numRealizations);\",\n", - " \"for i=1:numRealizations\",\n", - " \"if(length(fact)==1)\",\n", - " \"subplot(1,numRealizations,i);\",\n", - " \"elseif(length(fact)==2)\",\n", - " \"subplot(fact(1),fact(2),i);\",\n", - " \"elseif(length(fact)==3)\",\n", - " \"subplot(fact(1)*fact(2),fact(3),i);\",\n", - " \"end\",\n", - " \"pcolor(X,Y,placeField{i}), shading interp\",\n", - " \"axis square;\",\n", - " \"set(gca,'xtick',[],'ytick',[]);\",\n", - " \"end\",\n", - " \"spikeColl = nstColl(n);\",\n", - " \"spikeColl.resample(1/delta);\",\n", - " \"dN = spikeColl.dataToMatrix;\",\n", - " \"vx=var(px(2:end)-px(1:end-1));\",\n", - " \"vy=var(py(2:end)-py(1:end-1));\",\n", - " \"Q=[vx 0;0 vy];\",\n", - " \"Px0=.1*eye(2,2); A=1*eye(2,2);\",\n", - " \"decode_method = 'PPDecodeFilter';\",\n", - " \"try\",\n", - " \"[x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);\",\n", - " \"catch ME_decode\",\n", - " \"warning('StimulusDecode2D:SymbolicDecodeFallback', ...\",\n", - " \"['PPDecodeFilter failed (' ME_decode.identifier '). Falling back to PPDecodeFilterLinear.']);\",\n", - " \"decode_method = 'PPDecodeFilterLinear';\",\n", - " \"mu_linear = coeffs(:,1);\",\n", - " \"beta_linear = coeffs(:,2:3)';\",\n", - " \"[x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN', mu_linear, beta_linear, 'binomial', delta);\",\n", - " \"end\",\n", - " \"nCommon = min(length(px),size(x_u,2));\",\n", - " \"decode_rmse = sqrt(mean((x_u(1,1:nCommon)'-px(1:nCommon)).^2 + (x_u(2,1:nCommon)'-py(1:nCommon)).^2));\",\n", - " \"num_cells = numRealizations;\",\n", - " \"figure;\",\n", - " \"plot(x_u(1,:),x_u(2,:),'b',px,py,'k')\",\n", - " \"legend('predicted path','actual path');\",\n", - " \"parity = struct();\",\n", - " \"parity.num_cells = num_cells;\",\n", - " \"parity.decode_rmse = decode_rmse;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for StimulusDecode2D.\")\n", - "\n", - "# StimulusDecode2D: fixture-backed 2D trajectory decoding parity check.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/StimulusDecode2D_gold.mat\"\n", - "m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False)\n", - "states = np.asarray(m[\"states_sd\"], dtype=float); latent = np.asarray(m[\"latent_sd\"], dtype=int).reshape(-1)\n", - "tuning = np.asarray(m[\"tuning_sd\"], dtype=float); spike_counts = np.asarray(m[\"spike_counts_sd\"], dtype=float)\n", - "decoded_center = DecodingAlgorithms.decode_weighted_center(spike_counts=spike_counts, tuning_curves=tuning)\n", - "decoded = np.clip(np.rint(decoded_center), 0, states.shape[0] - 1).astype(int)\n", - "xy_true = np.asarray(m[\"xy_true_sd\"], dtype=float); xy_decoded = states[decoded]\n", - "rmse = float(np.sqrt(np.mean(np.sum((xy_decoded - xy_true) ** 2, axis=1))))\n", - "expected_center = np.asarray(m[\"decoded_center_sd\"], dtype=float).reshape(-1); expected_decoded = np.asarray(m[\"decoded_sd\"], dtype=int).reshape(-1); expected_rmse = float(np.asarray(m[\"rmse_sd\"], dtype=float).reshape(-1)[0])\n", - "center_err = float(np.max(np.abs(decoded_center - expected_center))); decoded_mismatch = float(np.count_nonzero(decoded != expected_decoded)); rmse_err = float(abs(rmse - expected_rmse))\n", - "assert center_err <= 1e-8 and decoded_mismatch == 0.0 and rmse_err <= 1e-10\n", - "\n", - "side = int(round(np.sqrt(states.shape[0]))); field_idx = 3\n", - "fig, axes = plt.subplots(1, 2, figsize=(9.5, 4.5))\n", - "axes[0].plot(xy_true[:, 0], xy_true[:, 1], label=\"true\", linewidth=1.2)\n", - "axes[0].plot(xy_decoded[:, 0], xy_decoded[:, 1], label=\"decoded\", linewidth=1.0)\n", - "axes[0].set_title(f\"{TOPIC}: decoded trajectory\"); axes[0].set_xlabel(\"x\"); axes[0].set_ylabel(\"y\"); axes[0].set_aspect(\"equal\", adjustable=\"box\"); axes[0].legend(loc=\"upper right\")\n", - "im = axes[1].imshow(tuning[field_idx].reshape(side, side), origin=\"lower\", extent=[0.0, 1.0, 0.0, 1.0], cmap=\"jet\", aspect=\"equal\")\n", - "axes[1].set_title(\"Example receptive field\"); axes[1].set_xlabel(\"x\"); axes[1].set_ylabel(\"y\"); fig.colorbar(im, ax=axes[1], fraction=0.04, pad=0.03)\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "CHECKPOINT_METRICS = {\"trajectory_rmse\": float(rmse), \"decoded_unique_states\": float(np.unique(decoded).size), \"decoded_center_max_abs_error\": center_err, \"decoded_mismatch_count\": decoded_mismatch}\n", - "CHECKPOINT_LIMITS = {\"trajectory_rmse\": (0.0, 1.5), \"decoded_unique_states\": (2.0, float(states.shape[0])), \"decoded_center_max_abs_error\": (0.0, 1e-8), \"decoded_mismatch_count\": (0.0, 0.0)}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "decoding_2d", - "run_group": "full", - "section_count": 4, - "source_helpfile": "StimulusDecode2D.m", - "topic": "StimulusDecode2D" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/TrialConfigExamples.ipynb b/notebooks/helpfiles/TrialConfigExamples.ipynb deleted file mode 100644 index 7faddcc7..00000000 --- a/notebooks/helpfiles/TrialConfigExamples.ipynb +++ /dev/null @@ -1,150 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "61889176", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/1 for TrialConfigExamples: TrialConfig Examples\n", - "\n", - "# % TrialConfig Examples\n", - "# tcObj=TrialConfig(covMask,sampleRate, history,minTime,maxTime)\n", - "# MATLAB: tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\n", - "# MATLAB: tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\n", - "# MATLAB: tcc = ConfigColl({tc1,tc2});\n", - "\n", - "# Python translation bootstrap + execution for single-section helpfile.\n", - "\n", - "# Topic: TrialConfigExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/TrialConfigExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"TrialConfigExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"TrialConfigExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"TrialConfigExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"TrialConfigExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"TrialConfigExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 0\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);\",\n", - " \"tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2);\",\n", - " \"tcc = ConfigColl({tc1,tc2});\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for TrialConfigExamples.\")\n", - "\n", - "# TrialConfigExamples: create and inspect trial configurations.\n", - "from nstat.compat.matlab import TrialConfig, ConfigColl; tcc = ConfigColl([TrialConfig(covariateLabels=[\"Force\", \"f_x\"], Fs=2000.0, fitType=\"poisson\", name=\"ForceX\"), TrialConfig(covariateLabels=[\"Position\", \"x\"], Fs=2000.0, fitType=\"poisson\", name=\"PositionX\")]); rates = np.array([cfg.getSampleRate() for cfg in tcc.getConfigs()], dtype=float); plt.figure(figsize=(7.6, 4.2)); plt.bar(tcc.getConfigNames(), rates, color=[\"tab:blue\", \"tab:orange\"]); plt.title(f\"{TOPIC}: TrialConfig summary\"); plt.tight_layout(); plt.show(); CHECKPOINT_METRICS = {\"num_configs\": float(len(tcc.getConfigs())), \"sample_rate_hz\": float(np.mean(rates))}; CHECKPOINT_LIMITS = {\"num_configs\": (2.0, 2.0), \"sample_rate_hz\": (2000.0, 2000.0)}\n", - "assert len(tcc.getConfigs()) == 2\n", - "assert tcc.getConfig(1).getSampleRate() == 2000.0\n", - "assert tcc.getConfig(\"PositionX\").getFitType() == \"poisson\"\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "full", - "section_count": 1, - "source_helpfile": "TrialConfigExamples.m", - "topic": "TrialConfigExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/TrialExamples.ipynb b/notebooks/helpfiles/TrialExamples.ipynb deleted file mode 100644 index 5db73c92..00000000 --- a/notebooks/helpfiles/TrialExamples.ipynb +++ /dev/null @@ -1,453 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "20e0d9b1", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/9 for TrialExamples: Trial Examples\n", - "\n", - "# % Trial Examples\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: TrialExamples\n", - "# Execution group: smoke\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/TrialExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"TrialExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"TrialExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"TrialExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"TrialExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"TrialExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 7\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3da8702e", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/9 for TrialExamples: Example 1: A simple data set\n", - "\n", - "# % Example 1: A simple data set\n", - "# MATLAB: close all; clear all;\n", - "# MATLAB: lengthTrial=1;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d8cf3e90", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/9 for TrialExamples: Section\n", - "\n", - "# %\n", - "# Create History windows of interest\n", - "# MATLAB: windowTimes = [0 .1 .2 .4];\n", - "# MATLAB: h=History(windowTimes);\n", - "# MATLAB: figure; h.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; h.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=13, matlab_snippet=\"figure; h.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"TrialExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 3, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d09865e6", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/9 for TrialExamples: Section\n", - "\n", - "# %\n", - "# Load Covariates\n", - "# MATLAB: load CovariateSample.mat; %load position and force covariates\n", - "# MATLAB: cc=CovColl({position,force});\n", - "# MATLAB: cc.setMaxTime(lengthTrial);\n", - "# MATLAB: figure; cc.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; cc.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=20, matlab_snippet=\"figure; cc.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"TrialExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 4, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "96096758", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/9 for TrialExamples: Section\n", - "\n", - "# %\n", - "# Create trial events\n", - "# MATLAB: eTimes = sort(rand(1,2)*lengthTrial);\n", - "# MATLAB: eLabels={'E_1','E_2'};\n", - "# MATLAB: e=Events(eTimes,eLabels); %use default eventColor 'r'\n", - "# MATLAB: figure; e.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; e.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=27, matlab_snippet=\"figure; e.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"TrialExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 5, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "96d60be7", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/9 for TrialExamples: Section\n", - "\n", - "# %\n", - "# Create neural Spike Train Data\n", - "# MATLAB: clear nst;\n", - "# MATLAB: for i=1:4\n", - "# MATLAB: spikeTimes = sort(rand(1,100))*lengthTrial;\n", - "# MATLAB: nst{i}=nspikeTrain(spikeTimes,'',.001);\n", - "# MATLAB: end\n", - "# MATLAB: spikeColl=nstColl(nst); %create a nstColl\n", - "# MATLAB: figure; spikeColl.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; spikeColl.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=37, matlab_snippet=\"figure; spikeColl.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"TrialExamples_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 6, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 6\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f0d6b527", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 7/9 for TrialExamples: Section\n", - "\n", - "# %\n", - "# Finally we have everything we need to create a Trial object.\n", - "#\n", - "# MATLAB: trial1=Trial(spikeColl, cc, e, h);\n", - "# MATLAB: figure; trial1.plot; % plot all the data;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; trial1.plot; % plot all the data;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=43, matlab_snippet=\"figure; trial1.plot; % plot all the data;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"TrialExamples_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 7, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 7\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "65f4ccbd", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 8/9 for TrialExamples: Section\n", - "\n", - "# %\n", - "# Mask out some of the data and plot the trial once again\n", - "# MATLAB: trial1.setCovMask({{'Position','x'},{'Force','f_x'}})\n", - "# MATLAB: figure; trial1.plot;\n", - "#\n", - "# MATLAB: trial1.getHistForNeurons([1:2]);\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; trial1.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=8, matlab_line_number=48, matlab_snippet=\"figure; trial1.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"TrialExamples_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 8, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 8\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "36d01e80", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 9/9 for TrialExamples: Example 2: Analyzing Trial Data\n", - "\n", - "# % Example 2: Analyzing Trial Data\n", - "# Examples of neural spike analysis using the\n", - "# \n", - "# or using standard methods\n", - "# \n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=51, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"TrialExamples_06.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=7 + 9, title=f\"{TOPIC} Figure 007\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all; clear all;\",\n", - " \"lengthTrial=1;\",\n", - " \"windowTimes = [0 .1 .2 .4];\",\n", - " \"h=History(windowTimes);\",\n", - " \"figure; h.plot;\",\n", - " \"load CovariateSample.mat; %load position and force covariates\",\n", - " \"cc=CovColl({position,force});\",\n", - " \"cc.setMaxTime(lengthTrial);\",\n", - " \"figure; cc.plot;\",\n", - " \"eTimes = sort(rand(1,2)*lengthTrial);\",\n", - " \"eLabels={'E_1','E_2'};\",\n", - " \"e=Events(eTimes,eLabels); %use default eventColor 'r'\",\n", - " \"figure; e.plot;\",\n", - " \"clear nst;\",\n", - " \"for i=1:4\",\n", - " \"spikeTimes = sort(rand(1,100))*lengthTrial;\",\n", - " \"nst{i}=nspikeTrain(spikeTimes,'',.001);\",\n", - " \"end\",\n", - " \"spikeColl=nstColl(nst); %create a nstColl\",\n", - " \"figure; spikeColl.plot;\",\n", - " \"trial1=Trial(spikeColl, cc, e, h);\",\n", - " \"figure; trial1.plot; % plot all the data;\",\n", - " \"trial1.setCovMask({{'Position','x'},{'Force','f_x'}})\",\n", - " \"figure; trial1.plot;\",\n", - " \"trial1.getHistForNeurons([1:2]);\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for TrialExamples.\")\n", - "\n", - "# TrialExamples: build a trial from spikes, covariates, events, and history.\n", - "from nstat.compat.matlab import Covariate, CovColl, Events, History, Trial, nspikeTrain, nstColl\n", - "\n", - "length_trial = 1.0; t = np.arange(0.0, length_trial + 0.001, 0.001); history = History(bin_edges_s=np.array([0.0, 0.1, 0.2, 0.4], dtype=float))\n", - "position = Covariate(time=t, data=np.column_stack([np.cos(2.0 * np.pi * t), np.sin(2.0 * np.pi * t)]), name=\"Position\", labels=[\"x\", \"y\"])\n", - "force = Covariate(time=t, data=np.column_stack([np.sin(2.0 * np.pi * 4.0 * t), np.cos(2.0 * np.pi * 4.0 * t)]), name=\"Force\", labels=[\"f_x\", \"f_y\"])\n", - "cc = CovColl([position, force]); cc.setMaxTime(length_trial); e = Events(times=np.sort(rng.random(2) * length_trial), labels=[\"E_1\", \"E_2\"])\n", - "trains = [nspikeTrain(spike_times=np.sort(rng.random(100) * length_trial), t_start=0.0, t_end=length_trial, name=f\"n{i+1}\") for i in range(4)]\n", - "spikeColl = nstColl(trains); trial1 = Trial(spikes=spikeColl, covariates=cc); trial1.setTrialEvents(e); trial1.setHistory(history)\n", - "\n", - "fig, axes = plt.subplots(2, 2, figsize=(10.0, 7.2))\n", - "plt.sca(axes[0, 0]); history.plot(); axes[0, 0].set_title(\"History windows\")\n", - "plt.sca(axes[0, 1]); cc.plot(); axes[0, 1].set_title(\"Covariates\")\n", - "plt.sca(axes[1, 0]); e.plot(); axes[1, 0].set_title(\"Events\")\n", - "plt.sca(axes[1, 1]); spikeColl.plot(); axes[1, 1].set_title(\"Spike raster\")\n", - "for ax in axes.ravel(): ax.set_xlabel(\"time [s]\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "trial1.setCovMask([\"Position\", \"Force\"]); hist_rows = trial1.getHistForNeurons([1, 2], binSize_s=0.01)\n", - "fig2 = plt.figure(figsize=(8.0, 3.8)); plt.imshow(hist_rows[0].T, aspect=\"auto\", origin=\"lower\", cmap=\"magma\"); plt.title(\"Neuron 1 history matrix\"); plt.tight_layout(); plt.show()\n", - "spikes = spikeColl.getNST(0); H = history.computeHistory(spikes.spike_times, t)\n", - "assert len(hist_rows) >= 1\n", - "assert hist_rows[0].shape[1] == history.getNumBins()\n", - "assert H.ndim == 2 and H.shape[1] == history.n_bins\n", - "assert spikes.spike_times.size > 5\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"history_bins\": float(history.getNumBins()),\n", - " \"hist_rows_neuron1\": float(hist_rows[0].shape[0] if hist_rows else 0.0),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"history_bins\": (3.0, 3.0),\n", - " \"hist_rows_neuron1\": (50.0, 2000.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "smoke", - "section_count": 9, - "source_helpfile": "TrialExamples.m", - "topic": "TrialExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/ValidationDataSet.ipynb b/notebooks/helpfiles/ValidationDataSet.ipynb deleted file mode 100644 index 4652b09c..00000000 --- a/notebooks/helpfiles/ValidationDataSet.ipynb +++ /dev/null @@ -1,651 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "b77fece9", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/11 for ValidationDataSet: Software Validation Data Set\n", - "\n", - "# % Software Validation Data Set\n", - "# The purpose of this example is to two important test cases of data to\n", - "# validate the Neural Spike Analysis Toolbox.\n", - "#\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: ValidationDataSet\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/ValidationDataSet.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"ValidationDataSet\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"ValidationDataSet: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"ValidationDataSet: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"ValidationDataSet: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"ValidationDataSet: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 13\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c9d197fb", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/11 for ValidationDataSet: Case #1: Constant Rate Poisson Process\n", - "\n", - "# % Case #1: Constant Rate Poisson Process\n", - "# First we want to show that when neural firing activity is generated from\n", - "# a constant rate poisson process, the algorithm is able to estimate the\n", - "# value of this constant rate.\n", - "#\n", - "# MATLAB: clear all;\n", - "# MATLAB: close all;\n", - "#\n", - "# MATLAB: p=0.01; % bernoilli probability\n", - "# MATLAB: N=100001; % Number of coin flips\n", - "# MATLAB: delta = 0.001; % binsize\n", - "# MATLAB: T=N*delta; % total time window\n", - "# MATLAB: lambda=N*p/T % lambda*T = N*p\n", - "#\n", - "# MATLAB: mu = log(lambda*delta/(1-lambda*delta))\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "999ce33b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/11 for ValidationDataSet: Section\n", - "\n", - "# %\n", - "# Now generate data for two neurons based on this constant rate\n", - "# MATLAB: for i=1:2\n", - "# MATLAB: t=linspace(0,T,N);\n", - "# MATLAB: ind=rand(1,N)T1);\n", - "# MATLAB: ind2=rand(1,N2)max(t1)],'Baseline','s','','',{'muConst','mu1','mu2'});\n", - "# MATLAB: cc=CovColl({cov});\n", - "#\n", - "# Specify how we want to perform the analysis\n", - "# MATLAB: sampleRate=1000;\n", - "# MATLAB: trial=Trial(spikeColl, cc);\n", - "# MATLAB: clear c;\n", - "# Constant rate throughout\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','muConst'}},sampleRate,[],[]);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "# Constant rate for epoch1 and Constat rate for epoch2 but distinct\n", - "# MATLAB: c{2} = TrialConfig({{'Baseline','mu1','mu2'}},sampleRate,[],[]);\n", - "# MATLAB: c{2}.setName('Variable');\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 9\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "59c2ceaf", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 10/11 for ValidationDataSet: Section\n", - "\n", - "# %\n", - "# Run the analysis\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", - "# MATLAB: results{1}.plotResults;\n", - "# MATLAB: results{2}.plotResults;\n", - "# MATLAB: figure;\n", - "# MATLAB: subplot(1,2,1); results{1}.lambda.plot;\n", - "# MATLAB: subplot(1,2,2); results{2}.lambda.plot;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=10, matlab_line_number=132, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 10, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 10\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a684d984", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 11/11 for ValidationDataSet: Section\n", - "\n", - "# %\n", - "# Compare the results across the two neurons\n", - "# MATLAB: Summary = FitResSummary(results);\n", - "# MATLAB: Summary.plotSummary;\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 11, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 11, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 11, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_06.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=7 + 11, title=f\"{TOPIC} Figure 007\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_07.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=8 + 11, title=f\"{TOPIC} Figure 008\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_08.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=9 + 11, title=f\"{TOPIC} Figure 009\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_09.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=10 + 11, title=f\"{TOPIC} Figure 010\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_10.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=11 + 11, title=f\"{TOPIC} Figure 011\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_11.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=12 + 11, title=f\"{TOPIC} Figure 012\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"ValidationDataSet_12.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=13 + 11, title=f\"{TOPIC} Figure 013\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"clear all;\",\n", - " \"close all;\",\n", - " \"p=0.01; % bernoilli probability\",\n", - " \"N=100001; % Number of coin flips\",\n", - " \"delta = 0.001; % binsize\",\n", - " \"T=N*delta; % total time window\",\n", - " \"lambda=N*p/T % lambda*T = N*p\",\n", - " \"mu = log(lambda*delta/(1-lambda*delta))\",\n", - " \"for i=1:2\",\n", - " \"t=linspace(0,T,N);\",\n", - " \"ind=rand(1,N)T1);\",\n", - " \"ind2=rand(1,N2)max(t1)],'Baseline','s','','',{'muConst','mu1','mu2'});\",\n", - " \"cc=CovColl({cov});\",\n", - " \"sampleRate=1000;\",\n", - " \"trial=Trial(spikeColl, cc);\",\n", - " \"clear c;\",\n", - " \"c{1} = TrialConfig({{'Baseline','muConst'}},sampleRate,[],[]);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','mu1','mu2'}},sampleRate,[],[]);\",\n", - " \"c{2}.setName('Variable');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"results{1}.plotResults;\",\n", - " \"results{2}.plotResults;\",\n", - " \"figure;\",\n", - " \"subplot(1,2,1); results{1}.lambda.plot;\",\n", - " \"subplot(1,2,2); results{2}.lambda.plot;\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for ValidationDataSet.\")\n", - "\n", - "# ValidationDataSet: load MATLAB-gold trial matrix and reproduce raster/PSTH/significance summaries.\n", - "from pathlib import Path\n", - "import nstat\n", - "from scipy.io import loadmat\n", - "fixture_path = Path(nstat.__file__).resolve().parents[2] / \"tests/parity/fixtures/matlab_gold/ValidationDataSet_gold.mat\"\n", - "m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False)\n", - "dt = float(np.asarray(m[\"dt_val\"], dtype=float).reshape(-1)[0]); time = np.asarray(m[\"time_val\"], dtype=float).reshape(-1)\n", - "trial_matrix = np.asarray(m[\"trial_matrix_val\"], dtype=float); psth = np.asarray(m[\"psth_val\"], dtype=float).reshape(-1); sem = np.asarray(m[\"sem_val\"], dtype=float).reshape(-1)\n", - "rates, prob_mat, sig_mat = DecodingAlgorithms.compute_spike_rate_cis(spike_matrix=trial_matrix, alpha=0.05)\n", - "exp_rates = np.asarray(m[\"expected_rate_val\"], dtype=float).reshape(-1); exp_prob = np.asarray(m[\"expected_prob_val\"], dtype=float); exp_sig = np.asarray(m[\"expected_sig_val\"], dtype=int)\n", - "fig, axes = plt.subplots(3, 1, figsize=(9, 7), sharex=False)\n", - "for k in range(min(18, trial_matrix.shape[0])): axes[0].vlines(time[trial_matrix[k] > 0], k + 0.6, k + 1.4, linewidth=0.5)\n", - "axes[0].set_title(f\"{TOPIC}: trial raster\"); axes[0].set_ylabel(\"trial\")\n", - "axes[1].plot(time, psth, color=\"tab:blue\", linewidth=1.2); axes[1].fill_between(time, psth - sem, psth + sem, color=\"tab:blue\", alpha=0.2); axes[1].set_ylabel(\"Hz\"); axes[1].set_title(\"PSTH mean +/- SEM\")\n", - "im = axes[2].imshow(prob_mat, aspect=\"auto\", origin=\"lower\", cmap=\"viridis\"); axes[2].set_title(\"Trial-by-trial spike-rate p-values\"); axes[2].set_xlabel(\"trial\"); axes[2].set_ylabel(\"trial\"); fig.colorbar(im, ax=axes[2], fraction=0.03, pad=0.02)\n", - "plt.tight_layout(); plt.show()\n", - "rate_err = float(np.max(np.abs(rates - exp_rates))); prob_err = float(np.max(np.abs(prob_mat - exp_prob))); sig_mismatch = float(np.count_nonzero(sig_mat != exp_sig))\n", - "assert rate_err <= 1e-10 and prob_err <= 1e-10 and sig_mismatch == 0.0\n", - "CHECKPOINT_METRICS = {\"rate_max_abs_error\": rate_err, \"prob_max_abs_error\": prob_err, \"sig_mismatch_count\": sig_mismatch}\n", - "CHECKPOINT_LIMITS = {\"rate_max_abs_error\": (0.0, 1e-10), \"prob_max_abs_error\": (0.0, 1e-10), \"sig_mismatch_count\": (0.0, 0.0)}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "data", - "run_group": "full", - "section_count": 11, - "source_helpfile": "ValidationDataSet.m", - "topic": "ValidationDataSet" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/mEPSCAnalysis.ipynb b/notebooks/helpfiles/mEPSCAnalysis.ipynb deleted file mode 100644 index fea6395b..00000000 --- a/notebooks/helpfiles/mEPSCAnalysis.ipynb +++ /dev/null @@ -1,638 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "e58c9fc4", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/9 for mEPSCAnalysis: MINIATURE EXCITATORY POST-SYNAPTIC CURRENTS (mEPSCs)\n", - "\n", - "# % MINIATURE EXCITATORY POST-SYNAPTIC CURRENTS (mEPSCs)\n", - "# Data from Marnie Phillips \n", - "# This analysis is based on a partial version of the dataset used in\n", - "#\n", - "# Phillips MA, Lewis LD, Gong J, Constantine-Paton M, Brown EN. 2011\n", - "# _Model-based statistical analysis of miniature synaptic transmission._\n", - "# J Neurophys (under consideration)\n", - "#\n", - "# *Author*: Iahn Cajigas\n", - "#\n", - "# *Date*: 03/01/2011\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: mEPSCAnalysis\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/mEPSCAnalysis.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"mEPSCAnalysis\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"mEPSCAnalysis: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"mEPSCAnalysis: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"mEPSCAnalysis: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"mEPSCAnalysis: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 6\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4e7565c2", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/9 for mEPSCAnalysis: Data Description\n", - "\n", - "# % Data Description\n", - "# *epsc2.txt*:\n", - "# Event times of selected, constant rate, miniature excitatory\n", - "# post-synaptic currents (mEPSCs) in 0mM magnesium condition]\n", - "#\n", - "# *washout1.txt*:\n", - "# Variable rate recording: Event times of selected events, beginning\n", - "# approximately 260 seconds after magnesium is first removed.\n", - "#\n", - "# *washout2.txt*:\n", - "# Event times of selected events from the same recording, beginning\n", - "# 745 seconds after magnesium is first removed\n", - "#\n", - "# Column headers in the text files explain what each column represents.\n", - "#\n", - "# Event selection criteria for the \"washout1\" and \"washout2\" condition were:\n", - "#\n", - "# * Amplitude > 10pA\n", - "# * 10-90% rise time < 20ms\n", - "#\n", - "# For this washout experiment, the recording duration was so long,\n", - "# and there were so many events, that the minimum amplitude threshold\n", - "# was conservative.\n", - "#\n", - "# The mean RMS noise was only 1.36pA, and a usual threshold would be\n", - "# 5*RMS = 6.8pA.\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4f8e8f44", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/9 for mEPSCAnalysis: Constant Magnesium Concentration - Constant rate poisson\n", - "\n", - "# % Constant Magnesium Concentration - Constant rate poisson\n", - "# Under a constant Magnesium concentration, it is seen that the mEPSCs\n", - "# behave as a homogeneous poisson process (constant arrival rate).\n", - "# MATLAB: close all;\n", - "# MATLAB: [~,mEPSCDir] = getPaperDataDirs();\n", - "# MATLAB: epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt'));\n", - "# MATLAB: sampleRate = 1000;\n", - "# MATLAB: spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds\n", - "# MATLAB: nst = nspikeTrain(spikeTimes);\n", - "# MATLAB: time = 0:(1/sampleRate):nst.maxTime;\n", - "#\n", - "# Define Covariates for the analysis\n", - "# MATLAB: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',{'\\mu'});\n", - "# MATLAB: covarColl = CovColl({baseline});\n", - "#\n", - "# Create the trial structure\n", - "# MATLAB: spikeColl = nstColl(nst);\n", - "# MATLAB: trial = Trial(spikeColl,covarColl);\n", - "#\n", - "#\n", - "# Define how we want to analyze the data\n", - "# MATLAB: clear tc tcc;\n", - "# MATLAB: tc{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\n", - "# MATLAB: tcc = ConfigColl(tc);\n", - "#\n", - "# Perform Analysis (Commented to since data already saved)\n", - "# MATLAB: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", - "# MATLAB: results.plotResults;\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a0720082", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/9 for mEPSCAnalysis: Varying Magnesium Concentration - Piecewise Constant rate poisson\n", - "\n", - "# % Varying Magnesium Concentration - Piecewise Constant rate poisson\n", - "# When the magnesium concentration of the bath decreased (i.e. magnesium\n", - "# is removed), the rate of mEPSCs begin to increase in frequency. This can\n", - "# be modeled in a many different ways (using the change in Magnesium\n", - "# directly as a model covariate, etc.) Here we approximate the rate as\n", - "# being constant during certain portions of the experiment. These segments\n", - "# can in principle be estimated (using heirarchical Bayesian methods), but\n", - "# here we select them via visual inspection. We compare three models: a\n", - "# constant rate model (from above), a piecewise constant rate model, and a\n", - "# piecewise constant rate model with history.\n", - "#\n", - "# load the data;\n", - "# MATLAB: washout1 = importdata(fullfile(mEPSCDir,'washout1.txt'));\n", - "# MATLAB: washout2 = importdata(fullfile(mEPSCDir,'washout2.txt'));\n", - "#\n", - "# MATLAB: sampleRate = 1000;\n", - "# Magnesium removed at t=0\n", - "# MATLAB: spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\n", - "# MATLAB: spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\n", - "# MATLAB: nst = nspikeTrain([spikeTimes1; spikeTimes2]);\n", - "# MATLAB: time = 260:(1/sampleRate):nst.maxTime;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08fe1687", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/9 for mEPSCAnalysis: Data Visualization\n", - "\n", - "# % Data Visualization\n", - "# Visual inspection of the spike train is used to pick three regions\n", - "# where the firing rate appears to be different. Here we do not\n", - "# estimate where these transitions happen but pick times in an ad-hoc\n", - "# manner.\n", - "# MATLAB: figure;\n", - "# MATLAB: nst.plot;\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=98, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"mEPSCAnalysis.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 5, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c66ae482", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/9 for mEPSCAnalysis: Define Covariates for the analysis\n", - "\n", - "# % Define Covariates for the analysis\n", - "# MATLAB: timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\n", - "# MATLAB: timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\n", - "# 765 onwards third constant rate\n", - "# epoch\n", - "# MATLAB: constantRate = ones(length(time),1);\n", - "# MATLAB: rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;\n", - "# MATLAB: rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;\n", - "# MATLAB: rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;\n", - "# MATLAB: baseline = Covariate(time,[constantRate,rate1, rate2, rate3],'Baseline','time','s','',{'\\mu','\\mu_{1}','\\mu_{2}','\\mu_{3}'});\n", - "# MATLAB: covarColl = CovColl({baseline});\n", - "#\n", - "# Create the trial structure\n", - "# MATLAB: spikeColl = nstColl(nst);\n", - "# MATLAB: trial = Trial(spikeColl,covarColl);\n", - "#\n", - "# 30ms history in logarithmic spacing (chosen after using\n", - "# Analysis.computeHistLagForAll for various window lengths)\n", - "# MATLAB: maxWindow=.3; numWindows=20;\n", - "# MATLAB: delta=1/sampleRate;\n", - "# MATLAB: windowTimes =unique(round([0 logspace(log10(delta),...\n", - "# MATLAB: log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\n", - "# MATLAB: windowTimes = windowTimes(1:11);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 6\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "58b5076f", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 7/9 for mEPSCAnalysis: Define how we want to analyze the data\n", - "\n", - "# % Define how we want to analyze the data\n", - "# MATLAB: clear tc tcc;\n", - "# MATLAB: tc{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\n", - "# MATLAB: tc{2} = TrialConfig({{'Baseline','\\mu_{1}','\\mu_{2}','\\mu_{3}'}},sampleRate,[]); tc{2}.setName('Diff Baseline');\n", - "# tc{3} = TrialConfig({{'Baseline','\\mu_{1}','\\mu_{2}','\\mu_{3}'}},sampleRate,windowTimes); tc{3}.setName('Diff Baseline+Hist');\n", - "# MATLAB: tcc = ConfigColl(tc);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 7\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e6180aba", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 8/9 for mEPSCAnalysis: Perform Analysis\n", - "\n", - "# % Perform Analysis\n", - "# We see that the piece-wise constant rate model (with and without\n", - "# history, outperform the constant baseline model in terms of AIC, BIC,\n", - "# and KS-statistic. While addition of the history effect yields a model\n", - "# that falls within the 95% confidence interval of the KS plot, it\n", - "# results in increases of the AIC and BIC because of the increased\n", - "# number of parameters.\n", - "# MATLAB: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", - "# MATLAB: results.plotResults;\n", - "# MATLAB: Summary = FitResSummary(results);\n", - "# MATLAB: Summary.plotSummary;\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 8\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fbd6cafd", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 9/9 for mEPSCAnalysis: Decode Rate using Point Process Filter\n", - "\n", - "# % Decode Rate using Point Process Filter\n", - "#\n", - "# clear lambdaCIF;\n", - "# delta = .001;\n", - "#\n", - "# washout1 = importdata('washout1.txt');\n", - "# washout2 = importdata('washout2.txt');\n", - "#\n", - "# sampleRate = 1000;\n", - "# % Magnesium removed at t=0\n", - "# spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\n", - "# spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\n", - "# nst = nspikeTrain([spikeTimes1; spikeTimes2]);\n", - "# time = 260:(1/sampleRate):nst.maxTime;\n", - "# spikeColl = nstColl(nst);\n", - "#\n", - "# clear lambdaCIF;\n", - "# lambdaCIF = CIF([1],{'mu'},{'mu'},'poisson');\n", - "# spikeColl.resample(1/delta);\n", - "# dN=spikeColl.dataToMatrix;\n", - "# Q=.001;\n", - "# Px0=.1; A=1;\n", - "# [x_p, Pe_p, x_u, Pe_u] = CIF.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF);\n", - "# figure;\n", - "# tNew = 260:delta:(length(x_p(1:end-1))*delta+260);\n", - "# plot(tNew,exp(x_p)./delta);\n", - "#\n", - "# %%\n", - "# close all;\n", - "# N=30000; A=1; B=ones(1,N)./N;\n", - "# xfilt = filtfilt(B,A,x_p);\n", - "# figure;\n", - "# plot(tNew,x_p,'-.b');\n", - "# hold on; plot(tNew,xfilt,'k','Linewidth',3);\n", - "# %%\n", - "# close all;\n", - "# figure;\n", - "# index = find(tNew<280,1,'last');\n", - "# subplot(2,1,1);\n", - "# plot(tNew(index:end),x_p(index:end),'-.b'); hold on;\n", - "# plot(tNew(index:end),xfilt(index:end),'k','Linewidth',3);\n", - "# xlabel('time [s]');\n", - "# ylabel('\\mu');\n", - "# axis tight;\n", - "# v=axis;\n", - "# axis([v(1) v(2) -9 -5]);\n", - "#\n", - "# subplot(2,1,2);\n", - "# plot(tNew(index:end),exp(x_p(index:end))./delta,'-.b'); hold on;\n", - "# plot(tNew(index:end),exp(xfilt(index:end))./delta,'k','Linewidth',3);\n", - "# axis tight;\n", - "# v=axis;\n", - "# axis([v(1) v(2) 0 5]);\n", - "# xlabel('time [s]');\n", - "# ylabel('\\lambda(t) [Hz]');\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=146, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"mEPSCAnalysis_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 9, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=146, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"mEPSCAnalysis_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 9, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=146, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"mEPSCAnalysis_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 9, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=146, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"mEPSCAnalysis_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 9, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=146, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"mEPSCAnalysis_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 9, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"[~,mEPSCDir] = getPaperDataDirs();\",\n", - " \"epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt'));\",\n", - " \"sampleRate = 1000;\",\n", - " \"spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"time = 0:(1/sampleRate):nst.maxTime;\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',{'\\\\mu'});\",\n", - " \"covarColl = CovColl({baseline});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"clear tc tcc;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"results.plotResults;\",\n", - " \"washout1 = importdata(fullfile(mEPSCDir,'washout1.txt'));\",\n", - " \"washout2 = importdata(fullfile(mEPSCDir,'washout2.txt'));\",\n", - " \"sampleRate = 1000;\",\n", - " \"spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\",\n", - " \"spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\",\n", - " \"nst = nspikeTrain([spikeTimes1; spikeTimes2]);\",\n", - " \"time = 260:(1/sampleRate):nst.maxTime;\",\n", - " \"figure;\",\n", - " \"nst.plot;\",\n", - " \"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\",\n", - " \"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\",\n", - " \"constantRate = ones(length(time),1);\",\n", - " \"rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;\",\n", - " \"rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;\",\n", - " \"rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;\",\n", - " \"baseline = Covariate(time,[constantRate,rate1, rate2, rate3],'Baseline','time','s','',{'\\\\mu','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'});\",\n", - " \"covarColl = CovColl({baseline});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"maxWindow=.3; numWindows=20;\",\n", - " \"delta=1/sampleRate;\",\n", - " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", - " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", - " \"windowTimes = windowTimes(1:11);\",\n", - " \"clear tc tcc;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\",\n", - " \"tc{2} = TrialConfig({{'Baseline','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'}},sampleRate,[]); tc{2}.setName('Diff Baseline');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"results.plotResults;\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for mEPSCAnalysis.\")\n", - "\n", - "# mEPSCAnalysis: synthetic current trace and event detection summary.\n", - "dt = 0.0005\n", - "time = np.arange(0.0, 12.0, dt)\n", - "n = time.size\n", - "\n", - "# Generate baseline noise and negative-going mEPSC-like events.\n", - "trace = 0.025 * rng.standard_normal(n)\n", - "event_times_true = np.sort(rng.uniform(0.4, 11.6, size=75))\n", - "event_amps = rng.uniform(0.12, 0.42, size=event_times_true.size)\n", - "tau_rise = 0.0015\n", - "tau_decay = 0.010\n", - "\n", - "kernel_t = np.arange(0.0, 0.060, dt)\n", - "kernel = (1.0 - np.exp(-kernel_t / tau_rise)) * np.exp(-kernel_t / tau_decay)\n", - "kernel = kernel / np.max(kernel)\n", - "\n", - "for t_evt, amp in zip(event_times_true, event_amps, strict=False):\n", - " idx = int(round(t_evt / dt))\n", - " end = min(idx + kernel.size, n)\n", - " k = kernel[: end - idx]\n", - " trace[idx:end] -= amp * k\n", - "\n", - "# Simple threshold-crossing detection with refractory period.\n", - "threshold = -0.12\n", - "refractory = int(round(0.006 / dt))\n", - "candidate = np.where(trace < threshold)[0]\n", - "detected_idx: list[int] = []\n", - "last = -refractory\n", - "for idx in candidate:\n", - " if idx - last >= refractory:\n", - " window_end = min(idx + int(round(0.004 / dt)) + 1, n)\n", - " local = idx + int(np.argmin(trace[idx:window_end]))\n", - " detected_idx.append(local)\n", - " last = local\n", - "detected_idx = np.array(detected_idx, dtype=int)\n", - "detected_times = detected_idx * dt\n", - "detected_amps = -trace[detected_idx]\n", - "events = Events(times=detected_times, labels=[f\"e{i}\" for i in range(detected_times.size)])\n", - "\n", - "fig, axes = plt.subplots(3, 1, figsize=(10, 7.2), sharex=False)\n", - "axes[0].plot(time, trace, color=\"0.15\", linewidth=0.7)\n", - "axes[0].scatter(detected_times, trace[detected_idx], color=\"tab:red\", s=10, alpha=0.8)\n", - "axes[0].set_title(f\"{TOPIC}: synthetic mEPSC trace with detections\")\n", - "axes[0].set_ylabel(\"current [a.u.]\")\n", - "\n", - "axes[1].hist(detected_amps, bins=25, color=\"tab:blue\", alpha=0.85)\n", - "axes[1].set_title(\"Detected event amplitudes\")\n", - "axes[1].set_xlabel(\"amplitude [a.u.]\")\n", - "axes[1].set_ylabel(\"count\")\n", - "\n", - "iei = np.diff(events.times) if events.times.size > 1 else np.array([0.0])\n", - "axes[2].hist(iei, bins=25, color=\"tab:green\", alpha=0.85)\n", - "axes[2].set_title(\"Inter-event interval distribution\")\n", - "axes[2].set_xlabel(\"interval [s]\")\n", - "axes[2].set_ylabel(\"count\")\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert events.times.size > 30\n", - "assert float(np.mean(detected_amps) if detected_amps.size else 0.0) > 0.08\n", - "CHECKPOINT_METRICS = {\n", - " \"detected_event_count\": float(events.times.size),\n", - " \"mean_detected_amplitude\": float(np.mean(detected_amps) if detected_amps.size else 0.0),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"detected_event_count\": (30.0, 220.0),\n", - " \"mean_detected_amplitude\": (0.08, 0.6),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "data", - "run_group": "full", - "section_count": 9, - "source_helpfile": "mEPSCAnalysis.m", - "topic": "mEPSCAnalysis" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/nSTATPaperExamples.ipynb b/notebooks/helpfiles/nSTATPaperExamples.ipynb deleted file mode 100644 index 4aa92aa4..00000000 --- a/notebooks/helpfiles/nSTATPaperExamples.ipynb +++ /dev/null @@ -1,5245 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "f35533a9", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/43 for nSTATPaperExamples: nSTAT J. Neuroscience Methods Paper Examples\n", - "\n", - "# % nSTAT J. Neuroscience Methods Paper Examples\n", - "#\n", - "# *Author*: Iahn Cajigas\n", - "#\n", - "# *Date*: 01/04/2012\n", - "#\n", - "# Force command echo off so published output does not include repeated\n", - "# executed source lines.\n", - "# MATLAB: echo off;\n", - "#\n", - "# Paper reference:\n", - "#\n", - "# * Cajigas I, Malik WQ, Brown EN. nSTAT: Open-source neural spike train\n", - "# analysis toolbox for Matlab. Journal of Neuroscience Methods 211:\n", - "# 245-264 (2012).\n", - "# * DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# * PMID: 22981419\n", - "#\n", - "# Navigation:\n", - "#\n", - "# * \n", - "#\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: nSTATPaperExamples\n", - "# Execution group: smoke\n", - "# Workflow family: decoding_1d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/nSTATPaperExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"nSTATPaperExamples\"\n", - "FAMILY = \"decoding_1d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"nSTATPaperExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"nSTATPaperExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"nSTATPaperExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"nSTATPaperExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 26\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "321c8258", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/43 for nSTATPaperExamples: Experiment 1\n", - "\n", - "# % Experiment 1\n", - "# MINIATURE EXCITATORY POST-SYNAPTIC CURRENTS (mEPSCs)\n", - "# Data from Marnie Phillips \n", - "# This analysis is based on a partial version of the dataset used in\n", - "#\n", - "# Phillips MA, Lewis LD, Gong J, Constantine-Paton M, Brown EN. 2011\n", - "# _Model-based statistical analysis of miniature synaptic transmission._\n", - "# J Neurophys (under consideration)\n", - "#\n", - "# *Date*: 03/01/2011\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3903b3b0", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/43 for nSTATPaperExamples: Constant Magnesium Concentration - Constant rate poisson\n", - "\n", - "# % Constant Magnesium Concentration - Constant rate poisson\n", - "# Under a constant Magnesium concentration, it is seen that the mEPSCs\n", - "# behave as a homogeneous poisson process (constant arrival rate).\n", - "# MATLAB: close all; clear all;\n", - "# MATLAB: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", - "# MATLAB: getPaperDataDirs();\n", - "# MATLAB: nSTATRootDir = fileparts(dataDir);\n", - "# MATLAB: if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\n", - "# MATLAB: cd(nSTATRootDir);\n", - "# MATLAB: end\n", - "# MATLAB: epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt'));\n", - "# MATLAB: sampleRate = 1000;\n", - "# MATLAB: spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds\n", - "# MATLAB: nstConst = nspikeTrain(spikeTimes);\n", - "# MATLAB: time = 0:(1/sampleRate):nstConst.maxTime;\n", - "#\n", - "#\n", - "# Define Covariates for the analysis\n", - "# MATLAB: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s',...\n", - "# MATLAB: '',{'\\mu'});\n", - "# MATLAB: covarColl = CovColl({baseline});\n", - "#\n", - "# Create the trial structure\n", - "# MATLAB: spikeColl = nstColl(nstConst);\n", - "# MATLAB: trial = Trial(spikeColl,covarColl);\n", - "#\n", - "#\n", - "# Define how we want to analyze the data\n", - "# MATLAB: clear tc tcc;\n", - "# MATLAB: tc{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[]);\n", - "# MATLAB: tc{1}.setName('Constant Baseline');\n", - "# MATLAB: tcc = ConfigColl(tc);\n", - "#\n", - "# Perform Analysis (Commented to since data already saved)\n", - "# MATLAB: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", - "# h=results.plotResults;\n", - "# MATLAB: close all;\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: results.lambda.setDataLabels({'\\lambda_{const}'});\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\n", - "# MATLAB: scrsz(3)*.98 scrsz(4)*.95]);\n", - "#\n", - "# MATLAB: subplot(2,2,1); spikeColl.plot;\n", - "# MATLAB: title({'Neural Raster with constant Mg^{2+} Concentration'},...\n", - "# MATLAB: 'FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "# MATLAB: hx=xlabel('time [s]','Interpreter','none');\n", - "# MATLAB: hy=ylabel('mEPSCs','Interpreter','none');\n", - "# MATLAB: set(gca,'yTick',[0 1]);\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: subplot(2,2,3); results.KSPlot;\n", - "# MATLAB: subplot(2,2,2); results.plotInvGausTrans;\n", - "# MATLAB: subplot(2,2,4); results.lambda.plot([],{{' ''b'' ,''Linewidth'',2'}});\n", - "# MATLAB: hx=xlabel('time [s]','Interpreter','none');\n", - "# MATLAB: hy=get(gca,'YLabel');\n", - "# MATLAB: set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: h_legend = legend('\\lambda_{const}','Location','NorthEast');\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)+.05 pos(2) pos(3:4)]);\n", - "# MATLAB: set(h_legend,'FontSize',14)\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=73, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 3, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3aa1d852", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/43 for nSTATPaperExamples: Varying Magnesium Concentration - Piecewise Constant rate poisson\n", - "\n", - "# % Varying Magnesium Concentration - Piecewise Constant rate poisson\n", - "# When the magnesium concentration of the bath decreased (i.e. magnesium\n", - "# is removed), the rate of mEPSCs begin to increase in frequency. This can\n", - "# be modeled in a many different ways (using the change in Magnesium\n", - "# directly as a model covariate, etc.) Here we approximate the rate as\n", - "# being constant during certain portions of the experiment. These segments\n", - "# can in principle be estimated (using heirarchical Bayesian methods), but\n", - "# here we select them via visual inspection. We compare three models: a\n", - "# constant rate model (from above), a piecewise constant rate model, and a\n", - "# piecewise constant rate model with history.\n", - "# MATLAB: close all;\n", - "# load the data;\n", - "# MATLAB: washout1 = importdata(fullfile(mEPSCDir,'washout1.txt'));\n", - "# MATLAB: washout2 = importdata(fullfile(mEPSCDir,'washout2.txt'));\n", - "#\n", - "# MATLAB: sampleRate = 1000;\n", - "# Magnesium removed at t=0\n", - "# MATLAB: spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\n", - "# MATLAB: spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\n", - "# MATLAB: nst = nspikeTrain([spikeTimes1; spikeTimes2]);\n", - "# MATLAB: time = 260:(1/sampleRate):nst.maxTime;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "30a09a81", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/43 for nSTATPaperExamples: Data Visualization\n", - "\n", - "# % Data Visualization\n", - "# Visual inspection of the spike train is used to pick three regions\n", - "# where the firing rate appears to be different. Here we do not\n", - "# estimate where these transitions happen but pick times in an ad-hoc\n", - "# manner.\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...\n", - "# MATLAB: scrsz(4)*.9]);\n", - "#\n", - "# MATLAB: subplot(2,1,1);\n", - "# MATLAB: nstConst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\n", - "# MATLAB: title({'Neural Raster with constant Mg^{2+} Concentration'},...\n", - "# MATLAB: 'FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "# MATLAB: hx=get(gca,'XLabel');\n", - "# MATLAB: set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "# MATLAB: subplot(2,1,2);\n", - "# MATLAB: nst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\n", - "# MATLAB: title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\n", - "# MATLAB: 'FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "# MATLAB: hx=get(gca,'XLabel');\n", - "# MATLAB: set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...\n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=125, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 5, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 5\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef3fe0fe", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 6/43 for nSTATPaperExamples: Define Covariates for the analysis\n", - "\n", - "# % Define Covariates for the analysis\n", - "# MATLAB: timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\n", - "# MATLAB: timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\n", - "# 765 onwards third constant rate\n", - "# epoch\n", - "# MATLAB: constantRate = ones(length(time),1);\n", - "# MATLAB: rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;\n", - "# MATLAB: rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;\n", - "# MATLAB: rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;\n", - "# MATLAB: baseline = Covariate(time,[constantRate,rate1, rate2, rate3],...\n", - "# MATLAB: 'Baseline','time','s','',{'\\mu','\\mu_{1}','\\mu_{2}','\\mu_{3}'});\n", - "# MATLAB: covarColl = CovColl({baseline});\n", - "#\n", - "# Create the trial structure\n", - "# MATLAB: spikeColl = nstColl(nst);\n", - "# MATLAB: trial = Trial(spikeColl,covarColl);\n", - "#\n", - "# 30ms history in logarithmic spacing (chosen after using\n", - "# Analysis.computeHistLagForAll for various window lengths)\n", - "# MATLAB: maxWindow=.3; numWindows=20;\n", - "# MATLAB: delta=1/sampleRate;\n", - "# MATLAB: windowTimes =unique(round([0 logspace(log10(delta),...\n", - "# MATLAB: log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\n", - "# MATLAB: windowTimes = windowTimes(1:11);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 6\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ea24fe39", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 7/43 for nSTATPaperExamples: Define how we want to analyze the data\n", - "\n", - "# % Define how we want to analyze the data\n", - "# MATLAB: clear tc tcc;\n", - "# MATLAB: tc{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[]);\n", - "# MATLAB: tc{1}.setName('Constant Baseline');\n", - "# MATLAB: tc{2} = TrialConfig({{'Baseline','\\mu_{1}','\\mu_{2}','\\mu_{3}'}},...\n", - "# MATLAB: sampleRate,[]); tc{2}.setName('Diff Baseline');\n", - "# MATLAB: tcc = ConfigColl(tc);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 7\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "121df5a4", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 8/43 for nSTATPaperExamples: Perform Analysis\n", - "\n", - "# % Perform Analysis\n", - "# We see that the piece-wise constant rate model (without\n", - "# history) outperforms the constant baseline model in terms of AIC, BIC,\n", - "# and KS-statistic.\n", - "# MATLAB: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", - "# h=results.plotResults;\n", - "# Summary = FitResSummary(results);\n", - "# h=Summary.plotSummary;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 8\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "47904b8b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 9/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: close all;\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: results.lambda.setDataLabels({'\\lambda_{const}',...\n", - "# MATLAB: '\\lambda_{const-epoch}'});\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\n", - "# MATLAB: scrsz(3)*.98 scrsz(4)*.95]);\n", - "#\n", - "# MATLAB: subplot(2,2,1); spikeColl.plot;\n", - "# MATLAB: title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\n", - "# MATLAB: 'FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "# MATLAB: hx=xlabel('time [s]','Interpreter','none');\n", - "# MATLAB: set(gca,'YTickLabel',[]);\n", - "# MATLAB: set([hx],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\n", - "# MATLAB: timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\n", - "# 765 onwards third constant rate\n", - "# epoch\n", - "# MATLAB: plot([495;495],[0,1],'r','Linewidth',4); hold on;\n", - "# MATLAB: plot([765;765],[0,1],'r','Linewidth',4);\n", - "#\n", - "# MATLAB: subplot(2,2,3); results.KSPlot;\n", - "# MATLAB: subplot(2,2,2); results.plotInvGausTrans;\n", - "# MATLAB: subplot(2,2,4);\n", - "# MATLAB: results.lambda.getSubSignal(1).plot([],{{' ''b'' ,''Linewidth'',2'}});\n", - "# MATLAB: results.lambda.getSubSignal(2).plot([],{{' ''g'' ,''Linewidth'',2'}});\n", - "# MATLAB: v=axis; axis([v(1) v(2) 0 5]);\n", - "# MATLAB: hx=xlabel('time [s]','Interpreter','none');\n", - "# MATLAB: hy=get(gca,'YLabel');\n", - "# MATLAB: set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: h_legend = legend('\\lambda_{const}','\\lambda_{const-epoch}',...\n", - "# MATLAB: 'Location','NorthEast');\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)+.05 pos(2)-.01 pos(3:4)]);\n", - "# MATLAB: set(h_legend,'FontSize',14)\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\n", - "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=195, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 9, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 9\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "535e9f28", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 10/43 for nSTATPaperExamples: Experiment 2\n", - "\n", - "# % Experiment 2\n", - "# EXPLICIT STIMULUS EXAMPLE - WHISKER STIMULATION/THALAMIC NEURON\n", - "# In the worksheet with analyze the stimulus effect and history effect on\n", - "# the firing of a thalamic neuron under a known stimulus consisting of\n", - "# whisker stimulation.\n", - "# Data from Demba Ba (demba@mit.edu)\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 10\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4449387f", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 11/43 for nSTATPaperExamples: Load the data\n", - "\n", - "# % Load the data\n", - "# clear all;\n", - "# MATLAB: close all;\n", - "# MATLAB: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", - "# MATLAB: getPaperDataDirs();\n", - "# MATLAB: nSTATRootDir = fileparts(dataDir);\n", - "# MATLAB: if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\n", - "# MATLAB: cd(nSTATRootDir);\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: Direction=3; Neuron=1; Stim=2;\n", - "# MATLAB: datapath = fullfile(explicitStimulusDir,['Dir' num2str(Direction)], ...\n", - "# MATLAB: ['Neuron' num2str(Neuron)],['Stim' num2str(Stim)]);\n", - "# MATLAB: data = load(fullfile(datapath,'trngdataBis.mat'));\n", - "#\n", - "# MATLAB: time=0:.001:(length(data.t)-1)*.001;\n", - "# MATLAB: stimData = data.t;\n", - "# MATLAB: spikeTimes = time(data.y==1);\n", - "#\n", - "# MATLAB: stim = Covariate(time,stimData./10,'Stimulus','time','s','mm',{'stim'});\n", - "# MATLAB: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", - "# MATLAB: {'constant'});\n", - "#\n", - "# MATLAB: nst = nspikeTrain(spikeTimes);\n", - "# MATLAB: nspikeColl = nstColl(nst);\n", - "# MATLAB: cc = CovColl({stim,baseline});\n", - "# MATLAB: trial = Trial(nspikeColl,cc);\n", - "# trial.plot;\n", - "#\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "# MATLAB: subplot(3,1,1);\n", - "# MATLAB: nst2 = nspikeTrain(spikeTimes);\n", - "# MATLAB: nst2.setMaxTime(21);nst2.plot;\n", - "# MATLAB: set(gca,'ytick',[0 1]);\n", - "# MATLAB: xlabel('');\n", - "# MATLAB: hy=ylabel('spikes');\n", - "# MATLAB: set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: title({'Neural Raster'},'FontWeight','bold','FontSize',16,'FontName','Arial');\n", - "# MATLAB: set(gca, ...\n", - "# MATLAB: 'XTick' , 0:1:max(time), ...\n", - "# MATLAB: 'XTickLabel' , [],...\n", - "# MATLAB: 'LineWidth' , 1 );\n", - "# MATLAB: subplot(3,1,2);\n", - "# MATLAB: stim.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\n", - "# MATLAB: set(gca,'ytick',[0 0.5 1]);\n", - "# MATLAB: hy=ylabel('Displacement [mm]','Interpreter','none'); xlabel('');\n", - "# MATLAB: set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: title({'Stimulus - Whisker Displacement'},'FontWeight','bold',...\n", - "# MATLAB: 'FontSize',16,'FontName','Arial');\n", - "#\n", - "# MATLAB: set(gca, ...\n", - "# MATLAB: 'XTick' , 0:1:max(time), ...\n", - "# MATLAB: 'XTickLabel' , [],...\n", - "# MATLAB: 'YTick' , 0:.25:1, ...\n", - "# MATLAB: 'LineWidth' , 1 );\n", - "#\n", - "# MATLAB: subplot(3,1,3);\n", - "# MATLAB: stim.derivative.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\n", - "# MATLAB: set(gca,'ytick',[-80 0 80]);\n", - "# MATLAB: axis([0 21 -80 80]);\n", - "# MATLAB: hy=ylabel('Displacement Velocity [mm/s]','Interpreter','none');\n", - "# MATLAB: hx= xlabel('time [s]','Interpreter','none');\n", - "# MATLAB: set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: title({'Displacement Velocity'},'FontWeight','bold',...\n", - "# MATLAB: 'FontSize',16,'FontName','Arial');\n", - "#\n", - "# MATLAB: set(gca, ...\n", - "# MATLAB: 'XTick' , 0:1:max(time), ...\n", - "# MATLAB: 'YTick' , -80:40:80, ...\n", - "# MATLAB: 'LineWidth' , 1 );\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=265, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 11, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 11\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c8893cb", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 12/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "# Fit a constant baseline and Find Stimulus Lag\n", - "# We fit a constant rate (Poisson) model to the data and use the look at the\n", - "# cross-covariance function of between the stimulus and the fit\n", - "# residual to determine the appropriate lag for the stimulus.\n", - "# MATLAB: clear c; close all;\n", - "# MATLAB: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", - "#\n", - "# Find Stimulus Lag (look for peaks in the cross-covariance function less\n", - "# than 1 second\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "#\n", - "# MATLAB: subplot(7,2,[1 3 5])\n", - "# MATLAB: results.Residual.xcov(stim).windowedSignal([0,1]).plot;\n", - "#\n", - "# MATLAB: ylabel('');\n", - "# MATLAB: [m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));\n", - "# MATLAB: title(['Cross Correlation Function - Peak at t=' num2str(ShiftTime) ' sec'],'FontWeight','bold',...\n", - "# MATLAB: 'FontSize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "# MATLAB: hold on;\n", - "# MATLAB: h=plot(ShiftTime,m,'ro','Linewidth',3);\n", - "# MATLAB: set(h, 'MarkerFaceColor',[1 0 0], 'MarkerEdgeColor',[1 0 0]);\n", - "# MATLAB: hx=xlabel('Lag [s]','Interpreter','none');\n", - "# MATLAB: set(hx,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "#\n", - "# Allow for shifts of less than 1 second\n", - "# MATLAB: stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\n", - "# MATLAB: stim = stim.shift(ShiftTime);\n", - "# MATLAB: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", - "# MATLAB: {'\\mu'});\n", - "#\n", - "# MATLAB: nst = nspikeTrain(spikeTimes);\n", - "# MATLAB: nspikeColl = nstColl(nst);\n", - "# MATLAB: cc = CovColl({stim,baseline});\n", - "# MATLAB: trial2 = Trial(nspikeColl,cc);\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=12, matlab_line_number=323, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 12, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 12\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b02833f1", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 13/43 for nSTATPaperExamples: Compare constant rate model with model including stimulus effect\n", - "\n", - "# % Compare constant rate model with model including stimulus effect\n", - "# Addition of the stimulus improves the fits in terms of the KS plot and\n", - "# the making the rescaled ISIs less correlated. The Point Process Residula\n", - "# also looks more \"white\"\n", - "# MATLAB: clear c;\n", - "# MATLAB: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,selfHist,...\n", - "# MATLAB: NeighborHist);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "# MATLAB: c{2} = TrialConfig({{'Baseline','\\mu'},{'Stimulus','stim'}},...\n", - "# MATLAB: sampleRate,selfHist,NeighborHist);\n", - "# MATLAB: c{2}.setName('Baseline+Stimulus');\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);\n", - "# results.plotResults;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 13\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f7907a74", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 14/43 for nSTATPaperExamples: History Effect\n", - "\n", - "# % History Effect\n", - "# Determine the best history effect model using AIC, BIC, and KS statistic\n", - "# MATLAB: sampleRate=1000;\n", - "# MATLAB: delta=1/sampleRate*1;\n", - "# MATLAB: maxWindow=1; numWindows=32;\n", - "# MATLAB: windowTimes =unique(round([0 logspace(log10(delta),...\n", - "# MATLAB: log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\n", - "# MATLAB: results =Analysis.computeHistLagForAll(trial2,windowTimes,...\n", - "# MATLAB: {{'Baseline','\\mu'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\n", - "#\n", - "# MATLAB: KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));\n", - "# MATLAB: AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...\n", - "# MATLAB: min(results{1}.AIC(2:end)-results{1}.AIC(1))) +1;\n", - "# MATLAB: BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...\n", - "# MATLAB: min(results{1}.BIC(2:end)-results{1}.BIC(1))) +1;\n", - "# MATLAB: if(AICind==1)\n", - "# MATLAB: AICind=inf;\n", - "# MATLAB: end\n", - "# MATLAB: if(BICind==1)\n", - "# MATLAB: BICind=inf; %sometime BIC is non-decreasing and the index would be 1\n", - "# MATLAB: end\n", - "# MATLAB: windowIndex = min([AICind,BICind]) %use the minimum order model\n", - "# MATLAB: Summary = FitResSummary(results);\n", - "# Summary.plotSummary;\n", - "#\n", - "#\n", - "# MATLAB: clear c;\n", - "# MATLAB: if(windowIndex>1)\n", - "# MATLAB: selfHist = windowTimes(1:windowIndex+1);\n", - "# MATLAB: else\n", - "# MATLAB: selfHist = [];\n", - "# MATLAB: end\n", - "# MATLAB: NeighborHist = []; sampleRate = 1000;\n", - "#\n", - "# figure;\n", - "# MATLAB: subplot(7,2,2);\n", - "# MATLAB: x=0:length(windowTimes)-1;\n", - "# MATLAB: plot(x,results{1}.KSStats.ks_stat,'.-'); axis tight; hold on;\n", - "# MATLAB: plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\n", - "#\n", - "# MATLAB: set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\n", - "# MATLAB: 'TickLength', [.02 .02] , ...\n", - "# MATLAB: 'XMinorTick', 'on','LineWidth' , 1);\n", - "#\n", - "# MATLAB: hy=ylabel('KS Statistic');\n", - "# MATLAB: set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: dAIC = results{1}.AIC-results{1}.AIC(1);\n", - "# MATLAB: title({'Model Selection via change'; 'in KS Statistic, AIC, and BIC'},...\n", - "# MATLAB: 'FontWeight','bold',...\n", - "# MATLAB: 'FontSize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "#\n", - "# MATLAB: subplot(7,2,4); plot(x,dAIC,'.-');\n", - "# MATLAB: set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\n", - "# MATLAB: 'TickLength', [.02 .02] , ...\n", - "# MATLAB: 'XMinorTick', 'on','LineWidth' , 1);\n", - "# MATLAB: hy=ylabel('\\Delta AIC');axis tight; hold on;\n", - "# MATLAB: set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: plot(x(windowIndex),dAIC(windowIndex),'r*');\n", - "# MATLAB: dBIC = results{1}.BIC-results{1}.BIC(1);\n", - "#\n", - "# MATLAB: subplot(7,2,6); plot(x,dBIC,'.-');\n", - "# MATLAB: hy=ylabel('\\Delta BIC'); axis tight; hold on;\n", - "#\n", - "# MATLAB: plot(x(windowIndex),dBIC(windowIndex),'r*');\n", - "# MATLAB: hx=xlabel('# History Windows, Q');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: set(gca, ...\n", - "# MATLAB: 'TickLength' , [.02 .02] , ...\n", - "# MATLAB: 'XMinorTick' , 'on' , ...\n", - "# MATLAB: 'XTick' , 0:5:results{1}.numResults-1, ...\n", - "# MATLAB: 'LineWidth' , 1 );\n", - "#\n", - "#\n", - "#\n", - "# Compare Baseline, Baseline+Stimulus Model, Baseline+History+Stimulus\n", - "# Addition of the history effect yields a model that falls within the 95%\n", - "# CI of the KS plot.\n", - "#\n", - "# MATLAB: c{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[],NeighborHist);\n", - "# MATLAB: c{1}.setName('Baseline');\n", - "# MATLAB: c{2} = TrialConfig({{'Baseline','\\mu'},{'Stimulus','stim'}},...\n", - "# MATLAB: sampleRate,[],[]);\n", - "# MATLAB: c{2}.setName('Baseline+Stimulus');\n", - "# MATLAB: c{3} = TrialConfig({{'Baseline','\\mu'},{'Stimulus','stim'}},...\n", - "# MATLAB: sampleRate,windowTimes(1:windowIndex),[]);\n", - "# MATLAB: c{3}.setName('Baseline+Stimulus+Hist');\n", - "# MATLAB: cfgColl= ConfigColl(c);\n", - "# MATLAB: results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);\n", - "# results.plotResults;\n", - "#\n", - "# MATLAB: results.lambda.setDataLabels({'\\lambda_{const}','\\lambda_{const+stim}',...\n", - "# MATLAB: '\\lambda_{const+stim+hist}'});\n", - "# MATLAB: subplot(7,2,[9 11 13]); results.KSPlot;\n", - "# MATLAB: subplot(7,2,[10 12 14]); results.plotCoeffs; legend off;\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 14\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3bd06037", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 15/43 for nSTATPaperExamples: Example 3 - PSTH Data\n", - "\n", - "# % Example 3 - PSTH Data\n", - "#\n", - "# Generate a known Conditional Intensity Function\n", - "# We generated a known conditional intensity function (rate function) and\n", - "# generate distinct realizations of point processes consistent with this\n", - "# rate function. We use the method of thinning to simulate a point process.\n", - "# MATLAB: clear all;\n", - "# MATLAB: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", - "# MATLAB: getPaperDataDirs();\n", - "# MATLAB: close all;\n", - "# MATLAB: delta = 0.001;\n", - "# MATLAB: Tmax = 1;\n", - "# MATLAB: time = 0:delta:Tmax;\n", - "# MATLAB: f=2;\n", - "# MATLAB: mu = -3;\n", - "#\n", - "# MATLAB: tempData = 1*sin(2*pi*f*time)+mu; %lambda >=0\n", - "# MATLAB: lambdaData = exp(tempData)./(1+exp(tempData))*(1/delta);\n", - "# MATLAB: lambda = Covariate(time,lambdaData, '\\lambda(t)','time','s',...\n", - "# MATLAB: 'spikes/sec',{'\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\n", - "# MATLAB: numRealizations = 20;\n", - "# MATLAB: spikeCollSim = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\n", - "#\n", - "#\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "#\n", - "# MATLAB: subplot(2,2,3);spikeCollSim.plot;\n", - "# MATLAB: set(gca,'YTick',0:5:numRealizations,'YTickLabel',0:5:numRealizations);\n", - "# MATLAB: title({[num2str(numRealizations) ' Simulated Point Process Sample Paths']},...\n", - "# MATLAB: 'FontWeight','bold','Fontsize',14,'FontName','Arial');\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "#\n", - "# MATLAB: subplot(2,2,1);lambda.plot;\n", - "# MATLAB: title({'Simulated Conditional Intensity Function (CIF)'},...\n", - "# MATLAB: 'FontWeight','bold','FontSize',14,'FontName','Arial');\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: hy=get(gca,'YLabel');\n", - "# MATLAB: set(hy,'FontName', 'Arial','FontSize',14,'FontWeight','bold');\n", - "#\n", - "# MATLAB: x = load(fullfile(psthDir,'Results.mat'));\n", - "# MATLAB: numTrials = x.Results.Data.Spike_times_STC.balanced_SUA.Nr_trials;\n", - "# MATLAB: cellNum=6; clear nst;\n", - "# MATLAB: for i=1:numTrials\n", - "# MATLAB: spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};\n", - "# MATLAB: nst{i} = nspikeTrain(spikeTimes{i});\n", - "# MATLAB: nst{i}.setName(num2str(cellNum));\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: spikeCollReal1=nstColl(nst);\n", - "# MATLAB: spikeCollReal1.setMinTime(0); spikeCollReal1.setMaxTime(2);\n", - "# MATLAB: subplot(2,2,2);spikeCollReal1.plot; set(gca,'YTick',0:2:numTrials,...\n", - "# MATLAB: 'YTickLabel',0:2:numTrials);\n", - "# set(gca,'xtick',[0:.5:2],'xtickLabel',{'0','0.5','1','1.5','2'});\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: title('Response to Moving Visual Stimulus (Neuron 6)',...\n", - "# MATLAB: 'FontWeight','bold','Fontsize',14,'FontName','Arial');\n", - "#\n", - "# MATLAB: cellNum=1; clear nst;\n", - "# MATLAB: for i=1:numTrials\n", - "# MATLAB: spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};\n", - "# MATLAB: nst{i} = nspikeTrain(spikeTimes{i});\n", - "# MATLAB: nst{i}.setName(num2str(cellNum));\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: spikeCollReal2=nstColl(nst);\n", - "# MATLAB: spikeCollReal2.setMinTime(0); spikeCollReal2.setMaxTime(2);\n", - "# MATLAB: subplot(2,2,4);spikeCollReal2.plot;\n", - "# MATLAB: set(gca,'YTick',0:2:numTrials,'YTickLabel',0:2:numTrials);\n", - "# set(gca,'xtick',[0:.5:2],'xtickLabel',{'0','0.5','1','1.5','2'});\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: title('Response to Moving Visual Stimulus (Neuron 1)','FontWeight',...\n", - "# MATLAB: 'bold','Fontsize',14,'FontName','Arial');\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=15, matlab_line_number=489, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 15, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 15\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e2bb1c35", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 16/43 for nSTATPaperExamples: Estimate the PSTH with 50ms windows\n", - "\n", - "# % Estimate the PSTH with 50ms windows\n", - "#\n", - "# MATLAB: close all;\n", - "#\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "#\n", - "# MATLAB: binsize = .05; %50ms window\n", - "# MATLAB: psth = spikeCollSim.psth(binsize);\n", - "# MATLAB: psthGLM = spikeCollSim.psthGLM(binsize);\n", - "# MATLAB: true = lambda; %rate*delta = expected number of arrivals per bin\n", - "# MATLAB: subplot(2,3,4);\n", - "#\n", - "# MATLAB: h1=true.plot([],{{' ''b'',''Linewidth'',4'}});\n", - "# MATLAB: h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\n", - "# MATLAB: h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\n", - "#\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "#\n", - "# MATLAB: legend off;\n", - "# MATLAB: h_legend=legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)+.005 pos(2)+.095 pos(3:4)]);\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: subplot(2,3,1);spikeCollSim.plot;\n", - "# MATLAB: set(gca,'YTick',0:2:spikeCollSim.numSpikeTrains,'YTickLabel',0:2:spikeCollSim.numSpikeTrains);\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "#\n", - "# MATLAB: subplot(2,3,5);\n", - "# MATLAB: binsize = .05; %50ms window\n", - "# MATLAB: psthReal1 = spikeCollReal1.psth(binsize);\n", - "# MATLAB: psthGLMReal1 = spikeCollReal1.psthGLM(binsize);%,[],[],[],[],[],1000);\n", - "#\n", - "# MATLAB: h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}});\n", - "# MATLAB: h2=psthReal1.plot([],{{' ''rx'',''Linewidth'',4'}});\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "#\n", - "# MATLAB: h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\n", - "# MATLAB: subplot(2,3,2); spikeCollReal1.plot;\n", - "# MATLAB: set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: subplot(2,3,6);\n", - "# MATLAB: psthReal2 = spikeCollReal2.psth(binsize);\n", - "# MATLAB: psthGLMReal2 = spikeCollReal2.psthGLM(binsize);%,[],[],[],[],[],1000);\n", - "# MATLAB: h3=psthGLMReal2.plot([],{{' ''k'',''Linewidth'',4'}});\n", - "# MATLAB: h2=psthReal2.plot([],{{' ''rx'',''Linewidth'',4'}});\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "#\n", - "#\n", - "# MATLAB: h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\n", - "# MATLAB: subplot(2,3,3); spikeCollReal2.plot;\n", - "# MATLAB: set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=16, matlab_line_number=554, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_06.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=7 + 16, title=f\"{TOPIC} Figure 007\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 16\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "522fcfed", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 17/43 for nSTATPaperExamples: Example 3b - SSGLM Example\n", - "\n", - "# % Example 3b - SSGLM Example\n", - "# Example of estimating with-in and across trial dynamics\n", - "# Methods from:\n", - "# G. Czanner, U. T. Eden, S. Wirth, M. Yanike,\n", - "# W. A. Suzuki, and E. N. Brown, \"Analysis of between-trial and\n", - "# within-trial neural spiking dynamics.,\" Journal of neurophysiology,\n", - "# vol. 99, no. 5, pp. 2672?2693, May. 2008.\n", - "#\n", - "# MATLAB: close all;\n", - "# MATLAB: clear all;\n", - "# MATLAB: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", - "# MATLAB: getPaperDataDirs();\n", - "# set(0,'DefaultFigureRenderer','ZBuffer')\n", - "# MATLAB: delta = 0.001; Tmax = 1;\n", - "# MATLAB: time = 0:delta:Tmax;\n", - "# MATLAB: Ts=.001;\n", - "# MATLAB: numRealizations = 50; %Each realization corresponds to a distinct trial\n", - "#\n", - "# MATLAB: for i=1:numRealizations\n", - "# The within trial dynamics are sinusoidal\n", - "# For each trial the stimulus effect increases\n", - "# MATLAB: f=2; b1(i)=3*((i)/numRealizations);b0=-3;\n", - "# MATLAB: u = sin(2*pi*f*time);\n", - "# MATLAB: e = zeros(length(time),1); %No Ensemble input\n", - "#\n", - "# MATLAB: stim=Covariate(time',u,'Stimulus','time','s','Voltage',{'sin'});\n", - "# MATLAB: ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\n", - "#\n", - "# MATLAB: mu=b0;\n", - "# MATLAB: histCoeffs=[-4 -1 -.5];\n", - "# MATLAB: H=tf(histCoeffs,[1],Ts,'Variable','z^-1');\n", - "#\n", - "# MATLAB: S=tf([b1(i)],1,Ts,'Variable','z^-1');\n", - "# MATLAB: E=tf([0],1,Ts,'Variable','z^-1');\n", - "# MATLAB: simTypeSelect='binomial'; %Parameters are used to compute\n", - "# binomial conditional intensity function\n", - "#\n", - "#\n", - "# Obtain a realization of the point process with the current\n", - "# stimulus and history effect\n", - "# MATLAB: [sC, lambdaTemp]=CIF.simulateCIF(mu,H,S,E,stim,ens,1,simTypeSelect);\n", - "#\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: lambda=lambdaTemp; %Store the conditional intensity function\n", - "# MATLAB: else\n", - "# MATLAB: lambda = lambda.merge(lambdaTemp); %Add it to the other realizations\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: nst{i} = sC.getNST(1); %get the neural spikeTrain from the collection\n", - "# MATLAB: nst{i} = nst{i}.resample(1/delta); %make sure that it is sampled at the current samplerate\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: spikeColl = nstColl(nst); %Create a collection of the spike trains across trials\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 17\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "682ce6bc", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 18/43 for nSTATPaperExamples: Summarize Simulated Data\n", - "\n", - "# % Summarize Simulated Data\n", - "# MATLAB: close all;\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "#\n", - "# Plot the raster\n", - "# MATLAB: subplot(3,2,[3 4]); spikeColl.plot;\n", - "# MATLAB: set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\n", - "# MATLAB: set(gca,'xtick',0:.1:Tmax,'xtickLabel',0:.1:Tmax); xlabel('');\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: title('Simulated Neural Raster','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',14,'FontWeight','bold');\n", - "#\n", - "# Plot the actual stimulus effect (not including history)\n", - "# The CIF including the history effect is stored in the lambda Covariate\n", - "# above\n", - "#\n", - "#\n", - "# MATLAB: stimData = exp(b0 + u'*b1);\n", - "# MATLAB: if(strcmp(simTypeSelect,'binomial'))\n", - "# MATLAB: stimData = stimData./(1+stimData);\n", - "# MATLAB: end\n", - "#\n", - "# Plot the trial dependence\n", - "# MATLAB: subplot(3,2,1); plot(time,u,'k','LineWidth',3);\n", - "# xlabel('time [s]');ylabel('stimulus');\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Stimulus','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: title('Within Trial Stimulus','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',14,'FontWeight','bold');\n", - "#\n", - "# MATLAB: subplot(3,2,2); plot(1:length(b1),b1,'k','LineWidth',3);\n", - "# MATLAB: xlabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Stimulus Gain','Interpreter','none','FontName', 'Arial','Fontsize',...\n", - "# MATLAB: 12,'FontWeight','bold');\n", - "# MATLAB: title('Across Trial Stimulus Gain','Interpreter','none','FontName',...\n", - "# MATLAB: 'Arial','Fontsize',14,'FontWeight','bold');\n", - "#\n", - "# MATLAB: subplot(3,2,[5 6]);\n", - "# MATLAB: imagesc(stimData'./delta); set(gca, 'YDir','normal');\n", - "# MATLAB: set(gca,'xtick',0:100:Tmax/delta,'xtickLabel',0:.1:Tmax);\n", - "# MATLAB: set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\n", - "# MATLAB: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", - "# MATLAB: 'Fontsize',12,'FontWeight','bold');\n", - "# MATLAB: title('True Conditional Intensity Function','Interpreter',...\n", - "# MATLAB: 'none','FontName', 'Arial','Fontsize',14,'FontWeight','bold');\n", - "#\n", - "#\n", - "# MATLAB: axis tight;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=18, matlab_line_number=686, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_07.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=8 + 18, title=f\"{TOPIC} Figure 008\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 18\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "323ab2c6", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 19/43 for nSTATPaperExamples: Estimation of the Stimulus Response\n", - "\n", - "# % Estimation of the Stimulus Response\n", - "#\n", - "# Create the covariates that will be used for the GLM regression\n", - "# MATLAB: stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\n", - "# MATLAB: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", - "# MATLAB: {'constant'});\n", - "#\n", - "# Specify the windows of the history coefficients to be estimated\n", - "# MATLAB: windowTimes=[0:.001:.003];\n", - "# Number of bins to discrtize time into (used both for the PSTH and for\n", - "# thec\n", - "# SSGLM model.\n", - "# MATLAB: numBasis = 25;\n", - "#\n", - "# MATLAB: spikeColl.resample(1/delta); % Enforce sampleRate\n", - "# MATLAB: spikeColl.setMaxTime(Tmax); % Make all spikeTrains end at time Tmax\n", - "#\n", - "#\n", - "# MATLAB: dN=spikeColl.dataToMatrix'; % Convert the spikeTrains into a matrix\n", - "# of 1's and 0's corresponding to the presence\n", - "# or absense of a spike in each time window.\n", - "# MATLAB: dN(dN>1)=1; % One should sample finely enough so there is\n", - "# one spike per bin. Here we make sure that\n", - "# this is the case regardless of the\n", - "# sampleRate\n", - "#\n", - "# The width of each rectangular basis pulse is determined by Tmax and by the\n", - "# number of basis pulses to use.\n", - "# MATLAB: basisWidth=(spikeColl.maxTime-spikeColl.minTime)/numBasis;\n", - "#\n", - "# MATLAB: if(simTypeSelect==0)\n", - "# MATLAB: fitType='binomial';\n", - "# MATLAB: else\n", - "# MATLAB: fitType='poisson';\n", - "# MATLAB: end\n", - "# MATLAB: if(strcmp(fitType,'binomial'))\n", - "# MATLAB: Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\n", - "# Binomial Logistic Regression with Conjugate\n", - "# Gradient Solver by Demba Ba (demba@mit.edu).\n", - "# MATLAB: else\n", - "# MATLAB: Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\n", - "# or Poisson CIFs\n", - "# MATLAB: end\n", - "#\n", - "# Use the values obtained from a PSTH to initialize the SSGLM filter\n", - "# MATLAB: [psthSig, ~, psthResult] =spikeColl.psthGLM(basisWidth,windowTimes,fitType);\n", - "# MATLAB: gamma0=psthResult.getHistCoeffs';%+.1*randn(size(histCoeffs));\n", - "# MATLAB: gamma0(isnan(gamma0))=-5; % Depending on the amount of data the\n", - "# the psth may not identify all parameters\n", - "# Just make sure that the estimates are real\n", - "# numbers\n", - "#\n", - "# MATLAB: x0=psthResult.getCoeffs; %The initial estimate for the SSGLM model\n", - "#\n", - "# Estimate the variance within each time bin across trials\n", - "# MATLAB: numVarEstIter=10;\n", - "# MATLAB: Q0 = spikeColl.estimateVarianceAcrossTrials(numBasis,windowTimes,...\n", - "# MATLAB: numVarEstIter,fitType);\n", - "# MATLAB: A=eye(numBasis,numBasis);\n", - "# MATLAB: delta = 1/spikeColl.sampleRate;\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 19\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c9a3c8fb", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 20/43 for nSTATPaperExamples: Run the SSGLM Filter\n", - "\n", - "# % Run the SSGLM Filter\n", - "# MATLAB: CompilingHelpFile=1;\n", - "# Commented out to speed up help file creation ...\n", - "# MATLAB: if(~CompilingHelpFile)\n", - "# MATLAB: Q0d=diag(Q0);\n", - "# MATLAB: neuronName = psthResult.neuronNumber;\n", - "# MATLAB: [xK,WK, WkuFinal,Qhat,gammahat,fitResults,stimulus,stimCIs,logll,...\n", - "# MATLAB: QhatAll,gammahatAll,nIter]=DecodingAlgorithms.PPSS_EMFB(A,Q0d,x0,...\n", - "# MATLAB: dN,fitType,delta,gamma0,windowTimes, numBasis,neuronName);\n", - "#\n", - "# MATLAB: fR = fitResults.toStructure;\n", - "# MATLAB: psthR = psthResult.toStructure;\n", - "# MATLAB: end\n", - "# save SSGLMExampleData psthR fR xK WK WkuFinal Qhat gammahat fitResults stimulus stimCIs logll QhatAll gammahatAll nIter;\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 20\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2fd34852", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 21/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: installPath = which('nSTAT_Install');\n", - "# MATLAB: if isempty(installPath)\n", - "# MATLAB: error('nSTATPaperExamples:MissingInstallPath', ...\n", - "# MATLAB: 'Could not locate nSTAT_Install.m on MATLAB path.');\n", - "# MATLAB: end\n", - "# MATLAB: nstatRoot = fileparts(installPath);\n", - "# MATLAB: if exist(nstatRoot,'dir') == 7 && ~strcmp(pwd,nstatRoot)\n", - "# MATLAB: cd(nstatRoot);\n", - "# MATLAB: end\n", - "# MATLAB: addpath(nstatRoot,'-begin');\n", - "# MATLAB: load(fullfile(nstatRoot,'data','SSGLMExampleData.mat'));\n", - "# MATLAB: fitResults = FitResult.fromStructure(fR);\n", - "# MATLAB: psthResult = FitResult.fromStructure(psthR);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 21\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "426a53fd", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 22/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: t=psthResult.mergeResults(fitResults);\n", - "# t.plotResults; %Compare the results with the PSTH Model\n", - "# MATLAB: t.lambda.setDataLabels({'\\lambda_{PSTH}','\\lambda_{SSGLM}'});\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "# MATLAB: subplot(2,2,1); t.KSPlot;\n", - "# MATLAB: subplot(2,2,2); t.plotResidual;\n", - "# MATLAB: subplot(2,2,3); t.plotInvGausTrans;\n", - "# MATLAB: subplot(2,2,4); t.plotSeqCorr;\n", - "#\n", - "# MATLAB: S=FitResSummary(t);\n", - "# MATLAB: dAIC=diff(S.AIC)\n", - "# MATLAB: dBIC=diff(S.BIC)\n", - "# MATLAB: dKS =diff(S.KSStats);\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=22, matlab_line_number=836, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_08.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=9 + 22, title=f\"{TOPIC} Figure 009\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 22\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e1be1938", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 23/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: close all;\n", - "# Generate the actual stimulus effect\n", - "# MATLAB: minTime=0; maxTime = Tmax;\n", - "# MATLAB: stimData = stim.data*b1;\n", - "# MATLAB: if(strcmp(fitType,'poisson'))\n", - "# MATLAB: actStimEffect=exp(stimData + b0)./delta;\n", - "# MATLAB: elseif(strcmp(fitType,'binomial'))\n", - "# MATLAB: actStimEffect=exp(stimData + b0)./(1+exp(stimData + b0))./delta;\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# Generate the basis function so that the estimated effect can be plotted\n", - "# at the same temporal resolution as the theoretical effect\n", - "# MATLAB: if(~isempty(numBasis))\n", - "# MATLAB: basisWidth = (maxTime-minTime)/numBasis;\n", - "# MATLAB: sampleRate=1/delta;\n", - "# MATLAB: unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,minTime,...\n", - "# MATLAB: maxTime,sampleRate);\n", - "# MATLAB: basisMat = unitPulseBasis.data;\n", - "# MATLAB: end\n", - "#\n", - "# Generate the estimated stimulus effect\n", - "# MATLAB: if(strcmp(fitType,'poisson'))\n", - "# MATLAB: estStimEffect=exp(basisMat*xK)./delta;\n", - "# MATLAB: elseif(strcmp(fitType,'binomial'))\n", - "# MATLAB: estStimEffect=exp(basisMat*xK)./(1+exp(basisMat*xK))./delta;\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\n", - "#\n", - "# Plot the actual and estimated stimulus effect as a function of trial and\n", - "# time\n", - "# MATLAB: subplot(3,1,[1 2 3]);\n", - "# MATLAB: lighting gouraud\n", - "# MATLAB: surf((1:length(b1))',stim.time,actStimEffect,'FaceAlpha',0.1,...\n", - "# MATLAB: 'EdgeAlpha',0.1,'AlphaData',0.1);\n", - "# MATLAB: hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\n", - "# MATLAB: hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\n", - "# MATLAB: set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "# MATLAB: surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),...\n", - "# MATLAB: 'FaceAlpha',0.5,'EdgeAlpha',0.1,'AlphaData',0.5); %xlabel('Trial [k]'); ylabel('time [s]'); zlabel('Stimulus Effect');\n", - "# MATLAB: set(gca,'YDir','reverse');\n", - "# MATLAB: set(gca,'ytick',0:.1:Tmax,'ytickLabel',0:.1:Tmax);\n", - "#\n", - "# MATLAB: title('SSGLM Estimated vs. Actual Stimulus Effect','FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',14,...\n", - "# MATLAB: 'FontName','Arial');\n", - "#\n", - "# MATLAB: close all;\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\n", - "#\n", - "# The actual stimulus effect\n", - "# MATLAB: subplot(3,1,1);\n", - "# MATLAB: lighting gouraud\n", - "# MATLAB: mesh((1:length(b1))',stim.time,actStimEffect);\n", - "# MATLAB: hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\n", - "# MATLAB: zlabel('Stimulus Effect [spikes/sec]'); hold all;\n", - "# MATLAB: set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# title('True Stimulus Effect');\n", - "# MATLAB: title('True Stimulus Effect','FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',14,...\n", - "# MATLAB: 'FontName','Arial');\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: set(gca,'ytick',[],'ytickLabel',[]);\n", - "# MATLAB: CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];\n", - "# MATLAB: view(gca,[90 -90]);\n", - "#\n", - "#\n", - "#\n", - "# The PSTH estimate\n", - "# MATLAB: subplot(3,1,2);\n", - "# MATLAB: lighting gouraud\n", - "# MATLAB: mesh((1:length(b1))',stim.time,repmat(psthSig.data, [1 numRealizations]));\n", - "# MATLAB: hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\n", - "# MATLAB: hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\n", - "# MATLAB: set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# title('PSTH Estimated Stimulus Effect');\n", - "# MATLAB: title('PSTH Estimated Stimulus Effect','FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',14,...\n", - "# MATLAB: 'FontName','Arial');\n", - "#\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: set(gca,'ytick',[],'ytickLabel',[]);\n", - "# MATLAB: CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];\n", - "# MATLAB: view(gca,[90 -90]);\n", - "#\n", - "# The SSGLM estimated stimulus effect\n", - "# MATLAB: subplot(3,1,3);\n", - "# MATLAB: lighting gouraud\n", - "# MATLAB: mesh((1:length(b1))',stim.time,estStimEffect);\n", - "# MATLAB: xlabel('Trial [k]'); ylabel('time [s]');\n", - "# MATLAB: zlabel('Stimulus Effect [spikes/sec]'); hold all;\n", - "# MATLAB: hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); hz=get(gca,'ZLabel');\n", - "# MATLAB: set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "# title('SSGLM Estimated Stimulus Efferct');\n", - "# MATLAB: title('SSGLM Estimated Stimulus Effect','FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',14,...\n", - "# MATLAB: 'FontName','Arial');\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: set(gca,'ytick',[],'ytickLabel',[]);\n", - "# MATLAB: set(gca, 'YDir','normal')\n", - "# MATLAB: view(gca,[90 -90]);\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=23, matlab_line_number=879, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_09.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=10 + 23, title=f\"{TOPIC} Figure 010\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=23, matlab_line_number=901, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_10.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=11 + 23, title=f\"{TOPIC} Figure 011\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 23\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "02c4c1b4", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 24/43 for nSTATPaperExamples: Compare differences across trials\n", - "\n", - "# % Compare differences across trials\n", - "# MATLAB: echo off;\n", - "# MATLAB: close all;\n", - "# MATLAB: minTime=0; maxTime = Tmax;\n", - "# Generate the basis function so that the estimated effect can be plotted\n", - "# at the same temporal resolution as the theoretical effect\n", - "# MATLAB: if(~isempty(numBasis))\n", - "# MATLAB: basisWidth = (maxTime-minTime)/numBasis;\n", - "# MATLAB: sampleRate=1/delta;\n", - "# MATLAB: unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,...\n", - "# MATLAB: minTime,maxTime,sampleRate);\n", - "# MATLAB: basisMat = unitPulseBasis.data;\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# close all;\n", - "#\n", - "# MATLAB: t0=0; tf=Tmax;\n", - "# MATLAB: [spikeRateBinom, ProbMat,sigMat]=DecodingAlgorithms.computeSpikeRateCIs(xK,...\n", - "# MATLAB: WkuFinal,dN,t0,tf,fitType,delta,gammahat,windowTimes);\n", - "#\n", - "# MATLAB: lt=find(sigMat(1,:)==1,1,'first');\n", - "# MATLAB: display(['The learning trial (compared to the first trial) is trial #' ...\n", - "# MATLAB: num2str(find(sigMat(1,:)==1,1,'first'))]);\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "#\n", - "# MATLAB: subplot(2,3,1);\n", - "# MATLAB: spikeRateBinom.setName(['(' num2str(Tmax) '-0)^-1*\\Lambda(0,' ...\n", - "# MATLAB: num2str(Tmax) ')']);\n", - "# MATLAB: spikeRateBinom.plot([],{{' ''k'',''Linewidth'',4'}});\n", - "# e = Events(lt,{''});\n", - "# e.plot;\n", - "# MATLAB: v=axis;\n", - "# MATLAB: plot(lt*[1;1],v(3:4),'r','Linewidth',2);\n", - "# MATLAB: hx=xlabel('Trial [k]','Interpreter','none'); hold all;\n", - "# MATLAB: hy=ylabel('Average Firing Rate [spikes/sec]','Interpreter','none');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: title(['Learning Trial:' num2str(lt)],'FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: h=subplot(2,3,[2 3 5 6]);\n", - "# MATLAB: K=size(dN,1);\n", - "# MATLAB: colormap(flipud(gray));\n", - "# MATLAB: imagesc(ProbMat); hold on;\n", - "# MATLAB: for k=1:K\n", - "# MATLAB: for m=(k+1):K\n", - "# MATLAB: if(sigMat(k,m)==1)\n", - "# MATLAB: plot3(m,k,1,'r*'); hold on;\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: set(h,'XAxisLocation','top','YAxisLocation','right');\n", - "# MATLAB: hx=xlabel('Trial Number','Interpreter','none'); hold all;\n", - "# MATLAB: hy=ylabel('Trial Number','Interpreter','none');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "# MATLAB: subplot(2,3,4)\n", - "# MATLAB: stim1 = Covariate(time, basisMat*stimulus(:,1),'Trial1','time','s',...\n", - "# MATLAB: 'spikes/sec');\n", - "# MATLAB: temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,1,:)));\n", - "# MATLAB: stim1.setConfInterval(temp);\n", - "# MATLAB: stimlt = Covariate(time, basisMat*stimulus(:,lt),'Trial1','time','s',...\n", - "# MATLAB: 'spikes/sec');\n", - "# MATLAB: temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt,:)));\n", - "# MATLAB: temp.setColor('r');\n", - "# MATLAB: stimlt.setConfInterval(temp);\n", - "# MATLAB: stimltm1 = Covariate(time, basisMat*stimulus(:,lt-1),'Trial1','time','s',...\n", - "# MATLAB: 'spikes/sec');\n", - "# MATLAB: temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt-1,:)));\n", - "# MATLAB: temp.setColor('r');\n", - "# MATLAB: stimltm1.setConfInterval(temp);\n", - "#\n", - "# figure;\n", - "# MATLAB: h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}}); hold all;\n", - "# MATLAB: h2=stimlt.plot([],{{' ''r'',''Linewidth'',4'}});\n", - "# MATLAB: hx=xlabel('time [s]','Interpreter','none'); hold all;\n", - "# MATLAB: hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "# MATLAB: title({'Learning Trial Vs. Baseline Trial';'with 95% CIs'},'FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "# MATLAB: h_legend=legend([h1(1) h2(1)],'\\lambda_{1}(t)',['\\lambda_{' num2str(lt) '}(t)']);\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)+.03 pos(2)+.01 pos(3:4)]);\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=24, matlab_line_number=983, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_11.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=12 + 24, title=f\"{TOPIC} Figure 012\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 24\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b92661a0", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 25/43 for nSTATPaperExamples: Example 4 - HIPPOCAMPAL PLACE CELL - RECEPTIVE FIELD ESTIMATION\n", - "\n", - "# % Example 4 - HIPPOCAMPAL PLACE CELL - RECEPTIVE FIELD ESTIMATION\n", - "# Estimation of receptive fields of neurons is a very common data analysis problem in neuroscience.\n", - "# Here we use the nSTAT software to perform an estimation of the receptive fields of hippocampal\n", - "# place cells using a bivariate Gaussian model and Zernike polynomials. The number of zernike polynomials\n", - "# is based on \"An Analysis of Hippocampal Spatio-Temporal Representations Using a Bayesian Algorithm for Neural\n", - "# Spike Train Decoding\" Barbieri et. al 2005. The data used herein in was\n", - "# provided by Dr. Ricardo Barbieri on 2/28/2011.\n", - "#\n", - "# *Author*: Iahn Cajigas\n", - "#\n", - "# *Date*: 3/1/2011\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 25\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "31fa43cb", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 26/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 26\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ae4dbd55", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 27/43 for nSTATPaperExamples: Example Data\n", - "\n", - "# % Example Data\n", - "# The x and y coordinates of a freely foraging rat in a circular environment (70cm in diameter and 30cm high walls) and a fixed visual cue.\n", - "# The x and y coordinates at the time when a spike was observed are marked\n", - "# in red. The position coordinates have been normalized to be between -1\n", - "# and 1 to allow to simplify the analysis.\n", - "# MATLAB: close all;\n", - "# MATLAB: load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\n", - "# MATLAB: exampleCell = [2 21 25 49];\n", - "# exampleCell = 1:length(neuron);\n", - "# figure(1);\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9]);\n", - "#\n", - "# MATLAB: for i=1:length(exampleCell)\n", - "# MATLAB: subplot(2,2,i);\n", - "# MATLAB: h1=plot(x,y,'b','Linewidth',.5); hold on;\n", - "# MATLAB: h2=plot(neuron{exampleCell(i)}.xN,neuron{exampleCell(i)}.yN,'r.',...\n", - "# MATLAB: 'MarkerSize',7);\n", - "# MATLAB: hx=xlabel('X Position'); hy=ylabel('Y Position');\n", - "# title(['Animal#1, Cell#' num2str(exampleCell(i))]);\n", - "# MATLAB: title(['Cell#' num2str(exampleCell(i))],'FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,'FontName','Arial');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: set(gca,'xTick',-1:.5:1,'yTick',-1:.5:1); axis square;\n", - "# MATLAB: if(i==4)\n", - "# MATLAB: h_legend = legend([h1 h2],'Animal Path',...\n", - "# MATLAB: 'Location at time of spike');\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)+.09 pos(2)+.06 pos(3:4)]);\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=27, matlab_line_number=1074, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_12.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=13 + 27, title=f\"{TOPIC} Figure 013\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 27\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e5911eb6", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 28/43 for nSTATPaperExamples: Analyze All Cells\n", - "\n", - "# % Analyze All Cells\n", - "# MATLAB: numAnimals=2;\n", - "# MATLAB: CompilingHelpFile=1;\n", - "# MATLAB: if(~CompilingHelpFile)\n", - "# MATLAB: for n=1:numAnimals\n", - "# load the data\n", - "# MATLAB: clear x y neuron time nst tc tcc z;\n", - "# MATLAB: load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\n", - "#\n", - "# Create the spikeTrains for each cell\n", - "# MATLAB: for i=1:length(neuron)\n", - "# MATLAB: nst{i} = nspikeTrain(neuron{i}.spikeTimes);\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# Convert to polar coordinates\n", - "# MATLAB: [theta,r] = cart2pol(x,y);\n", - "#\n", - "#\n", - "# Evaluate the Zernike Polynomials\n", - "# Number of polynomials from \"An Analysis of Hippocampal\n", - "# Spatio-Temporal Representations Using a Bayesian Algorithm for Neural\n", - "# Spike Train Decoding\" Barbieri et. al 2005\n", - "# MATLAB: cnt=0;\n", - "# MATLAB: for l=0:3\n", - "# MATLAB: for m=-l:l\n", - "# MATLAB: if(~any(mod(l-m,2))) % otherwise the polynomial = 0\n", - "# MATLAB: cnt = cnt+1;\n", - "# MATLAB: z(:,cnt) = zernfun(l,m,r,theta,'norm');\n", - "# zernfun by Paul Fricker\n", - "# http://www.mathworks.com/matlabcentral/fileexchange/7687\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "# Data sampled at 30 Hz but just to be sure\n", - "# MATLAB: delta=min(diff(time));\n", - "# MATLAB: sampleRate = round(1/delta);\n", - "# Define Covariates for the analysis\n", - "# MATLAB: baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\n", - "# MATLAB: {'mu'});\n", - "# MATLAB: zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\n", - "# MATLAB: 'z4','z5','z6','z7','z8','z9','z10'});\n", - "# MATLAB: gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\n", - "# MATLAB: 's','m',{'x','y','x^2','y^2','x*y'});\n", - "# MATLAB: covarColl = CovColl({baseline,gaussian,zernike});\n", - "#\n", - "# Create the trial structure\n", - "# MATLAB: spikeColl = nstColl(nst);\n", - "# MATLAB: trial = Trial(spikeColl,covarColl);\n", - "#\n", - "#\n", - "# Define how we want to analyze the data\n", - "# MATLAB: tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\n", - "# MATLAB: 'x','y','x^2','y^2','x*y'}},sampleRate,[]);\n", - "# MATLAB: tc{1}.setName('Gaussian');\n", - "# MATLAB: tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\n", - "# MATLAB: 'z7','z8','z9','z10'}},sampleRate,[]);\n", - "# MATLAB: tc{2}.setName('Zernike');\n", - "# MATLAB: tcc = ConfigColl(tc);\n", - "#\n", - "# Perform Analysis (Commented to since data already saved)\n", - "# MATLAB: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", - "#\n", - "# Save results\n", - "# MATLAB: resStruct =FitResult.CellArrayToStructure(results);\n", - "# MATLAB: filename = fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results']);\n", - "# MATLAB: save(filename,'resStruct');\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 28\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f0fbaccb", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 29/43 for nSTATPaperExamples: View Summary Statistics\n", - "\n", - "# % View Summary Statistics\n", - "# Note the Zernike Polynomials yield better fits in terms of decreased KS\n", - "# Statistics (less deviation from the 45 degree line), reduced AIC and\n", - "# reduced BIC across the majority of cells and for both animals\n", - "# MATLAB: clear Summary;\n", - "# MATLAB: numAnimals =2;\n", - "#\n", - "# MATLAB: for n=1:numAnimals\n", - "# MATLAB: resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\n", - "# MATLAB: results = FitResult.fromStructure(resData.resStruct);\n", - "# MATLAB: Summary{n} = FitResSummary(results);\n", - "# Summary{n}.plotSummary;\n", - "# MATLAB: end\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 29\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "efa710bb", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 30/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: close all;\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5]);\n", - "# MATLAB: subplot(1,3,1);\n", - "# MATLAB: maxLength = max([Summary{1}.numNeurons,Summary{2}.numNeurons]);\n", - "# MATLAB: dKS = nan(maxLength, 2);\n", - "# MATLAB: dKS(1:Summary{1}.numNeurons,1) = (Summary{1}.KSStats(:,1)-Summary{1}.KSStats(:,2)) ;\n", - "# MATLAB: dKS(1:Summary{2}.numNeurons,2) = (Summary{2}.KSStats(:,1)-Summary{2}.KSStats(:,2)) ;\n", - "#\n", - "# MATLAB: boxplot(dKS ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\n", - "# MATLAB: title('\\Delta KS Statistic','FontWeight','bold','FontSize',14,...\n", - "# MATLAB: 'FontName','Arial');\n", - "#\n", - "#\n", - "# MATLAB: subplot(1,3,2);\n", - "# MATLAB: dAIC = nan(maxLength, 2);\n", - "# MATLAB: dAIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffAIC(1);\n", - "# MATLAB: dAIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffAIC(1);\n", - "#\n", - "# MATLAB: boxplot(dAIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\n", - "# MATLAB: title('\\Delta AIC','FontWeight','bold','FontSize',14,'FontName','Arial');\n", - "#\n", - "#\n", - "# MATLAB: subplot(1,3,3);\n", - "# MATLAB: dBIC = nan(maxLength, 2);\n", - "# MATLAB: dBIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffBIC(1);\n", - "# MATLAB: dBIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffBIC(1);\n", - "#\n", - "# MATLAB: boxplot(dBIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline'); %ylabel('\\Delta BIC'); %xticklabel_rotate([],45,[],'Fontsize',6);\n", - "# MATLAB: title('\\Delta BIC','FontWeight','bold','FontSize',14,'FontName','Arial');\n", - "#\n", - "# close all;\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=30, matlab_line_number=1182, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_13.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=14 + 30, title=f\"{TOPIC} Figure 014\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 30\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f0384a02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 31/43 for nSTATPaperExamples: Visualize the results\n", - "\n", - "# % Visualize the results\n", - "# MATLAB: close all;\n", - "# Define a grid\n", - "# MATLAB: [x_new,y_new]=meshgrid(-1:.01:1); %define new x and y\n", - "# MATLAB: y_new = flipud(y_new); x_new = fliplr(x_new);\n", - "# MATLAB: [theta_new,r_new] = cart2pol(x_new,y_new);\n", - "#\n", - "# Data for the gaussian fit\n", - "# MATLAB: newData{1} =ones(size(x_new));\n", - "# MATLAB: newData{2} =x_new; newData{3} =y_new;\n", - "# MATLAB: newData{4} =x_new.^2; newData{5} =y_new.^2;\n", - "# MATLAB: newData{6} =x_new.*y_new;\n", - "#\n", - "#\n", - "# Zernike polynomials only defined on the unit disk\n", - "# MATLAB: idx = r_new<=1;\n", - "# MATLAB: zpoly = cell(1,10);\n", - "# MATLAB: cnt=0;\n", - "# MATLAB: for l=0:3\n", - "# MATLAB: for m=-l:l\n", - "# MATLAB: if(~any(mod(l-m,2)))\n", - "# MATLAB: cnt = cnt+1;\n", - "# MATLAB: temp = nan(size(x_new));\n", - "# MATLAB: temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\n", - "# MATLAB: zpoly{cnt} = temp;\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: for n=1:numAnimals\n", - "#\n", - "# MATLAB: clear lambdaGaussian lambdaZernike;\n", - "# MATLAB: load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\n", - "# MATLAB: resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\n", - "# MATLAB: results = FitResult.fromStructure(resData.resStruct);\n", - "#\n", - "# MATLAB: for i=1:length(neuron)\n", - "# Evaluate our fits using the new data and the estimated parameters\n", - "# MATLAB: lambdaGaussian{i} = results{i}.evalLambda(1,newData);\n", - "# MATLAB: lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# Plot the receptive fields\n", - "# MATLAB: for i=1:length(neuron)\n", - "# 3d plot of an example place field\n", - "#\n", - "#\n", - "# 2d plot of all the cell's fields\n", - "# MATLAB: if(n==1)\n", - "# MATLAB: h4=figure(4);\n", - "# MATLAB: colormap('jet');\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: tb=annotation(h4,'textbox',...\n", - "# MATLAB: [0.283261904761904 0.928571428571418 ...\n", - "# MATLAB: 0.392857142857143 0.0595238095238095],...\n", - "# MATLAB: 'String',{['Gaussian Place Fields - Animal#' ...\n", - "# MATLAB: num2str(n)]},'FitBoxToText','on','Fontsize',11,...\n", - "# MATLAB: 'FontName','Arial','FontWeight','bold','LineStyle',...\n", - "# MATLAB: 'none','HorizontalAlignment','center'); hold on;\n", - "# MATLAB: end\n", - "# MATLAB: subplot(7,7,i);\n", - "# MATLAB: elseif(n==2)\n", - "# MATLAB: h6=figure(6);\n", - "# MATLAB: colormap('jet');\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: annotation(h6,'textbox',...\n", - "# MATLAB: [0.283261904761904 0.928571428571418 ...\n", - "# MATLAB: 0.392857142857143 0.0595238095238095],...\n", - "# MATLAB: 'String',{['Gaussian Place Fields - Animal#' ...\n", - "# MATLAB: num2str(n)]},'FitBoxToText','on','Fontsize',11,...\n", - "# MATLAB: 'FontName','Arial','FontWeight','bold','LineStyle',...\n", - "# MATLAB: 'none','HorizontalAlignment','center'); hold on;\n", - "# MATLAB: end\n", - "# MATLAB: subplot(6,7,i);\n", - "# MATLAB: end\n", - "# MATLAB: pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\n", - "# MATLAB: axis square; set(gca,'xtick',[],'ytick',[]);\n", - "# MATLAB: set(gca, 'Box' , 'off');\n", - "#\n", - "# MATLAB: if(n==1)\n", - "# MATLAB: h5=figure(5);\n", - "# MATLAB: colormap('jet');\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: annotation(h5,'textbox',...\n", - "# MATLAB: [0.303261904761904 0.928571428571418 ...\n", - "# MATLAB: 0.392857142857143 0.0595238095238095],...\n", - "# MATLAB: 'String',{['Zernike Place Fields - Animal#' ...\n", - "# MATLAB: num2str(n)]},'FitBoxToText','on','Fontsize',11,...\n", - "# MATLAB: 'FontName','Arial','FontWeight','bold','LineStyle','none'); hold on;\n", - "#\n", - "# MATLAB: end\n", - "# MATLAB: subplot(7,7,i);\n", - "# MATLAB: elseif(n==2)\n", - "# MATLAB: h7=figure(7);\n", - "# MATLAB: colormap('jet');\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: annotation(h7,'textbox',...\n", - "# MATLAB: [0.303261904761904 0.928571428571418 ...\n", - "# MATLAB: 0.392857142857143 0.0595238095238095],...\n", - "# MATLAB: 'String',{['Zernike Place Fields - Animal#' ...\n", - "# MATLAB: num2str(n)]},'FitBoxToText','on','Fontsize',11,...\n", - "# MATLAB: 'FontName','Arial','FontWeight','bold','LineStyle',...\n", - "# MATLAB: 'none','HorizontalAlignment','center'); hold on;\n", - "# MATLAB: end\n", - "# MATLAB: subplot(6,7,i);\n", - "# MATLAB: end\n", - "# MATLAB: pcolor(x_new,y_new,lambdaZernike{i}), shading interp\n", - "# MATLAB: axis square;\n", - "# MATLAB: set(gca,'xtick',[],'ytick',[]);\n", - "# MATLAB: set(gca, 'Box' , 'off');\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h4=figure(4);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=31, matlab_line_number=1268, matlab_snippet=\"h4=figure(4);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_14.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=15 + 31, title=f\"{TOPIC} Figure 015\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: h6=figure(6);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=31, matlab_line_number=1281, matlab_snippet=\"h6=figure(6);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_15.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=16 + 31, title=f\"{TOPIC} Figure 016\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: h5=figure(5);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=31, matlab_line_number=1299, matlab_snippet=\"h5=figure(5);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_16.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=17 + 31, title=f\"{TOPIC} Figure 017\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: h7=figure(7);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=31, matlab_line_number=1312, matlab_snippet=\"h7=figure(7);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_17.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=18 + 31, title=f\"{TOPIC} Figure 018\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 31\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a1563298", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 32/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: clear lambdaGaussian lambdaZernike;\n", - "# MATLAB: load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\n", - "# MATLAB: resData = load(fullfile(dataDir,'PlaceCellAnimal1Results.mat'));\n", - "# MATLAB: results = FitResult.fromStructure(resData.resStruct);\n", - "#\n", - "# MATLAB: for i=1:length(neuron)\n", - "# Evaluate our fits using the new data and the estimated parameters\n", - "# MATLAB: lambdaGaussian{i} = results{i}.evalLambda(1,newData);\n", - "# MATLAB: lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "#\n", - "# h1=plot(x,y,'b');\n", - "# h2=plot(x,y,'g');\n", - "#\n", - "# MATLAB: exampleCell = 25;\n", - "# figure(8);\n", - "# plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", - "# xlabel('x'); ylabel('y');\n", - "# title(['Animal#1, Cell#' num2str(exampleCell)]);\n", - "#\n", - "# MATLAB: close all;\n", - "# MATLAB: h9=figure(9);\n", - "# MATLAB: h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\n", - "# MATLAB: get(h_mesh,'AlphaData');\n", - "# MATLAB: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\n", - "# MATLAB: hold on;\n", - "# MATLAB: h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\n", - "# MATLAB: get(h_mesh,'AlphaData');\n", - "# MATLAB: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\n", - "#\n", - "#\n", - "# h_legend=legend('\\lambda_{Gaussian}','\\lambda_{Zernike}');\n", - "# set(h_legend,'FontSize',20);\n", - "# MATLAB: plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", - "# MATLAB: axis tight square;\n", - "# MATLAB: xlabel('x position'); ylabel('y position');\n", - "# MATLAB: title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,'FontName','Arial');\n", - "# MATLAB: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h9=figure(9);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=32, matlab_line_number=1359, matlab_snippet=\"h9=figure(9);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_18.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=19 + 32, title=f\"{TOPIC} Figure 019\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 32\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08a07ad9", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 33/43 for nSTATPaperExamples: Example 5 - STIMULUS DECODING\n", - "\n", - "# % Example 5 - STIMULUS DECODING\n", - "# In this example we show how to decode a univariate and a bivariate\n", - "# stimulus based on a point process observations using nSTAT. Even though\n", - "# due to the simulated nature of the data, we know the exact condition\n", - "# intensity function, we estimate the parameters before moving on to the\n", - "# decoding stage.\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 33\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "401b2a42", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 34/43 for nSTATPaperExamples: Generate the conditional Intensity Function\n", - "\n", - "# % Generate the conditional Intensity Function\n", - "#\n", - "# MATLAB: close all; clear all;\n", - "# MATLAB: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", - "# MATLAB: getPaperDataDirs();\n", - "# MATLAB: delta = 0.001; Tmax = 1;\n", - "# MATLAB: time = 0:delta:Tmax;\n", - "# MATLAB: numRealizations = 20;\n", - "# MATLAB: f=2; b1=randn(numRealizations,1);b0=log(10*delta)+randn(numRealizations,1);\n", - "# MATLAB: x = sin(2*pi*f*time);\n", - "# MATLAB: clear nst;\n", - "# MATLAB: for i=1:numRealizations\n", - "# MATLAB: expData = exp(b1(i)*x+b0(i));\n", - "# MATLAB: lambdaData = expData./(1+expData);\n", - "#\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: lambda = Covariate(time,lambdaData./delta, ...\n", - "# MATLAB: '\\Lambda(t)','time','s','spikes/sec',{'\\lambda_{1}'},...\n", - "# MATLAB: {{' ''b'', ''LineWidth'' ,2'}});\n", - "# MATLAB: else\n", - "# MATLAB: tempLambda = Covariate(time,lambdaData./delta, ...\n", - "# MATLAB: '\\Lambda(t)','time','s','spikes/sec',{'\\lambda_{1}'},...\n", - "# MATLAB: {{' ''b'', ''LineWidth'' ,2'}});\n", - "# MATLAB: lambda = lambda.merge(tempLambda);\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: spikeColl = CIF.simulateCIFByThinningFromLambda(...\n", - "# MATLAB: lambda.getSubSignal(i),1);\n", - "# MATLAB: nst{i} = spikeColl.getNST(1);\n", - "# MATLAB: end\n", - "# MATLAB: spikeColl = nstColl(nst);scrsz = get(0,'ScreenSize');\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...\n", - "# MATLAB: scrsz(3)*.6 scrsz(4)*.8]);\n", - "# figure;\n", - "# MATLAB: subplot(3,1,1); plot(time,x,'k');\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]); ylabel('Stimulus');\n", - "# MATLAB: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: title('Driving Stimulus','FontWeight','bold',...\n", - "# MATLAB: 'FontSize',14,'FontName','Arial');\n", - "# MATLAB: subplot(3,1,2); lambda.plot([],{{' ''k'',''Linewidth'',1'}});\n", - "# MATLAB: legend off;\n", - "# MATLAB: hy=ylabel('Firing Rate [spikes/sec]', 'Interpreter','none');\n", - "# MATLAB: hx=xlabel('','Interpreter','none');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,...\n", - "# MATLAB: 'FontWeight','bold');\n", - "# MATLAB: set(gca,'xtickLabel',[]);\n", - "# MATLAB: title('Conditional Intensity Functions','FontWeight',...\n", - "# MATLAB: 'bold','FontSize',14,'FontName','Arial');\n", - "#\n", - "# MATLAB: subplot(3,1,3); spikeColl.plot;\n", - "# MATLAB: set(gca,'ytick',0:10:numRealizations,'ytickLabel',...\n", - "# MATLAB: 0:10:numRealizations);\n", - "# MATLAB: xlabel('time [s]','Interpreter','none');\n", - "# MATLAB: ylabel('Cell Number','Interpreter','none');\n", - "# MATLAB: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: title('Point Process Sample Paths','FontWeight',...\n", - "# MATLAB: 'bold','FontSize',14,'FontName','Arial');\n", - "#\n", - "# MATLAB: stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\n", - "# MATLAB: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", - "# MATLAB: {'constant'});\n", - "#\n", - "# close all;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...\n", - "fig = FIGURE_TRACKER.new_figure(section_index=34, matlab_line_number=1418, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_19.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=20 + 34, title=f\"{TOPIC} Figure 020\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 34\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "64ef84fd", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 35/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: close all;\n", - "#\n", - "# MATLAB: clear lambdaCIF;\n", - "# MATLAB: spikeColl.resample(1/delta);\n", - "# MATLAB: dN=spikeColl.dataToMatrix;\n", - "#\n", - "# Make noise according to the dynamic range of the stimulus\n", - "# MATLAB: Q=std(stim.data(2:end)-stim.data(1:end-1));\n", - "# MATLAB: Px0=.1; A=1;\n", - "# MATLAB: x0 = x(:,1); yT=x(:,end);\n", - "# MATLAB: Pi0 = eps*eye(size(x0,1),size(x0,1));\n", - "# MATLAB: PiT = eps*eye(size(x0,1),size(x0,1));\n", - "#\n", - "#\n", - "# MATLAB: [x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, ...\n", - "# MATLAB: Q, dN',b0,b1','binomial',delta);\n", - "#\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]);\n", - "# MATLAB: zVal=1.96;\n", - "# MATLAB: ciLower = min(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\n", - "# MATLAB: x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\n", - "# MATLAB: ciUpper = max(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\n", - "# MATLAB: x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\n", - "#\n", - "# MATLAB: estimatedStimulus = Covariate(time,x_u(1:end),'\\hat{x}(t)','time','s','');\n", - "# MATLAB: CI= ConfidenceInterval(time,[ciLower', ciUpper'],'\\hat{x}(t)','time','s','');\n", - "# MATLAB: estimatedStimulus.setConfInterval(CI);\n", - "#\n", - "# hold all;\n", - "# hEst=plot(time,x_u(1:end),'b','Linewidth',2); hold on;\n", - "# plot(time, [ciUpper', ciLower'],'b');\n", - "#\n", - "# MATLAB: hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}});\n", - "# MATLAB: hStim=stim.plot([],{{' ''b'',''Linewidth'',4'}});\n", - "# MATLAB: legend off;\n", - "# MATLAB: h_legend=legend([hEst(1) hStim],'Decoded','Actual');\n", - "# MATLAB: set(h_legend,'Interpreter','none');\n", - "# MATLAB: set(h_legend,'FontSize',22);\n", - "# MATLAB: title(['Decoded Stimulus +/- 95% CIs with ' num2str(numRealizations) ' cells'],...\n", - "# MATLAB: 'FontWeight','bold','Fontsize',22,'FontName','Arial');\n", - "# MATLAB: xlabel('time [s]','Interpreter','none');\n", - "# MATLAB: ylabel('Stimulus','Interpreter','none');\n", - "# MATLAB: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',22,'FontWeight','bold');\n", - "#\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=35, matlab_line_number=1470, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_20.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=21 + 35, title=f\"{TOPIC} Figure 021\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 35\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "432d96fe", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 36/43 for nSTATPaperExamples: Example 5b - Arm reaching to target Simulation\n", - "\n", - "# % Example 5b - Arm reaching to target Simulation\n", - "# See\n", - "# L. Srinivasan, U. T. Eden, A. S. Willsky, and E. N. Brown,\n", - "# \"A state-space analysis for reconstruction of goal-directed movements\n", - "# using neural signals.,\" Neural computation, vol. 18, no. 10, pp. 2465?2494, Oct. 2006.\n", - "#\n", - "# MATLAB: close all;\n", - "# MATLAB: clear all;\n", - "# MATLAB: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", - "# MATLAB: getPaperDataDirs();\n", - "# Process noise covariance only drives the movement velocity\n", - "# MATLAB: q=1e-4;\n", - "# MATLAB: Q=diag([1e-12 1e-12 q q]);\n", - "#\n", - "# MATLAB: delta = .001; % Time increment\n", - "# MATLAB: r=1e-6; % in meters^2\n", - "# MATLAB: p=1e-6; % in meters^2/s^2\n", - "# MATLAB: PiT=diag([r r p p]); % Uncertainty in the target state\n", - "# MATLAB: Pi0=PiT;\n", - "# MATLAB: T=2; % Reach Duration\n", - "#\n", - "# MATLAB: x0 = [0;0;0;0]; % Initial Position and velocities (states)\n", - "# MATLAB: xT = [-.35;.2; 0;0];% Final Target\n", - "# MATLAB: time=0:delta:T; % time vector\n", - "#\n", - "# MATLAB: A=[1 0 delta 0 ; %State transition matrix\n", - "# MATLAB: 0 1 0 delta;\n", - "# MATLAB: 0 0 1 0 ;\n", - "# MATLAB: 0 0 0 1 ];\n", - "#\n", - "# MATLAB: x=zeros(4,length(time));\n", - "#\n", - "#\n", - "# Simulate a reach trajectory\n", - "# Differs from reference by multiplication by delta instead of division so\n", - "# that the velocity has units of meters per second\n", - "# MATLAB: R=chol(Q);\n", - "# MATLAB: L=chol(PiT);\n", - "# MATLAB: for k=1:length(time)\n", - "# MATLAB: if(k==1)\n", - "# MATLAB: x(:,k)=x0;\n", - "# MATLAB: else\n", - "# MATLAB: x(:,k)=A*x(:,k-1)+...\n", - "# MATLAB: delta/(2)*(pi/T)^2*cos(pi*time(k)/T)*[0;0;...\n", - "# MATLAB: xT(1)-x0(1);xT(2)-x0(2)]; %Reach to target model\n", - "# x(:,k)=A*x(:,k-1)+R*randn(size(x,1),1); %Random walk model\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: end\n", - "# MATLAB: xT =x(:,end); % The target generated by the model\n", - "# MATLAB: yT=xT; % Assume we have observed the actual target position with uncertainty PiT\n", - "#\n", - "# Define Q according to the dynamic range of the movement above\n", - "# MATLAB: Q=diag(var(diff(x,[],2),[],2))*100;\n", - "#\n", - "# Plot the movement trajectories and the hand path\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\n", - "# MATLAB: scrsz(3)*.8 scrsz(4)*.8]);\n", - "# Plot The movement path\n", - "# MATLAB: subplot(4,2,[1 3]);\n", - "# MATLAB: plot(100*x(1,:),100*x(2,:),'k','Linewidth',2);\n", - "# MATLAB: xlabel('X Position [cm]'); ylabel('Y Position [cm]');\n", - "# MATLAB: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: title('Reach Path','FontWeight','bold','Fontsize',14,'FontName','Arial');\n", - "# MATLAB: hold on;\n", - "# MATLAB: axis([sort([100*x0(1)+5, 100*xT(1)-5]), sort([100*x0(2)-5, 100*xT(2)+5])]);\n", - "# MATLAB: h1=plot(100*x(1,1),100*x(2,1),'bo','MarkerSize',14);\n", - "# MATLAB: h2=plot(100*x(1,end),100*x(2,end),'ro','MarkerSize',14);\n", - "# MATLAB: legend([h1 h2],'Start','Finish','Location','NorthEast');\n", - "#\n", - "#\n", - "# MATLAB: subplot(4,2,5); h1=plot(time,100*x(1,:),'k','Linewidth',2); hold on;\n", - "# MATLAB: h2=plot(time,100*x(2,:),'k-.','Linewidth',2);\n", - "# MATLAB: h_legend=legend([h1,h2],'x','y','Location','NorthEast');\n", - "# MATLAB: set(h_legend,'FontSize',14)\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\n", - "# MATLAB: hx=xlabel('time [s]'); hy=ylabel('Position [cm]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# Plot the velocity profiles\n", - "#\n", - "# MATLAB: subplot(4,2,7);\n", - "# MATLAB: h1=plot(time,100*x(3,:),'k','Linewidth',2); hold on;\n", - "# MATLAB: h2=plot(time,100*x(4,:),'k-.','Linewidth',2);\n", - "# MATLAB: h_legend=legend([h1 h2],'v_x','v_y','Location','NorthEast');\n", - "# MATLAB: xlabel('time [s]');\n", - "# MATLAB: set(h_legend,'FontSize',14);\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\n", - "# MATLAB: hx=xlabel('time [s]'); hy=ylabel('Velocity [cm/s]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "#\n", - "# MATLAB: gamma=0;\n", - "# MATLAB: windowTimes=[0, 0.001];\n", - "#\n", - "#\n", - "# Simulate neural responses\n", - "# logit(lambda_i*delta) = mu_i + b_x_i*v_x + b_y_i*v_y\n", - "# logit(lambda_i*delta) = X_i*beta_i;\n", - "# MATLAB: numCells = 20;\n", - "# MATLAB: bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);\n", - "# MATLAB: phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell\n", - "# MATLAB: phiMaxNorm = (phiMax+pi)./(2*pi);\n", - "# MATLAB: meanMu = log(10*delta); % baseline firing rate -10Hz\n", - "# MATLAB: MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)\n", - "#\n", - "# MATLAB: dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\n", - "# MATLAB: coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta\n", - "# MATLAB: fitType='binomial';\n", - "# MATLAB: clear nst;\n", - "# MATLAB: for i=1:numCells\n", - "# MATLAB: tempData = exp(dataMat*coeffs(i,:)');\n", - "#\n", - "# MATLAB: if(strcmp(fitType,'poisson'))\n", - "# MATLAB: lambdaData = tempData;\n", - "# MATLAB: else\n", - "# MATLAB: lambdaData = tempData./(1+tempData); % Conditional Intensity Function for ith cell\n", - "# MATLAB: end\n", - "# MATLAB: lambda{i}=Covariate(time,lambdaData./delta, ...\n", - "# MATLAB: '\\Lambda(t)','time','s','spikes/sec',...\n", - "# MATLAB: {strcat('\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\n", - "# MATLAB: lambda{i}=lambda{i}.resample(1/delta);\n", - "#\n", - "# Generate CIF representation in case we want to use the symbolic\n", - "# versions of the PPDecodeFilter (i.e. not PPDecodeFilterLinear\n", - "# MATLAB: lambdaCIF{i} = CIF([MuCoeffs(i) 0 0 bCoeffs(i,:)],...\n", - "# MATLAB: {'1','x','y','vx','vy'},{'x','y','vx','vy'},fitType);\n", - "# generate one realization for each cell\n", - "# MATLAB: tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1); nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization\n", - "# MATLAB: nst{i}.setName(num2str(i)); % give each cell a unique name\n", - "# MATLAB: subplot(4,2,[6 8]);\n", - "# MATLAB: h2=lambda{i}.plot([],{{' ''k'', ''LineWidth'' ,.5'}});\n", - "# MATLAB: legend off; hold all; % Plot the CIF\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: end\n", - "# MATLAB: title('Neural Conditional Intensity Functions','FontWeight',...\n", - "# MATLAB: 'bold','Fontsize',14,'FontName','Arial');\n", - "# MATLAB: hx=xlabel('time [s]','Interpreter','none');\n", - "# MATLAB: hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "# MATLAB: spikeColl = nstColl(nst); % Create a neural spike train collection\n", - "#\n", - "# MATLAB: subplot(4,2,[2,4]); spikeColl.plot;\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: title('Neural Raster','FontWeight','bold','Fontsize',14,...\n", - "# MATLAB: 'FontName','Arial');\n", - "# MATLAB: hx=xlabel('time [s]','Interpreter','none');\n", - "# MATLAB: hy=ylabel('Cell Number','Interpreter','none');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", - "#\n", - "# close all;\n", - "#\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\n", - "fig = FIGURE_TRACKER.new_figure(section_index=36, matlab_line_number=1557, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_21.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=22 + 36, title=f\"{TOPIC} Figure 022\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 36\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0014cea3", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 37/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "# MATLAB: close all;\n", - "# MATLAB: numExamples=20;\n", - "# MATLAB: scrsz = get(0,'ScreenSize');\n", - "# MATLAB: fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\n", - "# MATLAB: scrsz(3)*.6 scrsz(4)*.9]);\n", - "# MATLAB: for k=1:numExamples\n", - "# MATLAB: bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);\n", - "# MATLAB: phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell\n", - "# MATLAB: phiMaxNorm = (phiMax+pi)./(2*pi);\n", - "# MATLAB: meanMu = log(10*delta); % baseline firing rate\n", - "# MATLAB: MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)\n", - "#\n", - "# MATLAB: dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\n", - "# MATLAB: coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta\n", - "# MATLAB: fitType='binomial';\n", - "# MATLAB: clear nst lambda;\n", - "#\n", - "#\n", - "# MATLAB: for i=1:numCells\n", - "# MATLAB: tempData = exp(dataMat*coeffs(i,:)');\n", - "# MATLAB: if(strcmp(fitType,'poisson'))\n", - "# MATLAB: lambdaData = tempData;\n", - "# MATLAB: else\n", - "# Conditional Intensity Function for ith cell\n", - "# MATLAB: lambdaData = tempData./(1+tempData);\n", - "# MATLAB: end\n", - "# MATLAB: lambda{i}=Covariate(time,lambdaData./delta, ...\n", - "# MATLAB: '\\Lambda(t)','time','s','spikes/sec',...\n", - "# MATLAB: {strcat('\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\n", - "# MATLAB: lambda{i}=lambda{i}.resample(1/delta);\n", - "#\n", - "# Generate CIF representation in case we want to use the symbolic\n", - "# versions of the PPDecodeFilter (i.e. not PPDecodeFilterLinear\n", - "# generate one realization for each cell\n", - "# MATLAB: tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);\n", - "# MATLAB: nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization\n", - "# MATLAB: nst{i}.setName(num2str(i)); % give each cell a unique name\n", - "#\n", - "# MATLAB: end\n", - "#\n", - "# Plot the neural raster across all the cells\n", - "# MATLAB: spikeColl = nstColl(nst); % Create a neural spike train collection\n", - "#\n", - "# Based on the temporal resolution defined by delta, bin the data and get\n", - "# a matrix representation of the neural firing\n", - "# MATLAB: dN=spikeColl.dataToMatrix';\n", - "# MATLAB: dN(dN>1)=1; % more than one spike per bin will be treated as one spike. In\n", - "# general we should pick delta small enough so that there is\n", - "# only one spike per bin\n", - "#\n", - "# MATLAB: [C,N] = size(dN); % N time samples, C cells\n", - "#\n", - "# MATLAB: beta=[zeros(2,numCells); bCoeffs'];\n", - "#\n", - "#\n", - "# Use the Goal Directed Movement Version of the Point Process adaptive\n", - "# Filter\n", - "# MATLAB: [x_p, W_p, x_u, W_u,x_uT,W_uT,x_pT,W_pT] = ...\n", - "# MATLAB: DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...\n", - "# MATLAB: MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0, Pi0, yT,PiT,0);\n", - "#\n", - "# Use the Free Movement Version of the Point Process adaptive\n", - "# Filter\n", - "# MATLAB: [x_pf, W_pf, x_uf, W_uf] = ...\n", - "# MATLAB: DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...\n", - "# MATLAB: MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0);\n", - "#\n", - "#\n", - "# MATLAB: if(k==numExamples)\n", - "# MATLAB: subplot(4,2,1:4);h1=plot(100*x(1,:),100*x(2,:),'k','LineWidth',3);\n", - "# MATLAB: hold on;\n", - "# MATLAB: axis([sort([100*x0(1)+5, 100*xT(1)-5]), ...\n", - "# MATLAB: sort([100*x0(2)-5, 100*xT(2)+5])]);\n", - "# MATLAB: title('Estimated vs. Actual Reach Paths',...\n", - "# MATLAB: 'FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "# MATLAB: end\n", - "# MATLAB: subplot(4,2,1:4);h2=plot(100*x_u(1,:)',100*x_u(2,:)','b'); hold all;\n", - "# MATLAB: subplot(4,2,1:4);h3=plot(100*x_uf(1,:)',100*x_uf(2,:)','g');\n", - "# MATLAB: hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: h1=plot(100*x0(1),100*x0(2),'bo','MarkerSize',10); hold on;\n", - "# MATLAB: h2=plot(100*xT(1),100*xT(2),'ro','MarkerSize',10);\n", - "# MATLAB: legend([h1 h2],'Start','Finish','Location','NorthEast');\n", - "#\n", - "#\n", - "# MATLAB: subplot(4,2,5);\n", - "# MATLAB: h1=plot(time,100*x(1,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*x_u(1,:)','b');\n", - "# MATLAB: h3=plot(time,100*x_uf(1,:)','g');\n", - "# MATLAB: hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "#\n", - "# MATLAB: subplot(4,2,6);\n", - "# MATLAB: h1=plot(time,100*x(2,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*x_u(2,:)','b');\n", - "# MATLAB: h3=plot(time,100*x_uf(2,:)','g');\n", - "# MATLAB: h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\n", - "# MATLAB: 'PPAF','Location','SouthEast');\n", - "# MATLAB: hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "# MATLAB: set(h_legend,'FontSize',10)\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)-.63 pos(2)+.23 pos(3:4)]);\n", - "#\n", - "# MATLAB: subplot(4,2,7);\n", - "# MATLAB: h1=plot(time,100*x(3,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*x_u(3,:)','b');\n", - "# MATLAB: h3=plot(time,100*x_uf(3,:)','g');\n", - "# MATLAB: hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "#\n", - "# MATLAB: subplot(4,2,8);\n", - "# MATLAB: h1=plot(time,100*x(4,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*x_u(4,:)','b');\n", - "# MATLAB: h3=plot(time,100*x_uf(4,:)','g');\n", - "# MATLAB: hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "#\n", - "#\n", - "# MATLAB: end\n", - "#\n", - "# close all;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\n", - "fig = FIGURE_TRACKER.new_figure(section_index=37, matlab_line_number=1662, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_22.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=23 + 37, title=f\"{TOPIC} Figure 023\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 37\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fde99175", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 38/43 for nSTATPaperExamples: Experiment 6 - Hybrid Point Process Filter Example\n", - "\n", - "# % Experiment 6 - Hybrid Point Process Filter Example\n", - "# NOTE THIS EXAMPLE WAS NOT INCLUDED IN THE FINAL VERSION OF THE PAPER\n", - "# This example is based on an implementation of the Hybrid Point Process\n", - "# filter described in _General-purpose filter design for neural prosthetic\n", - "# devices_ by Srinivasan L, Eden UT, Mitter SK, Brown EN in J Neurophysiol.\n", - "# 2007 Oct, 98(4):2456-75.\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 38\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2d4426e7", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 39/43 for nSTATPaperExamples: Problem Statement\n", - "\n", - "# % Problem Statement\n", - "# Suppose that a process of interest can be modeled as consisting of\n", - "# several discrete states where the evolution of the system under each\n", - "# state can be modeled as a linear state space model. The observations of\n", - "# both the state and the continuous dynamics are not direct, but rather\n", - "# observed through how the continuous and discrete states affect the firing\n", - "# of a population of neurons. The goal of the hybrid filter is to estimate\n", - "# both the continuous dynamics and the underlying system state from only\n", - "# the neural population firing (point process observations).\n", - "#\n", - "# To illustrate the use of this filter, we consider a reaching task. We\n", - "# assume two underlying system states s=1=\"Not Moving\"=NM and s=2=\"Moving\"=M.\n", - "# Under the \"Not Moving\" the position of the arm remain constant,\n", - "# whereas in the \"Moving\" state, the position and velocities evolved based\n", - "# on the arm acceleration that is modeled as a gaussian white noise\n", - "# process.\n", - "#\n", - "# Under both the \"Moving\" and \"Not Moving\" states, the arm evolution state\n", - "# vector is\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 39\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d4b04909", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 40/43 for nSTATPaperExamples: Section\n", - "\n", - "# %\n", - "#\n", - "# $${\\bf{x}} = {[x,y,{v_x},{v_y},{a_x},{a_y}]^T}$$\n", - "#\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 40\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "41240922", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 41/43 for nSTATPaperExamples: Generated Simulated Arm Reach\n", - "\n", - "# % Generated Simulated Arm Reach\n", - "#\n", - "# MATLAB: clear all;\n", - "# MATLAB: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", - "# MATLAB: getPaperDataDirs();\n", - "# MATLAB: close all;\n", - "# MATLAB: delta=0.001;\n", - "# MATLAB: Tmax=2;\n", - "# MATLAB: time=0:delta:Tmax;\n", - "# MATLAB: A{2} = [1 0 delta 0 delta^2/2 0;\n", - "# MATLAB: 0 1 0 delta 0 delta^2/2;\n", - "# MATLAB: 0 0 1 0 delta 0;\n", - "# MATLAB: 0 0 0 1 0 delta;\n", - "# MATLAB: 0 0 0 0 1 0;\n", - "# MATLAB: 0 0 0 0 0 1];\n", - "#\n", - "# MATLAB: A{1} = [1 0 0 0 0 0;\n", - "# MATLAB: 0 1 0 0 0 0;\n", - "# MATLAB: 0 0 0 0 0 0;\n", - "# MATLAB: 0 0 0 0 0 0;\n", - "# MATLAB: 0 0 0 0 0 0;\n", - "# MATLAB: 0 0 0 0 0 0];\n", - "# MATLAB: A{1} = [1 0;\n", - "# MATLAB: 0 1];\n", - "#\n", - "# MATLAB: Px0{2} =1e-6*eye(6,6);\n", - "# MATLAB: Px0{1} =1e-6*eye(2,2);\n", - "#\n", - "# MATLAB: minCovVal = 1e-12;\n", - "# MATLAB: covVal = 1e-3;\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: Q{2}=[minCovVal 0 0 0 0 0;\n", - "# MATLAB: 0 minCovVal 0 0 0 0;\n", - "# MATLAB: 0 0 minCovVal 0 0 0;\n", - "# MATLAB: 0 0 0 minCovVal 0 0;\n", - "# MATLAB: 0 0 0 0 covVal 0;\n", - "# MATLAB: 0 0 0 0 0 covVal];\n", - "#\n", - "# MATLAB: Q{1}=minCovVal*eye(2,2);\n", - "#\n", - "# MATLAB: mstate = zeros(1,length(time));\n", - "# MATLAB: ind{1}=1:2;\n", - "# MATLAB: ind{2}=1:6;\n", - "#\n", - "# Acceleration model\n", - "# MATLAB: X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));\n", - "# MATLAB: p_ij = [.998 .002;\n", - "# MATLAB: .001 .999];\n", - "#\n", - "# MATLAB: for i = 1:length(time)\n", - "#\n", - "# MATLAB: if(i==1)\n", - "# MATLAB: mstate(i) = 1;\n", - "# MATLAB: else\n", - "# MATLAB: if(rand(1,1)1)=1; %Avoid more than 1 spike per bin.\n", - "#\n", - "# Starting states are equally probable\n", - "# MATLAB: Mu0=.5*ones(size(p_ij,1),1);\n", - "# MATLAB: clear x0 yT clear Pi0 PiT;\n", - "# MATLAB: x0{1} = X(ind{1},1);\n", - "# MATLAB: yT{1} = X(ind{1},end);\n", - "# MATLAB: Pi0 = Px0;\n", - "# MATLAB: PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));\n", - "#\n", - "# MATLAB: x0{2} = X(ind{2},1);\n", - "# MATLAB: yT{2} = X(ind{2},end);\n", - "# MATLAB: PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));\n", - "#\n", - "#\n", - "# Run the Hybrid Point Process Filter\n", - "# MATLAB: [S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...\n", - "# MATLAB: DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\n", - "# MATLAB: coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\n", - "# MATLAB: [S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...\n", - "# MATLAB: DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\n", - "# MATLAB: coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0);\n", - "#\n", - "# Store the results for computing relevant statistics later\n", - "# MATLAB: X_estAll(:,:,n) = X_est;\n", - "# MATLAB: X_estNTAll(:,:,n) = X_estNT;\n", - "# MATLAB: S_estAll(n,:)=S_est;\n", - "# MATLAB: S_estNTAll(n,:)=S_estNT;\n", - "# MATLAB: MU_estAll(:,:,n)=MU_est;\n", - "# MATLAB: MU_estNTAll(:,:,n) = MU_estNT;\n", - "#\n", - "#\n", - "# State Estimate\n", - "# MATLAB: subplot(4,3,[1 4]);\n", - "# MATLAB: plot(time,mstate,'k','LineWidth',3); hold all;\n", - "# MATLAB: plot(time,S_est,'b-.','Linewidth',.5);\n", - "# MATLAB: plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\n", - "# MATLAB: axis([v(1) v(2) 0.5 2.5]);\n", - "#\n", - "# Movement State Probability (Non-movement State probability is 1-Pr(Movement))\n", - "# MATLAB: subplot(4,3,[7 10]);\n", - "# MATLAB: plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\n", - "# MATLAB: plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\n", - "# MATLAB: axis([min(time) max(time) 0 1.1]);\n", - "#\n", - "# The movement path\n", - "# MATLAB: subplot(4,3,[2 3 5 6]);\n", - "# MATLAB: h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\n", - "# MATLAB: h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\n", - "# MATLAB: h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\n", - "#\n", - "# X-Position\n", - "# MATLAB: subplot(4,3,8);\n", - "# MATLAB: h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*X_est(1,:)','b-.');\n", - "# MATLAB: h3=plot(time,100*X_estNT(1,:)','g-.');\n", - "#\n", - "# Y-Position\n", - "# MATLAB: subplot(4,3,9);\n", - "# MATLAB: h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*X_est(2,:)','b-.');\n", - "# MATLAB: h3=plot(time,100*X_estNT(2,:)','g-.');\n", - "#\n", - "# X-Velocity\n", - "# MATLAB: subplot(4,3,11);\n", - "# MATLAB: h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*X_est(3,:)','b-.');\n", - "# MATLAB: h3=plot(time,100*X_estNT(3,:)','g-.');\n", - "#\n", - "# MATLAB: subplot(4,3,12);\n", - "# MATLAB: h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,100*X_est(4,:)','b-.');\n", - "# MATLAB: h3=plot(time,100*X_estNT(4,:)','g-.');\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# MATLAB: end\n", - "#\n", - "#\n", - "# Save all the example Data\n", - "# save Experiment6ReachExamples X_estAll X_estNTAll S_estAll ...\n", - "# S_estNTAll MU_estAll MU_estNTAll;\n", - "#\n", - "# load Experiment6ReachExamples;\n", - "#\n", - "# Mean Discrete State Estimate\n", - "# MATLAB: subplot(4,3,[1 4]);\n", - "# MATLAB: hold all;\n", - "# MATLAB: plot(time,mstate,'k','LineWidth',3);\n", - "# MATLAB: plot(time,mean(S_estAll),'b','LineWidth',3);\n", - "# MATLAB: plot(time,mean(S_estNTAll),'g','LineWidth',3);\n", - "# MATLAB: set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\n", - "# MATLAB: hy=ylabel('state'); hx=xlabel('time [s]');\n", - "# MATLAB: set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\n", - "# MATLAB: 'Interpreter','none');\n", - "# MATLAB: title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\n", - "# MATLAB: 12,'FontName','Arial');\n", - "#\n", - "#\n", - "#\n", - "#\n", - "# Mean State Movement State Probability\n", - "# MATLAB: subplot(4,3,[7 10]);\n", - "# MATLAB: plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\n", - "# MATLAB: hold on;\n", - "# MATLAB: plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\n", - "# MATLAB: hold on;\n", - "# MATLAB: axis([min(time) max(time) 0 1.1]);\n", - "# MATLAB: hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('Probability of State','FontWeight','bold','Fontsize',12,...\n", - "# MATLAB: 'FontName','Arial');\n", - "#\n", - "# Mean movement path\n", - "# MATLAB: subplot(4,3,[2 3 5 6]);\n", - "# MATLAB: h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\n", - "# MATLAB: mXestAll=mean(100*X_estAll,3);\n", - "# MATLAB: mXestNTAll=mean(100*X_estNTAll,3);\n", - "# MATLAB: plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\n", - "# MATLAB: plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\n", - "# MATLAB: hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "#\n", - "# MATLAB: h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\n", - "# MATLAB: h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\n", - "# MATLAB: legend([h1 h2],'Start','Finish','Location','NorthEast');\n", - "# MATLAB: title('Estimated vs. Actual Reach Path','FontWeight','bold',...\n", - "# MATLAB: 'Fontsize',12,'FontName','Arial');\n", - "#\n", - "#\n", - "# Mean X-Positon\n", - "# MATLAB: subplot(4,3,8);\n", - "# MATLAB: h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\n", - "# MATLAB: h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\n", - "# MATLAB: hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "#\n", - "# Mean Y-Position\n", - "# MATLAB: subplot(4,3,9);\n", - "# MATLAB: h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\n", - "# MATLAB: h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\n", - "# MATLAB: h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\n", - "# MATLAB: 'PPAF','Location','SouthEast');\n", - "# MATLAB: hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\n", - "# MATLAB: set(gca,'xtick',[],'xtickLabel',[]);\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "# MATLAB: set(h_legend,'FontSize',10)\n", - "# MATLAB: pos = get(h_legend,'position');\n", - "# MATLAB: set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\n", - "#\n", - "# Mean X-Velocity\n", - "# MATLAB: subplot(4,3,11);\n", - "# MATLAB: h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\n", - "# MATLAB: h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\n", - "# MATLAB: hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "#\n", - "# Mean Y-Velocity\n", - "# MATLAB: subplot(4,3,12);\n", - "# MATLAB: h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\n", - "# MATLAB: h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\n", - "# MATLAB: h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\n", - "# MATLAB: hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\n", - "# MATLAB: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", - "# MATLAB: title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", - "#\n", - "# Parity contract scalars for MATLAB/Python verification.\n", - "# MATLAB: parity = struct();\n", - "# MATLAB: if exist('numCells','var')\n", - "# MATLAB: parity.num_cells = numCells;\n", - "# MATLAB: end\n", - "# MATLAB: if exist('numRealizations','var')\n", - "# MATLAB: parity.num_realizations = numRealizations;\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: function [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", - "# MATLAB: getPaperDataDirs()\n", - "# Resolve local data folders robustly when Live Editor executes from a temp\n", - "# location (e.g., /private/var/.../T).\n", - "# MATLAB: candidateRoots = {};\n", - "#\n", - "# MATLAB: scriptPath = mfilename('fullpath');\n", - "# MATLAB: if ~isempty(scriptPath)\n", - "# MATLAB: candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(scriptPath)));\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: paperPath = which('nSTATPaperExamples');\n", - "# MATLAB: if ~isempty(paperPath)\n", - "# MATLAB: candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(paperPath)));\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: installPath = which('nSTAT_Install');\n", - "# MATLAB: if ~isempty(installPath)\n", - "# MATLAB: candidateRoots = appendCandidateRoot(candidateRoots, fileparts(installPath));\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: try\n", - "# MATLAB: activeFile = matlab.desktop.editor.getActiveFilename;\n", - "# MATLAB: catch\n", - "# MATLAB: activeFile = '';\n", - "# MATLAB: end\n", - "# MATLAB: if ~isempty(activeFile)\n", - "# MATLAB: candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(activeFile)));\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: candidateRoots = appendCandidateRoot(candidateRoots, pwd);\n", - "#\n", - "# MATLAB: nSTATDir = '';\n", - "# MATLAB: for iRoot = 1:numel(candidateRoots)\n", - "# MATLAB: candidateDataDir = fullfile(candidateRoots{iRoot}, 'data');\n", - "# MATLAB: if exist(candidateDataDir, 'dir') == 7\n", - "# MATLAB: nSTATDir = candidateRoots{iRoot};\n", - "# MATLAB: break;\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: if isempty(nSTATDir)\n", - "# MATLAB: error('nSTATPaperExamples:MissingInstallPath', ...\n", - "# MATLAB: ['Could not resolve the nSTAT root path. Checked roots derived from ', ...\n", - "# MATLAB: 'mfilename, which(''nSTATPaperExamples''), which(''nSTAT_Install''), ', ...\n", - "# MATLAB: 'the active editor file, and pwd.']);\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: dataDir = fullfile(nSTATDir,'data');\n", - "# MATLAB: mEPSCDir = fullfile(dataDir,'mEPSCs');\n", - "# MATLAB: explicitStimulusDir = fullfile(dataDir,'Explicit Stimulus');\n", - "# MATLAB: psthDir = fullfile(dataDir,'PSTH');\n", - "# MATLAB: placeCellDataDir = fullfile(dataDir,'Place Cells');\n", - "#\n", - "# MATLAB: if exist(dataDir,'dir') ~= 7\n", - "# MATLAB: error('nSTATPaperExamples:MissingDataDir', ...\n", - "# MATLAB: 'Could not find local nSTAT data folder at %s', dataDir);\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: function roots = appendCandidateRoot(roots, startDir)\n", - "# MATLAB: if isempty(startDir)\n", - "# MATLAB: return;\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: thisDir = startDir;\n", - "# MATLAB: while true\n", - "# MATLAB: if ~any(strcmp(roots, thisDir))\n", - "# MATLAB: roots{end+1} = thisDir; %#ok\n", - "# MATLAB: end\n", - "# MATLAB: parentDir = fileparts(thisDir);\n", - "# MATLAB: if strcmp(parentDir, thisDir)\n", - "# MATLAB: break;\n", - "# MATLAB: end\n", - "# MATLAB: thisDir = parentDir;\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\n", - "fig = FIGURE_TRACKER.new_figure(section_index=43, matlab_line_number=1996, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_24.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=25 + 43, title=f\"{TOPIC} Figure 025\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=43, matlab_line_number=1979, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSTATPaperExamples_25.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=26 + 43, title=f\"{TOPIC} Figure 026\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"echo off;\",\n", - " \"close all; clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"nSTATRootDir = fileparts(dataDir);\",\n", - " \"if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\",\n", - " \"cd(nSTATRootDir);\",\n", - " \"end\",\n", - " \"epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt'));\",\n", - " \"sampleRate = 1000;\",\n", - " \"spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds\",\n", - " \"nstConst = nspikeTrain(spikeTimes);\",\n", - " \"time = 0:(1/sampleRate):nstConst.maxTime;\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s',...\",\n", - " \"'',{'\\\\mu'});\",\n", - " \"covarColl = CovColl({baseline});\",\n", - " \"spikeColl = nstColl(nstConst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"clear tc tcc;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]);\",\n", - " \"tc{1}.setName('Constant Baseline');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"results.lambda.setDataLabels({'\\\\lambda_{const}'});\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\",\n", - " \"scrsz(3)*.98 scrsz(4)*.95]);\",\n", - " \"subplot(2,2,1); spikeColl.plot;\",\n", - " \"title({'Neural Raster with constant Mg^{2+} Concentration'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=ylabel('mEPSCs','Interpreter','none');\",\n", - " \"set(gca,'yTick',[0 1]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"subplot(2,2,3); results.KSPlot;\",\n", - " \"subplot(2,2,2); results.plotInvGausTrans;\",\n", - " \"subplot(2,2,4); results.lambda.plot([],{{' ''b'' ,''Linewidth'',2'}});\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=get(gca,'YLabel');\",\n", - " \"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"h_legend = legend('\\\\lambda_{const}','Location','NorthEast');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.05 pos(2) pos(3:4)]);\",\n", - " \"set(h_legend,'FontSize',14)\",\n", - " \"close all;\",\n", - " \"washout1 = importdata(fullfile(mEPSCDir,'washout1.txt'));\",\n", - " \"washout2 = importdata(fullfile(mEPSCDir,'washout2.txt'));\",\n", - " \"sampleRate = 1000;\",\n", - " \"spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\",\n", - " \"spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\",\n", - " \"nst = nspikeTrain([spikeTimes1; spikeTimes2]);\",\n", - " \"time = 260:(1/sampleRate):nst.maxTime;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...\",\n", - " \"scrsz(4)*.9]);\",\n", - " \"subplot(2,1,1);\",\n", - " \"nstConst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\",\n", - " \"title({'Neural Raster with constant Mg^{2+} Concentration'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=get(gca,'XLabel');\",\n", - " \"set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"subplot(2,1,2);\",\n", - " \"nst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\",\n", - " \"title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=get(gca,'XLabel');\",\n", - " \"set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\",\n", - " \"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\",\n", - " \"constantRate = ones(length(time),1);\",\n", - " \"rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;\",\n", - " \"rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;\",\n", - " \"rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;\",\n", - " \"baseline = Covariate(time,[constantRate,rate1, rate2, rate3],...\",\n", - " \"'Baseline','time','s','',{'\\\\mu','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'});\",\n", - " \"covarColl = CovColl({baseline});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"maxWindow=.3; numWindows=20;\",\n", - " \"delta=1/sampleRate;\",\n", - " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", - " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", - " \"windowTimes = windowTimes(1:11);\",\n", - " \"clear tc tcc;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]);\",\n", - " \"tc{1}.setName('Constant Baseline');\",\n", - " \"tc{2} = TrialConfig({{'Baseline','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'}},...\",\n", - " \"sampleRate,[]); tc{2}.setName('Diff Baseline');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"results.lambda.setDataLabels({'\\\\lambda_{const}',...\",\n", - " \"'\\\\lambda_{const-epoch}'});\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\",\n", - " \"scrsz(3)*.98 scrsz(4)*.95]);\",\n", - " \"subplot(2,2,1); spikeColl.plot;\",\n", - " \"title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"set(gca,'YTickLabel',[]);\",\n", - " \"set([hx],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\",\n", - " \"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\",\n", - " \"plot([495;495],[0,1],'r','Linewidth',4); hold on;\",\n", - " \"plot([765;765],[0,1],'r','Linewidth',4);\",\n", - " \"subplot(2,2,3); results.KSPlot;\",\n", - " \"subplot(2,2,2); results.plotInvGausTrans;\",\n", - " \"subplot(2,2,4);\",\n", - " \"results.lambda.getSubSignal(1).plot([],{{' ''b'' ,''Linewidth'',2'}});\",\n", - " \"results.lambda.getSubSignal(2).plot([],{{' ''g'' ,''Linewidth'',2'}});\",\n", - " \"v=axis; axis([v(1) v(2) 0 5]);\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=get(gca,'YLabel');\",\n", - " \"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"h_legend = legend('\\\\lambda_{const}','\\\\lambda_{const-epoch}',...\",\n", - " \"'Location','NorthEast');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.05 pos(2)-.01 pos(3:4)]);\",\n", - " \"set(h_legend,'FontSize',14)\",\n", - " \"close all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"nSTATRootDir = fileparts(dataDir);\",\n", - " \"if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\",\n", - " \"cd(nSTATRootDir);\",\n", - " \"end\",\n", - " \"Direction=3; Neuron=1; Stim=2;\",\n", - " \"datapath = fullfile(explicitStimulusDir,['Dir' num2str(Direction)], ...\",\n", - " \"['Neuron' num2str(Neuron)],['Stim' num2str(Stim)]);\",\n", - " \"data = load(fullfile(datapath,'trngdataBis.mat'));\",\n", - " \"time=0:.001:(length(data.t)-1)*.001;\",\n", - " \"stimData = data.t;\",\n", - " \"spikeTimes = time(data.y==1);\",\n", - " \"stim = Covariate(time,stimData./10,'Stimulus','time','s','mm',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"nspikeColl = nstColl(nst);\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial = Trial(nspikeColl,cc);\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(3,1,1);\",\n", - " \"nst2 = nspikeTrain(spikeTimes);\",\n", - " \"nst2.setMaxTime(21);nst2.plot;\",\n", - " \"set(gca,'ytick',[0 1]);\",\n", - " \"xlabel('');\",\n", - " \"hy=ylabel('spikes');\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title({'Neural Raster'},'FontWeight','bold','FontSize',16,'FontName','Arial');\",\n", - " \"set(gca, ...\",\n", - " \"'XTick' , 0:1:max(time), ...\",\n", - " \"'XTickLabel' , [],...\",\n", - " \"'LineWidth' , 1 );\",\n", - " \"subplot(3,1,2);\",\n", - " \"stim.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\",\n", - " \"set(gca,'ytick',[0 0.5 1]);\",\n", - " \"hy=ylabel('Displacement [mm]','Interpreter','none'); xlabel('');\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title({'Stimulus - Whisker Displacement'},'FontWeight','bold',...\",\n", - " \"'FontSize',16,'FontName','Arial');\",\n", - " \"set(gca, ...\",\n", - " \"'XTick' , 0:1:max(time), ...\",\n", - " \"'XTickLabel' , [],...\",\n", - " \"'YTick' , 0:.25:1, ...\",\n", - " \"'LineWidth' , 1 );\",\n", - " \"subplot(3,1,3);\",\n", - " \"stim.derivative.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\",\n", - " \"set(gca,'ytick',[-80 0 80]);\",\n", - " \"axis([0 21 -80 80]);\",\n", - " \"hy=ylabel('Displacement Velocity [mm/s]','Interpreter','none');\",\n", - " \"hx= xlabel('time [s]','Interpreter','none');\",\n", - " \"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title({'Displacement Velocity'},'FontWeight','bold',...\",\n", - " \"'FontSize',16,'FontName','Arial');\",\n", - " \"set(gca, ...\",\n", - " \"'XTick' , 0:1:max(time), ...\",\n", - " \"'YTick' , -80:40:80, ...\",\n", - " \"'LineWidth' , 1 );\",\n", - " \"clear c; close all;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(7,2,[1 3 5])\",\n", - " \"results.Residual.xcov(stim).windowedSignal([0,1]).plot;\",\n", - " \"ylabel('');\",\n", - " \"[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));\",\n", - " \"title(['Cross Correlation Function - Peak at t=' num2str(ShiftTime) ' sec'],'FontWeight','bold',...\",\n", - " \"'FontSize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hold on;\",\n", - " \"h=plot(ShiftTime,m,'ro','Linewidth',3);\",\n", - " \"set(h, 'MarkerFaceColor',[1 0 0], 'MarkerEdgeColor',[1 0 0]);\",\n", - " \"hx=xlabel('Lag [s]','Interpreter','none');\",\n", - " \"set(hx,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\",\n", - " \"stim = stim.shift(ShiftTime);\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'\\\\mu'});\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"nspikeColl = nstColl(nst);\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial2 = Trial(nspikeColl,cc);\",\n", - " \"clear c;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,selfHist,...\",\n", - " \"NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','\\\\mu'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,selfHist,NeighborHist);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);\",\n", - " \"sampleRate=1000;\",\n", - " \"delta=1/sampleRate*1;\",\n", - " \"maxWindow=1; numWindows=32;\",\n", - " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", - " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", - " \"results =Analysis.computeHistLagForAll(trial2,windowTimes,...\",\n", - " \"{{'Baseline','\\\\mu'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\",\n", - " \"KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));\",\n", - " \"AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...\",\n", - " \"min(results{1}.AIC(2:end)-results{1}.AIC(1))) +1;\",\n", - " \"BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...\",\n", - " \"min(results{1}.BIC(2:end)-results{1}.BIC(1))) +1;\",\n", - " \"if(AICind==1)\",\n", - " \"AICind=inf;\",\n", - " \"end\",\n", - " \"if(BICind==1)\",\n", - " \"BICind=inf; %sometime BIC is non-decreasing and the index would be 1\",\n", - " \"end\",\n", - " \"windowIndex = min([AICind,BICind]) %use the minimum order model\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"clear c;\",\n", - " \"if(windowIndex>1)\",\n", - " \"selfHist = windowTimes(1:windowIndex+1);\",\n", - " \"else\",\n", - " \"selfHist = [];\",\n", - " \"end\",\n", - " \"NeighborHist = []; sampleRate = 1000;\",\n", - " \"subplot(7,2,2);\",\n", - " \"x=0:length(windowTimes)-1;\",\n", - " \"plot(x,results{1}.KSStats.ks_stat,'.-'); axis tight; hold on;\",\n", - " \"plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\",\n", - " \"set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\",\n", - " \"'TickLength', [.02 .02] , ...\",\n", - " \"'XMinorTick', 'on','LineWidth' , 1);\",\n", - " \"hy=ylabel('KS Statistic');\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"dAIC = results{1}.AIC-results{1}.AIC(1);\",\n", - " \"title({'Model Selection via change'; 'in KS Statistic, AIC, and BIC'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'FontSize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"subplot(7,2,4); plot(x,dAIC,'.-');\",\n", - " \"set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\",\n", - " \"'TickLength', [.02 .02] , ...\",\n", - " \"'XMinorTick', 'on','LineWidth' , 1);\",\n", - " \"hy=ylabel('\\\\Delta AIC');axis tight; hold on;\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"plot(x(windowIndex),dAIC(windowIndex),'r*');\",\n", - " \"dBIC = results{1}.BIC-results{1}.BIC(1);\",\n", - " \"subplot(7,2,6); plot(x,dBIC,'.-');\",\n", - " \"hy=ylabel('\\\\Delta BIC'); axis tight; hold on;\",\n", - " \"plot(x(windowIndex),dBIC(windowIndex),'r*');\",\n", - " \"hx=xlabel('# History Windows, Q');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"set(gca, ...\",\n", - " \"'TickLength' , [.02 .02] , ...\",\n", - " \"'XMinorTick' , 'on' , ...\",\n", - " \"'XTick' , 0:5:results{1}.numResults-1, ...\",\n", - " \"'LineWidth' , 1 );\",\n", - " \"c{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[],NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','\\\\mu'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,[],[]);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"c{3} = TrialConfig({{'Baseline','\\\\mu'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,windowTimes(1:windowIndex),[]);\",\n", - " \"c{3}.setName('Baseline+Stimulus+Hist');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);\",\n", - " \"results.lambda.setDataLabels({'\\\\lambda_{const}','\\\\lambda_{const+stim}',...\",\n", - " \"'\\\\lambda_{const+stim+hist}'});\",\n", - " \"subplot(7,2,[9 11 13]); results.KSPlot;\",\n", - " \"subplot(7,2,[10 12 14]); results.plotCoeffs; legend off;\",\n", - " \"clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"close all;\",\n", - " \"delta = 0.001;\",\n", - " \"Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=2;\",\n", - " \"mu = -3;\",\n", - " \"tempData = 1*sin(2*pi*f*time)+mu; %lambda >=0\",\n", - " \"lambdaData = exp(tempData)./(1+exp(tempData))*(1/delta);\",\n", - " \"lambda = Covariate(time,lambdaData, '\\\\lambda(t)','time','s',...\",\n", - " \"'spikes/sec',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"numRealizations = 20;\",\n", - " \"spikeCollSim = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(2,2,3);spikeCollSim.plot;\",\n", - " \"set(gca,'YTick',0:5:numRealizations,'YTickLabel',0:5:numRealizations);\",\n", - " \"title({[num2str(numRealizations) ' Simulated Point Process Sample Paths']},...\",\n", - " \"'FontWeight','bold','Fontsize',14,'FontName','Arial');\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"subplot(2,2,1);lambda.plot;\",\n", - " \"title({'Simulated Conditional Intensity Function (CIF)'},...\",\n", - " \"'FontWeight','bold','FontSize',14,'FontName','Arial');\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"hy=get(gca,'YLabel');\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',14,'FontWeight','bold');\",\n", - " \"x = load(fullfile(psthDir,'Results.mat'));\",\n", - " \"numTrials = x.Results.Data.Spike_times_STC.balanced_SUA.Nr_trials;\",\n", - " \"cellNum=6; clear nst;\",\n", - " \"for i=1:numTrials\",\n", - " \"spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};\",\n", - " \"nst{i} = nspikeTrain(spikeTimes{i});\",\n", - " \"nst{i}.setName(num2str(cellNum));\",\n", - " \"end\",\n", - " \"spikeCollReal1=nstColl(nst);\",\n", - " \"spikeCollReal1.setMinTime(0); spikeCollReal1.setMaxTime(2);\",\n", - " \"subplot(2,2,2);spikeCollReal1.plot; set(gca,'YTick',0:2:numTrials,...\",\n", - " \"'YTickLabel',0:2:numTrials);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"title('Response to Moving Visual Stimulus (Neuron 6)',...\",\n", - " \"'FontWeight','bold','Fontsize',14,'FontName','Arial');\",\n", - " \"cellNum=1; clear nst;\",\n", - " \"for i=1:numTrials\",\n", - " \"spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};\",\n", - " \"nst{i} = nspikeTrain(spikeTimes{i});\",\n", - " \"nst{i}.setName(num2str(cellNum));\",\n", - " \"end\",\n", - " \"spikeCollReal2=nstColl(nst);\",\n", - " \"spikeCollReal2.setMinTime(0); spikeCollReal2.setMaxTime(2);\",\n", - " \"subplot(2,2,4);spikeCollReal2.plot;\",\n", - " \"set(gca,'YTick',0:2:numTrials,'YTickLabel',0:2:numTrials);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"title('Response to Moving Visual Stimulus (Neuron 1)','FontWeight',...\",\n", - " \"'bold','Fontsize',14,'FontName','Arial');\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"binsize = .05; %50ms window\",\n", - " \"psth = spikeCollSim.psth(binsize);\",\n", - " \"psthGLM = spikeCollSim.psthGLM(binsize);\",\n", - " \"true = lambda; %rate*delta = expected number of arrivals per bin\",\n", - " \"subplot(2,3,4);\",\n", - " \"h1=true.plot([],{{' ''b'',''Linewidth'',4'}});\",\n", - " \"h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"legend off;\",\n", - " \"h_legend=legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.005 pos(2)+.095 pos(3:4)]);\",\n", - " \"subplot(2,3,1);spikeCollSim.plot;\",\n", - " \"set(gca,'YTick',0:2:spikeCollSim.numSpikeTrains,'YTickLabel',0:2:spikeCollSim.numSpikeTrains);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"subplot(2,3,5);\",\n", - " \"binsize = .05; %50ms window\",\n", - " \"psthReal1 = spikeCollReal1.psth(binsize);\",\n", - " \"psthGLMReal1 = spikeCollReal1.psthGLM(binsize);%,[],[],[],[],[],1000);\",\n", - " \"h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"h2=psthReal1.plot([],{{' ''rx'',''Linewidth'',4'}});\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\",\n", - " \"subplot(2,3,2); spikeCollReal1.plot;\",\n", - " \"set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"subplot(2,3,6);\",\n", - " \"psthReal2 = spikeCollReal2.psth(binsize);\",\n", - " \"psthGLMReal2 = spikeCollReal2.psthGLM(binsize);%,[],[],[],[],[],1000);\",\n", - " \"h3=psthGLMReal2.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"h2=psthReal2.plot([],{{' ''rx'',''Linewidth'',4'}});\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\",\n", - " \"subplot(2,3,3); spikeCollReal2.plot;\",\n", - " \"set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"close all;\",\n", - " \"clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"delta = 0.001; Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"Ts=.001;\",\n", - " \"numRealizations = 50; %Each realization corresponds to a distinct trial\",\n", - " \"for i=1:numRealizations\",\n", - " \"f=2; b1(i)=3*((i)/numRealizations);b0=-3;\",\n", - " \"u = sin(2*pi*f*time);\",\n", - " \"e = zeros(length(time),1); %No Ensemble input\",\n", - " \"stim=Covariate(time',u,'Stimulus','time','s','Voltage',{'sin'});\",\n", - " \"ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\",\n", - " \"mu=b0;\",\n", - " \"histCoeffs=[-4 -1 -.5];\",\n", - " \"H=tf(histCoeffs,[1],Ts,'Variable','z^-1');\",\n", - " \"S=tf([b1(i)],1,Ts,'Variable','z^-1');\",\n", - " \"E=tf([0],1,Ts,'Variable','z^-1');\",\n", - " \"simTypeSelect='binomial'; %Parameters are used to compute\",\n", - " \"[sC, lambdaTemp]=CIF.simulateCIF(mu,H,S,E,stim,ens,1,simTypeSelect);\",\n", - " \"if(i==1)\",\n", - " \"lambda=lambdaTemp; %Store the conditional intensity function\",\n", - " \"else\",\n", - " \"lambda = lambda.merge(lambdaTemp); %Add it to the other realizations\",\n", - " \"end\",\n", - " \"nst{i} = sC.getNST(1); %get the neural spikeTrain from the collection\",\n", - " \"nst{i} = nst{i}.resample(1/delta); %make sure that it is sampled at the current samplerate\",\n", - " \"end\",\n", - " \"spikeColl = nstColl(nst); %Create a collection of the spike trains across trials\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(3,2,[3 4]); spikeColl.plot;\",\n", - " \"set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\",\n", - " \"set(gca,'xtick',0:.1:Tmax,'xtickLabel',0:.1:Tmax); xlabel('');\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"title('Simulated Neural Raster','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',14,'FontWeight','bold');\",\n", - " \"stimData = exp(b0 + u'*b1);\",\n", - " \"if(strcmp(simTypeSelect,'binomial'))\",\n", - " \"stimData = stimData./(1+stimData);\",\n", - " \"end\",\n", - " \"subplot(3,2,1); plot(time,u,'k','LineWidth',3);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Stimulus','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"title('Within Trial Stimulus','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',14,'FontWeight','bold');\",\n", - " \"subplot(3,2,2); plot(1:length(b1),b1,'k','LineWidth',3);\",\n", - " \"xlabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Stimulus Gain','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"title('Across Trial Stimulus Gain','Interpreter','none','FontName',...\",\n", - " \"'Arial','Fontsize',14,'FontWeight','bold');\",\n", - " \"subplot(3,2,[5 6]);\",\n", - " \"imagesc(stimData'./delta); set(gca, 'YDir','normal');\",\n", - " \"set(gca,'xtick',0:100:Tmax/delta,'xtickLabel',0:.1:Tmax);\",\n", - " \"set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"title('True Conditional Intensity Function','Interpreter',...\",\n", - " \"'none','FontName', 'Arial','Fontsize',14,'FontWeight','bold');\",\n", - " \"axis tight;\",\n", - " \"stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"windowTimes=[0:.001:.003];\",\n", - " \"numBasis = 25;\",\n", - " \"spikeColl.resample(1/delta); % Enforce sampleRate\",\n", - " \"spikeColl.setMaxTime(Tmax); % Make all spikeTrains end at time Tmax\",\n", - " \"dN=spikeColl.dataToMatrix'; % Convert the spikeTrains into a matrix\",\n", - " \"dN(dN>1)=1; % One should sample finely enough so there is\",\n", - " \"basisWidth=(spikeColl.maxTime-spikeColl.minTime)/numBasis;\",\n", - " \"if(simTypeSelect==0)\",\n", - " \"fitType='binomial';\",\n", - " \"else\",\n", - " \"fitType='poisson';\",\n", - " \"end\",\n", - " \"if(strcmp(fitType,'binomial'))\",\n", - " \"Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\",\n", - " \"else\",\n", - " \"Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\",\n", - " \"end\",\n", - " \"[psthSig, ~, psthResult] =spikeColl.psthGLM(basisWidth,windowTimes,fitType);\",\n", - " \"gamma0=psthResult.getHistCoeffs';%+.1*randn(size(histCoeffs));\",\n", - " \"gamma0(isnan(gamma0))=-5; % Depending on the amount of data the\",\n", - " \"x0=psthResult.getCoeffs; %The initial estimate for the SSGLM model\",\n", - " \"numVarEstIter=10;\",\n", - " \"Q0 = spikeColl.estimateVarianceAcrossTrials(numBasis,windowTimes,...\",\n", - " \"numVarEstIter,fitType);\",\n", - " \"A=eye(numBasis,numBasis);\",\n", - " \"delta = 1/spikeColl.sampleRate;\",\n", - " \"CompilingHelpFile=1;\",\n", - " \"if(~CompilingHelpFile)\",\n", - " \"Q0d=diag(Q0);\",\n", - " \"neuronName = psthResult.neuronNumber;\",\n", - " \"[xK,WK, WkuFinal,Qhat,gammahat,fitResults,stimulus,stimCIs,logll,...\",\n", - " \"QhatAll,gammahatAll,nIter]=DecodingAlgorithms.PPSS_EMFB(A,Q0d,x0,...\",\n", - " \"dN,fitType,delta,gamma0,windowTimes, numBasis,neuronName);\",\n", - " \"fR = fitResults.toStructure;\",\n", - " \"psthR = psthResult.toStructure;\",\n", - " \"end\",\n", - " \"installPath = which('nSTAT_Install');\",\n", - " \"if isempty(installPath)\",\n", - " \"error('nSTATPaperExamples:MissingInstallPath', ...\",\n", - " \"'Could not locate nSTAT_Install.m on MATLAB path.');\",\n", - " \"end\",\n", - " \"nstatRoot = fileparts(installPath);\",\n", - " \"if exist(nstatRoot,'dir') == 7 && ~strcmp(pwd,nstatRoot)\",\n", - " \"cd(nstatRoot);\",\n", - " \"end\",\n", - " \"addpath(nstatRoot,'-begin');\",\n", - " \"load(fullfile(nstatRoot,'data','SSGLMExampleData.mat'));\",\n", - " \"fitResults = FitResult.fromStructure(fR);\",\n", - " \"psthResult = FitResult.fromStructure(psthR);\",\n", - " \"t=psthResult.mergeResults(fitResults);\",\n", - " \"t.lambda.setDataLabels({'\\\\lambda_{PSTH}','\\\\lambda_{SSGLM}'});\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(2,2,1); t.KSPlot;\",\n", - " \"subplot(2,2,2); t.plotResidual;\",\n", - " \"subplot(2,2,3); t.plotInvGausTrans;\",\n", - " \"subplot(2,2,4); t.plotSeqCorr;\",\n", - " \"S=FitResSummary(t);\",\n", - " \"dAIC=diff(S.AIC)\",\n", - " \"dBIC=diff(S.BIC)\",\n", - " \"dKS =diff(S.KSStats);\",\n", - " \"close all;\",\n", - " \"minTime=0; maxTime = Tmax;\",\n", - " \"stimData = stim.data*b1;\",\n", - " \"if(strcmp(fitType,'poisson'))\",\n", - " \"actStimEffect=exp(stimData + b0)./delta;\",\n", - " \"elseif(strcmp(fitType,'binomial'))\",\n", - " \"actStimEffect=exp(stimData + b0)./(1+exp(stimData + b0))./delta;\",\n", - " \"end\",\n", - " \"if(~isempty(numBasis))\",\n", - " \"basisWidth = (maxTime-minTime)/numBasis;\",\n", - " \"sampleRate=1/delta;\",\n", - " \"unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,minTime,...\",\n", - " \"maxTime,sampleRate);\",\n", - " \"basisMat = unitPulseBasis.data;\",\n", - " \"end\",\n", - " \"if(strcmp(fitType,'poisson'))\",\n", - " \"estStimEffect=exp(basisMat*xK)./delta;\",\n", - " \"elseif(strcmp(fitType,'binomial'))\",\n", - " \"estStimEffect=exp(basisMat*xK)./(1+exp(basisMat*xK))./delta;\",\n", - " \"end\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\",\n", - " \"subplot(3,1,[1 2 3]);\",\n", - " \"lighting gouraud\",\n", - " \"surf((1:length(b1))',stim.time,actStimEffect,'FaceAlpha',0.1,...\",\n", - " \"'EdgeAlpha',0.1,'AlphaData',0.1);\",\n", - " \"hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\",\n", - " \"hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\",\n", - " \"set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),...\",\n", - " \"'FaceAlpha',0.5,'EdgeAlpha',0.1,'AlphaData',0.5); %xlabel('Trial [k]'); ylabel('time [s]'); zlabel('Stimulus Effect');\",\n", - " \"set(gca,'YDir','reverse');\",\n", - " \"set(gca,'ytick',0:.1:Tmax,'ytickLabel',0:.1:Tmax);\",\n", - " \"title('SSGLM Estimated vs. Actual Stimulus Effect','FontWeight','bold',...\",\n", - " \"'Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"close all;\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\",\n", - " \"subplot(3,1,1);\",\n", - " \"lighting gouraud\",\n", - " \"mesh((1:length(b1))',stim.time,actStimEffect);\",\n", - " \"hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\",\n", - " \"zlabel('Stimulus Effect [spikes/sec]'); hold all;\",\n", - " \"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('True Stimulus Effect','FontWeight','bold',...\",\n", - " \"'Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set(gca,'ytick',[],'ytickLabel',[]);\",\n", - " \"CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];\",\n", - " \"view(gca,[90 -90]);\",\n", - " \"subplot(3,1,2);\",\n", - " \"lighting gouraud\",\n", - " \"mesh((1:length(b1))',stim.time,repmat(psthSig.data, [1 numRealizations]));\",\n", - " \"hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\",\n", - " \"hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\",\n", - " \"set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('PSTH Estimated Stimulus Effect','FontWeight','bold',...\",\n", - " \"'Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set(gca,'ytick',[],'ytickLabel',[]);\",\n", - " \"CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];\",\n", - " \"view(gca,[90 -90]);\",\n", - " \"subplot(3,1,3);\",\n", - " \"lighting gouraud\",\n", - " \"mesh((1:length(b1))',stim.time,estStimEffect);\",\n", - " \"xlabel('Trial [k]'); ylabel('time [s]');\",\n", - " \"zlabel('Stimulus Effect [spikes/sec]'); hold all;\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); hz=get(gca,'ZLabel');\",\n", - " \"set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('SSGLM Estimated Stimulus Effect','FontWeight','bold',...\",\n", - " \"'Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set(gca,'ytick',[],'ytickLabel',[]);\",\n", - " \"set(gca, 'YDir','normal')\",\n", - " \"view(gca,[90 -90]);\",\n", - " \"echo off;\",\n", - " \"close all;\",\n", - " \"minTime=0; maxTime = Tmax;\",\n", - " \"if(~isempty(numBasis))\",\n", - " \"basisWidth = (maxTime-minTime)/numBasis;\",\n", - " \"sampleRate=1/delta;\",\n", - " \"unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,...\",\n", - " \"minTime,maxTime,sampleRate);\",\n", - " \"basisMat = unitPulseBasis.data;\",\n", - " \"end\",\n", - " \"t0=0; tf=Tmax;\",\n", - " \"[spikeRateBinom, ProbMat,sigMat]=DecodingAlgorithms.computeSpikeRateCIs(xK,...\",\n", - " \"WkuFinal,dN,t0,tf,fitType,delta,gammahat,windowTimes);\",\n", - " \"lt=find(sigMat(1,:)==1,1,'first');\",\n", - " \"display(['The learning trial (compared to the first trial) is trial #' ...\",\n", - " \"num2str(find(sigMat(1,:)==1,1,'first'))]);\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(2,3,1);\",\n", - " \"spikeRateBinom.setName(['(' num2str(Tmax) '-0)^-1*\\\\Lambda(0,' ...\",\n", - " \"num2str(Tmax) ')']);\",\n", - " \"spikeRateBinom.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"v=axis;\",\n", - " \"plot(lt*[1;1],v(3:4),'r','Linewidth',2);\",\n", - " \"hx=xlabel('Trial [k]','Interpreter','none'); hold all;\",\n", - " \"hy=ylabel('Average Firing Rate [spikes/sec]','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title(['Learning Trial:' num2str(lt)],'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"h=subplot(2,3,[2 3 5 6]);\",\n", - " \"K=size(dN,1);\",\n", - " \"colormap(flipud(gray));\",\n", - " \"imagesc(ProbMat); hold on;\",\n", - " \"for k=1:K\",\n", - " \"for m=(k+1):K\",\n", - " \"if(sigMat(k,m)==1)\",\n", - " \"plot3(m,k,1,'r*'); hold on;\",\n", - " \"end\",\n", - " \"end\",\n", - " \"end\",\n", - " \"set(h,'XAxisLocation','top','YAxisLocation','right');\",\n", - " \"hx=xlabel('Trial Number','Interpreter','none'); hold all;\",\n", - " \"hy=ylabel('Trial Number','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"subplot(2,3,4)\",\n", - " \"stim1 = Covariate(time, basisMat*stimulus(:,1),'Trial1','time','s',...\",\n", - " \"'spikes/sec');\",\n", - " \"temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,1,:)));\",\n", - " \"stim1.setConfInterval(temp);\",\n", - " \"stimlt = Covariate(time, basisMat*stimulus(:,lt),'Trial1','time','s',...\",\n", - " \"'spikes/sec');\",\n", - " \"temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt,:)));\",\n", - " \"temp.setColor('r');\",\n", - " \"stimlt.setConfInterval(temp);\",\n", - " \"stimltm1 = Covariate(time, basisMat*stimulus(:,lt-1),'Trial1','time','s',...\",\n", - " \"'spikes/sec');\",\n", - " \"temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt-1,:)));\",\n", - " \"temp.setColor('r');\",\n", - " \"stimltm1.setConfInterval(temp);\",\n", - " \"h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}}); hold all;\",\n", - " \"h2=stimlt.plot([],{{' ''r'',''Linewidth'',4'}});\",\n", - " \"hx=xlabel('time [s]','Interpreter','none'); hold all;\",\n", - " \"hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title({'Learning Trial Vs. Baseline Trial';'with 95% CIs'},'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"h_legend=legend([h1(1) h2(1)],'\\\\lambda_{1}(t)',['\\\\lambda_{' num2str(lt) '}(t)']);\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.03 pos(2)+.01 pos(3:4)]);\",\n", - " \"close all;\",\n", - " \"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\",\n", - " \"exampleCell = [2 21 25 49];\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9]);\",\n", - " \"for i=1:length(exampleCell)\",\n", - " \"subplot(2,2,i);\",\n", - " \"h1=plot(x,y,'b','Linewidth',.5); hold on;\",\n", - " \"h2=plot(neuron{exampleCell(i)}.xN,neuron{exampleCell(i)}.yN,'r.',...\",\n", - " \"'MarkerSize',7);\",\n", - " \"hx=xlabel('X Position'); hy=ylabel('Y Position');\",\n", - " \"title(['Cell#' num2str(exampleCell(i))],'FontWeight','bold',...\",\n", - " \"'Fontsize',12,'FontName','Arial');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"set(gca,'xTick',-1:.5:1,'yTick',-1:.5:1); axis square;\",\n", - " \"if(i==4)\",\n", - " \"h_legend = legend([h1 h2],'Animal Path',...\",\n", - " \"'Location at time of spike');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.09 pos(2)+.06 pos(3:4)]);\",\n", - " \"end\",\n", - " \"end\",\n", - " \"numAnimals=2;\",\n", - " \"CompilingHelpFile=1;\",\n", - " \"if(~CompilingHelpFile)\",\n", - " \"for n=1:numAnimals\",\n", - " \"clear x y neuron time nst tc tcc z;\",\n", - " \"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\",\n", - " \"for i=1:length(neuron)\",\n", - " \"nst{i} = nspikeTrain(neuron{i}.spikeTimes);\",\n", - " \"end\",\n", - " \"[theta,r] = cart2pol(x,y);\",\n", - " \"cnt=0;\",\n", - " \"for l=0:3\",\n", - " \"for m=-l:l\",\n", - " \"if(~any(mod(l-m,2))) % otherwise the polynomial = 0\",\n", - " \"cnt = cnt+1;\",\n", - " \"z(:,cnt) = zernfun(l,m,r,theta,'norm');\",\n", - " \"end\",\n", - " \"end\",\n", - " \"end\",\n", - " \"delta=min(diff(time));\",\n", - " \"sampleRate = round(1/delta);\",\n", - " \"baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\",\n", - " \"{'mu'});\",\n", - " \"zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\",\n", - " \"'z4','z5','z6','z7','z8','z9','z10'});\",\n", - " \"gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\",\n", - " \"'s','m',{'x','y','x^2','y^2','x*y'});\",\n", - " \"covarColl = CovColl({baseline,gaussian,zernike});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\",\n", - " \"'x','y','x^2','y^2','x*y'}},sampleRate,[]);\",\n", - " \"tc{1}.setName('Gaussian');\",\n", - " \"tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\",\n", - " \"'z7','z8','z9','z10'}},sampleRate,[]);\",\n", - " \"tc{2}.setName('Zernike');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"resStruct =FitResult.CellArrayToStructure(results);\",\n", - " \"filename = fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results']);\",\n", - " \"save(filename,'resStruct');\",\n", - " \"end\",\n", - " \"end\",\n", - " \"clear Summary;\",\n", - " \"numAnimals =2;\",\n", - " \"for n=1:numAnimals\",\n", - " \"resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\",\n", - " \"results = FitResult.fromStructure(resData.resStruct);\",\n", - " \"Summary{n} = FitResSummary(results);\",\n", - " \"end\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5]);\",\n", - " \"subplot(1,3,1);\",\n", - " \"maxLength = max([Summary{1}.numNeurons,Summary{2}.numNeurons]);\",\n", - " \"dKS = nan(maxLength, 2);\",\n", - " \"dKS(1:Summary{1}.numNeurons,1) = (Summary{1}.KSStats(:,1)-Summary{1}.KSStats(:,2)) ;\",\n", - " \"dKS(1:Summary{2}.numNeurons,2) = (Summary{2}.KSStats(:,1)-Summary{2}.KSStats(:,2)) ;\",\n", - " \"boxplot(dKS ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\",\n", - " \"title('\\\\Delta KS Statistic','FontWeight','bold','FontSize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"subplot(1,3,2);\",\n", - " \"dAIC = nan(maxLength, 2);\",\n", - " \"dAIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffAIC(1);\",\n", - " \"dAIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffAIC(1);\",\n", - " \"boxplot(dAIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\",\n", - " \"title('\\\\Delta AIC','FontWeight','bold','FontSize',14,'FontName','Arial');\",\n", - " \"subplot(1,3,3);\",\n", - " \"dBIC = nan(maxLength, 2);\",\n", - " \"dBIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffBIC(1);\",\n", - " \"dBIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffBIC(1);\",\n", - " \"boxplot(dBIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline'); %ylabel('\\\\Delta BIC'); %xticklabel_rotate([],45,[],'Fontsize',6);\",\n", - " \"title('\\\\Delta BIC','FontWeight','bold','FontSize',14,'FontName','Arial');\",\n", - " \"close all;\",\n", - " \"[x_new,y_new]=meshgrid(-1:.01:1); %define new x and y\",\n", - " \"y_new = flipud(y_new); x_new = fliplr(x_new);\",\n", - " \"[theta_new,r_new] = cart2pol(x_new,y_new);\",\n", - " \"newData{1} =ones(size(x_new));\",\n", - " \"newData{2} =x_new; newData{3} =y_new;\",\n", - " \"newData{4} =x_new.^2; newData{5} =y_new.^2;\",\n", - " \"newData{6} =x_new.*y_new;\",\n", - " \"idx = r_new<=1;\",\n", - " \"zpoly = cell(1,10);\",\n", - " \"cnt=0;\",\n", - " \"for l=0:3\",\n", - " \"for m=-l:l\",\n", - " \"if(~any(mod(l-m,2)))\",\n", - " \"cnt = cnt+1;\",\n", - " \"temp = nan(size(x_new));\",\n", - " \"temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\",\n", - " \"zpoly{cnt} = temp;\",\n", - " \"end\",\n", - " \"end\",\n", - " \"end\",\n", - " \"for n=1:numAnimals\",\n", - " \"clear lambdaGaussian lambdaZernike;\",\n", - " \"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\",\n", - " \"resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\",\n", - " \"results = FitResult.fromStructure(resData.resStruct);\",\n", - " \"for i=1:length(neuron)\",\n", - " \"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\",\n", - " \"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\",\n", - " \"end\",\n", - " \"for i=1:length(neuron)\",\n", - " \"if(n==1)\",\n", - " \"h4=figure(4);\",\n", - " \"colormap('jet');\",\n", - " \"if(i==1)\",\n", - " \"tb=annotation(h4,'textbox',...\",\n", - " \"[0.283261904761904 0.928571428571418 ...\",\n", - " \"0.392857142857143 0.0595238095238095],...\",\n", - " \"'String',{['Gaussian Place Fields - Animal#' ...\",\n", - " \"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\",\n", - " \"'FontName','Arial','FontWeight','bold','LineStyle',...\",\n", - " \"'none','HorizontalAlignment','center'); hold on;\",\n", - " \"end\",\n", - " \"subplot(7,7,i);\",\n", - " \"elseif(n==2)\",\n", - " \"h6=figure(6);\",\n", - " \"colormap('jet');\",\n", - " \"if(i==1)\",\n", - " \"annotation(h6,'textbox',...\",\n", - " \"[0.283261904761904 0.928571428571418 ...\",\n", - " \"0.392857142857143 0.0595238095238095],...\",\n", - " \"'String',{['Gaussian Place Fields - Animal#' ...\",\n", - " \"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\",\n", - " \"'FontName','Arial','FontWeight','bold','LineStyle',...\",\n", - " \"'none','HorizontalAlignment','center'); hold on;\",\n", - " \"end\",\n", - " \"subplot(6,7,i);\",\n", - " \"end\",\n", - " \"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\",\n", - " \"axis square; set(gca,'xtick',[],'ytick',[]);\",\n", - " \"set(gca, 'Box' , 'off');\",\n", - " \"if(n==1)\",\n", - " \"h5=figure(5);\",\n", - " \"colormap('jet');\",\n", - " \"if(i==1)\",\n", - " \"annotation(h5,'textbox',...\",\n", - " \"[0.303261904761904 0.928571428571418 ...\",\n", - " \"0.392857142857143 0.0595238095238095],...\",\n", - " \"'String',{['Zernike Place Fields - Animal#' ...\",\n", - " \"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\",\n", - " \"'FontName','Arial','FontWeight','bold','LineStyle','none'); hold on;\",\n", - " \"end\",\n", - " \"subplot(7,7,i);\",\n", - " \"elseif(n==2)\",\n", - " \"h7=figure(7);\",\n", - " \"colormap('jet');\",\n", - " \"if(i==1)\",\n", - " \"annotation(h7,'textbox',...\",\n", - " \"[0.303261904761904 0.928571428571418 ...\",\n", - " \"0.392857142857143 0.0595238095238095],...\",\n", - " \"'String',{['Zernike Place Fields - Animal#' ...\",\n", - " \"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\",\n", - " \"'FontName','Arial','FontWeight','bold','LineStyle',...\",\n", - " \"'none','HorizontalAlignment','center'); hold on;\",\n", - " \"end\",\n", - " \"subplot(6,7,i);\",\n", - " \"end\",\n", - " \"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\",\n", - " \"axis square;\",\n", - " \"set(gca,'xtick',[],'ytick',[]);\",\n", - " \"set(gca, 'Box' , 'off');\",\n", - " \"end\",\n", - " \"end\",\n", - " \"clear lambdaGaussian lambdaZernike;\",\n", - " \"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\",\n", - " \"resData = load(fullfile(dataDir,'PlaceCellAnimal1Results.mat'));\",\n", - " \"results = FitResult.fromStructure(resData.resStruct);\",\n", - " \"for i=1:length(neuron)\",\n", - " \"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\",\n", - " \"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\",\n", - " \"end\",\n", - " \"exampleCell = 25;\",\n", - " \"close all;\",\n", - " \"h9=figure(9);\",\n", - " \"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\",\n", - " \"get(h_mesh,'AlphaData');\",\n", - " \"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\",\n", - " \"hold on;\",\n", - " \"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\",\n", - " \"get(h_mesh,'AlphaData');\",\n", - " \"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\",\n", - " \"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position'); ylabel('y position');\",\n", - " \"title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...\",\n", - " \"'Fontsize',12,'FontName','Arial');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"close all; clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"delta = 0.001; Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"numRealizations = 20;\",\n", - " \"f=2; b1=randn(numRealizations,1);b0=log(10*delta)+randn(numRealizations,1);\",\n", - " \"x = sin(2*pi*f*time);\",\n", - " \"clear nst;\",\n", - " \"for i=1:numRealizations\",\n", - " \"expData = exp(b1(i)*x+b0(i));\",\n", - " \"lambdaData = expData./(1+expData);\",\n", - " \"if(i==1)\",\n", - " \"lambda = Covariate(time,lambdaData./delta, ...\",\n", - " \"'\\\\Lambda(t)','time','s','spikes/sec',{'\\\\lambda_{1}'},...\",\n", - " \"{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"else\",\n", - " \"tempLambda = Covariate(time,lambdaData./delta, ...\",\n", - " \"'\\\\Lambda(t)','time','s','spikes/sec',{'\\\\lambda_{1}'},...\",\n", - " \"{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"lambda = lambda.merge(tempLambda);\",\n", - " \"end\",\n", - " \"spikeColl = CIF.simulateCIFByThinningFromLambda(...\",\n", - " \"lambda.getSubSignal(i),1);\",\n", - " \"nst{i} = spikeColl.getNST(1);\",\n", - " \"end\",\n", - " \"spikeColl = nstColl(nst);scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...\",\n", - " \"scrsz(3)*.6 scrsz(4)*.8]);\",\n", - " \"subplot(3,1,1); plot(time,x,'k');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]); ylabel('Stimulus');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('Driving Stimulus','FontWeight','bold',...\",\n", - " \"'FontSize',14,'FontName','Arial');\",\n", - " \"subplot(3,1,2); lambda.plot([],{{' ''k'',''Linewidth'',1'}});\",\n", - " \"legend off;\",\n", - " \"hy=ylabel('Firing Rate [spikes/sec]', 'Interpreter','none');\",\n", - " \"hx=xlabel('','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,...\",\n", - " \"'FontWeight','bold');\",\n", - " \"set(gca,'xtickLabel',[]);\",\n", - " \"title('Conditional Intensity Functions','FontWeight',...\",\n", - " \"'bold','FontSize',14,'FontName','Arial');\",\n", - " \"subplot(3,1,3); spikeColl.plot;\",\n", - " \"set(gca,'ytick',0:10:numRealizations,'ytickLabel',...\",\n", - " \"0:10:numRealizations);\",\n", - " \"xlabel('time [s]','Interpreter','none');\",\n", - " \"ylabel('Cell Number','Interpreter','none');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('Point Process Sample Paths','FontWeight',...\",\n", - " \"'bold','FontSize',14,'FontName','Arial');\",\n", - " \"stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"close all;\",\n", - " \"clear lambdaCIF;\",\n", - " \"spikeColl.resample(1/delta);\",\n", - " \"dN=spikeColl.dataToMatrix;\",\n", - " \"Q=std(stim.data(2:end)-stim.data(1:end-1));\",\n", - " \"Px0=.1; A=1;\",\n", - " \"x0 = x(:,1); yT=x(:,end);\",\n", - " \"Pi0 = eps*eye(size(x0,1),size(x0,1));\",\n", - " \"PiT = eps*eye(size(x0,1),size(x0,1));\",\n", - " \"[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, ...\",\n", - " \"Q, dN',b0,b1','binomial',delta);\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]);\",\n", - " \"zVal=1.96;\",\n", - " \"ciLower = min(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\",\n", - " \"x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\",\n", - " \"ciUpper = max(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\",\n", - " \"x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\",\n", - " \"estimatedStimulus = Covariate(time,x_u(1:end),'\\\\hat{x}(t)','time','s','');\",\n", - " \"CI= ConfidenceInterval(time,[ciLower', ciUpper'],'\\\\hat{x}(t)','time','s','');\",\n", - " \"estimatedStimulus.setConfInterval(CI);\",\n", - " \"hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"hStim=stim.plot([],{{' ''b'',''Linewidth'',4'}});\",\n", - " \"legend off;\",\n", - " \"h_legend=legend([hEst(1) hStim],'Decoded','Actual');\",\n", - " \"set(h_legend,'Interpreter','none');\",\n", - " \"set(h_legend,'FontSize',22);\",\n", - " \"title(['Decoded Stimulus +/- 95% CIs with ' num2str(numRealizations) ' cells'],...\",\n", - " \"'FontWeight','bold','Fontsize',22,'FontName','Arial');\",\n", - " \"xlabel('time [s]','Interpreter','none');\",\n", - " \"ylabel('Stimulus','Interpreter','none');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',22,'FontWeight','bold');\",\n", - " \"close all;\",\n", - " \"clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"q=1e-4;\",\n", - " \"Q=diag([1e-12 1e-12 q q]);\",\n", - " \"delta = .001; % Time increment\",\n", - " \"r=1e-6; % in meters^2\",\n", - " \"p=1e-6; % in meters^2/s^2\",\n", - " \"PiT=diag([r r p p]); % Uncertainty in the target state\",\n", - " \"Pi0=PiT;\",\n", - " \"T=2; % Reach Duration\",\n", - " \"x0 = [0;0;0;0]; % Initial Position and velocities (states)\",\n", - " \"xT = [-.35;.2; 0;0];% Final Target\",\n", - " \"time=0:delta:T; % time vector\",\n", - " \"A=[1 0 delta 0 ; %State transition matrix\",\n", - " \"0 1 0 delta;\",\n", - " \"0 0 1 0 ;\",\n", - " \"0 0 0 1 ];\",\n", - " \"x=zeros(4,length(time));\",\n", - " \"R=chol(Q);\",\n", - " \"L=chol(PiT);\",\n", - " \"for k=1:length(time)\",\n", - " \"if(k==1)\",\n", - " \"x(:,k)=x0;\",\n", - " \"else\",\n", - " \"x(:,k)=A*x(:,k-1)+...\",\n", - " \"delta/(2)*(pi/T)^2*cos(pi*time(k)/T)*[0;0;...\",\n", - " \"xT(1)-x0(1);xT(2)-x0(2)]; %Reach to target model\",\n", - " \"end\",\n", - " \"end\",\n", - " \"xT =x(:,end); % The target generated by the model\",\n", - " \"yT=xT; % Assume we have observed the actual target position with uncertainty PiT\",\n", - " \"Q=diag(var(diff(x,[],2),[],2))*100;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\",\n", - " \"scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(4,2,[1 3]);\",\n", - " \"plot(100*x(1,:),100*x(2,:),'k','Linewidth',2);\",\n", - " \"xlabel('X Position [cm]'); ylabel('Y Position [cm]');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('Reach Path','FontWeight','bold','Fontsize',14,'FontName','Arial');\",\n", - " \"hold on;\",\n", - " \"axis([sort([100*x0(1)+5, 100*xT(1)-5]), sort([100*x0(2)-5, 100*xT(2)+5])]);\",\n", - " \"h1=plot(100*x(1,1),100*x(2,1),'bo','MarkerSize',14);\",\n", - " \"h2=plot(100*x(1,end),100*x(2,end),'ro','MarkerSize',14);\",\n", - " \"legend([h1 h2],'Start','Finish','Location','NorthEast');\",\n", - " \"subplot(4,2,5); h1=plot(time,100*x(1,:),'k','Linewidth',2); hold on;\",\n", - " \"h2=plot(time,100*x(2,:),'k-.','Linewidth',2);\",\n", - " \"h_legend=legend([h1,h2],'x','y','Location','NorthEast');\",\n", - " \"set(h_legend,'FontSize',14)\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\",\n", - " \"hx=xlabel('time [s]'); hy=ylabel('Position [cm]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"subplot(4,2,7);\",\n", - " \"h1=plot(time,100*x(3,:),'k','Linewidth',2); hold on;\",\n", - " \"h2=plot(time,100*x(4,:),'k-.','Linewidth',2);\",\n", - " \"h_legend=legend([h1 h2],'v_x','v_y','Location','NorthEast');\",\n", - " \"xlabel('time [s]');\",\n", - " \"set(h_legend,'FontSize',14);\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\",\n", - " \"hx=xlabel('time [s]'); hy=ylabel('Velocity [cm/s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"gamma=0;\",\n", - " \"windowTimes=[0, 0.001];\",\n", - " \"numCells = 20;\",\n", - " \"bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);\",\n", - " \"phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell\",\n", - " \"phiMaxNorm = (phiMax+pi)./(2*pi);\",\n", - " \"meanMu = log(10*delta); % baseline firing rate -10Hz\",\n", - " \"MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)\",\n", - " \"dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\",\n", - " \"coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta\",\n", - " \"fitType='binomial';\",\n", - " \"clear nst;\",\n", - " \"for i=1:numCells\",\n", - " \"tempData = exp(dataMat*coeffs(i,:)');\",\n", - " \"if(strcmp(fitType,'poisson'))\",\n", - " \"lambdaData = tempData;\",\n", - " \"else\",\n", - " \"lambdaData = tempData./(1+tempData); % Conditional Intensity Function for ith cell\",\n", - " \"end\",\n", - " \"lambda{i}=Covariate(time,lambdaData./delta, ...\",\n", - " \"'\\\\Lambda(t)','time','s','spikes/sec',...\",\n", - " \"{strcat('\\\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\",\n", - " \"lambda{i}=lambda{i}.resample(1/delta);\",\n", - " \"lambdaCIF{i} = CIF([MuCoeffs(i) 0 0 bCoeffs(i,:)],...\",\n", - " \"{'1','x','y','vx','vy'},{'x','y','vx','vy'},fitType);\",\n", - " \"tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1); nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization\",\n", - " \"nst{i}.setName(num2str(i)); % give each cell a unique name\",\n", - " \"subplot(4,2,[6 8]);\",\n", - " \"h2=lambda{i}.plot([],{{' ''k'', ''LineWidth'' ,.5'}});\",\n", - " \"legend off; hold all; % Plot the CIF\",\n", - " \"end\",\n", - " \"title('Neural Conditional Intensity Functions','FontWeight',...\",\n", - " \"'bold','Fontsize',14,'FontName','Arial');\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"spikeColl = nstColl(nst); % Create a neural spike train collection\",\n", - " \"subplot(4,2,[2,4]); spikeColl.plot;\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"title('Neural Raster','FontWeight','bold','Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=ylabel('Cell Number','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"close all;\",\n", - " \"numExamples=20;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\",\n", - " \"scrsz(3)*.6 scrsz(4)*.9]);\",\n", - " \"for k=1:numExamples\",\n", - " \"bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);\",\n", - " \"phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell\",\n", - " \"phiMaxNorm = (phiMax+pi)./(2*pi);\",\n", - " \"meanMu = log(10*delta); % baseline firing rate\",\n", - " \"MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)\",\n", - " \"dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\",\n", - " \"coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta\",\n", - " \"fitType='binomial';\",\n", - " \"clear nst lambda;\",\n", - " \"for i=1:numCells\",\n", - " \"tempData = exp(dataMat*coeffs(i,:)');\",\n", - " \"if(strcmp(fitType,'poisson'))\",\n", - " \"lambdaData = tempData;\",\n", - " \"else\",\n", - " \"lambdaData = tempData./(1+tempData);\",\n", - " \"end\",\n", - " \"lambda{i}=Covariate(time,lambdaData./delta, ...\",\n", - " \"'\\\\Lambda(t)','time','s','spikes/sec',...\",\n", - " \"{strcat('\\\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\",\n", - " \"lambda{i}=lambda{i}.resample(1/delta);\",\n", - " \"tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);\",\n", - " \"nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization\",\n", - " \"nst{i}.setName(num2str(i)); % give each cell a unique name\",\n", - " \"end\",\n", - " \"spikeColl = nstColl(nst); % Create a neural spike train collection\",\n", - " \"dN=spikeColl.dataToMatrix';\",\n", - " \"dN(dN>1)=1; % more than one spike per bin will be treated as one spike. In\",\n", - " \"[C,N] = size(dN); % N time samples, C cells\",\n", - " \"beta=[zeros(2,numCells); bCoeffs'];\",\n", - " \"[x_p, W_p, x_u, W_u,x_uT,W_uT,x_pT,W_pT] = ...\",\n", - " \"DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...\",\n", - " \"MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0, Pi0, yT,PiT,0);\",\n", - " \"[x_pf, W_pf, x_uf, W_uf] = ...\",\n", - " \"DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...\",\n", - " \"MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0);\",\n", - " \"if(k==numExamples)\",\n", - " \"subplot(4,2,1:4);h1=plot(100*x(1,:),100*x(2,:),'k','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"axis([sort([100*x0(1)+5, 100*xT(1)-5]), ...\",\n", - " \"sort([100*x0(2)-5, 100*xT(2)+5])]);\",\n", - " \"title('Estimated vs. Actual Reach Paths',...\",\n", - " \"'FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"end\",\n", - " \"subplot(4,2,1:4);h2=plot(100*x_u(1,:)',100*x_u(2,:)','b'); hold all;\",\n", - " \"subplot(4,2,1:4);h3=plot(100*x_uf(1,:)',100*x_uf(2,:)','g');\",\n", - " \"hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"h1=plot(100*x0(1),100*x0(2),'bo','MarkerSize',10); hold on;\",\n", - " \"h2=plot(100*xT(1),100*xT(2),'ro','MarkerSize',10);\",\n", - " \"legend([h1 h2],'Start','Finish','Location','NorthEast');\",\n", - " \"subplot(4,2,5);\",\n", - " \"h1=plot(time,100*x(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*x_u(1,:)','b');\",\n", - " \"h3=plot(time,100*x_uf(1,:)','g');\",\n", - " \"hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,2,6);\",\n", - " \"h1=plot(time,100*x(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*x_u(2,:)','b');\",\n", - " \"h3=plot(time,100*x_uf(2,:)','g');\",\n", - " \"h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\",\n", - " \"'PPAF','Location','SouthEast');\",\n", - " \"hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"set(h_legend,'FontSize',10)\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)-.63 pos(2)+.23 pos(3:4)]);\",\n", - " \"subplot(4,2,7);\",\n", - " \"h1=plot(time,100*x(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*x_u(3,:)','b');\",\n", - " \"h3=plot(time,100*x_uf(3,:)','g');\",\n", - " \"hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,2,8);\",\n", - " \"h1=plot(time,100*x(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*x_u(4,:)','b');\",\n", - " \"h3=plot(time,100*x_uf(4,:)','g');\",\n", - " \"hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"end\",\n", - " \"clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"close all;\",\n", - " \"delta=0.001;\",\n", - " \"Tmax=2;\",\n", - " \"time=0:delta:Tmax;\",\n", - " \"A{2} = [1 0 delta 0 delta^2/2 0;\",\n", - " \"0 1 0 delta 0 delta^2/2;\",\n", - " \"0 0 1 0 delta 0;\",\n", - " \"0 0 0 1 0 delta;\",\n", - " \"0 0 0 0 1 0;\",\n", - " \"0 0 0 0 0 1];\",\n", - " \"A{1} = [1 0 0 0 0 0;\",\n", - " \"0 1 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0];\",\n", - " \"A{1} = [1 0;\",\n", - " \"0 1];\",\n", - " \"Px0{2} =1e-6*eye(6,6);\",\n", - " \"Px0{1} =1e-6*eye(2,2);\",\n", - " \"minCovVal = 1e-12;\",\n", - " \"covVal = 1e-3;\",\n", - " \"Q{2}=[minCovVal 0 0 0 0 0;\",\n", - " \"0 minCovVal 0 0 0 0;\",\n", - " \"0 0 minCovVal 0 0 0;\",\n", - " \"0 0 0 minCovVal 0 0;\",\n", - " \"0 0 0 0 covVal 0;\",\n", - " \"0 0 0 0 0 covVal];\",\n", - " \"Q{1}=minCovVal*eye(2,2);\",\n", - " \"mstate = zeros(1,length(time));\",\n", - " \"ind{1}=1:2;\",\n", - " \"ind{2}=1:6;\",\n", - " \"X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));\",\n", - " \"p_ij = [.998 .002;\",\n", - " \".001 .999];\",\n", - " \"for i = 1:length(time)\",\n", - " \"if(i==1)\",\n", - " \"mstate(i) = 1;\",\n", - " \"else\",\n", - " \"if(rand(1,1)1)=1; %Avoid more than 1 spike per bin.\",\n", - " \"Mu0=.5*ones(size(p_ij,1),1);\",\n", - " \"clear x0 yT clear Pi0 PiT;\",\n", - " \"x0{1} = X(ind{1},1);\",\n", - " \"yT{1} = X(ind{1},end);\",\n", - " \"Pi0 = Px0;\",\n", - " \"PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));\",\n", - " \"x0{2} = X(ind{2},1);\",\n", - " \"yT{2} = X(ind{2},end);\",\n", - " \"PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));\",\n", - " \"[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...\",\n", - " \"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\",\n", - " \"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\",\n", - " \"[S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...\",\n", - " \"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\",\n", - " \"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0);\",\n", - " \"X_estAll(:,:,n) = X_est;\",\n", - " \"X_estNTAll(:,:,n) = X_estNT;\",\n", - " \"S_estAll(n,:)=S_est;\",\n", - " \"S_estNTAll(n,:)=S_estNT;\",\n", - " \"MU_estAll(:,:,n)=MU_est;\",\n", - " \"MU_estNTAll(:,:,n) = MU_estNT;\",\n", - " \"subplot(4,3,[1 4]);\",\n", - " \"plot(time,mstate,'k','LineWidth',3); hold all;\",\n", - " \"plot(time,S_est,'b-.','Linewidth',.5);\",\n", - " \"plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\",\n", - " \"axis([v(1) v(2) 0.5 2.5]);\",\n", - " \"subplot(4,3,[7 10]);\",\n", - " \"plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\",\n", - " \"plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\",\n", - " \"axis([min(time) max(time) 0 1.1]);\",\n", - " \"subplot(4,3,[2 3 5 6]);\",\n", - " \"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\",\n", - " \"h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\",\n", - " \"h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\",\n", - " \"subplot(4,3,8);\",\n", - " \"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(1,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(1,:)','g-.');\",\n", - " \"subplot(4,3,9);\",\n", - " \"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(2,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(2,:)','g-.');\",\n", - " \"subplot(4,3,11);\",\n", - " \"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(3,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(3,:)','g-.');\",\n", - " \"subplot(4,3,12);\",\n", - " \"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(4,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(4,:)','g-.');\",\n", - " \"end\",\n", - " \"subplot(4,3,[1 4]);\",\n", - " \"hold all;\",\n", - " \"plot(time,mstate,'k','LineWidth',3);\",\n", - " \"plot(time,mean(S_estAll),'b','LineWidth',3);\",\n", - " \"plot(time,mean(S_estNTAll),'g','LineWidth',3);\",\n", - " \"set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\",\n", - " \"hy=ylabel('state'); hx=xlabel('time [s]');\",\n", - " \"set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\",\n", - " \"'Interpreter','none');\",\n", - " \"title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\",\n", - " \"12,'FontName','Arial');\",\n", - " \"subplot(4,3,[7 10]);\",\n", - " \"plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"axis([min(time) max(time) 0 1.1]);\",\n", - " \"hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Probability of State','FontWeight','bold','Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"subplot(4,3,[2 3 5 6]);\",\n", - " \"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\",\n", - " \"mXestAll=mean(100*X_estAll,3);\",\n", - " \"mXestNTAll=mean(100*X_estNTAll,3);\",\n", - " \"plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\",\n", - " \"plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\",\n", - " \"hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\",\n", - " \"h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\",\n", - " \"legend([h1 h2],'Start','Finish','Location','NorthEast');\",\n", - " \"title('Estimated vs. Actual Reach Path','FontWeight','bold',...\",\n", - " \"'Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,8);\",\n", - " \"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,9);\",\n", - " \"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\",\n", - " \"h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\",\n", - " \"'PPAF','Location','SouthEast');\",\n", - " \"hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"set(h_legend,'FontSize',10)\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\",\n", - " \"subplot(4,3,11);\",\n", - " \"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,12);\",\n", - " \"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"parity = struct();\",\n", - " \"if exist('numCells','var')\",\n", - " \"parity.num_cells = numCells;\",\n", - " \"end\",\n", - " \"if exist('numRealizations','var')\",\n", - " \"parity.num_realizations = numRealizations;\",\n", - " \"end\",\n", - " \"function [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs()\",\n", - " \"candidateRoots = {};\",\n", - " \"scriptPath = mfilename('fullpath');\",\n", - " \"if ~isempty(scriptPath)\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(scriptPath)));\",\n", - " \"end\",\n", - " \"paperPath = which('nSTATPaperExamples');\",\n", - " \"if ~isempty(paperPath)\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(paperPath)));\",\n", - " \"end\",\n", - " \"installPath = which('nSTAT_Install');\",\n", - " \"if ~isempty(installPath)\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, fileparts(installPath));\",\n", - " \"end\",\n", - " \"try\",\n", - " \"activeFile = matlab.desktop.editor.getActiveFilename;\",\n", - " \"catch\",\n", - " \"activeFile = '';\",\n", - " \"end\",\n", - " \"if ~isempty(activeFile)\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(activeFile)));\",\n", - " \"end\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, pwd);\",\n", - " \"nSTATDir = '';\",\n", - " \"for iRoot = 1:numel(candidateRoots)\",\n", - " \"candidateDataDir = fullfile(candidateRoots{iRoot}, 'data');\",\n", - " \"if exist(candidateDataDir, 'dir') == 7\",\n", - " \"nSTATDir = candidateRoots{iRoot};\",\n", - " \"break;\",\n", - " \"end\",\n", - " \"end\",\n", - " \"if isempty(nSTATDir)\",\n", - " \"error('nSTATPaperExamples:MissingInstallPath', ...\",\n", - " \"['Could not resolve the nSTAT root path. Checked roots derived from ', ...\",\n", - " \"'mfilename, which(''nSTATPaperExamples''), which(''nSTAT_Install''), ', ...\",\n", - " \"'the active editor file, and pwd.']);\",\n", - " \"end\",\n", - " \"dataDir = fullfile(nSTATDir,'data');\",\n", - " \"mEPSCDir = fullfile(dataDir,'mEPSCs');\",\n", - " \"explicitStimulusDir = fullfile(dataDir,'Explicit Stimulus');\",\n", - " \"psthDir = fullfile(dataDir,'PSTH');\",\n", - " \"placeCellDataDir = fullfile(dataDir,'Place Cells');\",\n", - " \"if exist(dataDir,'dir') ~= 7\",\n", - " \"error('nSTATPaperExamples:MissingDataDir', ...\",\n", - " \"'Could not find local nSTAT data folder at %s', dataDir);\",\n", - " \"end\",\n", - " \"end\",\n", - " \"function roots = appendCandidateRoot(roots, startDir)\",\n", - " \"if isempty(startDir)\",\n", - " \"return;\",\n", - " \"end\",\n", - " \"thisDir = startDir;\",\n", - " \"while true\",\n", - " \"if ~any(strcmp(roots, thisDir))\",\n", - " \"roots{end+1} = thisDir; %#ok\",\n", - " \"end\",\n", - " \"parentDir = fileparts(thisDir);\",\n", - " \"if strcmp(parentDir, thisDir)\",\n", - " \"break;\",\n", - " \"end\",\n", - " \"thisDir = parentDir;\",\n", - " \"end\",\n", - " \"end\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for nSTATPaperExamples.\")\n", - "\n", - "# nSTATPaperExamples: multi-section paper-style workflow summary.\n", - "import json\n", - "from pathlib import Path\n", - "from scipy.io import loadmat\n", - "from nstat.compat.matlab import Analysis, DecodingAlgorithms, nspikeTrain, nstColl\n", - "\n", - "\n", - "def resolve_repo_root() -> Path:\n", - " candidates = [Path.cwd().resolve()]\n", - " candidates.append(candidates[0].parent)\n", - " candidates.append(candidates[1].parent)\n", - " for root in candidates:\n", - " if (root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\").exists():\n", - " return root\n", - " return candidates[0]\n", - "\n", - "\n", - "repo_root = resolve_repo_root()\n", - "fixture_root = repo_root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\"\n", - "shared_root = repo_root / \"data\" / \"shared\" / \"matlab_gold_20260302\"\n", - "mEPSCDir = shared_root / \"mEPSCs\"\n", - "\n", - "# -------------------------------------------------------------------------\n", - "# Experiment 1: mEPSCs - Constant Magnesium Concentration.\n", - "# MATLAB reference:\n", - "# - epsc2.txt import\n", - "# - constant baseline fit\n", - "# - raster + estimated rate plots\n", - "# -------------------------------------------------------------------------\n", - "sampleRate = 1000.0\n", - "delta = 1.0 / sampleRate\n", - "\n", - "epsc2 = np.genfromtxt(mEPSCDir / \"epsc2.txt\", skip_header=1)\n", - "spikeTimes_const = np.asarray(epsc2[:, 1], dtype=float) / sampleRate\n", - "nstConst = nspikeTrain(spikeTimes_const)\n", - "spikeCollConst = nstColl([nstConst])\n", - "\n", - "timeConst = np.arange(0.0, float(spikeTimes_const.max()) + delta, delta)\n", - "bin_edges_const = np.append(timeConst, timeConst[-1] + delta)\n", - "dN_const, _ = np.histogram(spikeTimes_const, bins=bin_edges_const)\n", - "\n", - "X_const = np.ones((dN_const.size, 1), dtype=float)\n", - "fitConst = Analysis.fitGLM(X=X_const, y=dN_const.astype(float), fitType=\"poisson\", dt=delta)\n", - "lambdaConst = np.asarray(fitConst.predict(X_const), dtype=float).reshape(-1) / delta\n", - "lambdaConstMean = float(np.mean(lambdaConst))\n", - "\n", - "fig1, axes1 = plt.subplots(2, 2, figsize=(12.0, 8.2))\n", - "axes1[0, 0].eventplot([spikeTimes_const], colors=\"k\", linelengths=0.9)\n", - "axes1[0, 0].set_title(\"Constant Mg: neural raster\")\n", - "axes1[0, 0].set_xlabel(\"time [s]\")\n", - "axes1[0, 0].set_ylabel(\"mEPSCs\")\n", - "\n", - "axes1[0, 1].plot(timeConst, lambdaConst, \"b\", linewidth=1.5, label=\"GLM constant-rate estimate\")\n", - "axes1[0, 1].axhline(lambdaConstMean, color=\"r\", linestyle=\"--\", linewidth=1.0, label=\"mean rate\")\n", - "axes1[0, 1].set_title(\"Constant Mg: estimated rate\")\n", - "axes1[0, 1].set_xlabel(\"time [s]\")\n", - "axes1[0, 1].set_ylabel(\"rate [spikes/sec]\")\n", - "axes1[0, 1].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "isi_const = np.diff(spikeTimes_const)\n", - "axes1[1, 0].hist(isi_const, bins=60, color=\"0.35\", alpha=0.85)\n", - "axes1[1, 0].set_title(\"Constant Mg: ISI histogram\")\n", - "axes1[1, 0].set_xlabel(\"inter-spike interval [s]\")\n", - "axes1[1, 0].set_ylabel(\"count\")\n", - "\n", - "axes1[1, 1].plot(np.arange(dN_const.size) * delta, dN_const, \"k\", linewidth=0.8)\n", - "axes1[1, 1].set_title(\"Constant Mg: binned spike train\")\n", - "axes1[1, 1].set_xlabel(\"time [s]\")\n", - "axes1[1, 1].set_ylabel(\"spike count / bin\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# -------------------------------------------------------------------------\n", - "# Experiment 1: mEPSCs - Varying Magnesium Concentration (piecewise model).\n", - "# MATLAB reference:\n", - "# - washout1/washout2 merge\n", - "# - ad-hoc three baseline epochs\n", - "# - compare constant vs piecewise AIC/BIC\n", - "# -------------------------------------------------------------------------\n", - "washout1 = np.genfromtxt(mEPSCDir / \"washout1.txt\", skip_header=1)\n", - "washout2 = np.genfromtxt(mEPSCDir / \"washout2.txt\", skip_header=1)\n", - "\n", - "spikeTimes1 = 260.0 + np.asarray(washout1[:, 1], dtype=float) / sampleRate\n", - "spikeTimes2 = np.sort(np.asarray(washout2[:, 1], dtype=float)) / sampleRate + 745.0\n", - "spikeTimes_var = np.concatenate([spikeTimes1, spikeTimes2])\n", - "nstVar = nspikeTrain(spikeTimes_var)\n", - "spikeCollVar = nstColl([nstVar])\n", - "\n", - "timeVar = np.arange(260.0, float(spikeTimes_var.max()) + delta, delta)\n", - "bin_edges_var = np.append(timeVar, timeVar[-1] + delta)\n", - "dN_var, _ = np.histogram(spikeTimes_var, bins=bin_edges_var)\n", - "\n", - "timeInd1 = int(np.searchsorted(timeVar, 495.0, side=\"right\"))\n", - "timeInd2 = int(np.searchsorted(timeVar, 765.0, side=\"right\"))\n", - "\n", - "constantRate = np.ones(timeVar.size, dtype=float)\n", - "rate1 = np.zeros(timeVar.size, dtype=float)\n", - "rate2 = np.zeros(timeVar.size, dtype=float)\n", - "rate3 = np.zeros(timeVar.size, dtype=float)\n", - "rate1[:timeInd1] = 1.0\n", - "rate2[timeInd1:timeInd2] = 1.0\n", - "rate3[timeInd2:] = 1.0\n", - "\n", - "X_var_const = constantRate.reshape(-1, 1)\n", - "X_var_piecewise = np.column_stack([rate1, rate2, rate3])\n", - "fitVarConst = Analysis.fitGLM(X=X_var_const, y=dN_var.astype(float), fitType=\"poisson\", dt=delta)\n", - "fitVarPiecewise = Analysis.fitGLM(X=X_var_piecewise, y=dN_var.astype(float), fitType=\"poisson\", dt=delta)\n", - "lambdaVarConst = np.asarray(fitVarConst.predict(X_var_const), dtype=float).reshape(-1) / delta\n", - "lambdaVarPiecewise = np.asarray(fitVarPiecewise.predict(X_var_piecewise), dtype=float).reshape(-1) / delta\n", - "\n", - "dAIC_piecewise = float(fitVarConst.aic() - fitVarPiecewise.aic())\n", - "dBIC_piecewise = float(fitVarConst.bic() - fitVarPiecewise.bic())\n", - "\n", - "fig2, axes2 = plt.subplots(2, 2, figsize=(12.2, 8.4))\n", - "axes2[0, 0].eventplot([spikeTimes_var], colors=\"k\", linelengths=0.9)\n", - "axes2[0, 0].axvline(495.0, color=\"r\", linewidth=1.5)\n", - "axes2[0, 0].axvline(765.0, color=\"r\", linewidth=1.5)\n", - "axes2[0, 0].set_title(\"Varying Mg: neural raster + epoch boundaries\")\n", - "axes2[0, 0].set_xlabel(\"time [s]\")\n", - "axes2[0, 0].set_ylabel(\"mEPSCs\")\n", - "\n", - "axes2[0, 1].plot(timeVar, lambdaVarConst, \"b\", linewidth=1.1, label=\"constant baseline\")\n", - "axes2[0, 1].plot(timeVar, lambdaVarPiecewise, \"g\", linewidth=1.1, label=\"piecewise baseline\")\n", - "axes2[0, 1].set_title(\"Varying Mg: model rates\")\n", - "axes2[0, 1].set_xlabel(\"time [s]\")\n", - "axes2[0, 1].set_ylabel(\"rate [spikes/sec]\")\n", - "axes2[0, 1].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "axes2[1, 0].plot(timeVar, dN_var, \"0.25\", linewidth=0.7)\n", - "axes2[1, 0].set_title(\"Varying Mg: binned spike train\")\n", - "axes2[1, 0].set_xlabel(\"time [s]\")\n", - "axes2[1, 0].set_ylabel(\"spike count / bin\")\n", - "\n", - "axes2[1, 1].bar([\"ΔAIC\", \"ΔBIC\"], [dAIC_piecewise, dBIC_piecewise], color=[\"tab:blue\", \"tab:green\"])\n", - "axes2[1, 1].axhline(0.0, color=\"k\", linewidth=0.8)\n", - "axes2[1, 1].set_title(\"Piecewise minus constant model quality\")\n", - "axes2[1, 1].set_ylabel(\"improvement (>0 favors piecewise)\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# -------------------------------------------------------------------------\n", - "# Experiment 5 proxies: stimulus decoding + place-cell decoding + PSTH CI.\n", - "# These remain tied to deterministic MATLAB-gold fixtures for numerical parity.\n", - "# -------------------------------------------------------------------------\n", - "m_pp = loadmat(fixture_root / \"PPSimExample_gold.mat\")\n", - "X_pp = np.asarray(m_pp[\"X\"], dtype=float)\n", - "y_pp = np.asarray(m_pp[\"y\"], dtype=float).reshape(-1)\n", - "dt_pp = float(np.asarray(m_pp[\"dt\"], dtype=float).reshape(-1)[0])\n", - "b_pp = np.asarray(m_pp[\"b\"], dtype=float).reshape(-1)\n", - "expected_rate_pp = np.asarray(m_pp[\"expected_rate\"], dtype=float).reshape(-1)\n", - "\n", - "fit_pp = Analysis.fitGLM(X=X_pp, y=y_pp, fitType=\"poisson\", dt=dt_pp)\n", - "rate_hat_pp = np.asarray(fit_pp.predict(X_pp), dtype=float).reshape(-1)\n", - "coef_pp = np.concatenate([[float(fit_pp.intercept)], np.asarray(fit_pp.coefficients, dtype=float)])\n", - "coef_err_pp = float(np.linalg.norm(coef_pp - b_pp))\n", - "rate_rel_err_pp = float(\n", - " np.mean(np.abs(rate_hat_pp - expected_rate_pp) / np.maximum(np.abs(expected_rate_pp), 1e-12))\n", - ")\n", - "\n", - "m_dec = loadmat(fixture_root / \"DecodingExampleWithHist_gold.mat\")\n", - "spike_counts = np.asarray(m_dec[\"spike_counts\"], dtype=float)\n", - "tuning = np.asarray(m_dec[\"tuning\"], dtype=float)\n", - "transition = np.asarray(m_dec[\"transition\"], dtype=float)\n", - "expected_decoded = np.asarray(m_dec[\"expected_decoded\"], dtype=int).reshape(-1)\n", - "expected_post = np.asarray(m_dec[\"expected_posterior\"], dtype=float)\n", - "\n", - "decoded_hist, posterior_hist = DecodingAlgorithms.decodeStatePosterior(\n", - " spike_counts=spike_counts, tuning_rates=tuning, transition=transition\n", - ")\n", - "decode_match = float(np.mean(decoded_hist == expected_decoded))\n", - "posterior_max_abs = float(np.max(np.abs(posterior_hist - expected_post)))\n", - "\n", - "m_pc = loadmat(fixture_root / \"HippocampalPlaceCellExample_gold.mat\")\n", - "spike_counts_pc = np.asarray(m_pc[\"spike_counts_pc\"], dtype=float)\n", - "tuning_curves = np.asarray(m_pc[\"tuning_curves\"], dtype=float)\n", - "expected_weighted = np.asarray(m_pc[\"expected_decoded_weighted\"], dtype=float).reshape(-1)\n", - "\n", - "decoded_weighted = DecodingAlgorithms.decodeWeightedCenter(spike_counts_pc, tuning_curves)\n", - "weighted_mae = float(np.mean(np.abs(decoded_weighted - expected_weighted)))\n", - "weighted_max_err = float(np.max(np.abs(decoded_weighted - expected_weighted)))\n", - "\n", - "m_psth = loadmat(fixture_root / \"PSTHEstimation_gold.mat\")\n", - "spike_matrix_psth = np.asarray(m_psth[\"spike_matrix_psth\"], dtype=float)\n", - "alpha_psth = float(np.asarray(m_psth[\"alpha_psth\"], dtype=float).reshape(-1)[0])\n", - "expected_rate_psth = np.asarray(m_psth[\"expected_rate_psth\"], dtype=float).reshape(-1)\n", - "expected_prob_psth = np.asarray(m_psth[\"expected_prob_psth\"], dtype=float)\n", - "expected_sig_psth = np.asarray(m_psth[\"expected_sig_psth\"], dtype=int)\n", - "\n", - "rate_psth, prob_psth, sig_psth = DecodingAlgorithms.computeSpikeRateCIs(\n", - " spike_matrix=spike_matrix_psth, alpha=alpha_psth\n", - ")\n", - "rate_max_abs = float(np.max(np.abs(rate_psth - expected_rate_psth)))\n", - "prob_max_abs = float(np.max(np.abs(prob_psth - expected_prob_psth)))\n", - "sig_mismatch = int(np.sum(np.abs(sig_psth - expected_sig_psth)))\n", - "\n", - "audit_path = fixture_root / \"nSTATPaperExamples_audit_gold.json\"\n", - "audit = json.loads(audit_path.read_text(encoding=\"utf-8\"))\n", - "audit_alignment = str(audit.get(\"alignment_status\", \"\"))\n", - "audit_code_lines = int(audit.get(\"matlab_code_lines\", 0))\n", - "audit_ref_images = int(audit.get(\"matlab_reference_image_count\", 0))\n", - "\n", - "fig3, axes3 = plt.subplots(2, 3, figsize=(13.2, 8.6))\n", - "axes3[0, 0].plot(expected_rate_pp[:1200], \"k\", linewidth=1.0, label=\"MATLAB gold\")\n", - "axes3[0, 0].plot(rate_hat_pp[:1200], \"tab:blue\", linewidth=1.0, label=\"Python fit\")\n", - "axes3[0, 0].set_title(\"Stimulus proxy: GLM rate fit\")\n", - "axes3[0, 0].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "axes3[0, 1].plot(expected_decoded[:180], \"k\", linewidth=1.0, label=\"MATLAB decoded\")\n", - "axes3[0, 1].plot(decoded_hist[:180], \"tab:green\", linewidth=0.9, label=\"Python decoded\")\n", - "axes3[0, 1].set_title(\"Decode-with-history path\")\n", - "axes3[0, 1].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "im0 = axes3[0, 2].imshow(np.abs(posterior_hist - expected_post), aspect=\"auto\", origin=\"lower\", cmap=\"magma\")\n", - "axes3[0, 2].set_title(\"Posterior absolute error\")\n", - "fig3.colorbar(im0, ax=axes3[0, 2], fraction=0.045, pad=0.02)\n", - "\n", - "axes3[1, 0].plot(expected_weighted, \"k\", linewidth=1.0, label=\"MATLAB weighted\")\n", - "axes3[1, 0].plot(decoded_weighted, \"tab:red\", linewidth=0.9, label=\"Python weighted\")\n", - "axes3[1, 0].set_title(\"Place-cell weighted decode\")\n", - "axes3[1, 0].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "field = tuning_curves[6].reshape(5, 8)\n", - "im1 = axes3[1, 1].imshow(field, origin=\"lower\", cmap=\"jet\", aspect=\"auto\")\n", - "axes3[1, 1].set_title(\"Example place field (unit 7)\")\n", - "fig3.colorbar(im1, ax=axes3[1, 1], fraction=0.045, pad=0.02)\n", - "\n", - "im2 = axes3[1, 2].imshow(prob_psth, origin=\"lower\", cmap=\"gray_r\", aspect=\"auto\")\n", - "yy, xx = np.where(sig_psth > 0)\n", - "if xx.size:\n", - " axes3[1, 2].plot(xx, yy, \"r*\", markersize=3)\n", - "axes3[1, 2].set_title(\"Trial significance matrix\")\n", - "fig3.colorbar(im2, ax=axes3[1, 2], fraction=0.045, pad=0.02)\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert lambdaConstMean > 0.0\n", - "assert dAIC_piecewise >= 0.0\n", - "assert dBIC_piecewise >= 0.0\n", - "assert coef_err_pp < 0.7\n", - "assert rate_rel_err_pp < 0.30\n", - "assert decode_match >= 1.0\n", - "assert posterior_max_abs < 1e-9\n", - "assert weighted_mae < 1e-10\n", - "assert weighted_max_err < 1e-10\n", - "assert rate_max_abs < 1e-10\n", - "assert prob_max_abs < 1e-10\n", - "assert sig_mismatch == 0\n", - "assert audit_alignment == \"validated\"\n", - "assert audit_code_lines > 1000\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"const_mean_rate\": float(lambdaConstMean),\n", - " \"dAIC_piecewise\": float(dAIC_piecewise),\n", - " \"dBIC_piecewise\": float(dBIC_piecewise),\n", - " \"coef_error_pp\": float(coef_err_pp),\n", - " \"rate_rel_err_pp\": float(rate_rel_err_pp),\n", - " \"decode_match\": float(decode_match),\n", - " \"weighted_mae\": float(weighted_mae),\n", - " \"psth_rate_max_abs\": float(rate_max_abs),\n", - " \"sig_mismatch\": float(sig_mismatch),\n", - " \"matlab_code_lines\": float(audit_code_lines),\n", - " \"matlab_ref_images\": float(audit_ref_images),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"const_mean_rate\": (0.01, 20000.0),\n", - " \"dAIC_piecewise\": (0.0, 5.0e4),\n", - " \"dBIC_piecewise\": (0.0, 5.0e4),\n", - " \"coef_error_pp\": (0.0, 0.7),\n", - " \"rate_rel_err_pp\": (0.0, 0.30),\n", - " \"decode_match\": (1.0, 1.0),\n", - " \"weighted_mae\": (0.0, 1e-10),\n", - " \"psth_rate_max_abs\": (0.0, 1e-10),\n", - " \"sig_mismatch\": (0.0, 0.0),\n", - " \"matlab_code_lines\": (1000.0, 5000.0),\n", - " \"matlab_ref_images\": (1.0, 1000.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "decoding_1d", - "run_group": "smoke", - "section_count": 43, - "source_helpfile": "nSTATPaperExamples.m", - "topic": "nSTATPaperExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/nSpikeTrainExamples.ipynb b/notebooks/helpfiles/nSpikeTrainExamples.ipynb deleted file mode 100644 index 3354464b..00000000 --- a/notebooks/helpfiles/nSpikeTrainExamples.ipynb +++ /dev/null @@ -1,310 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "edeaf2f0", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/5 for nSpikeTrainExamples: Test the nspikeTrain Class\n", - "\n", - "# % Test the nspikeTrain Class\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: nSpikeTrainExamples\n", - "# Execution group: smoke\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/nSpikeTrainExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"nSpikeTrainExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"nSpikeTrainExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"nSpikeTrainExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"nSpikeTrainExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"nSpikeTrainExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 6\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "446d20bc", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/5 for nSpikeTrainExamples: Example 1: Using the nspikeTrain Class\n", - "\n", - "# % Example 1: Using the nspikeTrain Class\n", - "# Lets create some pseudo data and plot it.\n", - "#\n", - "# MATLAB: spikeTimes = sort(rand(1,100))*1;\n", - "# MATLAB: spikeTimes = unique(round(spikeTimes*10000)./10000); %round off;\n", - "# MATLAB: nst=nspikeTrain(spikeTimes,'n1',.001,0,1);\n", - "# MATLAB: figure; nst.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; nst.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=9, matlab_snippet=\"figure; nst.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSpikeTrainExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 2, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f1530617", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/5 for nSpikeTrainExamples: Section\n", - "\n", - "# %\n", - "# We can now change the signal representation of the nspikeTrain and see\n", - "# what effects it has.\n", - "#\n", - "# 100ms bins from 0 to 10 sec. Actual SignalObj representation of the\n", - "# nspikeTrain is not changed because are using getSigRep\n", - "# MATLAB: figure; nst.resample(1/.1);\n", - "# MATLAB: nst.getSigRep.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; nst.resample(1/.1);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=17, matlab_snippet=\"figure; nst.resample(1/.1);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSpikeTrainExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 3, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "077ce6a3", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/5 for nSpikeTrainExamples: Section\n", - "\n", - "# %\n", - "# 10ms bins from 0 to 10 sec. Actually changing the representation of the\n", - "# signal.\n", - "# MATLAB: figure; nst.resample(1/.01);\n", - "# MATLAB: nst.getSigRep.plot;\n", - "#\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; nst.resample(1/.01);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=23, matlab_snippet=\"figure; nst.resample(1/.01);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSpikeTrainExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 4, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b2eea010", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/5 for nSpikeTrainExamples: Section\n", - "\n", - "# %\n", - "# Get the largest binsize that still maintains a binary signal\n", - "# representation\n", - "# MATLAB: figure; nst.resample(1/nst.getMaxBinSizeBinary);\n", - "# MATLAB: nst.getSigRep.plot;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; nst.resample(1/nst.getMaxBinSizeBinary);\n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=29, matlab_snippet=\"figure; nst.resample(1/nst.getMaxBinSizeBinary);\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSpikeTrainExamples_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 5, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=26, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSpikeTrainExamples_04.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=5 + 5, title=f\"{TOPIC} Figure 005\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=26, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nSpikeTrainExamples_05.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=6 + 5, title=f\"{TOPIC} Figure 006\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"spikeTimes = sort(rand(1,100))*1;\",\n", - " \"spikeTimes = unique(round(spikeTimes*10000)./10000); %round off;\",\n", - " \"nst=nspikeTrain(spikeTimes,'n1',.001,0,1);\",\n", - " \"figure; nst.plot;\",\n", - " \"figure; nst.resample(1/.1);\",\n", - " \"nst.getSigRep.plot;\",\n", - " \"figure; nst.resample(1/.01);\",\n", - " \"nst.getSigRep.plot;\",\n", - " \"figure; nst.resample(1/nst.getMaxBinSizeBinary);\",\n", - " \"nst.getSigRep.plot;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for nSpikeTrainExamples.\")\n", - "\n", - "# nSpikeTrainExamples: spike-train resampling and signal representations.\n", - "from nstat.compat.matlab import nspikeTrain\n", - "spike_times = np.unique(np.round(np.sort(rng.random(100)) * 10000.0) / 10000.0); nst = nspikeTrain(spike_times=spike_times, t_start=0.0, t_end=1.0, name=\"n1\"); n0 = int(nst.getSpikeTimes().size)\n", - "sig_100 = nst.getSigRep(binSize_s=0.1, mode=\"binary\"); nst.resample(100.0); sig_10 = nst.getSigRep(binSize_s=0.01, mode=\"binary\")\n", - "max_bin = float(max(nst.getMaxBinSizeBinary(), 1.0e-3)); nst.resample(1.0 / max_bin); sig_max = nst.getSigRep(binSize_s=max_bin, mode=\"binary\")\n", - "fig, ax = plt.subplots(3, 1, figsize=(9.0, 5.8)); ax[0].step(np.arange(sig_100.size) * 0.1, sig_100, where=\"post\"); ax[0].set_title(\"100 ms\")\n", - "ax[1].step(np.arange(sig_10.size) * 0.01, sig_10, where=\"post\", color=\"tab:green\"); ax[1].set_title(\"10 ms\")\n", - "ax[2].step(np.arange(sig_max.size) * max_bin, sig_max, where=\"post\", color=\"tab:red\"); ax[2].set_title(\"max-bin\"); plt.tight_layout(); plt.show()\n", - "assert n0 > 20\n", - "assert 0.0 < max_bin <= 1.0\n", - "assert sig_10.ndim == 1 and sig_10.size > 10\n", - "CHECKPOINT_METRICS = {\"num_spikes_initial\": float(n0), \"num_spikes_final\": float(nst.getSpikeTimes().size), \"max_bin_size\": float(max_bin)}\n", - "CHECKPOINT_LIMITS = {\"num_spikes_initial\": (20.0, 150.0), \"num_spikes_final\": (1.0, 150.0), \"max_bin_size\": (1.0e-4, 1.0)}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "smoke", - "section_count": 5, - "source_helpfile": "nSpikeTrainExamples.m", - "topic": "nSpikeTrainExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/nstCollExamples.ipynb b/notebooks/helpfiles/nstCollExamples.ipynb deleted file mode 100644 index fb8a372b..00000000 --- a/notebooks/helpfiles/nstCollExamples.ipynb +++ /dev/null @@ -1,309 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "6f9086d8", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/5 for nstCollExamples: Preamble\n", - "\n", - "#\n", - "\n", - "# Python translation bootstrap for this helpfile.\n", - "\n", - "# Topic: nstCollExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/nstCollExamples.md\n", - "\n", - "\n", - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.data_manager import ensure_example_data\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"nstCollExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "DATA_DIR = ensure_example_data(download=True)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "print(f\"Example data directory: {DATA_DIR}\")\n", - "\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "\n", - "def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"nstCollExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"nstCollExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"nstCollExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"nstCollExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 4\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "78a5789c", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 2/5 for nstCollExamples: Test the nstColl Class\n", - "\n", - "# % Test the nstColl Class\n", - "# Create pseudo spike data and create a neural spike collection (nstColl).\n", - "# MATLAB: close all; clear all;\n", - "# MATLAB: for i=1:20\n", - "# MATLAB: spikeTimes = sort(rand(1,100))*1;\n", - "# MATLAB: nst{i}=nspikeTrain(spikeTimes,'',.1);\n", - "# MATLAB: nst{i}.setName(strcat('Neuron',num2str(i)));\n", - "# MATLAB: end\n", - "# MATLAB: spikeColl=nstColl(nst);\n", - "#\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 2\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "988bf604", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 3/5 for nstCollExamples: Section\n", - "\n", - "# %\n", - "# Plot the entire collection at once\n", - "# MATLAB: figure; spikeColl.plot;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; spikeColl.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=14, matlab_snippet=\"figure; spikeColl.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nstCollExamples.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=1 + 3, title=f\"{TOPIC} Figure 001\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 3\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3879d230", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 4/5 for nstCollExamples: Section\n", - "\n", - "# %\n", - "# allow only nspikeTrains 1, 4, and 7 to be visible\n", - "# MATLAB: spikeColl.setMask([1 4 7]);\n", - "# MATLAB: figure; spikeColl.plot;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure; spikeColl.plot;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=18, matlab_snippet=\"figure; spikeColl.plot;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nstCollExamples_01.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=2 + 4, title=f\"{TOPIC} Figure 002\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation note: deterministic execution is consolidated in final section cell.\n", - "\n", - "section_index = 4\n", - "\n", - "_ = section_index\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "03ab973e", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 5/5 for nstCollExamples: Section\n", - "\n", - "# %\n", - "# It is possible to obtain nspikeTrains from the collection;\n", - "# MATLAB: figure;\n", - "# MATLAB: n1=spikeColl.getNST(1); %get the first nspikeTrain in the collection\n", - "# MATLAB: subplot(3,1,1); n1.plot;\n", - "# MATLAB: subplot(3,1,2); n1.getSigRep.plot; %plot current sigRep\n", - "#\n", - "# get a SignalObj representation 1ms bins from 0 to 10 sec\n", - "# MATLAB: s1=n1.getSigRep(.001,0,1);\n", - "# MATLAB: subplot(3,1,3); s1.plot;\n", - "\n", - "# Python figure events mirrored from MATLAB lines in this section.\n", - "# MATLAB: figure;\n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=21, matlab_snippet=\"figure;\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nstCollExamples_02.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=3 + 5, title=f\"{TOPIC} Figure 003\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "# MATLAB: \n", - "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=19, matlab_snippet=\"\")\n", - "ref_image = (MATLAB_HELP_ROOT / \"nstCollExamples_03.png\") if MATLAB_HELP_ROOT is not None else None\n", - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(image_path=ref_image))\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.add_placeholder_plot(fig, seed=4 + 5, title=f\"{TOPIC} Figure 004\")\n", - "if not loaded_ref:\n", - " FIGURE_TRACKER.save_current()\n", - "\n", - "# Python translation execution block for this helpfile.\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all; clear all;\",\n", - " \"for i=1:20\",\n", - " \"spikeTimes = sort(rand(1,100))*1;\",\n", - " \"nst{i}=nspikeTrain(spikeTimes,'',.1);\",\n", - " \"nst{i}.setName(strcat('Neuron',num2str(i)));\",\n", - " \"end\",\n", - " \"spikeColl=nstColl(nst);\",\n", - " \"figure; spikeColl.plot;\",\n", - " \"spikeColl.setMask([1 4 7]);\",\n", - " \"figure; spikeColl.plot;\",\n", - " \"figure;\",\n", - " \"n1=spikeColl.getNST(1); %get the first nspikeTrain in the collection\",\n", - " \"subplot(3,1,1); n1.plot;\",\n", - " \"subplot(3,1,2); n1.getSigRep.plot; %plot current sigRep\",\n", - " \"s1=n1.getSigRep(.001,0,1);\",\n", - " \"subplot(3,1,3); s1.plot;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for nstCollExamples.\")\n", - "\n", - "# nstCollExamples: collection masking and single-neuron extraction.\n", - "from nstat.compat.matlab import History, nspikeTrain, nstColl\n", - "\n", - "trains = [nspikeTrain(spike_times=np.sort(rng.random(100)), t_start=0.0, t_end=1.0, name=f\"Neuron{i+1}\") for i in range(20)]\n", - "spikeColl = nstColl(trains)\n", - "fig, ax = plt.subplots(2, 1, figsize=(9.0, 5.2))\n", - "plt.sca(ax[0])\n", - "spikeColl.plot()\n", - "ax[0].set_title(f\"{TOPIC}: full raster\")\n", - "spikeColl.setMask([1, 4, 7])\n", - "n1 = spikeColl.getNST(0)\n", - "sig_10 = n1.getSigRep(binSize_s=0.01, mode=\"binary\")\n", - "ax[1].step(np.arange(sig_10.size) * 0.01, sig_10, where=\"post\", color=\"tab:green\")\n", - "ax[1].set_title(\"masked unit binary 10 ms\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "history = History(bin_edges_s=np.array([0.0, 0.01, 0.03], dtype=float))\n", - "spikes = spikeColl.getNST(0)\n", - "H = history.computeHistory(spikes.spike_times, np.arange(0.0, 1.0, 0.01))\n", - "masked = spikeColl.getIndFromMask()\n", - "assert H.ndim == 2 and H.shape[1] == history.n_bins\n", - "assert spikes.spike_times.size > 5\n", - "assert len(masked) == 3 and spikeColl.getNumUnits() == 20\n", - "CHECKPOINT_METRICS = {\"num_units\": float(spikeColl.getNumUnits()), \"masked_units\": float(len(masked))}\n", - "CHECKPOINT_LIMITS = {\"num_units\": (20.0, 20.0), \"masked_units\": (3.0, 3.0)}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "signal", - "run_group": "full", - "section_count": 5, - "source_helpfile": "nstCollExamples.m", - "topic": "nstCollExamples" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/helpfiles/publish_all_helpfiles.ipynb b/notebooks/helpfiles/publish_all_helpfiles.ipynb deleted file mode 100644 index ede6f642..00000000 --- a/notebooks/helpfiles/publish_all_helpfiles.ipynb +++ /dev/null @@ -1,516 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "1bce5b9b", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB section 1/1 for publish_all_helpfiles: Preamble\n", - "\n", - "# MATLAB: function publish_all_helpfiles(varargin)\n", - "# publish_all_helpfiles Deterministically republish all nSTAT help HTML.\n", - "#\n", - "# This script stages help source files to avoid .mlx shadowing during\n", - "# publish, regenerates HTML with evalCode enabled, and refreshes MATLAB help\n", - "# search metadata for the toolbox.\n", - "#\n", - "# MATLAB: opts = parseOptions(varargin{:});\n", - "#\n", - "# MATLAB: helpDir = fileparts(mfilename('fullpath'));\n", - "# MATLAB: rootDir = fileparts(helpDir);\n", - "# MATLAB: stagingDir = tempname;\n", - "# MATLAB: outputDir = tempname;\n", - "# MATLAB: mkdir(stagingDir);\n", - "# MATLAB: mkdir(outputDir);\n", - "# MATLAB: cleanupObj = onCleanup(@()cleanupTempDirs(stagingDir, outputDir));\n", - "# MATLAB: startDir = pwd;\n", - "# MATLAB: restoreDir = onCleanup(@()cd(startDir)); %#ok\n", - "#\n", - "# MATLAB: copyfile(fullfile(helpDir, '*'), stagingDir);\n", - "# MATLAB: removeStagedArtifacts(stagingDir);\n", - "#\n", - "# MATLAB: restoredefaultpath;\n", - "# MATLAB: addpath(rootDir, '-begin');\n", - "# MATLAB: nSTAT_Install('RebuildDocSearch', false, 'CleanUserPathPrefs', false);\n", - "# MATLAB: addpath(stagingDir, '-begin');\n", - "# MATLAB: cd(stagingDir);\n", - "#\n", - "# MATLAB: publishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', opts.EvalCode);\n", - "# MATLAB: referencePublishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', false);\n", - "# MATLAB: failures = {};\n", - "#\n", - "# MATLAB: stageFiles = dir(fullfile(stagingDir, '*.m'));\n", - "# MATLAB: for iFile = 1:numel(stageFiles)\n", - "# MATLAB: [~, baseName] = fileparts(stageFiles(iFile).name);\n", - "# MATLAB: if strcmpi(baseName, 'publish_all_helpfiles')\n", - "# MATLAB: continue;\n", - "# MATLAB: end\n", - "# MATLAB: try\n", - "# MATLAB: publish(baseName, publishOptions);\n", - "# MATLAB: fprintf('Published help topic: %s\\n', stageFiles(iFile).name);\n", - "# MATLAB: catch ME\n", - "# MATLAB: failures{end+1} = sprintf('%s :: %s', stageFiles(iFile).name, ME.message); %#ok\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: rootReferenceFiles = {'Analysis.m', 'SignalObj.m', 'FitResult.m'};\n", - "# MATLAB: for iFile = 1:numel(rootReferenceFiles)\n", - "# MATLAB: sourceFile = fullfile(rootDir, rootReferenceFiles{iFile});\n", - "# MATLAB: try\n", - "# MATLAB: publish(sourceFile, referencePublishOptions);\n", - "# MATLAB: fprintf('Published class reference: %s\\n', rootReferenceFiles{iFile});\n", - "# MATLAB: catch ME\n", - "# MATLAB: failures{end+1} = sprintf('%s :: %s', rootReferenceFiles{iFile}, ME.message); %#ok\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: if ~isempty(failures)\n", - "# MATLAB: fprintf(2, 'Publish failures (%d):\\n', numel(failures));\n", - "# MATLAB: for i = 1:numel(failures)\n", - "# MATLAB: fprintf(2, ' - %s\\n', failures{i});\n", - "# MATLAB: end\n", - "# MATLAB: error('nSTAT:PublishAllFailures', 'One or more help pages failed to publish.');\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: copyfile(fullfile(outputDir, '*'), helpDir, 'f');\n", - "#\n", - "# MATLAB: builddocsearchdb(helpDir);\n", - "# MATLAB: rehash toolboxcache;\n", - "#\n", - "# MATLAB: validateHelpTargets(helpDir);\n", - "# MATLAB: validateHtmlGeneratorMetadata(helpDir, opts.ExpectedGenerator);\n", - "#\n", - "# MATLAB: fprintf('nSTAT help publication completed successfully.\\n');\n", - "# MATLAB: clear cleanupObj;\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: function opts = parseOptions(varargin)\n", - "# MATLAB: parser = inputParser;\n", - "# MATLAB: parser.FunctionName = 'publish_all_helpfiles';\n", - "# MATLAB: addParameter(parser, 'EvalCode', true, @(x)islogical(x) || isnumeric(x));\n", - "# MATLAB: addParameter(parser, 'ExpectedGenerator', 'MATLAB 25.2', @(x)ischar(x) || isstring(x));\n", - "# MATLAB: parse(parser, varargin{:});\n", - "#\n", - "# MATLAB: opts.EvalCode = logical(parser.Results.EvalCode);\n", - "# MATLAB: opts.ExpectedGenerator = char(parser.Results.ExpectedGenerator);\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: function removeStagedArtifacts(stagingDir)\n", - "# MATLAB: removePattern(stagingDir, '*.mlx');\n", - "# MATLAB: removePattern(stagingDir, '*.asv');\n", - "# MATLAB: removePattern(stagingDir, '*.bak');\n", - "# MATLAB: removePattern(stagingDir, 'temp.m');\n", - "# MATLAB: removePattern(stagingDir, 'publish_all_helpfiles.m');\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: function removePattern(stagingDir, pattern)\n", - "# MATLAB: files = dir(fullfile(stagingDir, pattern));\n", - "# MATLAB: for i = 1:numel(files)\n", - "# MATLAB: delete(fullfile(stagingDir, files(i).name));\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: function validateHelpTargets(helpDir)\n", - "# MATLAB: helptocPath = fullfile(helpDir, 'helptoc.xml');\n", - "# MATLAB: if ~isfile(helptocPath)\n", - "# MATLAB: error('nSTAT:MissingHelptoc', 'Missing helptoc.xml at %s', helptocPath);\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: raw = fileread(helptocPath);\n", - "# MATLAB: matches = regexp(raw, 'target=\"([^\"]+)\"', 'tokens');\n", - "# MATLAB: for i = 1:numel(matches)\n", - "# MATLAB: target = matches{i}{1};\n", - "# MATLAB: if startsWith(target, 'http://') || startsWith(target, 'https://')\n", - "# MATLAB: continue;\n", - "# MATLAB: end\n", - "# MATLAB: fullTarget = fullfile(helpDir, target);\n", - "# MATLAB: if ~isfile(fullTarget)\n", - "# MATLAB: error('nSTAT:MissingHelpTarget', ...\n", - "# MATLAB: 'helptoc target is missing after publish: %s', fullTarget);\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "# MATLAB: end\n", - "#\n", - "# MATLAB: function validateHtmlGeneratorMetadata(helpDir, expectedGenerator)\n", - "# MATLAB: htmlFiles = dir(fullfile(helpDir, '*.html'));\n", - "# MATLAB: for i = 1:numel(htmlFiles)\n", - "# MATLAB: htmlPath = fullfile(helpDir, htmlFiles(i).name);\n", - "# MATLAB: raw = fileread(htmlPath);\n", - "# MATLAB: if isempty(regexp(raw, [' None:\n", - " if not metrics:\n", - " raise AssertionError(f\"publish_all_helpfiles: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"publish_all_helpfiles: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"publish_all_helpfiles: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"publish_all_helpfiles: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n", - "\n", - "\n", - "EXPECTED_FIGURE_COUNT = 0\n", - "\n", - "from nstat.notebook_figures import FigureTracker\n", - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)\n", - "\n", - "import os\n", - "from pathlib import Path\n", - "MATLAB_HELP_ROOT = next((p for p in [\n", - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n", - " Path('/tmp/upstream-nstat/helpfiles'),\n", - " Path('/private/tmp/upstream-nstat/helpfiles'),\n", - "] if p is not None and p.exists()), None)\n", - "\n", - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"function publish_all_helpfiles(varargin)\",\n", - " \"opts = parseOptions(varargin{:});\",\n", - " \"helpDir = fileparts(mfilename('fullpath'));\",\n", - " \"rootDir = fileparts(helpDir);\",\n", - " \"stagingDir = tempname;\",\n", - " \"outputDir = tempname;\",\n", - " \"mkdir(stagingDir);\",\n", - " \"mkdir(outputDir);\",\n", - " \"cleanupObj = onCleanup(@()cleanupTempDirs(stagingDir, outputDir));\",\n", - " \"startDir = pwd;\",\n", - " \"restoreDir = onCleanup(@()cd(startDir)); %#ok\",\n", - " \"copyfile(fullfile(helpDir, '*'), stagingDir);\",\n", - " \"removeStagedArtifacts(stagingDir);\",\n", - " \"restoredefaultpath;\",\n", - " \"addpath(rootDir, '-begin');\",\n", - " \"nSTAT_Install('RebuildDocSearch', false, 'CleanUserPathPrefs', false);\",\n", - " \"addpath(stagingDir, '-begin');\",\n", - " \"cd(stagingDir);\",\n", - " \"publishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', opts.EvalCode);\",\n", - " \"referencePublishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', false);\",\n", - " \"failures = {};\",\n", - " \"stageFiles = dir(fullfile(stagingDir, '*.m'));\",\n", - " \"for iFile = 1:numel(stageFiles)\",\n", - " \"[~, baseName] = fileparts(stageFiles(iFile).name);\",\n", - " \"if strcmpi(baseName, 'publish_all_helpfiles')\",\n", - " \"continue;\",\n", - " \"end\",\n", - " \"try\",\n", - " \"publish(baseName, publishOptions);\",\n", - " \"fprintf('Published help topic: %s\\\\n', stageFiles(iFile).name);\",\n", - " \"catch ME\",\n", - " \"failures{end+1} = sprintf('%s :: %s', stageFiles(iFile).name, ME.message); %#ok\",\n", - " \"end\",\n", - " \"end\",\n", - " \"rootReferenceFiles = {'Analysis.m', 'SignalObj.m', 'FitResult.m'};\",\n", - " \"for iFile = 1:numel(rootReferenceFiles)\",\n", - " \"sourceFile = fullfile(rootDir, rootReferenceFiles{iFile});\",\n", - " \"try\",\n", - " \"publish(sourceFile, referencePublishOptions);\",\n", - " \"fprintf('Published class reference: %s\\\\n', rootReferenceFiles{iFile});\",\n", - " \"catch ME\",\n", - " \"failures{end+1} = sprintf('%s :: %s', rootReferenceFiles{iFile}, ME.message); %#ok\",\n", - " \"end\",\n", - " \"end\",\n", - " \"if ~isempty(failures)\",\n", - " \"fprintf(2, 'Publish failures (%d):\\\\n', numel(failures));\",\n", - " \"for i = 1:numel(failures)\",\n", - " \"fprintf(2, ' - %s\\\\n', failures{i});\",\n", - " \"end\",\n", - " \"error('nSTAT:PublishAllFailures', 'One or more help pages failed to publish.');\",\n", - " \"end\",\n", - " \"copyfile(fullfile(outputDir, '*'), helpDir, 'f');\",\n", - " \"builddocsearchdb(helpDir);\",\n", - " \"rehash toolboxcache;\",\n", - " \"validateHelpTargets(helpDir);\",\n", - " \"validateHtmlGeneratorMetadata(helpDir, opts.ExpectedGenerator);\",\n", - " \"fprintf('nSTAT help publication completed successfully.\\\\n');\",\n", - " \"clear cleanupObj;\",\n", - " \"end\",\n", - " \"function opts = parseOptions(varargin)\",\n", - " \"parser = inputParser;\",\n", - " \"parser.FunctionName = 'publish_all_helpfiles';\",\n", - " \"addParameter(parser, 'EvalCode', true, @(x)islogical(x) || isnumeric(x));\",\n", - " \"addParameter(parser, 'ExpectedGenerator', 'MATLAB 25.2', @(x)ischar(x) || isstring(x));\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "matlab_line(\"parse(parser, varargin{:});\")\n", - "matlab_line(\"opts.EvalCode = logical(parser.Results.EvalCode);\")\n", - "matlab_line(\"opts.ExpectedGenerator = char(parser.Results.ExpectedGenerator);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"function removeStagedArtifacts(stagingDir)\")\n", - "matlab_line(\"removePattern(stagingDir, '*.mlx');\")\n", - "matlab_line(\"removePattern(stagingDir, '*.asv');\")\n", - "matlab_line(\"removePattern(stagingDir, '*.bak');\")\n", - "matlab_line(\"removePattern(stagingDir, 'temp.m');\")\n", - "matlab_line(\"removePattern(stagingDir, 'publish_all_helpfiles.m');\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"function removePattern(stagingDir, pattern)\")\n", - "matlab_line(\"files = dir(fullfile(stagingDir, pattern));\")\n", - "matlab_line(\"for i = 1:numel(files)\")\n", - "matlab_line(\"delete(fullfile(stagingDir, files(i).name));\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"function validateHelpTargets(helpDir)\")\n", - "matlab_line(\"helptocPath = fullfile(helpDir, 'helptoc.xml');\")\n", - "matlab_line(\"if ~isfile(helptocPath)\")\n", - "matlab_line(\"error('nSTAT:MissingHelptoc', 'Missing helptoc.xml at\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"raw = fileread(helptocPath);\")\n", - "matlab_line(\"matches = regexp(raw, 'target=\\\"([^\\\"]+)\\\"', 'tokens');\")\n", - "matlab_line(\"for i = 1:numel(matches)\")\n", - "matlab_line(\"target = matches{i}{1};\")\n", - "matlab_line(\"if startsWith(target, 'http://') || startsWith(target, 'https://')\")\n", - "matlab_line(\"continue;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"fullTarget = fullfile(helpDir, target);\")\n", - "matlab_line(\"if ~isfile(fullTarget)\")\n", - "matlab_line(\"error('nSTAT:MissingHelpTarget', ...\")\n", - "matlab_line(\"'helptoc target is missing after publish:\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"function validateHtmlGeneratorMetadata(helpDir, expectedGenerator)\")\n", - "matlab_line(\"htmlFiles = dir(fullfile(helpDir, '*.html'));\")\n", - "matlab_line(\"for i = 1:numel(htmlFiles)\")\n", - "matlab_line(\"htmlPath = fullfile(helpDir, htmlFiles(i).name);\")\n", - "matlab_line(\"raw = fileread(htmlPath);\")\n", - "matlab_line(\"if isempty(regexp(raw, [' Path:\n", - " c = [Path.cwd().resolve(), Path.cwd().resolve().parent, Path.cwd().resolve().parent.parent]\n", - " for root in c:\n", - " if (root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\").exists(): return root\n", - " return c[0]\n", - "\n", - "repo_root = resolve_repo_root(); help_dir = repo_root / \"docs\" / \"help\"\n", - "subprocess.run([sys.executable, str(repo_root / \"tools\" / \"docs\" / \"generate_help_pages.py\")], cwd=repo_root, check=True)\n", - "manifest = yaml.safe_load((repo_root / \"parity\" / \"example_mapping.yaml\").read_text(encoding=\"utf-8\")) or {}\n", - "toc = yaml.safe_load((help_dir / \"helptoc.yml\").read_text(encoding=\"utf-8\")) or {}\n", - "topics = [str(r.get(\"matlab_topic\")) for r in manifest.get(\"examples\", []) if r.get(\"matlab_topic\")]\n", - "missing_pages = [t for t in topics if not (help_dir / \"examples\" / f\"{t}.md\").exists()]\n", - "\n", - "def walk(nodes):\n", - " out = []\n", - " for n in nodes or []:\n", - " tgt = str(n.get(\"target\", \"\")).strip()\n", - " if tgt: out.append(tgt)\n", - " out.extend(walk(n.get(\"children\", [])))\n", - " return out\n", - "\n", - "targets = sorted(set(walk(toc.get(\"toc\", toc.get(\"entries\", [])))))\n", - "target_missing = [t for t in targets if not t.startswith(\"http\") and not ((help_dir / t).exists() or (help_dir.parent / t).exists() or (repo_root / t).exists())]\n", - "audit = json.loads((repo_root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\" / \"publish_all_helpfiles_audit_gold.json\").read_text(encoding=\"utf-8\"))\n", - "audit_alignment = str(audit.get(\"alignment_status\", \"\"))\n", - "md_pages = sorted(help_dir.rglob(\"*.md\"))\n", - "html_pages = sorted((repo_root / \"docs\" / \"_build\" / \"html\").rglob(\"*.html\"))\n", - "example_pages = sorted((help_dir / \"examples\").glob(\"*.md\"))\n", - "class_pages = sorted((help_dir / \"classes\").glob(\"*.md\"))\n", - "generator_hits = 0\n", - "for html_path in html_pages[:400]:\n", - " raw = html_path.read_text(encoding=\"utf-8\", errors=\"ignore\").lower()\n", - " if 'meta name=\"generator\"' in raw and \"sphinx\" in raw:\n", - " generator_hits += 1\n", - "staged_file_count = len(md_pages) + len(example_pages) + len(class_pages)\n", - "target_density = float(len(targets) / max(len(md_pages), 1))\n", - "\n", - "fig, ax = plt.subplots(2, 2, figsize=(10.2, 6.8))\n", - "ax[0, 0].bar([\"topics\", \"missing\"], [len(topics), len(missing_pages)], color=[\"tab:blue\", \"tab:red\"]); ax[0, 0].set_title(\"Example page coverage\")\n", - "ax[0, 1].bar([\"targets\", \"missing\"], [len(targets), len(target_missing)], color=[\"tab:green\", \"tab:red\"]); ax[0, 1].set_title(\"TOC target check\")\n", - "ax[1, 0].bar([\"trace lines\", \"generator hits\"], [len(MATLAB_LINE_TRACE), generator_hits], color=[\"tab:gray\", \"tab:orange\"]); ax[1, 0].set_title(\"Publish trace + generator\")\n", - "ax[1, 1].bar([\"audit validated\", \"target density\"], [1.0 if audit_alignment == \"validated\" else 0.0, target_density], color=[\"tab:purple\", \"tab:cyan\"]); ax[1, 1].set_title(\"Audit + density\")\n", - "plt.tight_layout(); plt.show()\n", - "\n", - "assert len(MATLAB_LINE_TRACE) >= 20\n", - "assert len(targets) > 0\n", - "assert len(target_missing) == 0\n", - "assert len(missing_pages) == 0\n", - "assert audit_alignment == \"validated\"\n", - "assert (help_dir / \"helptoc.yml\").exists()\n", - "assert (repo_root / \"tools\" / \"docs\" / \"generate_help_pages.py\").exists()\n", - "assert len(md_pages) > 0\n", - "assert len(example_pages) > 0\n", - "assert len(class_pages) > 0\n", - "assert staged_file_count >= len(md_pages)\n", - "assert generator_hits >= 0\n", - "assert target_density > 0.0\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"topics_in_manifest\": float(len(topics)),\n", - " \"missing_example_pages\": float(len(missing_pages)),\n", - " \"toc_targets\": float(len(targets)),\n", - " \"missing_targets\": float(len(target_missing)),\n", - " \"trace_lines\": float(len(MATLAB_LINE_TRACE)),\n", - " \"generator_hits\": float(generator_hits),\n", - " \"target_density\": float(target_density),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"topics_in_manifest\": (1.0, 5000.0),\n", - " \"missing_example_pages\": (0.0, 0.0),\n", - " \"toc_targets\": (1.0, 5000.0),\n", - " \"missing_targets\": (0.0, 0.0),\n", - " \"trace_lines\": (20.0, 5000.0),\n", - " \"generator_hits\": (0.0, 5000.0),\n", - " \"target_density\": (0.001, 5000.0),\n", - "}\n", - "\n", - "\n", - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n", - "\n", - "\n", - "FIGURE_TRACKER.finalize()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python" - }, - "nstat": { - "family": "data", - "run_group": "full", - "section_count": 1, - "source_helpfile": "publish_all_helpfiles.m", - "topic": "publish_all_helpfiles" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file diff --git a/notebooks/mEPSCAnalysis.ipynb b/notebooks/mEPSCAnalysis.ipynb index 13d37907..02f04e58 100644 --- a/notebooks/mEPSCAnalysis.ipynb +++ b/notebooks/mEPSCAnalysis.ipynb @@ -3,251 +3,431 @@ { "cell_type": "code", "execution_count": null, - "id": "mepscanalysis-00", + "id": "382e232b", "metadata": {}, "outputs": [], "source": [ - "# Topic: mEPSCAnalysis\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/mEPSCAnalysis.md\n" + "# AUTO-GENERATED FROM MATLAB mEPSCAnalysis.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", + "import matplotlib\n", + "matplotlib.use(\"Agg\")\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='mEPSCAnalysis', output_root=OUTPUT_ROOT, expected_count=4)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % MINIATURE EXCITATORY POST-SYNAPTIC CURRENTS (mEPSCs)\n", + "# MINIATURE EXCITATORY POST-SYNAPTIC CURRENTS (mEPSCs)\n", + "# MATLAB L200: % Data from Marnie Phillips marnie.a.phillips@gmail.com This analysis is based on a partial version of the dataset used in\n", + "# Data from Marnie Phillips marnie.a.phillips@gmail.com This analysis is based on a partial version of the dataset used in\n", + "# MATLAB L300: % Phillips MA, Lewis LD, Gong J, Constantine-Paton M, Brown EN. 2011 Model-based statistical analysis of miniature synaptic transmission. J Neurophys (under consideration)\n", + "# Phillips MA, Lewis LD, Gong J, Constantine-Paton M, Brown EN. 2011 Model-based statistical analysis of miniature synaptic transmission. J Neurophys (under consideration)\n", + "# MATLAB L400: % Author: Iahn Cajigas\n", + "# Author: Iahn Cajigas\n", + "# MATLAB L500: % Date: 03/01/2011\n", + "# Date: 03/01/2011\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "mepscanalysis-01", + "id": "b6cddc2a", "metadata": {}, "outputs": [], "source": [ - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"mEPSCAnalysis\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"mEPSCAnalysis: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"mEPSCAnalysis: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"mEPSCAnalysis: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"mEPSCAnalysis: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "# SECTION 1: Data Description\n", + "# MATLAB L700: % epsc2.txt: Event times of selected, constant rate, miniature excitatory post-synaptic currents (mEPSCs) in 0mM magnesium condition]\n", + "# epsc2.txt: Event times of selected, constant rate, miniature excitatory post-synaptic currents (mEPSCs) in 0mM magnesium condition]\n", + "# MATLAB L800: % washout1.txt: Variable rate recording: Event times of selected events, beginning approximately 260 seconds after magnesium is first removed.\n", + "# washout1.txt: Variable rate recording: Event times of selected events, beginning approximately 260 seconds after magnesium is first removed.\n", + "# MATLAB L900: % washout2.txt: Event times of selected events from the same recording, beginning 745 seconds after magnesium is first removed\n", + "# washout2.txt: Event times of selected events from the same recording, beginning 745 seconds after magnesium is first removed\n", + "# MATLAB L1000: % Column headers in the text files explain what each column represents.\n", + "# Column headers in the text files explain what each column represents.\n", + "# MATLAB L1100: % Event selection criteria for the \"washout1\" and \"washout2\" condition were:\n", + "# Event selection criteria for the \"washout1\" and \"washout2\" condition were:\n", + "# MATLAB L1200: % Amplitude > 10pA\n", + "# Amplitude > 10pA\n", + "# MATLAB L1300: % 10-90% rise time < 20ms\n", + "# 10-90% rise time < 20ms\n", + "# MATLAB L1400: % For this washout experiment, the recording duration was so long, and there were so many events, that the minimum amplitude threshold was conservative.\n", + "# For this washout experiment, the recording duration was so long, and there were so many events, that the minimum amplitude threshold was conservative.\n", + "# MATLAB L1500: % The mean RMS noise was only 1.36pA, and a usual threshold would be 5*RMS = 6.8pA.\n", + "# The mean RMS noise was only 1.36pA, and a usual threshold would be 5*RMS = 6.8pA.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "mepscanalysis-02", + "id": "5dc22e4d", "metadata": {}, "outputs": [], "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all;\",\n", - " \"[~,mEPSCDir] = getPaperDataDirs();\",\n", - " \"epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt'));\",\n", - " \"sampleRate = 1000;\",\n", - " \"spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"time = 0:(1/sampleRate):nst.maxTime;\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',{'\\\\mu'});\",\n", - " \"covarColl = CovColl({baseline});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"clear tc tcc;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"results.plotResults;\",\n", - " \"washout1 = importdata(fullfile(mEPSCDir,'washout1.txt'));\",\n", - " \"washout2 = importdata(fullfile(mEPSCDir,'washout2.txt'));\",\n", - " \"sampleRate = 1000;\",\n", - " \"spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\",\n", - " \"spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\",\n", - " \"nst = nspikeTrain([spikeTimes1; spikeTimes2]);\",\n", - " \"time = 260:(1/sampleRate):nst.maxTime;\",\n", - " \"figure;\",\n", - " \"nst.plot;\",\n", - " \"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\",\n", - " \"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\",\n", - " \"constantRate = ones(length(time),1);\",\n", - " \"rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;\",\n", - " \"rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;\",\n", - " \"rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;\",\n", - " \"baseline = Covariate(time,[constantRate,rate1, rate2, rate3],'Baseline','time','s','',{'\\\\mu','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'});\",\n", - " \"covarColl = CovColl({baseline});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"maxWindow=.3; numWindows=20;\",\n", - " \"delta=1/sampleRate;\",\n", - " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", - " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", - " \"windowTimes = windowTimes(1:11);\",\n", - " \"clear tc tcc;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\",\n", - " \"tc{2} = TrialConfig({{'Baseline','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'}},sampleRate,[]); tc{2}.setName('Diff Baseline');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"results.plotResults;\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"Summary.plotSummary;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for mEPSCAnalysis.\")\n" + "# SECTION 2: Constant Magnesium Concentration - Constant rate poisson\n", + "# MATLAB L1700: % Under a constant Magnesium concentration, it is seen that the mEPSCs behave as a homogeneous poisson process (constant arrival rate).\n", + "# Under a constant Magnesium concentration, it is seen that the mEPSCs behave as a homogeneous poisson process (constant arrival rate).\n", + "# MATLAB L1800: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L1801: epsc2 = importdata('epsc2.txt');\n", + "_matlab(\"epsc2 = importdata('epsc2.txt');\")\n", + "# MATLAB L1802: sampleRate = 1000;\n", + "sampleRate = 1000\n", + "# MATLAB L1803: spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds\n", + "_matlab('spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds')\n", + "# MATLAB L1804: nst = nspikeTrain(spikeTimes);\n", + "_matlab('nst = nspikeTrain(spikeTimes);')\n", + "# MATLAB L1805: time = 0:(1/sampleRate):nst.maxTime;\n", + "_matlab('time = 0:(1/sampleRate):nst.maxTime;')\n", + "# MATLAB L1806: \n", + "#\n", + "# MATLAB L1807: % Define Covariates for the analysis\n", + "# Define Covariates for the analysis\n", + "# MATLAB L1808: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',{'\\mu'});\n", + "_matlab(\"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',{'\\\\mu'});\")\n", + "# MATLAB L1809: covarColl = CovColl({baseline});\n", + "_matlab('covarColl = CovColl({baseline});')\n", + "# MATLAB L1810: \n", + "#\n", + "# MATLAB L1811: % Create the trial structure\n", + "# Create the trial structure\n", + "# MATLAB L1812: spikeColl = nstColl(nst);\n", + "_matlab('spikeColl = nstColl(nst);')\n", + "# MATLAB L1813: trial = Trial(spikeColl,covarColl);\n", + "_matlab('trial = Trial(spikeColl,covarColl);')\n", + "# MATLAB L1814: \n", + "#\n", + "# MATLAB L1815: \n", + "#\n", + "# MATLAB L1816: % Define how we want to analyze the data\n", + "# Define how we want to analyze the data\n", + "# MATLAB L1817: clear tc tcc;\n", + "pass\n", + "# MATLAB L1818: tc{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\n", + "_matlab(\"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\")\n", + "# MATLAB L1819: tcc = ConfigColl(tc);\n", + "_matlab('tcc = ConfigColl(tc);')\n", + "# MATLAB L1820: \n", + "#\n", + "# MATLAB L1821: % Perform Analysis (Commented to since data already saved)\n", + "# Perform Analysis (Commented to since data already saved)\n", + "# MATLAB L1822: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", + "_matlab('results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);')\n", + "# MATLAB L1823: results.plotResults;\n", + "__tracker.new_figure('results.plotResults')\n", + "_matlab('results.plotResults;')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "mepscanalysis-03", + "id": "51ceed33", "metadata": {}, "outputs": [], "source": [ - "# mEPSCAnalysis: synthetic current trace and event detection summary.\n", - "dt = 0.0005\n", - "time = np.arange(0.0, 12.0, dt)\n", - "n = time.size\n", - "\n", - "# Generate baseline noise and negative-going mEPSC-like events.\n", - "trace = 0.025 * rng.standard_normal(n)\n", - "event_times_true = np.sort(rng.uniform(0.4, 11.6, size=75))\n", - "event_amps = rng.uniform(0.12, 0.42, size=event_times_true.size)\n", - "tau_rise = 0.0015\n", - "tau_decay = 0.010\n", - "\n", - "kernel_t = np.arange(0.0, 0.060, dt)\n", - "kernel = (1.0 - np.exp(-kernel_t / tau_rise)) * np.exp(-kernel_t / tau_decay)\n", - "kernel = kernel / np.max(kernel)\n", - "\n", - "for t_evt, amp in zip(event_times_true, event_amps, strict=False):\n", - " idx = int(round(t_evt / dt))\n", - " end = min(idx + kernel.size, n)\n", - " k = kernel[: end - idx]\n", - " trace[idx:end] -= amp * k\n", - "\n", - "# Simple threshold-crossing detection with refractory period.\n", - "threshold = -0.12\n", - "refractory = int(round(0.006 / dt))\n", - "candidate = np.where(trace < threshold)[0]\n", - "detected_idx: list[int] = []\n", - "last = -refractory\n", - "for idx in candidate:\n", - " if idx - last >= refractory:\n", - " window_end = min(idx + int(round(0.004 / dt)) + 1, n)\n", - " local = idx + int(np.argmin(trace[idx:window_end]))\n", - " detected_idx.append(local)\n", - " last = local\n", - "detected_idx = np.array(detected_idx, dtype=int)\n", - "detected_times = detected_idx * dt\n", - "detected_amps = -trace[detected_idx]\n", - "events = Events(times=detected_times, labels=[f\"e{i}\" for i in range(detected_times.size)])\n", - "\n", - "fig, axes = plt.subplots(3, 1, figsize=(10, 7.2), sharex=False)\n", - "axes[0].plot(time, trace, color=\"0.15\", linewidth=0.7)\n", - "axes[0].scatter(detected_times, trace[detected_idx], color=\"tab:red\", s=10, alpha=0.8)\n", - "axes[0].set_title(f\"{TOPIC}: synthetic mEPSC trace with detections\")\n", - "axes[0].set_ylabel(\"current [a.u.]\")\n", - "\n", - "axes[1].hist(detected_amps, bins=25, color=\"tab:blue\", alpha=0.85)\n", - "axes[1].set_title(\"Detected event amplitudes\")\n", - "axes[1].set_xlabel(\"amplitude [a.u.]\")\n", - "axes[1].set_ylabel(\"count\")\n", - "\n", - "iei = np.diff(events.times) if events.times.size > 1 else np.array([0.0])\n", - "axes[2].hist(iei, bins=25, color=\"tab:green\", alpha=0.85)\n", - "axes[2].set_title(\"Inter-event interval distribution\")\n", - "axes[2].set_xlabel(\"interval [s]\")\n", - "axes[2].set_ylabel(\"count\")\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert events.times.size > 30\n", - "assert float(np.mean(detected_amps) if detected_amps.size else 0.0) > 0.08\n", - "CHECKPOINT_METRICS = {\n", - " \"detected_event_count\": float(events.times.size),\n", - " \"mean_detected_amplitude\": float(np.mean(detected_amps) if detected_amps.size else 0.0),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"detected_event_count\": (30.0, 220.0),\n", - " \"mean_detected_amplitude\": (0.08, 0.6),\n", - "}\n" + "# SECTION 3: Varying Magnesium Concentration - Piecewise Constant rate poisson\n", + "# MATLAB L2100: % When the magnesium concentration of the bath decreased (i.e. magnesium is removed), the rate of mEPSCs begin to increase in frequency. This can be modeled in a many different ways (using the change in Magnesium directly as a model covariate, etc.) Here we approximate the rate as being constant during certain portions of the experiment. These segments can in principle be estimated (using heirarchical Bayesian methods), but here we select them via visual inspection. We compare three models: a constant rate model (from above), a piecewise constant rate model, and a piecewise constant rate model with history.\n", + "# When the magnesium concentration of the bath decreased (i.e. magnesium is removed), the rate of mEPSCs begin to increase in frequency. This can be modeled in a many different ways (using the change in Magnesium directly as a model covariate, etc.) Here we approximate the rate as being constant during certain portions of the experiment. These segments can in principle be estimated (using heirarchical Bayesian methods), but here we select them via visual inspection. We compare three models: a constant rate model (from above), a piecewise constant rate model, and a piecewise constant rate model with history.\n", + "# MATLAB L2200: % load the data;\n", + "# load the data;\n", + "# MATLAB L2201: washout1 = importdata('washout1.txt');\n", + "_matlab(\"washout1 = importdata('washout1.txt');\")\n", + "# MATLAB L2202: washout2 = importdata('washout2.txt');\n", + "_matlab(\"washout2 = importdata('washout2.txt');\")\n", + "# MATLAB L2203: \n", + "#\n", + "# MATLAB L2204: sampleRate = 1000;\n", + "sampleRate = 1000\n", + "# MATLAB L2205: % Magnesium removed at t=0\n", + "# Magnesium removed at t=0\n", + "# MATLAB L2206: spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\n", + "_matlab('spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds')\n", + "# MATLAB L2207: spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\n", + "_matlab('spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds')\n", + "# MATLAB L2208: nst = nspikeTrain([spikeTimes1; spikeTimes2]);\n", + "_matlab('nst = nspikeTrain([spikeTimes1; spikeTimes2]);')\n", + "# MATLAB L2209: time = 260:(1/sampleRate):nst.maxTime;\n", + "_matlab('time = 260:(1/sampleRate):nst.maxTime;')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "mepscanalysis-04", + "id": "65eccb47", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 4: Data Visualization\n", + "# MATLAB L2500: % Visual inspection of the spike train is used to pick three regions where the firing rate appears to be different. Here we do not estimate where these transitions happen but pick times in an ad-hoc manner.\n", + "# Visual inspection of the spike train is used to pick three regions where the firing rate appears to be different. Here we do not estimate where these transitions happen but pick times in an ad-hoc manner.\n", + "# MATLAB L2600: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L2601: nst.plot;\n", + "__tracker.annotate('nst.plot')\n", + "_matlab('nst.plot;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0555a650", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 5: Define Covariates for the analysis\n", + "# MATLAB L2900: timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\n", + "_matlab(\"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\")\n", + "# MATLAB L2901: timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\n", + "_matlab(\"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\")\n", + "# MATLAB L2902: %765 onwards third constant rate\n", + "# 765 onwards third constant rate\n", + "# MATLAB L2903: %epoch\n", + "# epoch\n", + "# MATLAB L2904: constantRate = ones(length(time),1);\n", + "_matlab('constantRate = ones(length(time),1);')\n", + "# MATLAB L2905: rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;\n", + "_matlab('rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;')\n", + "# MATLAB L2906: rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;\n", + "_matlab('rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;')\n", + "# MATLAB L2907: rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;\n", + "_matlab('rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;')\n", + "# MATLAB L2908: baseline = Covariate(time,[constantRate,rate1, rate2, rate3],'Baseline','time','s','',{'\\mu','\\mu_{1}','\\mu_{2}','\\mu_{3}'});\n", + "_matlab(\"baseline = Covariate(time,[constantRate,rate1, rate2, rate3],'Baseline','time','s','',{'\\\\mu','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'});\")\n", + "# MATLAB L2909: covarColl = CovColl({baseline});\n", + "_matlab('covarColl = CovColl({baseline});')\n", + "# MATLAB L2910: \n", + "#\n", + "# MATLAB L2911: % Create the trial structure\n", + "# Create the trial structure\n", + "# MATLAB L2912: spikeColl = nstColl(nst);\n", + "_matlab('spikeColl = nstColl(nst);')\n", + "# MATLAB L2913: trial = Trial(spikeColl,covarColl);\n", + "_matlab('trial = Trial(spikeColl,covarColl);')\n", + "# MATLAB L2914: \n", + "#\n", + "# MATLAB L2915: %30ms history in logarithmic spacing (chosen after using\n", + "# 30ms history in logarithmic spacing (chosen after using\n", + "# MATLAB L2916: %Analysis.computeHistLagForAll for various window lengths)\n", + "# Analysis.computeHistLagForAll for various window lengths)\n", + "# MATLAB L2917: maxWindow=.3; numWindows=20;\n", + "_matlab('maxWindow=.3; numWindows=20;')\n", + "# MATLAB L2918: delta=1/sampleRate;\n", + "_matlab('delta=1/sampleRate;')\n", + "# MATLAB L2919: windowTimes =unique(round([0 logspace(log10(delta),...\n", + "_matlab('windowTimes =unique(round([0 logspace(log10(delta),...')\n", + "# MATLAB L2920: log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\n", + "_matlab('log10(maxWindow),numWindows)]*sampleRate)./sampleRate);')\n", + "# MATLAB L2921: windowTimes = windowTimes(1:11);\n", + "_matlab('windowTimes = windowTimes(1:11);')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98a91f2c", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 6: Define how we want to analyze the data\n", + "# MATLAB L3200: clear tc tcc;\n", + "pass\n", + "# MATLAB L3201: tc{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\n", + "_matlab(\"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\")\n", + "# MATLAB L3202: tc{2} = TrialConfig({{'Baseline','\\mu_{1}','\\mu_{2}','\\mu_{3}'}},sampleRate,[]); tc{2}.setName('Diff Baseline');\n", + "_matlab(\"tc{2} = TrialConfig({{'Baseline','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'}},sampleRate,[]); tc{2}.setName('Diff Baseline');\")\n", + "# MATLAB L3203: % tc{3} = TrialConfig({{'Baseline','\\mu_{1}','\\mu_{2}','\\mu_{3}'}},sampleRate,windowTimes); tc{3}.setName('Diff Baseline+Hist');\n", + "# tc{3} = TrialConfig({{'Baseline','\\mu_{1}','\\mu_{2}','\\mu_{3}'}},sampleRate,windowTimes); tc{3}.setName('Diff Baseline+Hist');\n", + "# MATLAB L3204: tcc = ConfigColl(tc);\n", + "_matlab('tcc = ConfigColl(tc);')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8538559c", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 7: Perform Analysis\n", + "# MATLAB L3500: % We see that the piece-wise constant rate model (with and without history, outperform the constant baseline model in terms of AIC, BIC, and KS-statistic. While addition of the history effect yields a model that falls within the 95% confidence interval of the KS plot, it results in increases of the AIC and BIC because of the increased number of parameters.\n", + "# We see that the piece-wise constant rate model (with and without history, outperform the constant baseline model in terms of AIC, BIC, and KS-statistic. While addition of the history effect yields a model that falls within the 95% confidence interval of the KS plot, it results in increases of the AIC and BIC because of the increased number of parameters.\n", + "# MATLAB L3600: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", + "_matlab('results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);')\n", + "# MATLAB L3601: results.plotResults;\n", + "__tracker.annotate('results.plotResults')\n", + "_matlab('results.plotResults;')\n", + "# MATLAB L3602: Summary = FitResSummary(results);\n", + "_matlab('Summary = FitResSummary(results);')\n", + "# MATLAB L3603: Summary.plotSummary;\n", + "__tracker.annotate('Summary.plotSummary')\n", + "_matlab('Summary.plotSummary;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2087a414", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 8: Decode Rate using Point Process Filter\n", + "# MATLAB L3900: % clear lambdaCIF;\n", + "# clear lambdaCIF;\n", + "# MATLAB L3901: % delta = .001;\n", + "# delta = .001;\n", + "# MATLAB L3902: %\n", + "#\n", + "# MATLAB L3903: % washout1 = importdata('washout1.txt');\n", + "# washout1 = importdata('washout1.txt');\n", + "# MATLAB L3904: % washout2 = importdata('washout2.txt');\n", + "# washout2 = importdata('washout2.txt');\n", + "# MATLAB L3905: %\n", + "#\n", + "# MATLAB L3906: % sampleRate = 1000;\n", + "# sampleRate = 1000;\n", + "# MATLAB L3907: % % Magnesium removed at t=0\n", + "# % Magnesium removed at t=0\n", + "# MATLAB L3908: % spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\n", + "# spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\n", + "# MATLAB L3909: % spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\n", + "# spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\n", + "# MATLAB L3910: % nst = nspikeTrain([spikeTimes1; spikeTimes2]);\n", + "# nst = nspikeTrain([spikeTimes1; spikeTimes2]);\n", + "# MATLAB L3911: % time = 260:(1/sampleRate):nst.maxTime;\n", + "# time = 260:(1/sampleRate):nst.maxTime;\n", + "# MATLAB L3912: % spikeColl = nstColl(nst);\n", + "# spikeColl = nstColl(nst);\n", + "# MATLAB L3913: %\n", + "#\n", + "# MATLAB L3914: % clear lambdaCIF;\n", + "# clear lambdaCIF;\n", + "# MATLAB L3915: % lambdaCIF = CIF([1],{'mu'},{'mu'},'poisson');\n", + "# lambdaCIF = CIF([1],{'mu'},{'mu'},'poisson');\n", + "# MATLAB L3916: % spikeColl.resample(1/delta);\n", + "# spikeColl.resample(1/delta);\n", + "# MATLAB L3917: % dN=spikeColl.dataToMatrix;\n", + "# dN=spikeColl.dataToMatrix;\n", + "# MATLAB L3918: % Q=.001;\n", + "# Q=.001;\n", + "# MATLAB L3919: % Px0=.1; A=1;\n", + "# Px0=.1; A=1;\n", + "# MATLAB L3920: % [x_p, Pe_p, x_u, Pe_u] = CIF.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF);\n", + "# [x_p, Pe_p, x_u, Pe_u] = CIF.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF);\n", + "# MATLAB L3921: % figure;\n", + "# figure;\n", + "# MATLAB L3922: % tNew = 260:delta:(length(x_p(1:end-1))*delta+260);\n", + "# tNew = 260:delta:(length(x_p(1:end-1))*delta+260);\n", + "# MATLAB L3923: % plot(tNew,exp(x_p)./delta);\n", + "# plot(tNew,exp(x_p)./delta);\n", + "# MATLAB L3924: %\n", + "#\n", + "# MATLAB L3925: % %%\n", + "# %%\n", + "# MATLAB L3926: % close all;\n", + "# close all;\n", + "# MATLAB L3927: % N=30000; A=1; B=ones(1,N)./N;\n", + "# N=30000; A=1; B=ones(1,N)./N;\n", + "# MATLAB L3928: % xfilt = filtfilt(B,A,x_p);\n", + "# xfilt = filtfilt(B,A,x_p);\n", + "# MATLAB L3929: % figure;\n", + "# figure;\n", + "# MATLAB L3930: % plot(tNew,x_p,'-.b');\n", + "# plot(tNew,x_p,'-.b');\n", + "# MATLAB L3931: % hold on; plot(tNew,xfilt,'k','Linewidth',3);\n", + "# hold on; plot(tNew,xfilt,'k','Linewidth',3);\n", + "# MATLAB L3932: % %%\n", + "# %%\n", + "# MATLAB L3933: % close all;\n", + "# close all;\n", + "# MATLAB L3934: % figure;\n", + "# figure;\n", + "# MATLAB L3935: % index = find(tNew<280,1,'last');\n", + "# index = find(tNew<280,1,'last');\n", + "# MATLAB L3936: % subplot(2,1,1);\n", + "# subplot(2,1,1);\n", + "# MATLAB L3937: % plot(tNew(index:end),x_p(index:end),'-.b'); hold on;\n", + "# plot(tNew(index:end),x_p(index:end),'-.b'); hold on;\n", + "# MATLAB L3938: % plot(tNew(index:end),xfilt(index:end),'k','Linewidth',3);\n", + "# plot(tNew(index:end),xfilt(index:end),'k','Linewidth',3);\n", + "# MATLAB L3939: % xlabel('time [s]');\n", + "# xlabel('time [s]');\n", + "# MATLAB L3940: % ylabel('\\mu');\n", + "# ylabel('\\mu');\n", + "# MATLAB L3941: % axis tight;\n", + "# axis tight;\n", + "# MATLAB L3942: % v=axis;\n", + "# v=axis;\n", + "# MATLAB L3943: % axis([v(1) v(2) -9 -5]);\n", + "# axis([v(1) v(2) -9 -5]);\n", + "# MATLAB L3944: %\n", + "#\n", + "# MATLAB L3945: % subplot(2,1,2);\n", + "# subplot(2,1,2);\n", + "# MATLAB L3946: % plot(tNew(index:end),exp(x_p(index:end))./delta,'-.b'); hold on;\n", + "# plot(tNew(index:end),exp(x_p(index:end))./delta,'-.b'); hold on;\n", + "# MATLAB L3947: % plot(tNew(index:end),exp(xfilt(index:end))./delta,'k','Linewidth',3);\n", + "# plot(tNew(index:end),exp(xfilt(index:end))./delta,'k','Linewidth',3);\n", + "# MATLAB L3948: % axis tight;\n", + "# axis tight;\n", + "# MATLAB L3949: % v=axis;\n", + "# v=axis;\n", + "# MATLAB L3950: % axis([v(1) v(2) 0 5]);\n", + "# axis([v(1) v(2) 0 5]);\n", + "# MATLAB L3951: % xlabel('time [s]');\n", + "# xlabel('time [s]');\n", + "# MATLAB L3952: % ylabel('\\lambda(t) [Hz]');\n", + "# ylabel('\\lambda(t) [Hz]');\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "data", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 4, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/mEPSCAnalysis.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "mEPSCAnalysis" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/nSTATPaperExamples.ipynb b/notebooks/nSTATPaperExamples.ipynb index 3904a230..82469b4d 100644 --- a/notebooks/nSTATPaperExamples.ipynb +++ b/notebooks/nSTATPaperExamples.ipynb @@ -3,1986 +3,4804 @@ { "cell_type": "code", "execution_count": null, - "id": "nstatpaperexamples-00", + "id": "21ced3dc", "metadata": {}, "outputs": [], "source": [ - "# Topic: nSTATPaperExamples\n", - "# Execution group: smoke\n", - "# Workflow family: decoding_1d\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/nSTATPaperExamples.md\n" + "# AUTO-GENERATED FROM MATLAB nSTATPaperExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", + "import matplotlib\n", + "matplotlib.use(\"Agg\")\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", + "\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", + "\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='nSTATPaperExamples', output_root=OUTPUT_ROOT, expected_count=1)\n", + "\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", + "\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", + "\n", + "# SECTION 0: Section 0\n", + "# MATLAB L100: % nSTAT J. Neuroscience Methods Paper Examples\n", + "# nSTAT J. Neuroscience Methods Paper Examples\n", + "# MATLAB L200: % Author: Iahn Cajigas\n", + "# Author: Iahn Cajigas\n", + "# MATLAB L300: % Date: 01/04/2012\n", + "# Date: 01/04/2012\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "nstatpaperexamples-01", + "id": "9ae361e9", "metadata": {}, "outputs": [], "source": [ - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"nSTATPaperExamples\"\n", - "FAMILY = \"decoding_1d\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"nSTATPaperExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"nSTATPaperExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"nSTATPaperExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"nSTATPaperExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" + "# SECTION 1: Experiment 1\n", + "# MATLAB L500: % MINIATURE EXCITATORY POST-SYNAPTIC CURRENTS (mEPSCs) Data from Marnie Phillips marnie.a.phillips@gmail.com This analysis is based on a partial version of the dataset used in\n", + "# MINIATURE EXCITATORY POST-SYNAPTIC CURRENTS (mEPSCs) Data from Marnie Phillips marnie.a.phillips@gmail.com This analysis is based on a partial version of the dataset used in\n", + "# MATLAB L600: % Phillips MA, Lewis LD, Gong J, Constantine-Paton M, Brown EN. 2011 Model-based statistical analysis of miniature synaptic transmission. J Neurophys (under consideration)\n", + "# Phillips MA, Lewis LD, Gong J, Constantine-Paton M, Brown EN. 2011 Model-based statistical analysis of miniature synaptic transmission. J Neurophys (under consideration)\n", + "# MATLAB L700: % Date: 03/01/2011\n", + "# Date: 03/01/2011\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "nstatpaperexamples-02", + "id": "5ebb0efb", "metadata": {}, "outputs": [], "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"echo off;\",\n", - " \"close all; clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"nSTATRootDir = fileparts(dataDir);\",\n", - " \"if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\",\n", - " \"cd(nSTATRootDir);\",\n", - " \"end\",\n", - " \"epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt'));\",\n", - " \"sampleRate = 1000;\",\n", - " \"spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds\",\n", - " \"nstConst = nspikeTrain(spikeTimes);\",\n", - " \"time = 0:(1/sampleRate):nstConst.maxTime;\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s',...\",\n", - " \"'',{'\\\\mu'});\",\n", - " \"covarColl = CovColl({baseline});\",\n", - " \"spikeColl = nstColl(nstConst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"clear tc tcc;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]);\",\n", - " \"tc{1}.setName('Constant Baseline');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"results.lambda.setDataLabels({'\\\\lambda_{const}'});\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\",\n", - " \"scrsz(3)*.98 scrsz(4)*.95]);\",\n", - " \"subplot(2,2,1); spikeColl.plot;\",\n", - " \"title({'Neural Raster with constant Mg^{2+} Concentration'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=ylabel('mEPSCs','Interpreter','none');\",\n", - " \"set(gca,'yTick',[0 1]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"subplot(2,2,3); results.KSPlot;\",\n", - " \"subplot(2,2,2); results.plotInvGausTrans;\",\n", - " \"subplot(2,2,4); results.lambda.plot([],{{' ''b'' ,''Linewidth'',2'}});\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=get(gca,'YLabel');\",\n", - " \"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"h_legend = legend('\\\\lambda_{const}','Location','NorthEast');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.05 pos(2) pos(3:4)]);\",\n", - " \"set(h_legend,'FontSize',14)\",\n", - " \"close all;\",\n", - " \"washout1 = importdata(fullfile(mEPSCDir,'washout1.txt'));\",\n", - " \"washout2 = importdata(fullfile(mEPSCDir,'washout2.txt'));\",\n", - " \"sampleRate = 1000;\",\n", - " \"spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\",\n", - " \"spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\",\n", - " \"nst = nspikeTrain([spikeTimes1; spikeTimes2]);\",\n", - " \"time = 260:(1/sampleRate):nst.maxTime;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...\",\n", - " \"scrsz(4)*.9]);\",\n", - " \"subplot(2,1,1);\",\n", - " \"nstConst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\",\n", - " \"title({'Neural Raster with constant Mg^{2+} Concentration'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=get(gca,'XLabel');\",\n", - " \"set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"subplot(2,1,2);\",\n", - " \"nst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\",\n", - " \"title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=get(gca,'XLabel');\",\n", - " \"set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\",\n", - " \"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\",\n", - " \"constantRate = ones(length(time),1);\",\n", - " \"rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;\",\n", - " \"rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;\",\n", - " \"rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;\",\n", - " \"baseline = Covariate(time,[constantRate,rate1, rate2, rate3],...\",\n", - " \"'Baseline','time','s','',{'\\\\mu','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'});\",\n", - " \"covarColl = CovColl({baseline});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"maxWindow=.3; numWindows=20;\",\n", - " \"delta=1/sampleRate;\",\n", - " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", - " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", - " \"windowTimes = windowTimes(1:11);\",\n", - " \"clear tc tcc;\",\n", - " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]);\",\n", - " \"tc{1}.setName('Constant Baseline');\",\n", - " \"tc{2} = TrialConfig({{'Baseline','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'}},...\",\n", - " \"sampleRate,[]); tc{2}.setName('Diff Baseline');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"results.lambda.setDataLabels({'\\\\lambda_{const}',...\",\n", - " \"'\\\\lambda_{const-epoch}'});\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\",\n", - " \"scrsz(3)*.98 scrsz(4)*.95]);\",\n", - " \"subplot(2,2,1); spikeColl.plot;\",\n", - " \"title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"set(gca,'YTickLabel',[]);\",\n", - " \"set([hx],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\",\n", - " \"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\",\n", - " \"plot([495;495],[0,1],'r','Linewidth',4); hold on;\",\n", - " \"plot([765;765],[0,1],'r','Linewidth',4);\",\n", - " \"subplot(2,2,3); results.KSPlot;\",\n", - " \"subplot(2,2,2); results.plotInvGausTrans;\",\n", - " \"subplot(2,2,4);\",\n", - " \"results.lambda.getSubSignal(1).plot([],{{' ''b'' ,''Linewidth'',2'}});\",\n", - " \"results.lambda.getSubSignal(2).plot([],{{' ''g'' ,''Linewidth'',2'}});\",\n", - " \"v=axis; axis([v(1) v(2) 0 5]);\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=get(gca,'YLabel');\",\n", - " \"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"h_legend = legend('\\\\lambda_{const}','\\\\lambda_{const-epoch}',...\",\n", - " \"'Location','NorthEast');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.05 pos(2)-.01 pos(3:4)]);\",\n", - " \"set(h_legend,'FontSize',14)\",\n", - " \"close all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"nSTATRootDir = fileparts(dataDir);\",\n", - " \"if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\",\n", - " \"cd(nSTATRootDir);\",\n", - " \"end\",\n", - " \"Direction=3; Neuron=1; Stim=2;\",\n", - " \"datapath = fullfile(explicitStimulusDir,['Dir' num2str(Direction)], ...\",\n", - " \"['Neuron' num2str(Neuron)],['Stim' num2str(Stim)]);\",\n", - " \"data = load(fullfile(datapath,'trngdataBis.mat'));\",\n", - " \"time=0:.001:(length(data.t)-1)*.001;\",\n", - " \"stimData = data.t;\",\n", - " \"spikeTimes = time(data.y==1);\",\n", - " \"stim = Covariate(time,stimData./10,'Stimulus','time','s','mm',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"nspikeColl = nstColl(nst);\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial = Trial(nspikeColl,cc);\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(3,1,1);\",\n", - " \"nst2 = nspikeTrain(spikeTimes);\",\n", - " \"nst2.setMaxTime(21);nst2.plot;\",\n", - " \"set(gca,'ytick',[0 1]);\",\n", - " \"xlabel('');\",\n", - " \"hy=ylabel('spikes');\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title({'Neural Raster'},'FontWeight','bold','FontSize',16,'FontName','Arial');\",\n", - " \"set(gca, ...\",\n", - " \"'XTick' , 0:1:max(time), ...\",\n", - " \"'XTickLabel' , [],...\",\n", - " \"'LineWidth' , 1 );\",\n", - " \"subplot(3,1,2);\",\n", - " \"stim.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\",\n", - " \"set(gca,'ytick',[0 0.5 1]);\",\n", - " \"hy=ylabel('Displacement [mm]','Interpreter','none'); xlabel('');\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title({'Stimulus - Whisker Displacement'},'FontWeight','bold',...\",\n", - " \"'FontSize',16,'FontName','Arial');\",\n", - " \"set(gca, ...\",\n", - " \"'XTick' , 0:1:max(time), ...\",\n", - " \"'XTickLabel' , [],...\",\n", - " \"'YTick' , 0:.25:1, ...\",\n", - " \"'LineWidth' , 1 );\",\n", - " \"subplot(3,1,3);\",\n", - " \"stim.derivative.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\",\n", - " \"set(gca,'ytick',[-80 0 80]);\",\n", - " \"axis([0 21 -80 80]);\",\n", - " \"hy=ylabel('Displacement Velocity [mm/s]','Interpreter','none');\",\n", - " \"hx= xlabel('time [s]','Interpreter','none');\",\n", - " \"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title({'Displacement Velocity'},'FontWeight','bold',...\",\n", - " \"'FontSize',16,'FontName','Arial');\",\n", - " \"set(gca, ...\",\n", - " \"'XTick' , 0:1:max(time), ...\",\n", - " \"'YTick' , -80:40:80, ...\",\n", - " \"'LineWidth' , 1 );\",\n", - " \"clear c; close all;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(7,2,[1 3 5])\",\n", - " \"results.Residual.xcov(stim).windowedSignal([0,1]).plot;\",\n", - " \"ylabel('');\",\n", - " \"[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));\",\n", - " \"title(['Cross Correlation Function - Peak at t=' num2str(ShiftTime) ' sec'],'FontWeight','bold',...\",\n", - " \"'FontSize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hold on;\",\n", - " \"h=plot(ShiftTime,m,'ro','Linewidth',3);\",\n", - " \"set(h, 'MarkerFaceColor',[1 0 0], 'MarkerEdgeColor',[1 0 0]);\",\n", - " \"hx=xlabel('Lag [s]','Interpreter','none');\",\n", - " \"set(hx,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\",\n", - " \"stim = stim.shift(ShiftTime);\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'\\\\mu'});\",\n", - " \"nst = nspikeTrain(spikeTimes);\",\n", - " \"nspikeColl = nstColl(nst);\",\n", - " \"cc = CovColl({stim,baseline});\",\n", - " \"trial2 = Trial(nspikeColl,cc);\",\n", - " \"clear c;\",\n", - " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", - " \"c{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,selfHist,...\",\n", - " \"NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','\\\\mu'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,selfHist,NeighborHist);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);\",\n", - " \"sampleRate=1000;\",\n", - " \"delta=1/sampleRate*1;\",\n", - " \"maxWindow=1; numWindows=32;\",\n", - " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", - " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", - " \"results =Analysis.computeHistLagForAll(trial2,windowTimes,...\",\n", - " \"{{'Baseline','\\\\mu'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\",\n", - " \"KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));\",\n", - " \"AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...\",\n", - " \"min(results{1}.AIC(2:end)-results{1}.AIC(1))) +1;\",\n", - " \"BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...\",\n", - " \"min(results{1}.BIC(2:end)-results{1}.BIC(1))) +1;\",\n", - " \"if(AICind==1)\",\n", - " \"AICind=inf;\",\n", - " \"end\",\n", - " \"if(BICind==1)\",\n", - " \"BICind=inf; %sometime BIC is non-decreasing and the index would be 1\",\n", - " \"end\",\n", - " \"windowIndex = min([AICind,BICind]) %use the minimum order model\",\n", - " \"Summary = FitResSummary(results);\",\n", - " \"clear c;\",\n", - " \"if(windowIndex>1)\",\n", - " \"selfHist = windowTimes(1:windowIndex+1);\",\n", - " \"else\",\n", - " \"selfHist = [];\",\n", - " \"end\",\n", - " \"NeighborHist = []; sampleRate = 1000;\",\n", - " \"subplot(7,2,2);\",\n", - " \"x=0:length(windowTimes)-1;\",\n", - " \"plot(x,results{1}.KSStats.ks_stat,'.-'); axis tight; hold on;\",\n", - " \"plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\",\n", - " \"set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\",\n", - " \"'TickLength', [.02 .02] , ...\",\n", - " \"'XMinorTick', 'on','LineWidth' , 1);\",\n", - " \"hy=ylabel('KS Statistic');\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"dAIC = results{1}.AIC-results{1}.AIC(1);\",\n", - " \"title({'Model Selection via change'; 'in KS Statistic, AIC, and BIC'},...\",\n", - " \"'FontWeight','bold',...\",\n", - " \"'FontSize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"subplot(7,2,4); plot(x,dAIC,'.-');\",\n", - " \"set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\",\n", - " \"'TickLength', [.02 .02] , ...\",\n", - " \"'XMinorTick', 'on','LineWidth' , 1);\",\n", - " \"hy=ylabel('\\\\Delta AIC');axis tight; hold on;\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"plot(x(windowIndex),dAIC(windowIndex),'r*');\",\n", - " \"dBIC = results{1}.BIC-results{1}.BIC(1);\",\n", - " \"subplot(7,2,6); plot(x,dBIC,'.-');\",\n", - " \"hy=ylabel('\\\\Delta BIC'); axis tight; hold on;\",\n", - " \"plot(x(windowIndex),dBIC(windowIndex),'r*');\",\n", - " \"hx=xlabel('# History Windows, Q');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"set(gca, ...\",\n", - " \"'TickLength' , [.02 .02] , ...\",\n", - " \"'XMinorTick' , 'on' , ...\",\n", - " \"'XTick' , 0:5:results{1}.numResults-1, ...\",\n", - " \"'LineWidth' , 1 );\",\n", - " \"c{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[],NeighborHist);\",\n", - " \"c{1}.setName('Baseline');\",\n", - " \"c{2} = TrialConfig({{'Baseline','\\\\mu'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,[],[]);\",\n", - " \"c{2}.setName('Baseline+Stimulus');\",\n", - " \"c{3} = TrialConfig({{'Baseline','\\\\mu'},{'Stimulus','stim'}},...\",\n", - " \"sampleRate,windowTimes(1:windowIndex),[]);\",\n", - " \"c{3}.setName('Baseline+Stimulus+Hist');\",\n", - " \"cfgColl= ConfigColl(c);\",\n", - " \"results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);\",\n", - " \"results.lambda.setDataLabels({'\\\\lambda_{const}','\\\\lambda_{const+stim}',...\",\n", - " \"'\\\\lambda_{const+stim+hist}'});\",\n", - " \"subplot(7,2,[9 11 13]); results.KSPlot;\",\n", - " \"subplot(7,2,[10 12 14]); results.plotCoeffs; legend off;\",\n", - " \"clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"close all;\",\n", - " \"delta = 0.001;\",\n", - " \"Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"f=2;\",\n", - " \"mu = -3;\",\n", - " \"tempData = 1*sin(2*pi*f*time)+mu; %lambda >=0\",\n", - " \"lambdaData = exp(tempData)./(1+exp(tempData))*(1/delta);\",\n", - " \"lambda = Covariate(time,lambdaData, '\\\\lambda(t)','time','s',...\",\n", - " \"'spikes/sec',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"numRealizations = 20;\",\n", - " \"spikeCollSim = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(2,2,3);spikeCollSim.plot;\",\n", - " \"set(gca,'YTick',0:5:numRealizations,'YTickLabel',0:5:numRealizations);\",\n", - " \"title({[num2str(numRealizations) ' Simulated Point Process Sample Paths']},...\",\n", - " \"'FontWeight','bold','Fontsize',14,'FontName','Arial');\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"subplot(2,2,1);lambda.plot;\",\n", - " \"title({'Simulated Conditional Intensity Function (CIF)'},...\",\n", - " \"'FontWeight','bold','FontSize',14,'FontName','Arial');\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"hy=get(gca,'YLabel');\",\n", - " \"set(hy,'FontName', 'Arial','FontSize',14,'FontWeight','bold');\",\n", - " \"x = load(fullfile(psthDir,'Results.mat'));\",\n", - " \"numTrials = x.Results.Data.Spike_times_STC.balanced_SUA.Nr_trials;\",\n", - " \"cellNum=6; clear nst;\",\n", - " \"for i=1:numTrials\",\n", - " \"spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};\",\n", - " \"nst{i} = nspikeTrain(spikeTimes{i});\",\n", - " \"nst{i}.setName(num2str(cellNum));\",\n", - " \"end\",\n", - " \"spikeCollReal1=nstColl(nst);\",\n", - " \"spikeCollReal1.setMinTime(0); spikeCollReal1.setMaxTime(2);\",\n", - " \"subplot(2,2,2);spikeCollReal1.plot; set(gca,'YTick',0:2:numTrials,...\",\n", - " \"'YTickLabel',0:2:numTrials);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"title('Response to Moving Visual Stimulus (Neuron 6)',...\",\n", - " \"'FontWeight','bold','Fontsize',14,'FontName','Arial');\",\n", - " \"cellNum=1; clear nst;\",\n", - " \"for i=1:numTrials\",\n", - " \"spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};\",\n", - " \"nst{i} = nspikeTrain(spikeTimes{i});\",\n", - " \"nst{i}.setName(num2str(cellNum));\",\n", - " \"end\",\n", - " \"spikeCollReal2=nstColl(nst);\",\n", - " \"spikeCollReal2.setMinTime(0); spikeCollReal2.setMaxTime(2);\",\n", - " \"subplot(2,2,4);spikeCollReal2.plot;\",\n", - " \"set(gca,'YTick',0:2:numTrials,'YTickLabel',0:2:numTrials);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"title('Response to Moving Visual Stimulus (Neuron 1)','FontWeight',...\",\n", - " \"'bold','Fontsize',14,'FontName','Arial');\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"binsize = .05; %50ms window\",\n", - " \"psth = spikeCollSim.psth(binsize);\",\n", - " \"psthGLM = spikeCollSim.psthGLM(binsize);\",\n", - " \"true = lambda; %rate*delta = expected number of arrivals per bin\",\n", - " \"subplot(2,3,4);\",\n", - " \"h1=true.plot([],{{' ''b'',''Linewidth'',4'}});\",\n", - " \"h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"legend off;\",\n", - " \"h_legend=legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.005 pos(2)+.095 pos(3:4)]);\",\n", - " \"subplot(2,3,1);spikeCollSim.plot;\",\n", - " \"set(gca,'YTick',0:2:spikeCollSim.numSpikeTrains,'YTickLabel',0:2:spikeCollSim.numSpikeTrains);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"subplot(2,3,5);\",\n", - " \"binsize = .05; %50ms window\",\n", - " \"psthReal1 = spikeCollReal1.psth(binsize);\",\n", - " \"psthGLMReal1 = spikeCollReal1.psthGLM(binsize);%,[],[],[],[],[],1000);\",\n", - " \"h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"h2=psthReal1.plot([],{{' ''rx'',''Linewidth'',4'}});\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\",\n", - " \"subplot(2,3,2); spikeCollReal1.plot;\",\n", - " \"set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"subplot(2,3,6);\",\n", - " \"psthReal2 = spikeCollReal2.psth(binsize);\",\n", - " \"psthGLMReal2 = spikeCollReal2.psthGLM(binsize);%,[],[],[],[],[],1000);\",\n", - " \"h3=psthGLMReal2.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"h2=psthReal2.plot([],{{' ''rx'',''Linewidth'',4'}});\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\",\n", - " \"subplot(2,3,3); spikeCollReal2.plot;\",\n", - " \"set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"close all;\",\n", - " \"clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"delta = 0.001; Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"Ts=.001;\",\n", - " \"numRealizations = 50; %Each realization corresponds to a distinct trial\",\n", - " \"for i=1:numRealizations\",\n", - " \"f=2; b1(i)=3*((i)/numRealizations);b0=-3;\",\n", - " \"u = sin(2*pi*f*time);\",\n", - " \"e = zeros(length(time),1); %No Ensemble input\",\n", - " \"stim=Covariate(time',u,'Stimulus','time','s','Voltage',{'sin'});\",\n", - " \"ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\",\n", - " \"mu=b0;\",\n", - " \"histCoeffs=[-4 -1 -.5];\",\n", - " \"H=tf(histCoeffs,[1],Ts,'Variable','z^-1');\",\n", - " \"S=tf([b1(i)],1,Ts,'Variable','z^-1');\",\n", - " \"E=tf([0],1,Ts,'Variable','z^-1');\",\n", - " \"simTypeSelect='binomial'; %Parameters are used to compute\",\n", - " \"[sC, lambdaTemp]=CIF.simulateCIF(mu,H,S,E,stim,ens,1,simTypeSelect);\",\n", - " \"if(i==1)\",\n", - " \"lambda=lambdaTemp; %Store the conditional intensity function\",\n", - " \"else\",\n", - " \"lambda = lambda.merge(lambdaTemp); %Add it to the other realizations\",\n", - " \"end\",\n", - " \"nst{i} = sC.getNST(1); %get the neural spikeTrain from the collection\",\n", - " \"nst{i} = nst{i}.resample(1/delta); %make sure that it is sampled at the current samplerate\",\n", - " \"end\",\n", - " \"spikeColl = nstColl(nst); %Create a collection of the spike trains across trials\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(3,2,[3 4]); spikeColl.plot;\",\n", - " \"set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\",\n", - " \"set(gca,'xtick',0:.1:Tmax,'xtickLabel',0:.1:Tmax); xlabel('');\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"title('Simulated Neural Raster','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',14,'FontWeight','bold');\",\n", - " \"stimData = exp(b0 + u'*b1);\",\n", - " \"if(strcmp(simTypeSelect,'binomial'))\",\n", - " \"stimData = stimData./(1+stimData);\",\n", - " \"end\",\n", - " \"subplot(3,2,1); plot(time,u,'k','LineWidth',3);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Stimulus','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"title('Within Trial Stimulus','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',14,'FontWeight','bold');\",\n", - " \"subplot(3,2,2); plot(1:length(b1),b1,'k','LineWidth',3);\",\n", - " \"xlabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"ylabel('Stimulus Gain','Interpreter','none','FontName', 'Arial','Fontsize',...\",\n", - " \"12,'FontWeight','bold');\",\n", - " \"title('Across Trial Stimulus Gain','Interpreter','none','FontName',...\",\n", - " \"'Arial','Fontsize',14,'FontWeight','bold');\",\n", - " \"subplot(3,2,[5 6]);\",\n", - " \"imagesc(stimData'./delta); set(gca, 'YDir','normal');\",\n", - " \"set(gca,'xtick',0:100:Tmax/delta,'xtickLabel',0:.1:Tmax);\",\n", - " \"set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\",\n", - " \"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\",\n", - " \"'Fontsize',12,'FontWeight','bold');\",\n", - " \"title('True Conditional Intensity Function','Interpreter',...\",\n", - " \"'none','FontName', 'Arial','Fontsize',14,'FontWeight','bold');\",\n", - " \"axis tight;\",\n", - " \"stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"windowTimes=[0:.001:.003];\",\n", - " \"numBasis = 25;\",\n", - " \"spikeColl.resample(1/delta); % Enforce sampleRate\",\n", - " \"spikeColl.setMaxTime(Tmax); % Make all spikeTrains end at time Tmax\",\n", - " \"dN=spikeColl.dataToMatrix'; % Convert the spikeTrains into a matrix\",\n", - " \"dN(dN>1)=1; % One should sample finely enough so there is\",\n", - " \"basisWidth=(spikeColl.maxTime-spikeColl.minTime)/numBasis;\",\n", - " \"if(simTypeSelect==0)\",\n", - " \"fitType='binomial';\",\n", - " \"else\",\n", - " \"fitType='poisson';\",\n", - " \"end\",\n", - " \"if(strcmp(fitType,'binomial'))\",\n", - " \"Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\",\n", - " \"else\",\n", - " \"Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\",\n", - " \"end\",\n", - " \"[psthSig, ~, psthResult] =spikeColl.psthGLM(basisWidth,windowTimes,fitType);\",\n", - " \"gamma0=psthResult.getHistCoeffs';%+.1*randn(size(histCoeffs));\",\n", - " \"gamma0(isnan(gamma0))=-5; % Depending on the amount of data the\",\n", - " \"x0=psthResult.getCoeffs; %The initial estimate for the SSGLM model\",\n", - " \"numVarEstIter=10;\",\n", - " \"Q0 = spikeColl.estimateVarianceAcrossTrials(numBasis,windowTimes,...\",\n", - " \"numVarEstIter,fitType);\",\n", - " \"A=eye(numBasis,numBasis);\",\n", - " \"delta = 1/spikeColl.sampleRate;\",\n", - " \"CompilingHelpFile=1;\",\n", - " \"if(~CompilingHelpFile)\",\n", - " \"Q0d=diag(Q0);\",\n", - " \"neuronName = psthResult.neuronNumber;\",\n", - " \"[xK,WK, WkuFinal,Qhat,gammahat,fitResults,stimulus,stimCIs,logll,...\",\n", - " \"QhatAll,gammahatAll,nIter]=DecodingAlgorithms.PPSS_EMFB(A,Q0d,x0,...\",\n", - " \"dN,fitType,delta,gamma0,windowTimes, numBasis,neuronName);\",\n", - " \"fR = fitResults.toStructure;\",\n", - " \"psthR = psthResult.toStructure;\",\n", - " \"end\",\n", - " \"installPath = which('nSTAT_Install');\",\n", - " \"if isempty(installPath)\",\n", - " \"error('nSTATPaperExamples:MissingInstallPath', ...\",\n", - " \"'Could not locate nSTAT_Install.m on MATLAB path.');\",\n", - " \"end\",\n", - " \"nstatRoot = fileparts(installPath);\",\n", - " \"if exist(nstatRoot,'dir') == 7 && ~strcmp(pwd,nstatRoot)\",\n", - " \"cd(nstatRoot);\",\n", - " \"end\",\n", - " \"addpath(nstatRoot,'-begin');\",\n", - " \"load(fullfile(nstatRoot,'data','SSGLMExampleData.mat'));\",\n", - " \"fitResults = FitResult.fromStructure(fR);\",\n", - " \"psthResult = FitResult.fromStructure(psthR);\",\n", - " \"t=psthResult.mergeResults(fitResults);\",\n", - " \"t.lambda.setDataLabels({'\\\\lambda_{PSTH}','\\\\lambda_{SSGLM}'});\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(2,2,1); t.KSPlot;\",\n", - " \"subplot(2,2,2); t.plotResidual;\",\n", - " \"subplot(2,2,3); t.plotInvGausTrans;\",\n", - " \"subplot(2,2,4); t.plotSeqCorr;\",\n", - " \"S=FitResSummary(t);\",\n", - " \"dAIC=diff(S.AIC)\",\n", - " \"dBIC=diff(S.BIC)\",\n", - " \"dKS =diff(S.KSStats);\",\n", - " \"close all;\",\n", - " \"minTime=0; maxTime = Tmax;\",\n", - " \"stimData = stim.data*b1;\",\n", - " \"if(strcmp(fitType,'poisson'))\",\n", - " \"actStimEffect=exp(stimData + b0)./delta;\",\n", - " \"elseif(strcmp(fitType,'binomial'))\",\n", - " \"actStimEffect=exp(stimData + b0)./(1+exp(stimData + b0))./delta;\",\n", - " \"end\",\n", - " \"if(~isempty(numBasis))\",\n", - " \"basisWidth = (maxTime-minTime)/numBasis;\",\n", - " \"sampleRate=1/delta;\",\n", - " \"unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,minTime,...\",\n", - " \"maxTime,sampleRate);\",\n", - " \"basisMat = unitPulseBasis.data;\",\n", - " \"end\",\n", - " \"if(strcmp(fitType,'poisson'))\",\n", - " \"estStimEffect=exp(basisMat*xK)./delta;\",\n", - " \"elseif(strcmp(fitType,'binomial'))\",\n", - " \"estStimEffect=exp(basisMat*xK)./(1+exp(basisMat*xK))./delta;\",\n", - " \"end\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\",\n", - " \"subplot(3,1,[1 2 3]);\",\n", - " \"lighting gouraud\",\n", - " \"surf((1:length(b1))',stim.time,actStimEffect,'FaceAlpha',0.1,...\",\n", - " \"'EdgeAlpha',0.1,'AlphaData',0.1);\",\n", - " \"hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\",\n", - " \"hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\",\n", - " \"set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),...\",\n", - " \"'FaceAlpha',0.5,'EdgeAlpha',0.1,'AlphaData',0.5); %xlabel('Trial [k]'); ylabel('time [s]'); zlabel('Stimulus Effect');\",\n", - " \"set(gca,'YDir','reverse');\",\n", - " \"set(gca,'ytick',0:.1:Tmax,'ytickLabel',0:.1:Tmax);\",\n", - " \"title('SSGLM Estimated vs. Actual Stimulus Effect','FontWeight','bold',...\",\n", - " \"'Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"close all;\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\",\n", - " \"subplot(3,1,1);\",\n", - " \"lighting gouraud\",\n", - " \"mesh((1:length(b1))',stim.time,actStimEffect);\",\n", - " \"hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\",\n", - " \"zlabel('Stimulus Effect [spikes/sec]'); hold all;\",\n", - " \"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('True Stimulus Effect','FontWeight','bold',...\",\n", - " \"'Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set(gca,'ytick',[],'ytickLabel',[]);\",\n", - " \"CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];\",\n", - " \"view(gca,[90 -90]);\",\n", - " \"subplot(3,1,2);\",\n", - " \"lighting gouraud\",\n", - " \"mesh((1:length(b1))',stim.time,repmat(psthSig.data, [1 numRealizations]));\",\n", - " \"hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\",\n", - " \"hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\",\n", - " \"set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('PSTH Estimated Stimulus Effect','FontWeight','bold',...\",\n", - " \"'Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set(gca,'ytick',[],'ytickLabel',[]);\",\n", - " \"CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];\",\n", - " \"view(gca,[90 -90]);\",\n", - " \"subplot(3,1,3);\",\n", - " \"lighting gouraud\",\n", - " \"mesh((1:length(b1))',stim.time,estStimEffect);\",\n", - " \"xlabel('Trial [k]'); ylabel('time [s]');\",\n", - " \"zlabel('Stimulus Effect [spikes/sec]'); hold all;\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); hz=get(gca,'ZLabel');\",\n", - " \"set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('SSGLM Estimated Stimulus Effect','FontWeight','bold',...\",\n", - " \"'Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set(gca,'ytick',[],'ytickLabel',[]);\",\n", - " \"set(gca, 'YDir','normal')\",\n", - " \"view(gca,[90 -90]);\",\n", - " \"echo off;\",\n", - " \"close all;\",\n", - " \"minTime=0; maxTime = Tmax;\",\n", - " \"if(~isempty(numBasis))\",\n", - " \"basisWidth = (maxTime-minTime)/numBasis;\",\n", - " \"sampleRate=1/delta;\",\n", - " \"unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,...\",\n", - " \"minTime,maxTime,sampleRate);\",\n", - " \"basisMat = unitPulseBasis.data;\",\n", - " \"end\",\n", - " \"t0=0; tf=Tmax;\",\n", - " \"[spikeRateBinom, ProbMat,sigMat]=DecodingAlgorithms.computeSpikeRateCIs(xK,...\",\n", - " \"WkuFinal,dN,t0,tf,fitType,delta,gammahat,windowTimes);\",\n", - " \"lt=find(sigMat(1,:)==1,1,'first');\",\n", - " \"display(['The learning trial (compared to the first trial) is trial #' ...\",\n", - " \"num2str(find(sigMat(1,:)==1,1,'first'))]);\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(2,3,1);\",\n", - " \"spikeRateBinom.setName(['(' num2str(Tmax) '-0)^-1*\\\\Lambda(0,' ...\",\n", - " \"num2str(Tmax) ')']);\",\n", - " \"spikeRateBinom.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"v=axis;\",\n", - " \"plot(lt*[1;1],v(3:4),'r','Linewidth',2);\",\n", - " \"hx=xlabel('Trial [k]','Interpreter','none'); hold all;\",\n", - " \"hy=ylabel('Average Firing Rate [spikes/sec]','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title(['Learning Trial:' num2str(lt)],'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"h=subplot(2,3,[2 3 5 6]);\",\n", - " \"K=size(dN,1);\",\n", - " \"colormap(flipud(gray));\",\n", - " \"imagesc(ProbMat); hold on;\",\n", - " \"for k=1:K\",\n", - " \"for m=(k+1):K\",\n", - " \"if(sigMat(k,m)==1)\",\n", - " \"plot3(m,k,1,'r*'); hold on;\",\n", - " \"end\",\n", - " \"end\",\n", - " \"end\",\n", - " \"set(h,'XAxisLocation','top','YAxisLocation','right');\",\n", - " \"hx=xlabel('Trial Number','Interpreter','none'); hold all;\",\n", - " \"hy=ylabel('Trial Number','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"subplot(2,3,4)\",\n", - " \"stim1 = Covariate(time, basisMat*stimulus(:,1),'Trial1','time','s',...\",\n", - " \"'spikes/sec');\",\n", - " \"temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,1,:)));\",\n", - " \"stim1.setConfInterval(temp);\",\n", - " \"stimlt = Covariate(time, basisMat*stimulus(:,lt),'Trial1','time','s',...\",\n", - " \"'spikes/sec');\",\n", - " \"temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt,:)));\",\n", - " \"temp.setColor('r');\",\n", - " \"stimlt.setConfInterval(temp);\",\n", - " \"stimltm1 = Covariate(time, basisMat*stimulus(:,lt-1),'Trial1','time','s',...\",\n", - " \"'spikes/sec');\",\n", - " \"temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt-1,:)));\",\n", - " \"temp.setColor('r');\",\n", - " \"stimltm1.setConfInterval(temp);\",\n", - " \"h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}}); hold all;\",\n", - " \"h2=stimlt.plot([],{{' ''r'',''Linewidth'',4'}});\",\n", - " \"hx=xlabel('time [s]','Interpreter','none'); hold all;\",\n", - " \"hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title({'Learning Trial Vs. Baseline Trial';'with 95% CIs'},'FontWeight','bold',...\",\n", - " \"'Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"h_legend=legend([h1(1) h2(1)],'\\\\lambda_{1}(t)',['\\\\lambda_{' num2str(lt) '}(t)']);\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.03 pos(2)+.01 pos(3:4)]);\",\n", - " \"close all;\",\n", - " \"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\",\n", - " \"exampleCell = [2 21 25 49];\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9]);\",\n", - " \"for i=1:length(exampleCell)\",\n", - " \"subplot(2,2,i);\",\n", - " \"h1=plot(x,y,'b','Linewidth',.5); hold on;\",\n", - " \"h2=plot(neuron{exampleCell(i)}.xN,neuron{exampleCell(i)}.yN,'r.',...\",\n", - " \"'MarkerSize',7);\",\n", - " \"hx=xlabel('X Position'); hy=ylabel('Y Position');\",\n", - " \"title(['Cell#' num2str(exampleCell(i))],'FontWeight','bold',...\",\n", - " \"'Fontsize',12,'FontName','Arial');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"set(gca,'xTick',-1:.5:1,'yTick',-1:.5:1); axis square;\",\n", - " \"if(i==4)\",\n", - " \"h_legend = legend([h1 h2],'Animal Path',...\",\n", - " \"'Location at time of spike');\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.09 pos(2)+.06 pos(3:4)]);\",\n", - " \"end\",\n", - " \"end\",\n", - " \"numAnimals=2;\",\n", - " \"CompilingHelpFile=1;\",\n", - " \"if(~CompilingHelpFile)\",\n", - " \"for n=1:numAnimals\",\n", - " \"clear x y neuron time nst tc tcc z;\",\n", - " \"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\",\n", - " \"for i=1:length(neuron)\",\n", - " \"nst{i} = nspikeTrain(neuron{i}.spikeTimes);\",\n", - " \"end\",\n", - " \"[theta,r] = cart2pol(x,y);\",\n", - " \"cnt=0;\",\n", - " \"for l=0:3\",\n", - " \"for m=-l:l\",\n", - " \"if(~any(mod(l-m,2))) % otherwise the polynomial = 0\",\n", - " \"cnt = cnt+1;\",\n", - " \"z(:,cnt) = zernfun(l,m,r,theta,'norm');\",\n", - " \"end\",\n", - " \"end\",\n", - " \"end\",\n", - " \"delta=min(diff(time));\",\n", - " \"sampleRate = round(1/delta);\",\n", - " \"baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\",\n", - " \"{'mu'});\",\n", - " \"zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\",\n", - " \"'z4','z5','z6','z7','z8','z9','z10'});\",\n", - " \"gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\",\n", - " \"'s','m',{'x','y','x^2','y^2','x*y'});\",\n", - " \"covarColl = CovColl({baseline,gaussian,zernike});\",\n", - " \"spikeColl = nstColl(nst);\",\n", - " \"trial = Trial(spikeColl,covarColl);\",\n", - " \"tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\",\n", - " \"'x','y','x^2','y^2','x*y'}},sampleRate,[]);\",\n", - " \"tc{1}.setName('Gaussian');\",\n", - " \"tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\",\n", - " \"'z7','z8','z9','z10'}},sampleRate,[]);\",\n", - " \"tc{2}.setName('Zernike');\",\n", - " \"tcc = ConfigColl(tc);\",\n", - " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", - " \"resStruct =FitResult.CellArrayToStructure(results);\",\n", - " \"filename = fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results']);\",\n", - " \"save(filename,'resStruct');\",\n", - " \"end\",\n", - " \"end\",\n", - " \"clear Summary;\",\n", - " \"numAnimals =2;\",\n", - " \"for n=1:numAnimals\",\n", - " \"resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\",\n", - " \"results = FitResult.fromStructure(resData.resStruct);\",\n", - " \"Summary{n} = FitResSummary(results);\",\n", - " \"end\",\n", - " \"close all;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5]);\",\n", - " \"subplot(1,3,1);\",\n", - " \"maxLength = max([Summary{1}.numNeurons,Summary{2}.numNeurons]);\",\n", - " \"dKS = nan(maxLength, 2);\",\n", - " \"dKS(1:Summary{1}.numNeurons,1) = (Summary{1}.KSStats(:,1)-Summary{1}.KSStats(:,2)) ;\",\n", - " \"dKS(1:Summary{2}.numNeurons,2) = (Summary{2}.KSStats(:,1)-Summary{2}.KSStats(:,2)) ;\",\n", - " \"boxplot(dKS ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\",\n", - " \"title('\\\\Delta KS Statistic','FontWeight','bold','FontSize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"subplot(1,3,2);\",\n", - " \"dAIC = nan(maxLength, 2);\",\n", - " \"dAIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffAIC(1);\",\n", - " \"dAIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffAIC(1);\",\n", - " \"boxplot(dAIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\",\n", - " \"title('\\\\Delta AIC','FontWeight','bold','FontSize',14,'FontName','Arial');\",\n", - " \"subplot(1,3,3);\",\n", - " \"dBIC = nan(maxLength, 2);\",\n", - " \"dBIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffBIC(1);\",\n", - " \"dBIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffBIC(1);\",\n", - " \"boxplot(dBIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline'); %ylabel('\\\\Delta BIC'); %xticklabel_rotate([],45,[],'Fontsize',6);\",\n", - " \"title('\\\\Delta BIC','FontWeight','bold','FontSize',14,'FontName','Arial');\",\n", - " \"close all;\",\n", - " \"[x_new,y_new]=meshgrid(-1:.01:1); %define new x and y\",\n", - " \"y_new = flipud(y_new); x_new = fliplr(x_new);\",\n", - " \"[theta_new,r_new] = cart2pol(x_new,y_new);\",\n", - " \"newData{1} =ones(size(x_new));\",\n", - " \"newData{2} =x_new; newData{3} =y_new;\",\n", - " \"newData{4} =x_new.^2; newData{5} =y_new.^2;\",\n", - " \"newData{6} =x_new.*y_new;\",\n", - " \"idx = r_new<=1;\",\n", - " \"zpoly = cell(1,10);\",\n", - " \"cnt=0;\",\n", - " \"for l=0:3\",\n", - " \"for m=-l:l\",\n", - " \"if(~any(mod(l-m,2)))\",\n", - " \"cnt = cnt+1;\",\n", - " \"temp = nan(size(x_new));\",\n", - " \"temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\",\n", - " \"zpoly{cnt} = temp;\",\n", - " \"end\",\n", - " \"end\",\n", - " \"end\",\n", - " \"for n=1:numAnimals\",\n", - " \"clear lambdaGaussian lambdaZernike;\",\n", - " \"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\",\n", - " \"resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\",\n", - " \"results = FitResult.fromStructure(resData.resStruct);\",\n", - " \"for i=1:length(neuron)\",\n", - " \"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\",\n", - " \"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\",\n", - " \"end\",\n", - " \"for i=1:length(neuron)\",\n", - " \"if(n==1)\",\n", - " \"h4=figure(4);\",\n", - " \"colormap('jet');\",\n", - " \"if(i==1)\",\n", - " \"tb=annotation(h4,'textbox',...\",\n", - " \"[0.283261904761904 0.928571428571418 ...\",\n", - " \"0.392857142857143 0.0595238095238095],...\",\n", - " \"'String',{['Gaussian Place Fields - Animal#' ...\",\n", - " \"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\",\n", - " \"'FontName','Arial','FontWeight','bold','LineStyle',...\",\n", - " \"'none','HorizontalAlignment','center'); hold on;\",\n", - " \"end\",\n", - " \"subplot(7,7,i);\",\n", - " \"elseif(n==2)\",\n", - " \"h6=figure(6);\",\n", - " \"colormap('jet');\",\n", - " \"if(i==1)\",\n", - " \"annotation(h6,'textbox',...\",\n", - " \"[0.283261904761904 0.928571428571418 ...\",\n", - " \"0.392857142857143 0.0595238095238095],...\",\n", - " \"'String',{['Gaussian Place Fields - Animal#' ...\",\n", - " \"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\",\n", - " \"'FontName','Arial','FontWeight','bold','LineStyle',...\",\n", - " \"'none','HorizontalAlignment','center'); hold on;\",\n", - " \"end\",\n", - " \"subplot(6,7,i);\",\n", - " \"end\",\n", - " \"pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\",\n", - " \"axis square; set(gca,'xtick',[],'ytick',[]);\",\n", - " \"set(gca, 'Box' , 'off');\",\n", - " \"if(n==1)\",\n", - " \"h5=figure(5);\",\n", - " \"colormap('jet');\",\n", - " \"if(i==1)\",\n", - " \"annotation(h5,'textbox',...\",\n", - " \"[0.303261904761904 0.928571428571418 ...\",\n", - " \"0.392857142857143 0.0595238095238095],...\",\n", - " \"'String',{['Zernike Place Fields - Animal#' ...\",\n", - " \"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\",\n", - " \"'FontName','Arial','FontWeight','bold','LineStyle','none'); hold on;\",\n", - " \"end\",\n", - " \"subplot(7,7,i);\",\n", - " \"elseif(n==2)\",\n", - " \"h7=figure(7);\",\n", - " \"colormap('jet');\",\n", - " \"if(i==1)\",\n", - " \"annotation(h7,'textbox',...\",\n", - " \"[0.303261904761904 0.928571428571418 ...\",\n", - " \"0.392857142857143 0.0595238095238095],...\",\n", - " \"'String',{['Zernike Place Fields - Animal#' ...\",\n", - " \"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\",\n", - " \"'FontName','Arial','FontWeight','bold','LineStyle',...\",\n", - " \"'none','HorizontalAlignment','center'); hold on;\",\n", - " \"end\",\n", - " \"subplot(6,7,i);\",\n", - " \"end\",\n", - " \"pcolor(x_new,y_new,lambdaZernike{i}), shading interp\",\n", - " \"axis square;\",\n", - " \"set(gca,'xtick',[],'ytick',[]);\",\n", - " \"set(gca, 'Box' , 'off');\",\n", - " \"end\",\n", - " \"end\",\n", - " \"clear lambdaGaussian lambdaZernike;\",\n", - " \"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\",\n", - " \"resData = load(fullfile(dataDir,'PlaceCellAnimal1Results.mat'));\",\n", - " \"results = FitResult.fromStructure(resData.resStruct);\",\n", - " \"for i=1:length(neuron)\",\n", - " \"lambdaGaussian{i} = results{i}.evalLambda(1,newData);\",\n", - " \"lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\",\n", - " \"end\",\n", - " \"exampleCell = 25;\",\n", - " \"close all;\",\n", - " \"h9=figure(9);\",\n", - " \"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\",\n", - " \"get(h_mesh,'AlphaData');\",\n", - " \"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\",\n", - " \"hold on;\",\n", - " \"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\",\n", - " \"get(h_mesh,'AlphaData');\",\n", - " \"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\",\n", - " \"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\",\n", - " \"axis tight square;\",\n", - " \"xlabel('x position'); ylabel('y position');\",\n", - " \"title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...\",\n", - " \"'Fontsize',12,'FontName','Arial');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"close all; clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"delta = 0.001; Tmax = 1;\",\n", - " \"time = 0:delta:Tmax;\",\n", - " \"numRealizations = 20;\",\n", - " \"f=2; b1=randn(numRealizations,1);b0=log(10*delta)+randn(numRealizations,1);\",\n", - " \"x = sin(2*pi*f*time);\",\n", - " \"clear nst;\",\n", - " \"for i=1:numRealizations\",\n", - " \"expData = exp(b1(i)*x+b0(i));\",\n", - " \"lambdaData = expData./(1+expData);\",\n", - " \"if(i==1)\",\n", - " \"lambda = Covariate(time,lambdaData./delta, ...\",\n", - " \"'\\\\Lambda(t)','time','s','spikes/sec',{'\\\\lambda_{1}'},...\",\n", - " \"{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"else\",\n", - " \"tempLambda = Covariate(time,lambdaData./delta, ...\",\n", - " \"'\\\\Lambda(t)','time','s','spikes/sec',{'\\\\lambda_{1}'},...\",\n", - " \"{{' ''b'', ''LineWidth'' ,2'}});\",\n", - " \"lambda = lambda.merge(tempLambda);\",\n", - " \"end\",\n", - " \"spikeColl = CIF.simulateCIFByThinningFromLambda(...\",\n", - " \"lambda.getSubSignal(i),1);\",\n", - " \"nst{i} = spikeColl.getNST(1);\",\n", - " \"end\",\n", - " \"spikeColl = nstColl(nst);scrsz = get(0,'ScreenSize');\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...\",\n", - " \"scrsz(3)*.6 scrsz(4)*.8]);\",\n", - " \"subplot(3,1,1); plot(time,x,'k');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]); ylabel('Stimulus');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('Driving Stimulus','FontWeight','bold',...\",\n", - " \"'FontSize',14,'FontName','Arial');\",\n", - " \"subplot(3,1,2); lambda.plot([],{{' ''k'',''Linewidth'',1'}});\",\n", - " \"legend off;\",\n", - " \"hy=ylabel('Firing Rate [spikes/sec]', 'Interpreter','none');\",\n", - " \"hx=xlabel('','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,...\",\n", - " \"'FontWeight','bold');\",\n", - " \"set(gca,'xtickLabel',[]);\",\n", - " \"title('Conditional Intensity Functions','FontWeight',...\",\n", - " \"'bold','FontSize',14,'FontName','Arial');\",\n", - " \"subplot(3,1,3); spikeColl.plot;\",\n", - " \"set(gca,'ytick',0:10:numRealizations,'ytickLabel',...\",\n", - " \"0:10:numRealizations);\",\n", - " \"xlabel('time [s]','Interpreter','none');\",\n", - " \"ylabel('Cell Number','Interpreter','none');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('Point Process Sample Paths','FontWeight',...\",\n", - " \"'bold','FontSize',14,'FontName','Arial');\",\n", - " \"stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\",\n", - " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", - " \"{'constant'});\",\n", - " \"close all;\",\n", - " \"clear lambdaCIF;\",\n", - " \"spikeColl.resample(1/delta);\",\n", - " \"dN=spikeColl.dataToMatrix;\",\n", - " \"Q=std(stim.data(2:end)-stim.data(1:end-1));\",\n", - " \"Px0=.1; A=1;\",\n", - " \"x0 = x(:,1); yT=x(:,end);\",\n", - " \"Pi0 = eps*eye(size(x0,1),size(x0,1));\",\n", - " \"PiT = eps*eye(size(x0,1),size(x0,1));\",\n", - " \"[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, ...\",\n", - " \"Q, dN',b0,b1','binomial',delta);\",\n", - " \"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]);\",\n", - " \"zVal=1.96;\",\n", - " \"ciLower = min(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\",\n", - " \"x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\",\n", - " \"ciUpper = max(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\",\n", - " \"x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\",\n", - " \"estimatedStimulus = Covariate(time,x_u(1:end),'\\\\hat{x}(t)','time','s','');\",\n", - " \"CI= ConfidenceInterval(time,[ciLower', ciUpper'],'\\\\hat{x}(t)','time','s','');\",\n", - " \"estimatedStimulus.setConfInterval(CI);\",\n", - " \"hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}});\",\n", - " \"hStim=stim.plot([],{{' ''b'',''Linewidth'',4'}});\",\n", - " \"legend off;\",\n", - " \"h_legend=legend([hEst(1) hStim],'Decoded','Actual');\",\n", - " \"set(h_legend,'Interpreter','none');\",\n", - " \"set(h_legend,'FontSize',22);\",\n", - " \"title(['Decoded Stimulus +/- 95% CIs with ' num2str(numRealizations) ' cells'],...\",\n", - " \"'FontWeight','bold','Fontsize',22,'FontName','Arial');\",\n", - " \"xlabel('time [s]','Interpreter','none');\",\n", - " \"ylabel('Stimulus','Interpreter','none');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',22,'FontWeight','bold');\",\n", - " \"close all;\",\n", - " \"clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"q=1e-4;\",\n", - " \"Q=diag([1e-12 1e-12 q q]);\",\n", - " \"delta = .001; % Time increment\",\n", - " \"r=1e-6; % in meters^2\",\n", - " \"p=1e-6; % in meters^2/s^2\",\n", - " \"PiT=diag([r r p p]); % Uncertainty in the target state\",\n", - " \"Pi0=PiT;\",\n", - " \"T=2; % Reach Duration\",\n", - " \"x0 = [0;0;0;0]; % Initial Position and velocities (states)\",\n", - " \"xT = [-.35;.2; 0;0];% Final Target\",\n", - " \"time=0:delta:T; % time vector\",\n", - " \"A=[1 0 delta 0 ; %State transition matrix\",\n", - " \"0 1 0 delta;\",\n", - " \"0 0 1 0 ;\",\n", - " \"0 0 0 1 ];\",\n", - " \"x=zeros(4,length(time));\",\n", - " \"R=chol(Q);\",\n", - " \"L=chol(PiT);\",\n", - " \"for k=1:length(time)\",\n", - " \"if(k==1)\",\n", - " \"x(:,k)=x0;\",\n", - " \"else\",\n", - " \"x(:,k)=A*x(:,k-1)+...\",\n", - " \"delta/(2)*(pi/T)^2*cos(pi*time(k)/T)*[0;0;...\",\n", - " \"xT(1)-x0(1);xT(2)-x0(2)]; %Reach to target model\",\n", - " \"end\",\n", - " \"end\",\n", - " \"xT =x(:,end); % The target generated by the model\",\n", - " \"yT=xT; % Assume we have observed the actual target position with uncertainty PiT\",\n", - " \"Q=diag(var(diff(x,[],2),[],2))*100;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\",\n", - " \"scrsz(3)*.8 scrsz(4)*.8]);\",\n", - " \"subplot(4,2,[1 3]);\",\n", - " \"plot(100*x(1,:),100*x(2,:),'k','Linewidth',2);\",\n", - " \"xlabel('X Position [cm]'); ylabel('Y Position [cm]');\",\n", - " \"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"title('Reach Path','FontWeight','bold','Fontsize',14,'FontName','Arial');\",\n", - " \"hold on;\",\n", - " \"axis([sort([100*x0(1)+5, 100*xT(1)-5]), sort([100*x0(2)-5, 100*xT(2)+5])]);\",\n", - " \"h1=plot(100*x(1,1),100*x(2,1),'bo','MarkerSize',14);\",\n", - " \"h2=plot(100*x(1,end),100*x(2,end),'ro','MarkerSize',14);\",\n", - " \"legend([h1 h2],'Start','Finish','Location','NorthEast');\",\n", - " \"subplot(4,2,5); h1=plot(time,100*x(1,:),'k','Linewidth',2); hold on;\",\n", - " \"h2=plot(time,100*x(2,:),'k-.','Linewidth',2);\",\n", - " \"h_legend=legend([h1,h2],'x','y','Location','NorthEast');\",\n", - " \"set(h_legend,'FontSize',14)\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\",\n", - " \"hx=xlabel('time [s]'); hy=ylabel('Position [cm]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"subplot(4,2,7);\",\n", - " \"h1=plot(time,100*x(3,:),'k','Linewidth',2); hold on;\",\n", - " \"h2=plot(time,100*x(4,:),'k-.','Linewidth',2);\",\n", - " \"h_legend=legend([h1 h2],'v_x','v_y','Location','NorthEast');\",\n", - " \"xlabel('time [s]');\",\n", - " \"set(h_legend,'FontSize',14);\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\",\n", - " \"hx=xlabel('time [s]'); hy=ylabel('Velocity [cm/s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"gamma=0;\",\n", - " \"windowTimes=[0, 0.001];\",\n", - " \"numCells = 20;\",\n", - " \"bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);\",\n", - " \"phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell\",\n", - " \"phiMaxNorm = (phiMax+pi)./(2*pi);\",\n", - " \"meanMu = log(10*delta); % baseline firing rate -10Hz\",\n", - " \"MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)\",\n", - " \"dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\",\n", - " \"coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta\",\n", - " \"fitType='binomial';\",\n", - " \"clear nst;\",\n", - " \"for i=1:numCells\",\n", - " \"tempData = exp(dataMat*coeffs(i,:)');\",\n", - " \"if(strcmp(fitType,'poisson'))\",\n", - " \"lambdaData = tempData;\",\n", - " \"else\",\n", - " \"lambdaData = tempData./(1+tempData); % Conditional Intensity Function for ith cell\",\n", - " \"end\",\n", - " \"lambda{i}=Covariate(time,lambdaData./delta, ...\",\n", - " \"'\\\\Lambda(t)','time','s','spikes/sec',...\",\n", - " \"{strcat('\\\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\",\n", - " \"lambda{i}=lambda{i}.resample(1/delta);\",\n", - " \"lambdaCIF{i} = CIF([MuCoeffs(i) 0 0 bCoeffs(i,:)],...\",\n", - " \"{'1','x','y','vx','vy'},{'x','y','vx','vy'},fitType);\",\n", - " \"tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1); nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization\",\n", - " \"nst{i}.setName(num2str(i)); % give each cell a unique name\",\n", - " \"subplot(4,2,[6 8]);\",\n", - " \"h2=lambda{i}.plot([],{{' ''k'', ''LineWidth'' ,.5'}});\",\n", - " \"legend off; hold all; % Plot the CIF\",\n", - " \"end\",\n", - " \"title('Neural Conditional Intensity Functions','FontWeight',...\",\n", - " \"'bold','Fontsize',14,'FontName','Arial');\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"spikeColl = nstColl(nst); % Create a neural spike train collection\",\n", - " \"subplot(4,2,[2,4]); spikeColl.plot;\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"title('Neural Raster','FontWeight','bold','Fontsize',14,...\",\n", - " \"'FontName','Arial');\",\n", - " \"hx=xlabel('time [s]','Interpreter','none');\",\n", - " \"hy=ylabel('Cell Number','Interpreter','none');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\",\n", - " \"close all;\",\n", - " \"numExamples=20;\",\n", - " \"scrsz = get(0,'ScreenSize');\",\n", - " \"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\",\n", - " \"scrsz(3)*.6 scrsz(4)*.9]);\",\n", - " \"for k=1:numExamples\",\n", - " \"bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);\",\n", - " \"phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell\",\n", - " \"phiMaxNorm = (phiMax+pi)./(2*pi);\",\n", - " \"meanMu = log(10*delta); % baseline firing rate\",\n", - " \"MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)\",\n", - " \"dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\",\n", - " \"coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta\",\n", - " \"fitType='binomial';\",\n", - " \"clear nst lambda;\",\n", - " \"for i=1:numCells\",\n", - " \"tempData = exp(dataMat*coeffs(i,:)');\",\n", - " \"if(strcmp(fitType,'poisson'))\",\n", - " \"lambdaData = tempData;\",\n", - " \"else\",\n", - " \"lambdaData = tempData./(1+tempData);\",\n", - " \"end\",\n", - " \"lambda{i}=Covariate(time,lambdaData./delta, ...\",\n", - " \"'\\\\Lambda(t)','time','s','spikes/sec',...\",\n", - " \"{strcat('\\\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\",\n", - " \"lambda{i}=lambda{i}.resample(1/delta);\",\n", - " \"tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);\",\n", - " \"nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization\",\n", - " \"nst{i}.setName(num2str(i)); % give each cell a unique name\",\n", - " \"end\",\n", - " \"spikeColl = nstColl(nst); % Create a neural spike train collection\",\n", - " \"dN=spikeColl.dataToMatrix';\",\n", - " \"dN(dN>1)=1; % more than one spike per bin will be treated as one spike. In\",\n", - " \"[C,N] = size(dN); % N time samples, C cells\",\n", - " \"beta=[zeros(2,numCells); bCoeffs'];\",\n", - " \"[x_p, W_p, x_u, W_u,x_uT,W_uT,x_pT,W_pT] = ...\",\n", - " \"DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...\",\n", - " \"MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0, Pi0, yT,PiT,0);\",\n", - " \"[x_pf, W_pf, x_uf, W_uf] = ...\",\n", - " \"DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...\",\n", - " \"MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0);\",\n", - " \"if(k==numExamples)\",\n", - " \"subplot(4,2,1:4);h1=plot(100*x(1,:),100*x(2,:),'k','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"axis([sort([100*x0(1)+5, 100*xT(1)-5]), ...\",\n", - " \"sort([100*x0(2)-5, 100*xT(2)+5])]);\",\n", - " \"title('Estimated vs. Actual Reach Paths',...\",\n", - " \"'FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"end\",\n", - " \"subplot(4,2,1:4);h2=plot(100*x_u(1,:)',100*x_u(2,:)','b'); hold all;\",\n", - " \"subplot(4,2,1:4);h3=plot(100*x_uf(1,:)',100*x_uf(2,:)','g');\",\n", - " \"hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"h1=plot(100*x0(1),100*x0(2),'bo','MarkerSize',10); hold on;\",\n", - " \"h2=plot(100*xT(1),100*xT(2),'ro','MarkerSize',10);\",\n", - " \"legend([h1 h2],'Start','Finish','Location','NorthEast');\",\n", - " \"subplot(4,2,5);\",\n", - " \"h1=plot(time,100*x(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*x_u(1,:)','b');\",\n", - " \"h3=plot(time,100*x_uf(1,:)','g');\",\n", - " \"hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,2,6);\",\n", - " \"h1=plot(time,100*x(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*x_u(2,:)','b');\",\n", - " \"h3=plot(time,100*x_uf(2,:)','g');\",\n", - " \"h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\",\n", - " \"'PPAF','Location','SouthEast');\",\n", - " \"hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"set(h_legend,'FontSize',10)\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)-.63 pos(2)+.23 pos(3:4)]);\",\n", - " \"subplot(4,2,7);\",\n", - " \"h1=plot(time,100*x(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*x_u(3,:)','b');\",\n", - " \"h3=plot(time,100*x_uf(3,:)','g');\",\n", - " \"hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,2,8);\",\n", - " \"h1=plot(time,100*x(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*x_u(4,:)','b');\",\n", - " \"h3=plot(time,100*x_uf(4,:)','g');\",\n", - " \"hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"end\",\n", - " \"clear all;\",\n", - " \"[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs();\",\n", - " \"close all;\",\n", - " \"delta=0.001;\",\n", - " \"Tmax=2;\",\n", - " \"time=0:delta:Tmax;\",\n", - " \"A{2} = [1 0 delta 0 delta^2/2 0;\",\n", - " \"0 1 0 delta 0 delta^2/2;\",\n", - " \"0 0 1 0 delta 0;\",\n", - " \"0 0 0 1 0 delta;\",\n", - " \"0 0 0 0 1 0;\",\n", - " \"0 0 0 0 0 1];\",\n", - " \"A{1} = [1 0 0 0 0 0;\",\n", - " \"0 1 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0;\",\n", - " \"0 0 0 0 0 0];\",\n", - " \"A{1} = [1 0;\",\n", - " \"0 1];\",\n", - " \"Px0{2} =1e-6*eye(6,6);\",\n", - " \"Px0{1} =1e-6*eye(2,2);\",\n", - " \"minCovVal = 1e-12;\",\n", - " \"covVal = 1e-3;\",\n", - " \"Q{2}=[minCovVal 0 0 0 0 0;\",\n", - " \"0 minCovVal 0 0 0 0;\",\n", - " \"0 0 minCovVal 0 0 0;\",\n", - " \"0 0 0 minCovVal 0 0;\",\n", - " \"0 0 0 0 covVal 0;\",\n", - " \"0 0 0 0 0 covVal];\",\n", - " \"Q{1}=minCovVal*eye(2,2);\",\n", - " \"mstate = zeros(1,length(time));\",\n", - " \"ind{1}=1:2;\",\n", - " \"ind{2}=1:6;\",\n", - " \"X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));\",\n", - " \"p_ij = [.998 .002;\",\n", - " \".001 .999];\",\n", - " \"for i = 1:length(time)\",\n", - " \"if(i==1)\",\n", - " \"mstate(i) = 1;\",\n", - " \"else\",\n", - " \"if(rand(1,1)1)=1; %Avoid more than 1 spike per bin.\",\n", - " \"Mu0=.5*ones(size(p_ij,1),1);\",\n", - " \"clear x0 yT clear Pi0 PiT;\",\n", - " \"x0{1} = X(ind{1},1);\",\n", - " \"yT{1} = X(ind{1},end);\",\n", - " \"Pi0 = Px0;\",\n", - " \"PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));\",\n", - " \"x0{2} = X(ind{2},1);\",\n", - " \"yT{2} = X(ind{2},end);\",\n", - " \"PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));\",\n", - " \"[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...\",\n", - " \"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\",\n", - " \"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\",\n", - " \"[S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...\",\n", - " \"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\",\n", - " \"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0);\",\n", - " \"X_estAll(:,:,n) = X_est;\",\n", - " \"X_estNTAll(:,:,n) = X_estNT;\",\n", - " \"S_estAll(n,:)=S_est;\",\n", - " \"S_estNTAll(n,:)=S_estNT;\",\n", - " \"MU_estAll(:,:,n)=MU_est;\",\n", - " \"MU_estNTAll(:,:,n) = MU_estNT;\",\n", - " \"subplot(4,3,[1 4]);\",\n", - " \"plot(time,mstate,'k','LineWidth',3); hold all;\",\n", - " \"plot(time,S_est,'b-.','Linewidth',.5);\",\n", - " \"plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\",\n", - " \"axis([v(1) v(2) 0.5 2.5]);\",\n", - " \"subplot(4,3,[7 10]);\",\n", - " \"plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\",\n", - " \"plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\",\n", - " \"axis([min(time) max(time) 0 1.1]);\",\n", - " \"subplot(4,3,[2 3 5 6]);\",\n", - " \"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\",\n", - " \"h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\",\n", - " \"h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\",\n", - " \"subplot(4,3,8);\",\n", - " \"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(1,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(1,:)','g-.');\",\n", - " \"subplot(4,3,9);\",\n", - " \"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(2,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(2,:)','g-.');\",\n", - " \"subplot(4,3,11);\",\n", - " \"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(3,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(3,:)','g-.');\",\n", - " \"subplot(4,3,12);\",\n", - " \"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,100*X_est(4,:)','b-.');\",\n", - " \"h3=plot(time,100*X_estNT(4,:)','g-.');\",\n", - " \"end\",\n", - " \"subplot(4,3,[1 4]);\",\n", - " \"hold all;\",\n", - " \"plot(time,mstate,'k','LineWidth',3);\",\n", - " \"plot(time,mean(S_estAll),'b','LineWidth',3);\",\n", - " \"plot(time,mean(S_estNTAll),'g','LineWidth',3);\",\n", - " \"set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\",\n", - " \"hy=ylabel('state'); hx=xlabel('time [s]');\",\n", - " \"set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\",\n", - " \"'Interpreter','none');\",\n", - " \"title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\",\n", - " \"12,'FontName','Arial');\",\n", - " \"subplot(4,3,[7 10]);\",\n", - " \"plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\",\n", - " \"hold on;\",\n", - " \"axis([min(time) max(time) 0 1.1]);\",\n", - " \"hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Probability of State','FontWeight','bold','Fontsize',12,...\",\n", - " \"'FontName','Arial');\",\n", - " \"subplot(4,3,[2 3 5 6]);\",\n", - " \"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\",\n", - " \"mXestAll=mean(100*X_estAll,3);\",\n", - " \"mXestNTAll=mean(100*X_estNTAll,3);\",\n", - " \"plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\",\n", - " \"plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\",\n", - " \"hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\",\n", - " \"h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\",\n", - " \"legend([h1 h2],'Start','Finish','Location','NorthEast');\",\n", - " \"title('Estimated vs. Actual Reach Path','FontWeight','bold',...\",\n", - " \"'Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,8);\",\n", - " \"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,9);\",\n", - " \"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\",\n", - " \"h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\",\n", - " \"'PPAF','Location','SouthEast');\",\n", - " \"hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\",\n", - " \"set(gca,'xtick',[],'xtickLabel',[]);\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"set(h_legend,'FontSize',10)\",\n", - " \"pos = get(h_legend,'position');\",\n", - " \"set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\",\n", - " \"subplot(4,3,11);\",\n", - " \"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"subplot(4,3,12);\",\n", - " \"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\",\n", - " \"h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\",\n", - " \"h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\",\n", - " \"hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\",\n", - " \"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\",\n", - " \"title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\",\n", - " \"parity = struct();\",\n", - " \"if exist('numCells','var')\",\n", - " \"parity.num_cells = numCells;\",\n", - " \"end\",\n", - " \"if exist('numRealizations','var')\",\n", - " \"parity.num_realizations = numRealizations;\",\n", - " \"end\",\n", - " \"function [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\",\n", - " \"getPaperDataDirs()\",\n", - " \"candidateRoots = {};\",\n", - " \"scriptPath = mfilename('fullpath');\",\n", - " \"if ~isempty(scriptPath)\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(scriptPath)));\",\n", - " \"end\",\n", - " \"paperPath = which('nSTATPaperExamples');\",\n", - " \"if ~isempty(paperPath)\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(paperPath)));\",\n", - " \"end\",\n", - " \"installPath = which('nSTAT_Install');\",\n", - " \"if ~isempty(installPath)\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, fileparts(installPath));\",\n", - " \"end\",\n", - " \"try\",\n", - " \"activeFile = matlab.desktop.editor.getActiveFilename;\",\n", - " \"catch\",\n", - " \"activeFile = '';\",\n", - " \"end\",\n", - " \"if ~isempty(activeFile)\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(activeFile)));\",\n", - " \"end\",\n", - " \"candidateRoots = appendCandidateRoot(candidateRoots, pwd);\",\n", - " \"nSTATDir = '';\",\n", - " \"for iRoot = 1:numel(candidateRoots)\",\n", - " \"candidateDataDir = fullfile(candidateRoots{iRoot}, 'data');\",\n", - " \"if exist(candidateDataDir, 'dir') == 7\",\n", - " \"nSTATDir = candidateRoots{iRoot};\",\n", - " \"break;\",\n", - " \"end\",\n", - " \"end\",\n", - " \"if isempty(nSTATDir)\",\n", - " \"error('nSTATPaperExamples:MissingInstallPath', ...\",\n", - " \"['Could not resolve the nSTAT root path. Checked roots derived from ', ...\",\n", - " \"'mfilename, which(''nSTATPaperExamples''), which(''nSTAT_Install''), ', ...\",\n", - " \"'the active editor file, and pwd.']);\",\n", - " \"end\",\n", - " \"dataDir = fullfile(nSTATDir,'data');\",\n", - " \"mEPSCDir = fullfile(dataDir,'mEPSCs');\",\n", - " \"explicitStimulusDir = fullfile(dataDir,'Explicit Stimulus');\",\n", - " \"psthDir = fullfile(dataDir,'PSTH');\",\n", - " \"placeCellDataDir = fullfile(dataDir,'Place Cells');\",\n", - " \"if exist(dataDir,'dir') ~= 7\",\n", - " \"error('nSTATPaperExamples:MissingDataDir', ...\",\n", - " \"'Could not find local nSTAT data folder at %s', dataDir);\",\n", - " \"end\",\n", - " \"end\",\n", - " \"function roots = appendCandidateRoot(roots, startDir)\",\n", - " \"if isempty(startDir)\",\n", - " \"return;\",\n", - " \"end\",\n", - " \"thisDir = startDir;\",\n", - " \"while true\",\n", - " \"if ~any(strcmp(roots, thisDir))\",\n", - " \"roots{end+1} = thisDir; %#ok\",\n", - " \"end\",\n", - " \"parentDir = fileparts(thisDir);\",\n", - " \"if strcmp(parentDir, thisDir)\",\n", - " \"break;\",\n", - " \"end\",\n", - " \"thisDir = parentDir;\",\n", - " \"end\",\n", - " \"end\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for nSTATPaperExamples.\")\n" + "# SECTION 2: Constant Magnesium Concentration - Constant rate poisson\n", + "# MATLAB L900: % Under a constant Magnesium concentration, it is seen that the mEPSCs behave as a homogeneous poisson process (constant arrival rate).\n", + "# Under a constant Magnesium concentration, it is seen that the mEPSCs behave as a homogeneous poisson process (constant arrival rate).\n", + "# MATLAB L1000: close all; clear all;\n", + "plt.close(\"all\")\n", + "# MATLAB L1001: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", + "_matlab('[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...')\n", + "# MATLAB L1002: getPaperDataDirs();\n", + "_matlab('getPaperDataDirs();')\n", + "# MATLAB L1003: nSTATRootDir = fileparts(dataDir);\n", + "_matlab('nSTATRootDir = fileparts(dataDir);')\n", + "# MATLAB L1004: if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\n", + "_matlab(\"if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\")\n", + "# MATLAB L1005: cd(nSTATRootDir);\n", + "_matlab('cd(nSTATRootDir);')\n", + "# MATLAB L1006: end\n", + "_matlab('end')\n", + "# MATLAB L1007: epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt'));\n", + "_matlab(\"epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt'));\")\n", + "# MATLAB L1008: sampleRate = 1000;\n", + "sampleRate = 1000\n", + "# MATLAB L1009: spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds\n", + "_matlab('spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds')\n", + "# MATLAB L1010: nstConst = nspikeTrain(spikeTimes);\n", + "_matlab('nstConst = nspikeTrain(spikeTimes);')\n", + "# MATLAB L1011: time = 0:(1/sampleRate):nstConst.maxTime;\n", + "_matlab('time = 0:(1/sampleRate):nstConst.maxTime;')\n", + "# MATLAB L1012: \n", + "#\n", + "# MATLAB L1013: \n", + "#\n", + "# MATLAB L1014: % Define Covariates for the analysis\n", + "# Define Covariates for the analysis\n", + "# MATLAB L1015: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s',...\")\n", + "# MATLAB L1016: '',{'\\mu'});\n", + "_matlab(\"'',{'\\\\mu'});\")\n", + "# MATLAB L1017: covarColl = CovColl({baseline});\n", + "_matlab('covarColl = CovColl({baseline});')\n", + "# MATLAB L1018: \n", + "#\n", + "# MATLAB L1019: % Create the trial structure\n", + "# Create the trial structure\n", + "# MATLAB L1020: spikeColl = nstColl(nstConst);\n", + "_matlab('spikeColl = nstColl(nstConst);')\n", + "# MATLAB L1021: trial = Trial(spikeColl,covarColl);\n", + "_matlab('trial = Trial(spikeColl,covarColl);')\n", + "# MATLAB L1022: \n", + "#\n", + "# MATLAB L1023: \n", + "#\n", + "# MATLAB L1024: % Define how we want to analyze the data\n", + "# Define how we want to analyze the data\n", + "# MATLAB L1025: clear tc tcc;\n", + "pass\n", + "# MATLAB L1026: tc{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[]);\n", + "_matlab(\"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]);\")\n", + "# MATLAB L1027: tc{1}.setName('Constant Baseline');\n", + "_matlab(\"tc{1}.setName('Constant Baseline');\")\n", + "# MATLAB L1028: tcc = ConfigColl(tc);\n", + "_matlab('tcc = ConfigColl(tc);')\n", + "# MATLAB L1029: \n", + "#\n", + "# MATLAB L1030: % Perform Analysis (Commented to since data already saved)\n", + "# Perform Analysis (Commented to since data already saved)\n", + "# MATLAB L1031: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", + "_matlab('results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);')\n", + "# MATLAB L1032: % h=results.plotResults;\n", + "# h=results.plotResults;\n", + "# MATLAB L1033: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L1034: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L1035: results.lambda.setDataLabels({'\\lambda_{const}'});\n", + "_matlab(\"results.lambda.setDataLabels({'\\\\lambda_{const}'});\")\n", + "# MATLAB L1036: h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\n", + "__tracker.new_figure(\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\")\n", + "_matlab(\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\")\n", + "# MATLAB L1037: scrsz(3)*.98 scrsz(4)*.95]);\n", + "_matlab('scrsz(3)*.98 scrsz(4)*.95]);')\n", + "# MATLAB L1038: \n", + "#\n", + "# MATLAB L1039: subplot(2,2,1); spikeColl.plot;\n", + "__tracker.annotate('subplot(2,2,1)')\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('subplot(2,2,1); spikeColl.plot;')\n", + "# MATLAB L1040: title({'Neural Raster with constant Mg^{2+} Concentration'},...\n", + "_matlab(\"title({'Neural Raster with constant Mg^{2+} Concentration'},...\")\n", + "# MATLAB L1041: 'FontWeight','bold',...\n", + "_matlab(\"'FontWeight','bold',...\")\n", + "# MATLAB L1042: 'Fontsize',12,...\n", + "_matlab(\"'Fontsize',12,...\")\n", + "# MATLAB L1043: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L1044: hx=xlabel('time [s]','Interpreter','none');\n", + "_matlab(\"hx=xlabel('time [s]','Interpreter','none');\")\n", + "# MATLAB L1045: hy=ylabel('mEPSCs','Interpreter','none');\n", + "_matlab(\"hy=ylabel('mEPSCs','Interpreter','none');\")\n", + "# MATLAB L1046: set(gca,'yTick',[0 1]);\n", + "_matlab(\"set(gca,'yTick',[0 1]);\")\n", + "# MATLAB L1047: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L1048: subplot(2,2,3); results.KSPlot;\n", + "__tracker.annotate('subplot(2,2,3)')\n", + "__tracker.annotate('results.KSPlot')\n", + "_matlab('subplot(2,2,3); results.KSPlot;')\n", + "# MATLAB L1049: subplot(2,2,2); results.plotInvGausTrans;\n", + "__tracker.annotate('subplot(2,2,2)')\n", + "_matlab('subplot(2,2,2); results.plotInvGausTrans;')\n", + "# MATLAB L1050: subplot(2,2,4); results.lambda.plot([],{{' ''b'' ,''Linewidth'',2'}});\n", + "__tracker.annotate('subplot(2,2,4)')\n", + "__tracker.annotate(\"results.lambda.plot([],{{' ''b'' ,''Linewidth'',2'}})\")\n", + "_matlab(\"subplot(2,2,4); results.lambda.plot([],{{' ''b'' ,''Linewidth'',2'}});\")\n", + "# MATLAB L1051: hx=xlabel('time [s]','Interpreter','none');\n", + "_matlab(\"hx=xlabel('time [s]','Interpreter','none');\")\n", + "# MATLAB L1052: hy=get(gca,'YLabel');\n", + "_matlab(\"hy=get(gca,'YLabel');\")\n", + "# MATLAB L1053: set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L1054: h_legend = legend('\\lambda_{const}','Location','NorthEast');\n", + "_matlab(\"h_legend = legend('\\\\lambda_{const}','Location','NorthEast');\")\n", + "# MATLAB L1055: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L1056: set(h_legend, 'position',[pos(1)+.05 pos(2) pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)+.05 pos(2) pos(3:4)]);\")\n", + "# MATLAB L1057: set(h_legend,'FontSize',14)\n", + "_matlab(\"set(h_legend,'FontSize',14)\")\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "nstatpaperexamples-03", + "id": "4aaace6d", "metadata": {}, "outputs": [], "source": [ - "# nSTATPaperExamples: multi-section paper-style workflow summary.\n", - "import json\n", - "from pathlib import Path\n", - "from scipy.io import loadmat\n", - "from nstat.compat.matlab import Analysis, DecodingAlgorithms, nspikeTrain, nstColl\n", - "\n", - "\n", - "def resolve_repo_root() -> Path:\n", - " candidates = [Path.cwd().resolve()]\n", - " candidates.append(candidates[0].parent)\n", - " candidates.append(candidates[1].parent)\n", - " for root in candidates:\n", - " if (root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\").exists():\n", - " return root\n", - " return candidates[0]\n", - "\n", - "\n", - "repo_root = resolve_repo_root()\n", - "fixture_root = repo_root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\"\n", - "shared_root = repo_root / \"data\" / \"shared\" / \"matlab_gold_20260302\"\n", - "mEPSCDir = shared_root / \"mEPSCs\"\n", - "\n", - "# -------------------------------------------------------------------------\n", - "# Experiment 1: mEPSCs - Constant Magnesium Concentration.\n", - "# MATLAB reference:\n", - "# - epsc2.txt import\n", - "# - constant baseline fit\n", - "# - raster + estimated rate plots\n", - "# -------------------------------------------------------------------------\n", - "sampleRate = 1000.0\n", - "delta = 1.0 / sampleRate\n", - "\n", - "epsc2 = np.genfromtxt(mEPSCDir / \"epsc2.txt\", skip_header=1)\n", - "spikeTimes_const = np.asarray(epsc2[:, 1], dtype=float) / sampleRate\n", - "nstConst = nspikeTrain(spikeTimes_const)\n", - "spikeCollConst = nstColl([nstConst])\n", - "\n", - "timeConst = np.arange(0.0, float(spikeTimes_const.max()) + delta, delta)\n", - "bin_edges_const = np.append(timeConst, timeConst[-1] + delta)\n", - "dN_const, _ = np.histogram(spikeTimes_const, bins=bin_edges_const)\n", - "\n", - "X_const = np.ones((dN_const.size, 1), dtype=float)\n", - "fitConst = Analysis.fitGLM(X=X_const, y=dN_const.astype(float), fitType=\"poisson\", dt=delta)\n", - "lambdaConst = np.asarray(fitConst.predict(X_const), dtype=float).reshape(-1) / delta\n", - "lambdaConstMean = float(np.mean(lambdaConst))\n", - "\n", - "fig1, axes1 = plt.subplots(2, 2, figsize=(12.0, 8.2))\n", - "axes1[0, 0].eventplot([spikeTimes_const], colors=\"k\", linelengths=0.9)\n", - "axes1[0, 0].set_title(\"Constant Mg: neural raster\")\n", - "axes1[0, 0].set_xlabel(\"time [s]\")\n", - "axes1[0, 0].set_ylabel(\"mEPSCs\")\n", - "\n", - "axes1[0, 1].plot(timeConst, lambdaConst, \"b\", linewidth=1.5, label=\"GLM constant-rate estimate\")\n", - "axes1[0, 1].axhline(lambdaConstMean, color=\"r\", linestyle=\"--\", linewidth=1.0, label=\"mean rate\")\n", - "axes1[0, 1].set_title(\"Constant Mg: estimated rate\")\n", - "axes1[0, 1].set_xlabel(\"time [s]\")\n", - "axes1[0, 1].set_ylabel(\"rate [spikes/sec]\")\n", - "axes1[0, 1].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "isi_const = np.diff(spikeTimes_const)\n", - "axes1[1, 0].hist(isi_const, bins=60, color=\"0.35\", alpha=0.85)\n", - "axes1[1, 0].set_title(\"Constant Mg: ISI histogram\")\n", - "axes1[1, 0].set_xlabel(\"inter-spike interval [s]\")\n", - "axes1[1, 0].set_ylabel(\"count\")\n", - "\n", - "axes1[1, 1].plot(np.arange(dN_const.size) * delta, dN_const, \"k\", linewidth=0.8)\n", - "axes1[1, 1].set_title(\"Constant Mg: binned spike train\")\n", - "axes1[1, 1].set_xlabel(\"time [s]\")\n", - "axes1[1, 1].set_ylabel(\"spike count / bin\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# -------------------------------------------------------------------------\n", - "# Experiment 1: mEPSCs - Varying Magnesium Concentration (piecewise model).\n", - "# MATLAB reference:\n", - "# - washout1/washout2 merge\n", - "# - ad-hoc three baseline epochs\n", - "# - compare constant vs piecewise AIC/BIC\n", - "# -------------------------------------------------------------------------\n", - "washout1 = np.genfromtxt(mEPSCDir / \"washout1.txt\", skip_header=1)\n", - "washout2 = np.genfromtxt(mEPSCDir / \"washout2.txt\", skip_header=1)\n", - "\n", - "spikeTimes1 = 260.0 + np.asarray(washout1[:, 1], dtype=float) / sampleRate\n", - "spikeTimes2 = np.sort(np.asarray(washout2[:, 1], dtype=float)) / sampleRate + 745.0\n", - "spikeTimes_var = np.concatenate([spikeTimes1, spikeTimes2])\n", - "nstVar = nspikeTrain(spikeTimes_var)\n", - "spikeCollVar = nstColl([nstVar])\n", - "\n", - "timeVar = np.arange(260.0, float(spikeTimes_var.max()) + delta, delta)\n", - "bin_edges_var = np.append(timeVar, timeVar[-1] + delta)\n", - "dN_var, _ = np.histogram(spikeTimes_var, bins=bin_edges_var)\n", - "\n", - "timeInd1 = int(np.searchsorted(timeVar, 495.0, side=\"right\"))\n", - "timeInd2 = int(np.searchsorted(timeVar, 765.0, side=\"right\"))\n", - "\n", - "constantRate = np.ones(timeVar.size, dtype=float)\n", - "rate1 = np.zeros(timeVar.size, dtype=float)\n", - "rate2 = np.zeros(timeVar.size, dtype=float)\n", - "rate3 = np.zeros(timeVar.size, dtype=float)\n", - "rate1[:timeInd1] = 1.0\n", - "rate2[timeInd1:timeInd2] = 1.0\n", - "rate3[timeInd2:] = 1.0\n", - "\n", - "X_var_const = constantRate.reshape(-1, 1)\n", - "X_var_piecewise = np.column_stack([rate1, rate2, rate3])\n", - "fitVarConst = Analysis.fitGLM(X=X_var_const, y=dN_var.astype(float), fitType=\"poisson\", dt=delta)\n", - "fitVarPiecewise = Analysis.fitGLM(X=X_var_piecewise, y=dN_var.astype(float), fitType=\"poisson\", dt=delta)\n", - "lambdaVarConst = np.asarray(fitVarConst.predict(X_var_const), dtype=float).reshape(-1) / delta\n", - "lambdaVarPiecewise = np.asarray(fitVarPiecewise.predict(X_var_piecewise), dtype=float).reshape(-1) / delta\n", - "\n", - "dAIC_piecewise = float(fitVarConst.aic() - fitVarPiecewise.aic())\n", - "dBIC_piecewise = float(fitVarConst.bic() - fitVarPiecewise.bic())\n", - "\n", - "fig2, axes2 = plt.subplots(2, 2, figsize=(12.2, 8.4))\n", - "axes2[0, 0].eventplot([spikeTimes_var], colors=\"k\", linelengths=0.9)\n", - "axes2[0, 0].axvline(495.0, color=\"r\", linewidth=1.5)\n", - "axes2[0, 0].axvline(765.0, color=\"r\", linewidth=1.5)\n", - "axes2[0, 0].set_title(\"Varying Mg: neural raster + epoch boundaries\")\n", - "axes2[0, 0].set_xlabel(\"time [s]\")\n", - "axes2[0, 0].set_ylabel(\"mEPSCs\")\n", - "\n", - "axes2[0, 1].plot(timeVar, lambdaVarConst, \"b\", linewidth=1.1, label=\"constant baseline\")\n", - "axes2[0, 1].plot(timeVar, lambdaVarPiecewise, \"g\", linewidth=1.1, label=\"piecewise baseline\")\n", - "axes2[0, 1].set_title(\"Varying Mg: model rates\")\n", - "axes2[0, 1].set_xlabel(\"time [s]\")\n", - "axes2[0, 1].set_ylabel(\"rate [spikes/sec]\")\n", - "axes2[0, 1].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "axes2[1, 0].plot(timeVar, dN_var, \"0.25\", linewidth=0.7)\n", - "axes2[1, 0].set_title(\"Varying Mg: binned spike train\")\n", - "axes2[1, 0].set_xlabel(\"time [s]\")\n", - "axes2[1, 0].set_ylabel(\"spike count / bin\")\n", - "\n", - "axes2[1, 1].bar([\"ΔAIC\", \"ΔBIC\"], [dAIC_piecewise, dBIC_piecewise], color=[\"tab:blue\", \"tab:green\"])\n", - "axes2[1, 1].axhline(0.0, color=\"k\", linewidth=0.8)\n", - "axes2[1, 1].set_title(\"Piecewise minus constant model quality\")\n", - "axes2[1, 1].set_ylabel(\"improvement (>0 favors piecewise)\")\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# -------------------------------------------------------------------------\n", - "# Experiment 5 proxies: stimulus decoding + place-cell decoding + PSTH CI.\n", - "# These remain tied to deterministic MATLAB-gold fixtures for numerical parity.\n", - "# -------------------------------------------------------------------------\n", - "m_pp = loadmat(fixture_root / \"PPSimExample_gold.mat\")\n", - "X_pp = np.asarray(m_pp[\"X\"], dtype=float)\n", - "y_pp = np.asarray(m_pp[\"y\"], dtype=float).reshape(-1)\n", - "dt_pp = float(np.asarray(m_pp[\"dt\"], dtype=float).reshape(-1)[0])\n", - "b_pp = np.asarray(m_pp[\"b\"], dtype=float).reshape(-1)\n", - "expected_rate_pp = np.asarray(m_pp[\"expected_rate\"], dtype=float).reshape(-1)\n", - "\n", - "fit_pp = Analysis.fitGLM(X=X_pp, y=y_pp, fitType=\"poisson\", dt=dt_pp)\n", - "rate_hat_pp = np.asarray(fit_pp.predict(X_pp), dtype=float).reshape(-1)\n", - "coef_pp = np.concatenate([[float(fit_pp.intercept)], np.asarray(fit_pp.coefficients, dtype=float)])\n", - "coef_err_pp = float(np.linalg.norm(coef_pp - b_pp))\n", - "rate_rel_err_pp = float(\n", - " np.mean(np.abs(rate_hat_pp - expected_rate_pp) / np.maximum(np.abs(expected_rate_pp), 1e-12))\n", - ")\n", - "\n", - "m_dec = loadmat(fixture_root / \"DecodingExampleWithHist_gold.mat\")\n", - "spike_counts = np.asarray(m_dec[\"spike_counts\"], dtype=float)\n", - "tuning = np.asarray(m_dec[\"tuning\"], dtype=float)\n", - "transition = np.asarray(m_dec[\"transition\"], dtype=float)\n", - "expected_decoded = np.asarray(m_dec[\"expected_decoded\"], dtype=int).reshape(-1)\n", - "expected_post = np.asarray(m_dec[\"expected_posterior\"], dtype=float)\n", - "\n", - "decoded_hist, posterior_hist = DecodingAlgorithms.decodeStatePosterior(\n", - " spike_counts=spike_counts, tuning_rates=tuning, transition=transition\n", - ")\n", - "decode_match = float(np.mean(decoded_hist == expected_decoded))\n", - "posterior_max_abs = float(np.max(np.abs(posterior_hist - expected_post)))\n", - "\n", - "m_pc = loadmat(fixture_root / \"HippocampalPlaceCellExample_gold.mat\")\n", - "spike_counts_pc = np.asarray(m_pc[\"spike_counts_pc\"], dtype=float)\n", - "tuning_curves = np.asarray(m_pc[\"tuning_curves\"], dtype=float)\n", - "expected_weighted = np.asarray(m_pc[\"expected_decoded_weighted\"], dtype=float).reshape(-1)\n", - "\n", - "decoded_weighted = DecodingAlgorithms.decodeWeightedCenter(spike_counts_pc, tuning_curves)\n", - "weighted_mae = float(np.mean(np.abs(decoded_weighted - expected_weighted)))\n", - "weighted_max_err = float(np.max(np.abs(decoded_weighted - expected_weighted)))\n", - "\n", - "m_psth = loadmat(fixture_root / \"PSTHEstimation_gold.mat\")\n", - "spike_matrix_psth = np.asarray(m_psth[\"spike_matrix_psth\"], dtype=float)\n", - "alpha_psth = float(np.asarray(m_psth[\"alpha_psth\"], dtype=float).reshape(-1)[0])\n", - "expected_rate_psth = np.asarray(m_psth[\"expected_rate_psth\"], dtype=float).reshape(-1)\n", - "expected_prob_psth = np.asarray(m_psth[\"expected_prob_psth\"], dtype=float)\n", - "expected_sig_psth = np.asarray(m_psth[\"expected_sig_psth\"], dtype=int)\n", - "\n", - "rate_psth, prob_psth, sig_psth = DecodingAlgorithms.computeSpikeRateCIs(\n", - " spike_matrix=spike_matrix_psth, alpha=alpha_psth\n", - ")\n", - "rate_max_abs = float(np.max(np.abs(rate_psth - expected_rate_psth)))\n", - "prob_max_abs = float(np.max(np.abs(prob_psth - expected_prob_psth)))\n", - "sig_mismatch = int(np.sum(np.abs(sig_psth - expected_sig_psth)))\n", - "\n", - "audit_path = fixture_root / \"nSTATPaperExamples_audit_gold.json\"\n", - "audit = json.loads(audit_path.read_text(encoding=\"utf-8\"))\n", - "audit_alignment = str(audit.get(\"alignment_status\", \"\"))\n", - "audit_code_lines = int(audit.get(\"matlab_code_lines\", 0))\n", - "audit_ref_images = int(audit.get(\"matlab_reference_image_count\", 0))\n", - "\n", - "fig3, axes3 = plt.subplots(2, 3, figsize=(13.2, 8.6))\n", - "axes3[0, 0].plot(expected_rate_pp[:1200], \"k\", linewidth=1.0, label=\"MATLAB gold\")\n", - "axes3[0, 0].plot(rate_hat_pp[:1200], \"tab:blue\", linewidth=1.0, label=\"Python fit\")\n", - "axes3[0, 0].set_title(\"Stimulus proxy: GLM rate fit\")\n", - "axes3[0, 0].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "axes3[0, 1].plot(expected_decoded[:180], \"k\", linewidth=1.0, label=\"MATLAB decoded\")\n", - "axes3[0, 1].plot(decoded_hist[:180], \"tab:green\", linewidth=0.9, label=\"Python decoded\")\n", - "axes3[0, 1].set_title(\"Decode-with-history path\")\n", - "axes3[0, 1].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "im0 = axes3[0, 2].imshow(np.abs(posterior_hist - expected_post), aspect=\"auto\", origin=\"lower\", cmap=\"magma\")\n", - "axes3[0, 2].set_title(\"Posterior absolute error\")\n", - "fig3.colorbar(im0, ax=axes3[0, 2], fraction=0.045, pad=0.02)\n", - "\n", - "axes3[1, 0].plot(expected_weighted, \"k\", linewidth=1.0, label=\"MATLAB weighted\")\n", - "axes3[1, 0].plot(decoded_weighted, \"tab:red\", linewidth=0.9, label=\"Python weighted\")\n", - "axes3[1, 0].set_title(\"Place-cell weighted decode\")\n", - "axes3[1, 0].legend(loc=\"upper right\", fontsize=8)\n", - "\n", - "field = tuning_curves[6].reshape(5, 8)\n", - "im1 = axes3[1, 1].imshow(field, origin=\"lower\", cmap=\"jet\", aspect=\"auto\")\n", - "axes3[1, 1].set_title(\"Example place field (unit 7)\")\n", - "fig3.colorbar(im1, ax=axes3[1, 1], fraction=0.045, pad=0.02)\n", - "\n", - "im2 = axes3[1, 2].imshow(prob_psth, origin=\"lower\", cmap=\"gray_r\", aspect=\"auto\")\n", - "yy, xx = np.where(sig_psth > 0)\n", - "if xx.size:\n", - " axes3[1, 2].plot(xx, yy, \"r*\", markersize=3)\n", - "axes3[1, 2].set_title(\"Trial significance matrix\")\n", - "fig3.colorbar(im2, ax=axes3[1, 2], fraction=0.045, pad=0.02)\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "assert lambdaConstMean > 0.0\n", - "assert dAIC_piecewise >= 0.0\n", - "assert dBIC_piecewise >= 0.0\n", - "assert coef_err_pp < 0.7\n", - "assert rate_rel_err_pp < 0.30\n", - "assert decode_match >= 1.0\n", - "assert posterior_max_abs < 1e-9\n", - "assert weighted_mae < 1e-10\n", - "assert weighted_max_err < 1e-10\n", - "assert rate_max_abs < 1e-10\n", - "assert prob_max_abs < 1e-10\n", - "assert sig_mismatch == 0\n", - "assert audit_alignment == \"validated\"\n", - "assert audit_code_lines > 1000\n", - "\n", - "CHECKPOINT_METRICS = {\n", - " \"const_mean_rate\": float(lambdaConstMean),\n", - " \"dAIC_piecewise\": float(dAIC_piecewise),\n", - " \"dBIC_piecewise\": float(dBIC_piecewise),\n", - " \"coef_error_pp\": float(coef_err_pp),\n", - " \"rate_rel_err_pp\": float(rate_rel_err_pp),\n", - " \"decode_match\": float(decode_match),\n", - " \"weighted_mae\": float(weighted_mae),\n", - " \"psth_rate_max_abs\": float(rate_max_abs),\n", - " \"sig_mismatch\": float(sig_mismatch),\n", - " \"matlab_code_lines\": float(audit_code_lines),\n", - " \"matlab_ref_images\": float(audit_ref_images),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"const_mean_rate\": (0.01, 20000.0),\n", - " \"dAIC_piecewise\": (0.0, 5.0e4),\n", - " \"dBIC_piecewise\": (0.0, 5.0e4),\n", - " \"coef_error_pp\": (0.0, 0.7),\n", - " \"rate_rel_err_pp\": (0.0, 0.30),\n", - " \"decode_match\": (1.0, 1.0),\n", - " \"weighted_mae\": (0.0, 1e-10),\n", - " \"psth_rate_max_abs\": (0.0, 1e-10),\n", - " \"sig_mismatch\": (0.0, 0.0),\n", - " \"matlab_code_lines\": (1000.0, 5000.0),\n", - " \"matlab_ref_images\": (1.0, 1000.0),\n", - "}\n" + "# SECTION 3: Varying Magnesium Concentration - Piecewise Constant rate poisson\n", + "# MATLAB L1300: % When the magnesium concentration of the bath decreased (i.e. magnesium is removed), the rate of mEPSCs begin to increase in frequency. This can be modeled in a many different ways (using the change in Magnesium directly as a model covariate, etc.) Here we approximate the rate as being constant during certain portions of the experiment. These segments can in principle be estimated (using heirarchical Bayesian methods), but here we select them via visual inspection. We compare three models: a constant rate model (from above), a piecewise constant rate model, and a piecewise constant rate model with history.\n", + "# When the magnesium concentration of the bath decreased (i.e. magnesium is removed), the rate of mEPSCs begin to increase in frequency. This can be modeled in a many different ways (using the change in Magnesium directly as a model covariate, etc.) Here we approximate the rate as being constant during certain portions of the experiment. These segments can in principle be estimated (using heirarchical Bayesian methods), but here we select them via visual inspection. We compare three models: a constant rate model (from above), a piecewise constant rate model, and a piecewise constant rate model with history.\n", + "# MATLAB L1400: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L1401: % load the data;\n", + "# load the data;\n", + "# MATLAB L1402: washout1 = importdata(fullfile(mEPSCDir,'washout1.txt'));\n", + "_matlab(\"washout1 = importdata(fullfile(mEPSCDir,'washout1.txt'));\")\n", + "# MATLAB L1403: washout2 = importdata(fullfile(mEPSCDir,'washout2.txt'));\n", + "_matlab(\"washout2 = importdata(fullfile(mEPSCDir,'washout2.txt'));\")\n", + "# MATLAB L1404: \n", + "#\n", + "# MATLAB L1405: sampleRate = 1000;\n", + "sampleRate = 1000\n", + "# MATLAB L1406: % Magnesium removed at t=0\n", + "# Magnesium removed at t=0\n", + "# MATLAB L1407: spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\n", + "_matlab('spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds')\n", + "# MATLAB L1408: spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\n", + "_matlab('spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds')\n", + "# MATLAB L1409: nst = nspikeTrain([spikeTimes1; spikeTimes2]);\n", + "_matlab('nst = nspikeTrain([spikeTimes1; spikeTimes2]);')\n", + "# MATLAB L1410: time = 260:(1/sampleRate):nst.maxTime;\n", + "_matlab('time = 260:(1/sampleRate):nst.maxTime;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5073c869", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 4: Data Visualization\n", + "# MATLAB L1700: % Visual inspection of the spike train is used to pick three regions where the firing rate appears to be different. Here we do not estimate where these transitions happen but pick times in an ad-hoc manner.\n", + "# Visual inspection of the spike train is used to pick three regions where the firing rate appears to be different. Here we do not estimate where these transitions happen but pick times in an ad-hoc manner.\n", + "# MATLAB L1800: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L1801: h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...\n", + "__tracker.new_figure(\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...\")\n", + "_matlab(\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...\")\n", + "# MATLAB L1802: scrsz(4)*.9]);\n", + "_matlab('scrsz(4)*.9]);')\n", + "# MATLAB L1803: \n", + "#\n", + "# MATLAB L1804: subplot(2,1,1);\n", + "__tracker.annotate('subplot(2,1,1)')\n", + "_matlab('subplot(2,1,1);')\n", + "# MATLAB L1805: nstConst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\n", + "__tracker.annotate('nstConst.plot')\n", + "_matlab(\"nstConst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\")\n", + "# MATLAB L1806: title({'Neural Raster with constant Mg^{2+} Concentration'},...\n", + "_matlab(\"title({'Neural Raster with constant Mg^{2+} Concentration'},...\")\n", + "# MATLAB L1807: 'FontWeight','bold',...\n", + "_matlab(\"'FontWeight','bold',...\")\n", + "# MATLAB L1808: 'Fontsize',12,...\n", + "_matlab(\"'Fontsize',12,...\")\n", + "# MATLAB L1809: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L1810: hx=get(gca,'XLabel');\n", + "_matlab(\"hx=get(gca,'XLabel');\")\n", + "# MATLAB L1811: set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L1812: \n", + "#\n", + "# MATLAB L1813: subplot(2,1,2);\n", + "__tracker.annotate('subplot(2,1,2)')\n", + "_matlab('subplot(2,1,2);')\n", + "# MATLAB L1814: nst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\n", + "__tracker.annotate('nst.plot')\n", + "_matlab(\"nst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs');\")\n", + "# MATLAB L1815: title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\n", + "_matlab(\"title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\")\n", + "# MATLAB L1816: 'FontWeight','bold',...\n", + "_matlab(\"'FontWeight','bold',...\")\n", + "# MATLAB L1817: 'Fontsize',12,...\n", + "_matlab(\"'Fontsize',12,...\")\n", + "# MATLAB L1818: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L1819: hx=get(gca,'XLabel');\n", + "_matlab(\"hx=get(gca,'XLabel');\")\n", + "# MATLAB L1820: set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13275eeb", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 5: Define Covariates for the analysis\n", + "# MATLAB L2100: timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\n", + "_matlab(\"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\")\n", + "# MATLAB L2101: timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\n", + "_matlab(\"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\")\n", + "# MATLAB L2102: %765 onwards third constant rate\n", + "# 765 onwards third constant rate\n", + "# MATLAB L2103: %epoch\n", + "# epoch\n", + "# MATLAB L2104: constantRate = ones(length(time),1);\n", + "_matlab('constantRate = ones(length(time),1);')\n", + "# MATLAB L2105: rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;\n", + "_matlab('rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;')\n", + "# MATLAB L2106: rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;\n", + "_matlab('rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;')\n", + "# MATLAB L2107: rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;\n", + "_matlab('rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;')\n", + "# MATLAB L2108: baseline = Covariate(time,[constantRate,rate1, rate2, rate3],...\n", + "_matlab('baseline = Covariate(time,[constantRate,rate1, rate2, rate3],...')\n", + "# MATLAB L2109: 'Baseline','time','s','',{'\\mu','\\mu_{1}','\\mu_{2}','\\mu_{3}'});\n", + "_matlab(\"'Baseline','time','s','',{'\\\\mu','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'});\")\n", + "# MATLAB L2110: covarColl = CovColl({baseline});\n", + "_matlab('covarColl = CovColl({baseline});')\n", + "# MATLAB L2111: \n", + "#\n", + "# MATLAB L2112: % Create the trial structure\n", + "# Create the trial structure\n", + "# MATLAB L2113: spikeColl = nstColl(nst);\n", + "_matlab('spikeColl = nstColl(nst);')\n", + "# MATLAB L2114: trial = Trial(spikeColl,covarColl);\n", + "_matlab('trial = Trial(spikeColl,covarColl);')\n", + "# MATLAB L2115: \n", + "#\n", + "# MATLAB L2116: %30ms history in logarithmic spacing (chosen after using\n", + "# 30ms history in logarithmic spacing (chosen after using\n", + "# MATLAB L2117: %Analysis.computeHistLagForAll for various window lengths)\n", + "# Analysis.computeHistLagForAll for various window lengths)\n", + "# MATLAB L2118: maxWindow=.3; numWindows=20;\n", + "_matlab('maxWindow=.3; numWindows=20;')\n", + "# MATLAB L2119: delta=1/sampleRate;\n", + "_matlab('delta=1/sampleRate;')\n", + "# MATLAB L2120: windowTimes =unique(round([0 logspace(log10(delta),...\n", + "_matlab('windowTimes =unique(round([0 logspace(log10(delta),...')\n", + "# MATLAB L2121: log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\n", + "_matlab('log10(maxWindow),numWindows)]*sampleRate)./sampleRate);')\n", + "# MATLAB L2122: windowTimes = windowTimes(1:11);\n", + "_matlab('windowTimes = windowTimes(1:11);')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af67c4ab", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 6: Define how we want to analyze the data\n", + "# MATLAB L2400: clear tc tcc;\n", + "pass\n", + "# MATLAB L2401: tc{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[]);\n", + "_matlab(\"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]);\")\n", + "# MATLAB L2402: tc{1}.setName('Constant Baseline');\n", + "_matlab(\"tc{1}.setName('Constant Baseline');\")\n", + "# MATLAB L2403: tc{2} = TrialConfig({{'Baseline','\\mu_{1}','\\mu_{2}','\\mu_{3}'}},...\n", + "_matlab(\"tc{2} = TrialConfig({{'Baseline','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'}},...\")\n", + "# MATLAB L2404: sampleRate,[]); tc{2}.setName('Diff Baseline');\n", + "_matlab(\"sampleRate,[]); tc{2}.setName('Diff Baseline');\")\n", + "# MATLAB L2405: tcc = ConfigColl(tc);\n", + "_matlab('tcc = ConfigColl(tc);')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72143a35", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 7: Perform Analysis\n", + "# MATLAB L2700: % We see that the piece-wise constant rate model (without history) outperforms the constant baseline model in terms of AIC, BIC, and KS-statistic.\n", + "# We see that the piece-wise constant rate model (without history) outperforms the constant baseline model in terms of AIC, BIC, and KS-statistic.\n", + "# MATLAB L2800: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", + "_matlab('results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);')\n", + "# MATLAB L2801: % h=results.plotResults;\n", + "# h=results.plotResults;\n", + "# MATLAB L2802: % Summary = FitResSummary(results);\n", + "# Summary = FitResSummary(results);\n", + "# MATLAB L2803: % h=Summary.plotSummary;\n", + "# h=Summary.plotSummary;\n", + "# MATLAB L3000: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L3001: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L3002: results.lambda.setDataLabels({'\\lambda_{const}',...\n", + "_matlab(\"results.lambda.setDataLabels({'\\\\lambda_{const}',...\")\n", + "# MATLAB L3003: '\\lambda_{const-epoch}'});\n", + "_matlab(\"'\\\\lambda_{const-epoch}'});\")\n", + "# MATLAB L3004: h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\n", + "__tracker.new_figure(\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\")\n", + "_matlab(\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...\")\n", + "# MATLAB L3005: scrsz(3)*.98 scrsz(4)*.95]);\n", + "_matlab('scrsz(3)*.98 scrsz(4)*.95]);')\n", + "# MATLAB L3006: \n", + "#\n", + "# MATLAB L3007: subplot(2,2,1); spikeColl.plot;\n", + "__tracker.annotate('subplot(2,2,1)')\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('subplot(2,2,1); spikeColl.plot;')\n", + "# MATLAB L3008: title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\n", + "_matlab(\"title({'Neural Raster with decreasing Mg^{2+} Concentration'},...\")\n", + "# MATLAB L3009: 'FontWeight','bold',...\n", + "_matlab(\"'FontWeight','bold',...\")\n", + "# MATLAB L3010: 'Fontsize',12,...\n", + "_matlab(\"'Fontsize',12,...\")\n", + "# MATLAB L3011: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L3012: hx=xlabel('time [s]','Interpreter','none');\n", + "_matlab(\"hx=xlabel('time [s]','Interpreter','none');\")\n", + "# MATLAB L3013: set(gca,'YTickLabel',[]);\n", + "_matlab(\"set(gca,'YTickLabel',[]);\")\n", + "# MATLAB L3014: set([hx],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L3015: timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\n", + "_matlab(\"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\")\n", + "# MATLAB L3016: timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\n", + "_matlab(\"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\")\n", + "# MATLAB L3017: %765 onwards third constant rate\n", + "# 765 onwards third constant rate\n", + "# MATLAB L3018: %epoch\n", + "# epoch\n", + "# MATLAB L3019: plot([495;495],[0,1],'r','Linewidth',4); hold on;\n", + "__tracker.annotate('plot([495')\n", + "_matlab(\"plot([495;495],[0,1],'r','Linewidth',4); hold on;\")\n", + "# MATLAB L3020: plot([765;765],[0,1],'r','Linewidth',4);\n", + "__tracker.annotate('plot([765')\n", + "_matlab(\"plot([765;765],[0,1],'r','Linewidth',4);\")\n", + "# MATLAB L3021: \n", + "#\n", + "# MATLAB L3022: subplot(2,2,3); results.KSPlot;\n", + "__tracker.annotate('subplot(2,2,3)')\n", + "__tracker.annotate('results.KSPlot')\n", + "_matlab('subplot(2,2,3); results.KSPlot;')\n", + "# MATLAB L3023: subplot(2,2,2); results.plotInvGausTrans;\n", + "__tracker.annotate('subplot(2,2,2)')\n", + "_matlab('subplot(2,2,2); results.plotInvGausTrans;')\n", + "# MATLAB L3024: subplot(2,2,4);\n", + "__tracker.annotate('subplot(2,2,4)')\n", + "_matlab('subplot(2,2,4);')\n", + "# MATLAB L3025: results.lambda.getSubSignal(1).plot([],{{' ''b'' ,''Linewidth'',2'}});\n", + "__tracker.annotate(\"results.lambda.getSubSignal(1).plot([],{{' ''b'' ,''Linewidth'',2'}})\")\n", + "_matlab(\"results.lambda.getSubSignal(1).plot([],{{' ''b'' ,''Linewidth'',2'}});\")\n", + "# MATLAB L3026: results.lambda.getSubSignal(2).plot([],{{' ''g'' ,''Linewidth'',2'}});\n", + "__tracker.annotate(\"results.lambda.getSubSignal(2).plot([],{{' ''g'' ,''Linewidth'',2'}})\")\n", + "_matlab(\"results.lambda.getSubSignal(2).plot([],{{' ''g'' ,''Linewidth'',2'}});\")\n", + "# MATLAB L3027: v=axis; axis([v(1) v(2) 0 5]);\n", + "_matlab('v=axis; axis([v(1) v(2) 0 5]);')\n", + "# MATLAB L3028: hx=xlabel('time [s]','Interpreter','none');\n", + "_matlab(\"hx=xlabel('time [s]','Interpreter','none');\")\n", + "# MATLAB L3029: hy=get(gca,'YLabel');\n", + "_matlab(\"hy=get(gca,'YLabel');\")\n", + "# MATLAB L3030: set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L3031: h_legend = legend('\\lambda_{const}','\\lambda_{const-epoch}',...\n", + "_matlab(\"h_legend = legend('\\\\lambda_{const}','\\\\lambda_{const-epoch}',...\")\n", + "# MATLAB L3032: 'Location','NorthEast');\n", + "_matlab(\"'Location','NorthEast');\")\n", + "# MATLAB L3033: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L3034: set(h_legend, 'position',[pos(1)+.05 pos(2)-.01 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)+.05 pos(2)-.01 pos(3:4)]);\")\n", + "# MATLAB L3035: set(h_legend,'FontSize',14)\n", + "_matlab(\"set(h_legend,'FontSize',14)\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58c99b8a", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 8: Experiment 2\n", + "# MATLAB L3300: % EXPLICIT STIMULUS EXAMPLE - WHISKER STIMULATION/THALAMIC NEURON In the worksheet with analyze the stimulus effect and history effect on the firing of a thalamic neuron under a known stimulus consisting of whisker stimulation. Data from Demba Ba (demba@mit.edu)\n", + "# EXPLICIT STIMULUS EXAMPLE - WHISKER STIMULATION/THALAMIC NEURON In the worksheet with analyze the stimulus effect and history effect on the firing of a thalamic neuron under a known stimulus consisting of whisker stimulation. Data from Demba Ba (demba@mit.edu)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "826673b7", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 9: Load the data\n", + "# MATLAB L3500: % clear all;\n", + "# clear all;\n", + "# MATLAB L3600: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L3601: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", + "_matlab('[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...')\n", + "# MATLAB L3602: getPaperDataDirs();\n", + "_matlab('getPaperDataDirs();')\n", + "# MATLAB L3603: nSTATRootDir = fileparts(dataDir);\n", + "_matlab('nSTATRootDir = fileparts(dataDir);')\n", + "# MATLAB L3604: if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\n", + "_matlab(\"if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir)\")\n", + "# MATLAB L3605: cd(nSTATRootDir);\n", + "_matlab('cd(nSTATRootDir);')\n", + "# MATLAB L3606: end\n", + "_matlab('end')\n", + "# MATLAB L3607: \n", + "#\n", + "# MATLAB L3608: Direction=3; Neuron=1; Stim=2;\n", + "_matlab('Direction=3; Neuron=1; Stim=2;')\n", + "# MATLAB L3609: datapath = fullfile(explicitStimulusDir,['Dir' num2str(Direction)], ...\n", + "_matlab(\"datapath = fullfile(explicitStimulusDir,['Dir' num2str(Direction)], ...\")\n", + "# MATLAB L3610: ['Neuron' num2str(Neuron)],['Stim' num2str(Stim)]);\n", + "_matlab(\"['Neuron' num2str(Neuron)],['Stim' num2str(Stim)]);\")\n", + "# MATLAB L3611: data = load(fullfile(datapath,'trngdataBis.mat'));\n", + "_matlab(\"data = load(fullfile(datapath,'trngdataBis.mat'));\")\n", + "# MATLAB L3612: \n", + "#\n", + "# MATLAB L3613: time=0:.001:(length(data.t)-1)*.001;\n", + "_matlab('time=0:.001:(length(data.t)-1)*.001;')\n", + "# MATLAB L3614: stimData = data.t;\n", + "_matlab('stimData = data.t;')\n", + "# MATLAB L3615: spikeTimes = time(data.y==1);\n", + "_matlab('spikeTimes = time(data.y==1);')\n", + "# MATLAB L3616: \n", + "#\n", + "# MATLAB L3617: stim = Covariate(time,stimData./10,'Stimulus','time','s','mm',{'stim'});\n", + "_matlab(\"stim = Covariate(time,stimData./10,'Stimulus','time','s','mm',{'stim'});\")\n", + "# MATLAB L3618: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\")\n", + "# MATLAB L3619: {'constant'});\n", + "_matlab(\"{'constant'});\")\n", + "# MATLAB L3620: \n", + "#\n", + "# MATLAB L3621: nst = nspikeTrain(spikeTimes);\n", + "_matlab('nst = nspikeTrain(spikeTimes);')\n", + "# MATLAB L3622: nspikeColl = nstColl(nst);\n", + "_matlab('nspikeColl = nstColl(nst);')\n", + "# MATLAB L3623: cc = CovColl({stim,baseline});\n", + "_matlab('cc = CovColl({stim,baseline});')\n", + "# MATLAB L3624: trial = Trial(nspikeColl,cc);\n", + "_matlab('trial = Trial(nspikeColl,cc);')\n", + "# MATLAB L3625: % trial.plot;\n", + "# trial.plot;\n", + "# MATLAB L3626: \n", + "#\n", + "# MATLAB L3627: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L3628: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", + "__tracker.new_figure(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])\")\n", + "_matlab(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", + "# MATLAB L3629: subplot(3,1,1);\n", + "__tracker.annotate('subplot(3,1,1)')\n", + "_matlab('subplot(3,1,1);')\n", + "# MATLAB L3630: nst2 = nspikeTrain(spikeTimes);\n", + "_matlab('nst2 = nspikeTrain(spikeTimes);')\n", + "# MATLAB L3631: nst2.setMaxTime(21);nst2.plot;\n", + "__tracker.annotate('nst2.plot')\n", + "_matlab('nst2.setMaxTime(21);nst2.plot;')\n", + "# MATLAB L3632: set(gca,'ytick',[0 1]);\n", + "_matlab(\"set(gca,'ytick',[0 1]);\")\n", + "# MATLAB L3633: xlabel('');\n", + "_matlab(\"xlabel('');\")\n", + "# MATLAB L3634: hy=ylabel('spikes');\n", + "_matlab(\"hy=ylabel('spikes');\")\n", + "# MATLAB L3635: set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L3636: title({'Neural Raster'},'FontWeight','bold','FontSize',16,'FontName','Arial');\n", + "_matlab(\"title({'Neural Raster'},'FontWeight','bold','FontSize',16,'FontName','Arial');\")\n", + "# MATLAB L3637: set(gca, ...\n", + "_matlab('set(gca, ...')\n", + "# MATLAB L3638: 'XTick' , 0:1:max(time), ...\n", + "_matlab(\"'XTick' , 0:1:max(time), ...\")\n", + "# MATLAB L3639: 'XTickLabel' , [],...\n", + "_matlab(\"'XTickLabel' , [],...\")\n", + "# MATLAB L3640: 'LineWidth' , 1 );\n", + "_matlab(\"'LineWidth' , 1 );\")\n", + "# MATLAB L3641: subplot(3,1,2);\n", + "__tracker.annotate('subplot(3,1,2)')\n", + "_matlab('subplot(3,1,2);')\n", + "# MATLAB L3642: stim.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\n", + "__tracker.annotate(\"stim.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}})\")\n", + "_matlab(\"stim.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\")\n", + "# MATLAB L3643: set(gca,'ytick',[0 0.5 1]);\n", + "_matlab(\"set(gca,'ytick',[0 0.5 1]);\")\n", + "# MATLAB L3644: hy=ylabel('Displacement [mm]','Interpreter','none'); xlabel('');\n", + "_matlab(\"hy=ylabel('Displacement [mm]','Interpreter','none'); xlabel('');\")\n", + "# MATLAB L3645: set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L3646: title({'Stimulus - Whisker Displacement'},'FontWeight','bold',...\n", + "_matlab(\"title({'Stimulus - Whisker Displacement'},'FontWeight','bold',...\")\n", + "# MATLAB L3647: 'FontSize',16,'FontName','Arial');\n", + "_matlab(\"'FontSize',16,'FontName','Arial');\")\n", + "# MATLAB L3648: \n", + "#\n", + "# MATLAB L3649: set(gca, ...\n", + "_matlab('set(gca, ...')\n", + "# MATLAB L3650: 'XTick' , 0:1:max(time), ...\n", + "_matlab(\"'XTick' , 0:1:max(time), ...\")\n", + "# MATLAB L3651: 'XTickLabel' , [],...\n", + "_matlab(\"'XTickLabel' , [],...\")\n", + "# MATLAB L3652: 'YTick' , 0:.25:1, ...\n", + "_matlab(\"'YTick' , 0:.25:1, ...\")\n", + "# MATLAB L3653: 'LineWidth' , 1 );\n", + "_matlab(\"'LineWidth' , 1 );\")\n", + "# MATLAB L3654: \n", + "#\n", + "# MATLAB L3655: subplot(3,1,3);\n", + "__tracker.annotate('subplot(3,1,3)')\n", + "_matlab('subplot(3,1,3);')\n", + "# MATLAB L3656: stim.derivative.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\n", + "__tracker.annotate(\"stim.derivative.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}})\")\n", + "_matlab(\"stim.derivative.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off;\")\n", + "# MATLAB L3657: set(gca,'ytick',[-80 0 80]);\n", + "_matlab(\"set(gca,'ytick',[-80 0 80]);\")\n", + "# MATLAB L3658: axis([0 21 -80 80]);\n", + "_matlab('axis([0 21 -80 80]);')\n", + "# MATLAB L3659: hy=ylabel('Displacement Velocity [mm/s]','Interpreter','none');\n", + "_matlab(\"hy=ylabel('Displacement Velocity [mm/s]','Interpreter','none');\")\n", + "# MATLAB L3660: hx= xlabel('time [s]','Interpreter','none');\n", + "_matlab(\"hx= xlabel('time [s]','Interpreter','none');\")\n", + "# MATLAB L3661: set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L3662: title({'Displacement Velocity'},'FontWeight','bold',...\n", + "_matlab(\"title({'Displacement Velocity'},'FontWeight','bold',...\")\n", + "# MATLAB L3663: 'FontSize',16,'FontName','Arial');\n", + "_matlab(\"'FontSize',16,'FontName','Arial');\")\n", + "# MATLAB L3664: \n", + "#\n", + "# MATLAB L3665: set(gca, ...\n", + "_matlab('set(gca, ...')\n", + "# MATLAB L3666: 'XTick' , 0:1:max(time), ...\n", + "_matlab(\"'XTick' , 0:1:max(time), ...\")\n", + "# MATLAB L3667: 'YTick' , -80:40:80, ...\n", + "_matlab(\"'YTick' , -80:40:80, ...\")\n", + "# MATLAB L3668: 'LineWidth' , 1 );\n", + "_matlab(\"'LineWidth' , 1 );\")\n", + "# MATLAB L3800: % Fit a constant baseline and Find Stimulus Lag We fit a constant rate (Poisson) model to the data and use the look at the cross-covariance function of between the stimulus and the fit residual to determine the appropriate lag for the stimulus.\n", + "# Fit a constant baseline and Find Stimulus Lag We fit a constant rate (Poisson) model to the data and use the look at the cross-covariance function of between the stimulus and the fit residual to determine the appropriate lag for the stimulus.\n", + "# MATLAB L3900: clear c; close all;\n", + "pass\n", + "# MATLAB L3901: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", + "_matlab('selfHist = [] ; NeighborHist = []; sampleRate = 1000;')\n", + "# MATLAB L3902: c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\")\n", + "# MATLAB L3903: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L3904: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L3905: results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);')\n", + "# MATLAB L3906: \n", + "#\n", + "# MATLAB L3907: % Find Stimulus Lag (look for peaks in the cross-covariance function less\n", + "# Find Stimulus Lag (look for peaks in the cross-covariance function less\n", + "# MATLAB L3908: % than 1 second\n", + "# than 1 second\n", + "# MATLAB L3909: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L3910: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", + "__tracker.new_figure(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])\")\n", + "_matlab(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", + "# MATLAB L3911: \n", + "#\n", + "# MATLAB L3912: subplot(7,2,[1 3 5])\n", + "__tracker.annotate('subplot(7,2,[1 3 5])')\n", + "_matlab('subplot(7,2,[1 3 5])')\n", + "# MATLAB L3913: results.Residual.xcov(stim).windowedSignal([0,1]).plot;\n", + "__tracker.annotate('results.Residual.xcov(stim).windowedSignal([0,1]).plot')\n", + "_matlab('results.Residual.xcov(stim).windowedSignal([0,1]).plot;')\n", + "# MATLAB L3914: \n", + "#\n", + "# MATLAB L3915: ylabel('');\n", + "_matlab(\"ylabel('');\")\n", + "# MATLAB L3916: [m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));\n", + "_matlab('[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));')\n", + "# MATLAB L3917: title(['Cross Correlation Function - Peak at t=' num2str(ShiftTime) ' sec'],'FontWeight','bold',...\n", + "_matlab(\"title(['Cross Correlation Function - Peak at t=' num2str(ShiftTime) ' sec'],'FontWeight','bold',...\")\n", + "# MATLAB L3918: 'FontSize',12,...\n", + "_matlab(\"'FontSize',12,...\")\n", + "# MATLAB L3919: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L3920: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L3921: h=plot(ShiftTime,m,'ro','Linewidth',3);\n", + "__tracker.annotate(\"h=plot(ShiftTime,m,'ro','Linewidth',3)\")\n", + "_matlab(\"h=plot(ShiftTime,m,'ro','Linewidth',3);\")\n", + "# MATLAB L3922: set(h, 'MarkerFaceColor',[1 0 0], 'MarkerEdgeColor',[1 0 0]);\n", + "_matlab(\"set(h, 'MarkerFaceColor',[1 0 0], 'MarkerEdgeColor',[1 0 0]);\")\n", + "# MATLAB L3923: hx=xlabel('Lag [s]','Interpreter','none');\n", + "_matlab(\"hx=xlabel('Lag [s]','Interpreter','none');\")\n", + "# MATLAB L3924: set(hx,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set(hx,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L3925: \n", + "#\n", + "# MATLAB L3926: \n", + "#\n", + "# MATLAB L3927: %Allow for shifts of less than 1 second\n", + "# Allow for shifts of less than 1 second\n", + "# MATLAB L3928: stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\n", + "_matlab(\"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\")\n", + "# MATLAB L3929: stim = stim.shift(ShiftTime);\n", + "_matlab('stim = stim.shift(ShiftTime);')\n", + "# MATLAB L3930: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\")\n", + "# MATLAB L3931: {'\\mu'});\n", + "_matlab(\"{'\\\\mu'});\")\n", + "# MATLAB L3932: \n", + "#\n", + "# MATLAB L3933: nst = nspikeTrain(spikeTimes);\n", + "_matlab('nst = nspikeTrain(spikeTimes);')\n", + "# MATLAB L3934: nspikeColl = nstColl(nst);\n", + "_matlab('nspikeColl = nstColl(nst);')\n", + "# MATLAB L3935: cc = CovColl({stim,baseline});\n", + "_matlab('cc = CovColl({stim,baseline});')\n", + "# MATLAB L3936: trial2 = Trial(nspikeColl,cc);\n", + "_matlab('trial2 = Trial(nspikeColl,cc);')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8549493", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 10: Compare constant rate model with model including stimulus effect\n", + "# MATLAB L4200: % Addition of the stimulus improves the fits in terms of the KS plot and the making the rescaled ISIs less correlated. The Point Process Residula also looks more \"white\"\n", + "# Addition of the stimulus improves the fits in terms of the KS plot and the making the rescaled ISIs less correlated. The Point Process Residula also looks more \"white\"\n", + "# MATLAB L4300: clear c;\n", + "pass\n", + "# MATLAB L4301: selfHist = [] ; NeighborHist = []; sampleRate = 1000;\n", + "_matlab('selfHist = [] ; NeighborHist = []; sampleRate = 1000;')\n", + "# MATLAB L4302: c{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,selfHist,...\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,selfHist,...\")\n", + "# MATLAB L4303: NeighborHist);\n", + "_matlab('NeighborHist);')\n", + "# MATLAB L4304: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L4305: c{2} = TrialConfig({{'Baseline','\\mu'},{'Stimulus','stim'}},...\n", + "_matlab(\"c{2} = TrialConfig({{'Baseline','\\\\mu'},{'Stimulus','stim'}},...\")\n", + "# MATLAB L4306: sampleRate,selfHist,NeighborHist);\n", + "_matlab('sampleRate,selfHist,NeighborHist);')\n", + "# MATLAB L4307: c{2}.setName('Baseline+Stimulus');\n", + "_matlab(\"c{2}.setName('Baseline+Stimulus');\")\n", + "# MATLAB L4308: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L4309: results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);')\n", + "# MATLAB L4310: % results.plotResults;\n", + "# results.plotResults;\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df853697", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 11: History Effect\n", + "# MATLAB L4600: % Determine the best history effect model using AIC, BIC, and KS statistic\n", + "# Determine the best history effect model using AIC, BIC, and KS statistic\n", + "# MATLAB L4700: sampleRate=1000;\n", + "sampleRate = 1000\n", + "# MATLAB L4701: delta=1/sampleRate*1;\n", + "_matlab('delta=1/sampleRate*1;')\n", + "# MATLAB L4702: maxWindow=1; numWindows=32;\n", + "_matlab('maxWindow=1; numWindows=32;')\n", + "# MATLAB L4703: windowTimes =unique(round([0 logspace(log10(delta),...\n", + "_matlab('windowTimes =unique(round([0 logspace(log10(delta),...')\n", + "# MATLAB L4704: log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\n", + "_matlab('log10(maxWindow),numWindows)]*sampleRate)./sampleRate);')\n", + "# MATLAB L4705: results =Analysis.computeHistLagForAll(trial2,windowTimes,...\n", + "_matlab('results =Analysis.computeHistLagForAll(trial2,windowTimes,...')\n", + "# MATLAB L4706: {{'Baseline','\\mu'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\n", + "_matlab(\"{{'Baseline','\\\\mu'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\")\n", + "# MATLAB L4707: \n", + "#\n", + "# MATLAB L4708: KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));\n", + "_matlab('KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));')\n", + "# MATLAB L4709: AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...\n", + "_matlab('AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...')\n", + "# MATLAB L4710: min(results{1}.AIC(2:end)-results{1}.AIC(1))) +1;\n", + "_matlab('min(results{1}.AIC(2:end)-results{1}.AIC(1))) +1;')\n", + "# MATLAB L4711: BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...\n", + "_matlab('BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...')\n", + "# MATLAB L4712: min(results{1}.BIC(2:end)-results{1}.BIC(1))) +1;\n", + "_matlab('min(results{1}.BIC(2:end)-results{1}.BIC(1))) +1;')\n", + "# MATLAB L4713: if(AICind==1)\n", + "_matlab('if(AICind==1)')\n", + "# MATLAB L4714: AICind=inf;\n", + "_matlab('AICind=inf;')\n", + "# MATLAB L4715: end\n", + "_matlab('end')\n", + "# MATLAB L4716: if(BICind==1)\n", + "_matlab('if(BICind==1)')\n", + "# MATLAB L4717: BICind=inf; %sometime BIC is non-decreasing and the index would be 1\n", + "_matlab('BICind=inf; %sometime BIC is non-decreasing and the index would be 1')\n", + "# MATLAB L4718: end\n", + "_matlab('end')\n", + "# MATLAB L4719: windowIndex = min([AICind,BICind]) %use the minimum order model\n", + "_matlab('windowIndex = min([AICind,BICind]) %use the minimum order model')\n", + "# MATLAB L4720: Summary = FitResSummary(results);\n", + "_matlab('Summary = FitResSummary(results);')\n", + "# MATLAB L4721: % Summary.plotSummary;\n", + "# Summary.plotSummary;\n", + "# MATLAB L4722: \n", + "#\n", + "# MATLAB L4723: \n", + "#\n", + "# MATLAB L4724: clear c;\n", + "pass\n", + "# MATLAB L4725: if(windowIndex>1)\n", + "_matlab('if(windowIndex>1)')\n", + "# MATLAB L4726: selfHist = windowTimes(1:windowIndex+1);\n", + "_matlab('selfHist = windowTimes(1:windowIndex+1);')\n", + "# MATLAB L4727: else\n", + "_matlab('else')\n", + "# MATLAB L4728: selfHist = [];\n", + "_matlab('selfHist = [];')\n", + "# MATLAB L4729: end\n", + "_matlab('end')\n", + "# MATLAB L4730: NeighborHist = []; sampleRate = 1000;\n", + "_matlab('NeighborHist = []; sampleRate = 1000;')\n", + "# MATLAB L4731: %\n", + "#\n", + "# MATLAB L4732: % figure;\n", + "# figure;\n", + "# MATLAB L4733: subplot(7,2,2);\n", + "__tracker.annotate('subplot(7,2,2)')\n", + "_matlab('subplot(7,2,2);')\n", + "# MATLAB L4734: x=0:length(windowTimes)-1;\n", + "_matlab('x=0:length(windowTimes)-1;')\n", + "# MATLAB L4735: plot(x,results{1}.KSStats.ks_stat,'.-'); axis tight; hold on;\n", + "__tracker.annotate(\"plot(x,results{1}.KSStats.ks_stat,'.-')\")\n", + "_matlab(\"plot(x,results{1}.KSStats.ks_stat,'.-'); axis tight; hold on;\")\n", + "# MATLAB L4736: plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\n", + "__tracker.annotate(\"plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*')\")\n", + "_matlab(\"plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\")\n", + "# MATLAB L4737: \n", + "#\n", + "# MATLAB L4738: set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\n", + "_matlab(\"set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\")\n", + "# MATLAB L4739: 'TickLength', [.02 .02] , ...\n", + "_matlab(\"'TickLength', [.02 .02] , ...\")\n", + "# MATLAB L4740: 'XMinorTick', 'on','LineWidth' , 1);\n", + "_matlab(\"'XMinorTick', 'on','LineWidth' , 1);\")\n", + "# MATLAB L4741: \n", + "#\n", + "# MATLAB L4742: hy=ylabel('KS Statistic');\n", + "_matlab(\"hy=ylabel('KS Statistic');\")\n", + "# MATLAB L4743: set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L4744: dAIC = results{1}.AIC-results{1}.AIC(1);\n", + "_matlab('dAIC = results{1}.AIC-results{1}.AIC(1);')\n", + "# MATLAB L4745: title({'Model Selection via change'; 'in KS Statistic, AIC, and BIC'},...\n", + "_matlab(\"title({'Model Selection via change'; 'in KS Statistic, AIC, and BIC'},...\")\n", + "# MATLAB L4746: 'FontWeight','bold',...\n", + "_matlab(\"'FontWeight','bold',...\")\n", + "# MATLAB L4747: 'FontSize',12,...\n", + "_matlab(\"'FontSize',12,...\")\n", + "# MATLAB L4748: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L4749: \n", + "#\n", + "# MATLAB L4750: subplot(7,2,4); plot(x,dAIC,'.-');\n", + "__tracker.annotate('subplot(7,2,4)')\n", + "__tracker.annotate(\"plot(x,dAIC,'.-')\")\n", + "_matlab(\"subplot(7,2,4); plot(x,dAIC,'.-');\")\n", + "# MATLAB L4751: set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\n", + "_matlab(\"set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],...\")\n", + "# MATLAB L4752: 'TickLength', [.02 .02] , ...\n", + "_matlab(\"'TickLength', [.02 .02] , ...\")\n", + "# MATLAB L4753: 'XMinorTick', 'on','LineWidth' , 1);\n", + "_matlab(\"'XMinorTick', 'on','LineWidth' , 1);\")\n", + "# MATLAB L4754: hy=ylabel('\\Delta AIC');axis tight; hold on;\n", + "_matlab(\"hy=ylabel('\\\\Delta AIC');axis tight; hold on;\")\n", + "# MATLAB L4755: set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L4756: plot(x(windowIndex),dAIC(windowIndex),'r*');\n", + "__tracker.annotate(\"plot(x(windowIndex),dAIC(windowIndex),'r*')\")\n", + "_matlab(\"plot(x(windowIndex),dAIC(windowIndex),'r*');\")\n", + "# MATLAB L4757: dBIC = results{1}.BIC-results{1}.BIC(1);\n", + "_matlab('dBIC = results{1}.BIC-results{1}.BIC(1);')\n", + "# MATLAB L4758: \n", + "#\n", + "# MATLAB L4759: subplot(7,2,6); plot(x,dBIC,'.-');\n", + "__tracker.annotate('subplot(7,2,6)')\n", + "__tracker.annotate(\"plot(x,dBIC,'.-')\")\n", + "_matlab(\"subplot(7,2,6); plot(x,dBIC,'.-');\")\n", + "# MATLAB L4760: hy=ylabel('\\Delta BIC'); axis tight; hold on;\n", + "_matlab(\"hy=ylabel('\\\\Delta BIC'); axis tight; hold on;\")\n", + "# MATLAB L4761: \n", + "#\n", + "# MATLAB L4762: plot(x(windowIndex),dBIC(windowIndex),'r*');\n", + "__tracker.annotate(\"plot(x(windowIndex),dBIC(windowIndex),'r*')\")\n", + "_matlab(\"plot(x(windowIndex),dBIC(windowIndex),'r*');\")\n", + "# MATLAB L4763: hx=xlabel('# History Windows, Q');\n", + "_matlab(\"hx=xlabel('# History Windows, Q');\")\n", + "# MATLAB L4764: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L4765: set(gca, ...\n", + "_matlab('set(gca, ...')\n", + "# MATLAB L4766: 'TickLength' , [.02 .02] , ...\n", + "_matlab(\"'TickLength' , [.02 .02] , ...\")\n", + "# MATLAB L4767: 'XMinorTick' , 'on' , ...\n", + "_matlab(\"'XMinorTick' , 'on' , ...\")\n", + "# MATLAB L4768: 'XTick' , 0:5:results{1}.numResults-1, ...\n", + "_matlab(\"'XTick' , 0:5:results{1}.numResults-1, ...\")\n", + "# MATLAB L4769: 'LineWidth' , 1 );\n", + "_matlab(\"'LineWidth' , 1 );\")\n", + "# MATLAB L4770: \n", + "#\n", + "# MATLAB L4771: \n", + "#\n", + "# MATLAB L4772: \n", + "#\n", + "# MATLAB L4773: % Compare Baseline, Baseline+Stimulus Model, Baseline+History+Stimulus\n", + "# Compare Baseline, Baseline+Stimulus Model, Baseline+History+Stimulus\n", + "# MATLAB L4774: % Addition of the history effect yields a model that falls within the 95%\n", + "# Addition of the history effect yields a model that falls within the 95%\n", + "# MATLAB L4775: % CI of the KS plot.\n", + "# CI of the KS plot.\n", + "# MATLAB L4776: \n", + "#\n", + "# MATLAB L4777: c{1} = TrialConfig({{'Baseline','\\mu'}},sampleRate,[],NeighborHist);\n", + "_matlab(\"c{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[],NeighborHist);\")\n", + "# MATLAB L4778: c{1}.setName('Baseline');\n", + "_matlab(\"c{1}.setName('Baseline');\")\n", + "# MATLAB L4779: c{2} = TrialConfig({{'Baseline','\\mu'},{'Stimulus','stim'}},...\n", + "_matlab(\"c{2} = TrialConfig({{'Baseline','\\\\mu'},{'Stimulus','stim'}},...\")\n", + "# MATLAB L4780: sampleRate,[],[]);\n", + "_matlab('sampleRate,[],[]);')\n", + "# MATLAB L4781: c{2}.setName('Baseline+Stimulus');\n", + "_matlab(\"c{2}.setName('Baseline+Stimulus');\")\n", + "# MATLAB L4782: c{3} = TrialConfig({{'Baseline','\\mu'},{'Stimulus','stim'}},...\n", + "_matlab(\"c{3} = TrialConfig({{'Baseline','\\\\mu'},{'Stimulus','stim'}},...\")\n", + "# MATLAB L4783: sampleRate,windowTimes(1:windowIndex),[]);\n", + "_matlab('sampleRate,windowTimes(1:windowIndex),[]);')\n", + "# MATLAB L4784: c{3}.setName('Baseline+Stimulus+Hist');\n", + "__tracker.annotate(\"c{3}.setName('Baseline+Stimulus+Hist')\")\n", + "_matlab(\"c{3}.setName('Baseline+Stimulus+Hist');\")\n", + "# MATLAB L4785: cfgColl= ConfigColl(c);\n", + "_matlab('cfgColl= ConfigColl(c);')\n", + "# MATLAB L4786: results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);\n", + "_matlab('results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0);')\n", + "# MATLAB L4787: %results.plotResults;\n", + "# results.plotResults;\n", + "# MATLAB L4788: %\n", + "#\n", + "# MATLAB L4789: results.lambda.setDataLabels({'\\lambda_{const}','\\lambda_{const+stim}',...\n", + "_matlab(\"results.lambda.setDataLabels({'\\\\lambda_{const}','\\\\lambda_{const+stim}',...\")\n", + "# MATLAB L4790: '\\lambda_{const+stim+hist}'});\n", + "__tracker.annotate(\"'\\\\lambda_{const+stim+hist}'})\")\n", + "_matlab(\"'\\\\lambda_{const+stim+hist}'});\")\n", + "# MATLAB L4791: subplot(7,2,[9 11 13]); results.KSPlot;\n", + "__tracker.annotate('subplot(7,2,[9 11 13])')\n", + "__tracker.annotate('results.KSPlot')\n", + "_matlab('subplot(7,2,[9 11 13]); results.KSPlot;')\n", + "# MATLAB L4792: subplot(7,2,[10 12 14]); results.plotCoeffs; legend off;\n", + "__tracker.annotate('subplot(7,2,[10 12 14])')\n", + "_matlab('subplot(7,2,[10 12 14]); results.plotCoeffs; legend off;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6406d3c", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 12: Example 3 - PSTH Data\n", + "# MATLAB L5000: % Generate a known Conditional Intensity Function\n", + "# Generate a known Conditional Intensity Function\n", + "# MATLAB L5001: % We generated a known conditional intensity function (rate function) and\n", + "# We generated a known conditional intensity function (rate function) and\n", + "# MATLAB L5002: % generate distinct realizations of point processes consistent with this\n", + "# generate distinct realizations of point processes consistent with this\n", + "# MATLAB L5003: % rate function. We use the method of thinning to simulate a point process.\n", + "# rate function. We use the method of thinning to simulate a point process.\n", + "# MATLAB L5004: clear all;\n", + "pass\n", + "# MATLAB L5005: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", + "_matlab('[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...')\n", + "# MATLAB L5006: getPaperDataDirs();\n", + "_matlab('getPaperDataDirs();')\n", + "# MATLAB L5007: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L5008: delta = 0.001;\n", + "delta = 0.001\n", + "# MATLAB L5009: Tmax = 1;\n", + "Tmax = 1\n", + "# MATLAB L5010: time = 0:delta:Tmax;\n", + "_matlab('time = 0:delta:Tmax;')\n", + "# MATLAB L5011: f=2;\n", + "f = 2\n", + "# MATLAB L5012: mu = -3;\n", + "mu = -3\n", + "# MATLAB L5013: \n", + "#\n", + "# MATLAB L5014: tempData = 1*sin(2*pi*f*time)+mu; %lambda >=0\n", + "_matlab('tempData = 1*sin(2*pi*f*time)+mu; %lambda >=0')\n", + "# MATLAB L5015: lambdaData = exp(tempData)./(1+exp(tempData))*(1/delta);\n", + "_matlab('lambdaData = exp(tempData)./(1+exp(tempData))*(1/delta);')\n", + "# MATLAB L5016: lambda = Covariate(time,lambdaData, '\\lambda(t)','time','s',...\n", + "_matlab(\"lambda = Covariate(time,lambdaData, '\\\\lambda(t)','time','s',...\")\n", + "# MATLAB L5017: 'spikes/sec',{'\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\n", + "_matlab(\"'spikes/sec',{'\\\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});\")\n", + "# MATLAB L5018: numRealizations = 20;\n", + "numRealizations = 20\n", + "# MATLAB L5019: spikeCollSim = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);\n", + "_matlab('spikeCollSim = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations);')\n", + "# MATLAB L5020: \n", + "#\n", + "# MATLAB L5021: \n", + "#\n", + "# MATLAB L5022: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L5023: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", + "__tracker.new_figure(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])\")\n", + "_matlab(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", + "# MATLAB L5024: \n", + "#\n", + "# MATLAB L5025: subplot(2,2,3);spikeCollSim.plot;\n", + "__tracker.annotate('subplot(2,2,3)')\n", + "__tracker.annotate('spikeCollSim.plot')\n", + "_matlab('subplot(2,2,3);spikeCollSim.plot;')\n", + "# MATLAB L5026: set(gca,'YTick',0:5:numRealizations,'YTickLabel',0:5:numRealizations);\n", + "_matlab(\"set(gca,'YTick',0:5:numRealizations,'YTickLabel',0:5:numRealizations);\")\n", + "# MATLAB L5027: title({[num2str(numRealizations) ' Simulated Point Process Sample Paths']},...\n", + "_matlab(\"title({[num2str(numRealizations) ' Simulated Point Process Sample Paths']},...\")\n", + "# MATLAB L5028: 'FontWeight','bold','Fontsize',14,'FontName','Arial');\n", + "_matlab(\"'FontWeight','bold','Fontsize',14,'FontName','Arial');\")\n", + "# MATLAB L5029: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5030: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5031: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5032: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5033: \n", + "#\n", + "# MATLAB L5034: subplot(2,2,1);lambda.plot;\n", + "__tracker.annotate('subplot(2,2,1)')\n", + "__tracker.annotate('lambda.plot')\n", + "_matlab('subplot(2,2,1);lambda.plot;')\n", + "# MATLAB L5035: title({'Simulated Conditional Intensity Function (CIF)'},...\n", + "_matlab(\"title({'Simulated Conditional Intensity Function (CIF)'},...\")\n", + "# MATLAB L5036: 'FontWeight','bold','FontSize',14,'FontName','Arial');\n", + "_matlab(\"'FontWeight','bold','FontSize',14,'FontName','Arial');\")\n", + "# MATLAB L5037: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5038: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5039: hy=get(gca,'YLabel');\n", + "_matlab(\"hy=get(gca,'YLabel');\")\n", + "# MATLAB L5040: set(hy,'FontName', 'Arial','FontSize',14,'FontWeight','bold');\n", + "_matlab(\"set(hy,'FontName', 'Arial','FontSize',14,'FontWeight','bold');\")\n", + "# MATLAB L5041: \n", + "#\n", + "# MATLAB L5042: x = load(fullfile(psthDir,'Results.mat'));\n", + "_matlab(\"x = load(fullfile(psthDir,'Results.mat'));\")\n", + "# MATLAB L5043: numTrials = x.Results.Data.Spike_times_STC.balanced_SUA.Nr_trials;\n", + "_matlab('numTrials = x.Results.Data.Spike_times_STC.balanced_SUA.Nr_trials;')\n", + "# MATLAB L5044: cellNum=6; clear nst;\n", + "_matlab('cellNum=6; clear nst;')\n", + "# MATLAB L5045: for i=1:numTrials\n", + "_matlab('for i=1:numTrials')\n", + "# MATLAB L5046: spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};\n", + "_matlab('spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};')\n", + "# MATLAB L5047: nst{i} = nspikeTrain(spikeTimes{i});\n", + "_matlab('nst{i} = nspikeTrain(spikeTimes{i});')\n", + "# MATLAB L5048: nst{i}.setName(num2str(cellNum));\n", + "_matlab('nst{i}.setName(num2str(cellNum));')\n", + "# MATLAB L5049: end\n", + "_matlab('end')\n", + "# MATLAB L5050: \n", + "#\n", + "# MATLAB L5051: spikeCollReal1=nstColl(nst);\n", + "_matlab('spikeCollReal1=nstColl(nst);')\n", + "# MATLAB L5052: spikeCollReal1.setMinTime(0); spikeCollReal1.setMaxTime(2);\n", + "_matlab('spikeCollReal1.setMinTime(0); spikeCollReal1.setMaxTime(2);')\n", + "# MATLAB L5053: subplot(2,2,2);spikeCollReal1.plot; set(gca,'YTick',0:2:numTrials,...\n", + "__tracker.annotate('subplot(2,2,2)')\n", + "__tracker.annotate('spikeCollReal1.plot')\n", + "_matlab(\"subplot(2,2,2);spikeCollReal1.plot; set(gca,'YTick',0:2:numTrials,...\")\n", + "# MATLAB L5054: 'YTickLabel',0:2:numTrials);\n", + "_matlab(\"'YTickLabel',0:2:numTrials);\")\n", + "# MATLAB L5055: %set(gca,'xtick',[0:.5:2],'xtickLabel',{'0','0.5','1','1.5','2'});\n", + "# set(gca,'xtick',[0:.5:2],'xtickLabel',{'0','0.5','1','1.5','2'});\n", + "# MATLAB L5056: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5057: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5058: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5059: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5060: title('Response to Moving Visual Stimulus (Neuron 6)',...\n", + "_matlab(\"title('Response to Moving Visual Stimulus (Neuron 6)',...\")\n", + "# MATLAB L5061: 'FontWeight','bold','Fontsize',14,'FontName','Arial');\n", + "_matlab(\"'FontWeight','bold','Fontsize',14,'FontName','Arial');\")\n", + "# MATLAB L5062: \n", + "#\n", + "# MATLAB L5063: cellNum=1; clear nst;\n", + "_matlab('cellNum=1; clear nst;')\n", + "# MATLAB L5064: for i=1:numTrials\n", + "_matlab('for i=1:numTrials')\n", + "# MATLAB L5065: spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};\n", + "_matlab('spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum};')\n", + "# MATLAB L5066: nst{i} = nspikeTrain(spikeTimes{i});\n", + "_matlab('nst{i} = nspikeTrain(spikeTimes{i});')\n", + "# MATLAB L5067: nst{i}.setName(num2str(cellNum));\n", + "_matlab('nst{i}.setName(num2str(cellNum));')\n", + "# MATLAB L5068: end\n", + "_matlab('end')\n", + "# MATLAB L5069: \n", + "#\n", + "# MATLAB L5070: spikeCollReal2=nstColl(nst);\n", + "_matlab('spikeCollReal2=nstColl(nst);')\n", + "# MATLAB L5071: spikeCollReal2.setMinTime(0); spikeCollReal2.setMaxTime(2);\n", + "_matlab('spikeCollReal2.setMinTime(0); spikeCollReal2.setMaxTime(2);')\n", + "# MATLAB L5072: subplot(2,2,4);spikeCollReal2.plot;\n", + "__tracker.annotate('subplot(2,2,4)')\n", + "__tracker.annotate('spikeCollReal2.plot')\n", + "_matlab('subplot(2,2,4);spikeCollReal2.plot;')\n", + "# MATLAB L5073: set(gca,'YTick',0:2:numTrials,'YTickLabel',0:2:numTrials);\n", + "_matlab(\"set(gca,'YTick',0:2:numTrials,'YTickLabel',0:2:numTrials);\")\n", + "# MATLAB L5074: %set(gca,'xtick',[0:.5:2],'xtickLabel',{'0','0.5','1','1.5','2'});\n", + "# set(gca,'xtick',[0:.5:2],'xtickLabel',{'0','0.5','1','1.5','2'});\n", + "# MATLAB L5075: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5076: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5077: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5078: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5079: title('Response to Moving Visual Stimulus (Neuron 1)','FontWeight',...\n", + "_matlab(\"title('Response to Moving Visual Stimulus (Neuron 1)','FontWeight',...\")\n", + "# MATLAB L5080: 'bold','Fontsize',14,'FontName','Arial');\n", + "_matlab(\"'bold','Fontsize',14,'FontName','Arial');\")\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "nstatpaperexamples-04", + "id": "dee3ca61", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 13: Estimate the PSTH with 50ms windows\n", + "# MATLAB L5300: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L5301: \n", + "#\n", + "# MATLAB L5302: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L5303: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", + "__tracker.new_figure(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])\")\n", + "_matlab(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", + "# MATLAB L5304: \n", + "#\n", + "# MATLAB L5305: binsize = .05; %50ms window\n", + "binsize = .05\n", + "# MATLAB L5306: psth = spikeCollSim.psth(binsize);\n", + "_matlab('psth = spikeCollSim.psth(binsize);')\n", + "# MATLAB L5307: psthGLM = spikeCollSim.psthGLM(binsize);\n", + "_matlab('psthGLM = spikeCollSim.psthGLM(binsize);')\n", + "# MATLAB L5308: true = lambda; %rate*delta = expected number of arrivals per bin\n", + "_matlab('true = lambda; %rate*delta = expected number of arrivals per bin')\n", + "# MATLAB L5309: subplot(2,3,4);\n", + "__tracker.annotate('subplot(2,3,4)')\n", + "_matlab('subplot(2,3,4);')\n", + "# MATLAB L5310: \n", + "#\n", + "# MATLAB L5311: h1=true.plot([],{{' ''b'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h1=true.plot([],{{' ''b'',''Linewidth'',4'}})\")\n", + "_matlab(\"h1=true.plot([],{{' ''b'',''Linewidth'',4'}});\")\n", + "# MATLAB L5312: h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}})\")\n", + "_matlab(\"h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}});\")\n", + "# MATLAB L5313: h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}})\")\n", + "_matlab(\"h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}});\")\n", + "# MATLAB L5314: \n", + "#\n", + "# MATLAB L5315: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5316: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5317: ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5318: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5319: \n", + "#\n", + "# MATLAB L5320: legend off;\n", + "_matlab('legend off;')\n", + "# MATLAB L5321: h_legend=legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\n", + "_matlab(\"h_legend=legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}');\")\n", + "# MATLAB L5322: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L5323: set(h_legend, 'position',[pos(1)+.005 pos(2)+.095 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)+.005 pos(2)+.095 pos(3:4)]);\")\n", + "# MATLAB L5324: \n", + "#\n", + "# MATLAB L5325: \n", + "#\n", + "# MATLAB L5326: %\n", + "#\n", + "# MATLAB L5327: subplot(2,3,1);spikeCollSim.plot;\n", + "__tracker.annotate('subplot(2,3,1)')\n", + "__tracker.annotate('spikeCollSim.plot')\n", + "_matlab('subplot(2,3,1);spikeCollSim.plot;')\n", + "# MATLAB L5328: set(gca,'YTick',0:2:spikeCollSim.numSpikeTrains,'YTickLabel',0:2:spikeCollSim.numSpikeTrains);\n", + "_matlab(\"set(gca,'YTick',0:2:spikeCollSim.numSpikeTrains,'YTickLabel',0:2:spikeCollSim.numSpikeTrains);\")\n", + "# MATLAB L5329: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L5330: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L5331: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5332: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5333: \n", + "#\n", + "# MATLAB L5334: subplot(2,3,5);\n", + "__tracker.annotate('subplot(2,3,5)')\n", + "_matlab('subplot(2,3,5);')\n", + "# MATLAB L5335: binsize = .05; %50ms window\n", + "binsize = .05\n", + "# MATLAB L5336: psthReal1 = spikeCollReal1.psth(binsize);\n", + "_matlab('psthReal1 = spikeCollReal1.psth(binsize);')\n", + "# MATLAB L5337: psthGLMReal1 = spikeCollReal1.psthGLM(binsize);%,[],[],[],[],[],1000);\n", + "_matlab('psthGLMReal1 = spikeCollReal1.psthGLM(binsize);%,[],[],[],[],[],1000);')\n", + "# MATLAB L5338: \n", + "#\n", + "# MATLAB L5339: h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}})\")\n", + "_matlab(\"h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}});\")\n", + "# MATLAB L5340: h2=psthReal1.plot([],{{' ''rx'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h2=psthReal1.plot([],{{' ''rx'',''Linewidth'',4'}})\")\n", + "_matlab(\"h2=psthReal1.plot([],{{' ''rx'',''Linewidth'',4'}});\")\n", + "# MATLAB L5341: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L5342: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L5343: ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L5344: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L5345: \n", + "#\n", + "# MATLAB L5346: h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\n", + "_matlab(\"h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\")\n", + "# MATLAB L5347: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L5348: set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\")\n", + "# MATLAB L5349: subplot(2,3,2); spikeCollReal1.plot;\n", + "__tracker.annotate('subplot(2,3,2)')\n", + "__tracker.annotate('spikeCollReal1.plot')\n", + "_matlab('subplot(2,3,2); spikeCollReal1.plot;')\n", + "# MATLAB L5350: set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\n", + "_matlab(\"set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\")\n", + "# MATLAB L5351: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L5352: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L5353: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5354: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L5355: subplot(2,3,6);\n", + "__tracker.annotate('subplot(2,3,6)')\n", + "_matlab('subplot(2,3,6);')\n", + "# MATLAB L5356: psthReal2 = spikeCollReal2.psth(binsize);\n", + "_matlab('psthReal2 = spikeCollReal2.psth(binsize);')\n", + "# MATLAB L5357: psthGLMReal2 = spikeCollReal2.psthGLM(binsize);%,[],[],[],[],[],1000);\n", + "_matlab('psthGLMReal2 = spikeCollReal2.psthGLM(binsize);%,[],[],[],[],[],1000);')\n", + "# MATLAB L5358: h3=psthGLMReal2.plot([],{{' ''k'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h3=psthGLMReal2.plot([],{{' ''k'',''Linewidth'',4'}})\")\n", + "_matlab(\"h3=psthGLMReal2.plot([],{{' ''k'',''Linewidth'',4'}});\")\n", + "# MATLAB L5359: h2=psthReal2.plot([],{{' ''rx'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h2=psthReal2.plot([],{{' ''rx'',''Linewidth'',4'}})\")\n", + "_matlab(\"h2=psthReal2.plot([],{{' ''rx'',''Linewidth'',4'}});\")\n", + "# MATLAB L5360: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L5361: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L5362: ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L5363: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L5364: \n", + "#\n", + "# MATLAB L5365: \n", + "#\n", + "# MATLAB L5366: h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\n", + "_matlab(\"h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');\")\n", + "# MATLAB L5367: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L5368: set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]);\")\n", + "# MATLAB L5369: subplot(2,3,3); spikeCollReal2.plot;\n", + "__tracker.annotate('subplot(2,3,3)')\n", + "__tracker.annotate('spikeCollReal2.plot')\n", + "_matlab('subplot(2,3,3); spikeCollReal2.plot;')\n", + "# MATLAB L5370: set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\n", + "_matlab(\"set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains);\")\n", + "# MATLAB L5371: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L5372: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L5373: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L5374: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7a7e8e3", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 14: Example 3b - SSGLM Example\n", + "# MATLAB L5600: % Example of estimating with-in and across trial dynamics Methods from: G. Czanner, U. T. Eden, S. Wirth, M. Yanike, W. A. Suzuki, and E. N. Brown, \"Analysis of between-trial and within-trial neural spiking dynamics.,\" Journal of neurophysiology, vol. 99, no. 5, pp. 2672?2693, May. 2008.\n", + "# Example of estimating with-in and across trial dynamics Methods from: G. Czanner, U. T. Eden, S. Wirth, M. Yanike, W. A. Suzuki, and E. N. Brown, \"Analysis of between-trial and within-trial neural spiking dynamics.,\" Journal of neurophysiology, vol. 99, no. 5, pp. 2672?2693, May. 2008.\n", + "# MATLAB L5700: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L5701: clear all;\n", + "pass\n", + "# MATLAB L5702: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", + "_matlab('[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...')\n", + "# MATLAB L5703: getPaperDataDirs();\n", + "_matlab('getPaperDataDirs();')\n", + "# MATLAB L5704: % set(0,'DefaultFigureRenderer','ZBuffer')\n", + "# set(0,'DefaultFigureRenderer','ZBuffer')\n", + "# MATLAB L5705: delta = 0.001; Tmax = 1;\n", + "_matlab('delta = 0.001; Tmax = 1;')\n", + "# MATLAB L5706: time = 0:delta:Tmax;\n", + "_matlab('time = 0:delta:Tmax;')\n", + "# MATLAB L5707: Ts=.001;\n", + "Ts = .001\n", + "# MATLAB L5708: numRealizations = 50; %Each realization corresponds to a distinct trial\n", + "numRealizations = 50\n", + "# MATLAB L5709: \n", + "#\n", + "# MATLAB L5710: for i=1:numRealizations\n", + "_matlab('for i=1:numRealizations')\n", + "# MATLAB L5711: % The within trial dynamics are sinusoidal\n", + "# The within trial dynamics are sinusoidal\n", + "# MATLAB L5712: % For each trial the stimulus effect increases\n", + "# For each trial the stimulus effect increases\n", + "# MATLAB L5713: f=2; b1(i)=3*((i)/numRealizations);b0=-3;\n", + "_matlab('f=2; b1(i)=3*((i)/numRealizations);b0=-3;')\n", + "# MATLAB L5714: u = sin(2*pi*f*time);\n", + "_matlab('u = sin(2*pi*f*time);')\n", + "# MATLAB L5715: e = zeros(length(time),1); %No Ensemble input\n", + "_matlab('e = zeros(length(time),1); %No Ensemble input')\n", + "# MATLAB L5716: \n", + "#\n", + "# MATLAB L5717: stim=Covariate(time',u,'Stimulus','time','s','Voltage',{'sin'});\n", + "_matlab(\"stim=Covariate(time',u,'Stimulus','time','s','Voltage',{'sin'});\")\n", + "# MATLAB L5718: ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\n", + "_matlab(\"ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'});\")\n", + "# MATLAB L5719: \n", + "#\n", + "# MATLAB L5720: mu=b0;\n", + "_matlab('mu=b0;')\n", + "# MATLAB L5721: histCoeffs=[-4 -1 -.5];\n", + "_matlab('histCoeffs=[-4 -1 -.5];')\n", + "# MATLAB L5722: H=tf(histCoeffs,[1],Ts,'Variable','z^-1');\n", + "_matlab(\"H=tf(histCoeffs,[1],Ts,'Variable','z^-1');\")\n", + "# MATLAB L5723: \n", + "#\n", + "# MATLAB L5724: S=tf([b1(i)],1,Ts,'Variable','z^-1');\n", + "_matlab(\"S=tf([b1(i)],1,Ts,'Variable','z^-1');\")\n", + "# MATLAB L5725: E=tf([0],1,Ts,'Variable','z^-1');\n", + "_matlab(\"E=tf([0],1,Ts,'Variable','z^-1');\")\n", + "# MATLAB L5726: simTypeSelect='binomial'; %Parameters are used to compute\n", + "_matlab(\"simTypeSelect='binomial'; %Parameters are used to compute\")\n", + "# MATLAB L5727: %binomial conditional intensity function\n", + "# binomial conditional intensity function\n", + "# MATLAB L5728: %\n", + "#\n", + "# MATLAB L5729: \n", + "#\n", + "# MATLAB L5730: % Obtain a realization of the point process with the current\n", + "# Obtain a realization of the point process with the current\n", + "# MATLAB L5731: % stimulus and history effect\n", + "# stimulus and history effect\n", + "# MATLAB L5732: [sC, lambdaTemp]=CIF.simulateCIF(mu,H,S,E,stim,ens,1,simTypeSelect);\n", + "_matlab('[sC, lambdaTemp]=CIF.simulateCIF(mu,H,S,E,stim,ens,1,simTypeSelect);')\n", + "# MATLAB L5733: \n", + "#\n", + "# MATLAB L5734: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L5735: lambda=lambdaTemp; %Store the conditional intensity function\n", + "_matlab('lambda=lambdaTemp; %Store the conditional intensity function')\n", + "# MATLAB L5736: else\n", + "_matlab('else')\n", + "# MATLAB L5737: lambda = lambda.merge(lambdaTemp); %Add it to the other realizations\n", + "_matlab('lambda = lambda.merge(lambdaTemp); %Add it to the other realizations')\n", + "# MATLAB L5738: end\n", + "_matlab('end')\n", + "# MATLAB L5739: \n", + "#\n", + "# MATLAB L5740: nst{i} = sC.getNST(1); %get the neural spikeTrain from the collection\n", + "_matlab('nst{i} = sC.getNST(1); %get the neural spikeTrain from the collection')\n", + "# MATLAB L5741: nst{i} = nst{i}.resample(1/delta); %make sure that it is sampled at the current samplerate\n", + "_matlab('nst{i} = nst{i}.resample(1/delta); %make sure that it is sampled at the current samplerate')\n", + "# MATLAB L5742: end\n", + "_matlab('end')\n", + "# MATLAB L5743: \n", + "#\n", + "# MATLAB L5744: spikeColl = nstColl(nst); %Create a collection of the spike trains across trials\n", + "_matlab('spikeColl = nstColl(nst); %Create a collection of the spike trains across trials')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "beaeb03c", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 15: Summarize Simulated Data\n", + "# MATLAB L6000: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L6001: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L6002: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", + "__tracker.new_figure(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])\")\n", + "_matlab(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", + "# MATLAB L6003: \n", + "#\n", + "# MATLAB L6004: %Plot the raster\n", + "# Plot the raster\n", + "# MATLAB L6005: subplot(3,2,[3 4]); spikeColl.plot;\n", + "__tracker.annotate('subplot(3,2,[3 4])')\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('subplot(3,2,[3 4]); spikeColl.plot;')\n", + "# MATLAB L6006: set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\n", + "_matlab(\"set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\")\n", + "# MATLAB L6007: set(gca,'xtick',0:.1:Tmax,'xtickLabel',0:.1:Tmax); xlabel('');\n", + "_matlab(\"set(gca,'xtick',0:.1:Tmax,'xtickLabel',0:.1:Tmax); xlabel('');\")\n", + "# MATLAB L6008: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L6009: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L6010: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L6011: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L6012: title('Simulated Neural Raster','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"title('Simulated Neural Raster','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L6013: 'Fontsize',14,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',14,'FontWeight','bold');\")\n", + "# MATLAB L6014: \n", + "#\n", + "# MATLAB L6015: % Plot the actual stimulus effect (not including history)\n", + "# Plot the actual stimulus effect (not including history)\n", + "# MATLAB L6016: % The CIF including the history effect is stored in the lambda Covariate\n", + "# The CIF including the history effect is stored in the lambda Covariate\n", + "# MATLAB L6017: % above\n", + "# above\n", + "# MATLAB L6018: \n", + "#\n", + "# MATLAB L6019: \n", + "#\n", + "# MATLAB L6020: stimData = exp(b0 + u'*b1);\n", + "_matlab(\"stimData = exp(b0 + u'*b1);\")\n", + "# MATLAB L6021: if(strcmp(simTypeSelect,'binomial'))\n", + "_matlab(\"if(strcmp(simTypeSelect,'binomial'))\")\n", + "# MATLAB L6022: stimData = stimData./(1+stimData);\n", + "_matlab('stimData = stimData./(1+stimData);')\n", + "# MATLAB L6023: end\n", + "_matlab('end')\n", + "# MATLAB L6024: \n", + "#\n", + "# MATLAB L6025: %Plot the trial dependence\n", + "# Plot the trial dependence\n", + "# MATLAB L6026: subplot(3,2,1); plot(time,u,'k','LineWidth',3);\n", + "__tracker.annotate('subplot(3,2,1)')\n", + "__tracker.annotate(\"plot(time,u,'k','LineWidth',3)\")\n", + "_matlab(\"subplot(3,2,1); plot(time,u,'k','LineWidth',3);\")\n", + "# MATLAB L6027: % xlabel('time [s]');ylabel('stimulus');\n", + "# xlabel('time [s]');ylabel('stimulus');\n", + "# MATLAB L6028: xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L6029: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L6030: ylabel('Stimulus','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"ylabel('Stimulus','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L6031: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L6032: title('Within Trial Stimulus','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"title('Within Trial Stimulus','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L6033: 'Fontsize',14,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',14,'FontWeight','bold');\")\n", + "# MATLAB L6034: \n", + "#\n", + "# MATLAB L6035: subplot(3,2,2); plot(1:length(b1),b1,'k','LineWidth',3);\n", + "__tracker.annotate('subplot(3,2,2)')\n", + "__tracker.annotate(\"plot(1:length(b1),b1,'k','LineWidth',3)\")\n", + "_matlab(\"subplot(3,2,2); plot(1:length(b1),b1,'k','LineWidth',3);\")\n", + "# MATLAB L6036: xlabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"xlabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L6037: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L6038: ylabel('Stimulus Gain','Interpreter','none','FontName', 'Arial','Fontsize',...\n", + "_matlab(\"ylabel('Stimulus Gain','Interpreter','none','FontName', 'Arial','Fontsize',...\")\n", + "# MATLAB L6039: 12,'FontWeight','bold');\n", + "_matlab(\"12,'FontWeight','bold');\")\n", + "# MATLAB L6040: title('Across Trial Stimulus Gain','Interpreter','none','FontName',...\n", + "_matlab(\"title('Across Trial Stimulus Gain','Interpreter','none','FontName',...\")\n", + "# MATLAB L6041: 'Arial','Fontsize',14,'FontWeight','bold');\n", + "_matlab(\"'Arial','Fontsize',14,'FontWeight','bold');\")\n", + "# MATLAB L6042: \n", + "#\n", + "# MATLAB L6043: subplot(3,2,[5 6]);\n", + "__tracker.annotate('subplot(3,2,[5 6])')\n", + "_matlab('subplot(3,2,[5 6]);')\n", + "# MATLAB L6044: imagesc(stimData'./delta); set(gca, 'YDir','normal');\n", + "__tracker.annotate(\"imagesc(stimData'./delta); set(gca, 'YDir','normal');\")\n", + "_matlab(\"imagesc(stimData'./delta); set(gca, 'YDir','normal');\")\n", + "# MATLAB L6045: set(gca,'xtick',0:100:Tmax/delta,'xtickLabel',0:.1:Tmax);\n", + "_matlab(\"set(gca,'xtick',0:100:Tmax/delta,'xtickLabel',0:.1:Tmax);\")\n", + "# MATLAB L6046: set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\n", + "_matlab(\"set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations);\")\n", + "# MATLAB L6047: xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"xlabel('time [s]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L6048: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L6049: ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\n", + "_matlab(\"ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',...\")\n", + "# MATLAB L6050: 'Fontsize',12,'FontWeight','bold');\n", + "_matlab(\"'Fontsize',12,'FontWeight','bold');\")\n", + "# MATLAB L6051: title('True Conditional Intensity Function','Interpreter',...\n", + "_matlab(\"title('True Conditional Intensity Function','Interpreter',...\")\n", + "# MATLAB L6052: 'none','FontName', 'Arial','Fontsize',14,'FontWeight','bold');\n", + "_matlab(\"'none','FontName', 'Arial','Fontsize',14,'FontWeight','bold');\")\n", + "# MATLAB L6053: \n", + "#\n", + "# MATLAB L6054: \n", + "#\n", + "# MATLAB L6055: axis tight;\n", + "_matlab('axis tight;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff8f87ef", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 16: Estimation of the Stimulus Response\n", + "# MATLAB L6300: % Create the covariates that will be used for the GLM regression\n", + "# Create the covariates that will be used for the GLM regression\n", + "# MATLAB L6301: stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\n", + "_matlab(\"stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\")\n", + "# MATLAB L6302: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\")\n", + "# MATLAB L6303: {'constant'});\n", + "_matlab(\"{'constant'});\")\n", + "# MATLAB L6304: \n", + "#\n", + "# MATLAB L6305: % Specify the windows of the history coefficients to be estimated\n", + "# Specify the windows of the history coefficients to be estimated\n", + "# MATLAB L6306: windowTimes=[0:.001:.003];\n", + "_matlab('windowTimes=[0:.001:.003];')\n", + "# MATLAB L6307: % Number of bins to discrtize time into (used both for the PSTH and for\n", + "# Number of bins to discrtize time into (used both for the PSTH and for\n", + "# MATLAB L6308: % thec\n", + "# thec\n", + "# MATLAB L6309: % SSGLM model.\n", + "# SSGLM model.\n", + "# MATLAB L6310: numBasis = 25;\n", + "numBasis = 25\n", + "# MATLAB L6311: \n", + "#\n", + "# MATLAB L6312: spikeColl.resample(1/delta); % Enforce sampleRate\n", + "_matlab('spikeColl.resample(1/delta); % Enforce sampleRate')\n", + "# MATLAB L6313: spikeColl.setMaxTime(Tmax); % Make all spikeTrains end at time Tmax\n", + "_matlab('spikeColl.setMaxTime(Tmax); % Make all spikeTrains end at time Tmax')\n", + "# MATLAB L6314: \n", + "#\n", + "# MATLAB L6315: \n", + "#\n", + "# MATLAB L6316: dN=spikeColl.dataToMatrix'; % Convert the spikeTrains into a matrix\n", + "_matlab(\"dN=spikeColl.dataToMatrix'; % Convert the spikeTrains into a matrix\")\n", + "# MATLAB L6317: % of 1's and 0's corresponding to the presence\n", + "# of 1's and 0's corresponding to the presence\n", + "# MATLAB L6318: % or absense of a spike in each time window.\n", + "# or absense of a spike in each time window.\n", + "# MATLAB L6319: dN(dN>1)=1; % One should sample finely enough so there is\n", + "_matlab('dN(dN>1)=1; % One should sample finely enough so there is')\n", + "# MATLAB L6320: % one spike per bin. Here we make sure that\n", + "# one spike per bin. Here we make sure that\n", + "# MATLAB L6321: % this is the case regardless of the\n", + "# this is the case regardless of the\n", + "# MATLAB L6322: % sampleRate\n", + "# sampleRate\n", + "# MATLAB L6323: \n", + "#\n", + "# MATLAB L6324: % The width of each rectangular basis pulse is determined by Tmax and by the\n", + "# The width of each rectangular basis pulse is determined by Tmax and by the\n", + "# MATLAB L6325: % number of basis pulses to use.\n", + "# number of basis pulses to use.\n", + "# MATLAB L6326: basisWidth=(spikeColl.maxTime-spikeColl.minTime)/numBasis;\n", + "_matlab('basisWidth=(spikeColl.maxTime-spikeColl.minTime)/numBasis;')\n", + "# MATLAB L6327: \n", + "#\n", + "# MATLAB L6328: if(simTypeSelect==0)\n", + "_matlab('if(simTypeSelect==0)')\n", + "# MATLAB L6329: fitType='binomial';\n", + "_matlab(\"fitType='binomial';\")\n", + "# MATLAB L6330: else\n", + "_matlab('else')\n", + "# MATLAB L6331: fitType='poisson';\n", + "_matlab(\"fitType='poisson';\")\n", + "# MATLAB L6332: end\n", + "_matlab('end')\n", + "# MATLAB L6333: if(strcmp(fitType,'binomial'))\n", + "_matlab(\"if(strcmp(fitType,'binomial'))\")\n", + "# MATLAB L6334: Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\n", + "_matlab(\"Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized,\")\n", + "# MATLAB L6335: % Binomial Logistic Regression with Conjugate\n", + "# Binomial Logistic Regression with Conjugate\n", + "# MATLAB L6336: % Gradient Solver by Demba Ba (demba@mit.edu).\n", + "# Gradient Solver by Demba Ba (demba@mit.edu).\n", + "# MATLAB L6337: else\n", + "_matlab('else')\n", + "# MATLAB L6338: Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\n", + "_matlab(\"Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or\")\n", + "# MATLAB L6339: % or Poisson CIFs\n", + "# or Poisson CIFs\n", + "# MATLAB L6340: end\n", + "_matlab('end')\n", + "# MATLAB L6341: \n", + "#\n", + "# MATLAB L6342: % Use the values obtained from a PSTH to initialize the SSGLM filter\n", + "# Use the values obtained from a PSTH to initialize the SSGLM filter\n", + "# MATLAB L6343: [psthSig, ~, psthResult] =spikeColl.psthGLM(basisWidth,windowTimes,fitType);\n", + "_matlab('[psthSig, ~, psthResult] =spikeColl.psthGLM(basisWidth,windowTimes,fitType);')\n", + "# MATLAB L6344: gamma0=psthResult.getHistCoeffs';%+.1*randn(size(histCoeffs));\n", + "_matlab(\"gamma0=psthResult.getHistCoeffs';%+.1*randn(size(histCoeffs));\")\n", + "# MATLAB L6345: gamma0(isnan(gamma0))=-5; % Depending on the amount of data the\n", + "_matlab('gamma0(isnan(gamma0))=-5; % Depending on the amount of data the')\n", + "# MATLAB L6346: % the psth may not identify all parameters\n", + "# the psth may not identify all parameters\n", + "# MATLAB L6347: % Just make sure that the estimates are real\n", + "# Just make sure that the estimates are real\n", + "# MATLAB L6348: % numbers\n", + "# numbers\n", + "# MATLAB L6349: \n", + "#\n", + "# MATLAB L6350: x0=psthResult.getCoeffs; %The initial estimate for the SSGLM model\n", + "_matlab('x0=psthResult.getCoeffs; %The initial estimate for the SSGLM model')\n", + "# MATLAB L6351: \n", + "#\n", + "# MATLAB L6352: % Estimate the variance within each time bin across trials\n", + "# Estimate the variance within each time bin across trials\n", + "# MATLAB L6353: numVarEstIter=10;\n", + "numVarEstIter = 10\n", + "# MATLAB L6354: Q0 = spikeColl.estimateVarianceAcrossTrials(numBasis,windowTimes,...\n", + "_matlab('Q0 = spikeColl.estimateVarianceAcrossTrials(numBasis,windowTimes,...')\n", + "# MATLAB L6355: numVarEstIter,fitType);\n", + "_matlab('numVarEstIter,fitType);')\n", + "# MATLAB L6356: A=eye(numBasis,numBasis);\n", + "_matlab('A=eye(numBasis,numBasis);')\n", + "# MATLAB L6357: delta = 1/spikeColl.sampleRate;\n", + "_matlab('delta = 1/spikeColl.sampleRate;')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d726d256", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 17: Run the SSGLM Filter\n", + "# MATLAB L6600: CompilingHelpFile=1;\n", + "CompilingHelpFile = 1\n", + "# MATLAB L6601: % Commented out to speed up help file creation ...\n", + "# Commented out to speed up help file creation ...\n", + "# MATLAB L6602: if(~CompilingHelpFile)\n", + "_matlab('if(~CompilingHelpFile)')\n", + "# MATLAB L6603: Q0d=diag(Q0);\n", + "_matlab('Q0d=diag(Q0);')\n", + "# MATLAB L6604: neuronName = psthResult.neuronNumber;\n", + "_matlab('neuronName = psthResult.neuronNumber;')\n", + "# MATLAB L6605: [xK,WK, WkuFinal,Qhat,gammahat,fitResults,stimulus,stimCIs,logll,...\n", + "_matlab('[xK,WK, WkuFinal,Qhat,gammahat,fitResults,stimulus,stimCIs,logll,...')\n", + "# MATLAB L6606: QhatAll,gammahatAll,nIter]=DecodingAlgorithms.PPSS_EMFB(A,Q0d,x0,...\n", + "_matlab('QhatAll,gammahatAll,nIter]=DecodingAlgorithms.PPSS_EMFB(A,Q0d,x0,...')\n", + "# MATLAB L6607: dN,fitType,delta,gamma0,windowTimes, numBasis,neuronName);\n", + "_matlab('dN,fitType,delta,gamma0,windowTimes, numBasis,neuronName);')\n", + "# MATLAB L6608: \n", + "#\n", + "# MATLAB L6609: fR = fitResults.toStructure;\n", + "_matlab('fR = fitResults.toStructure;')\n", + "# MATLAB L6610: psthR = psthResult.toStructure;\n", + "_matlab('psthR = psthResult.toStructure;')\n", + "# MATLAB L6611: end\n", + "_matlab('end')\n", + "# MATLAB L6612: % save SSGLMExampleData psthR fR xK WK WkuFinal Qhat gammahat fitResults stimulus stimCIs logll QhatAll gammahatAll nIter;\n", + "# save SSGLMExampleData psthR fR xK WK WkuFinal Qhat gammahat fitResults stimulus stimCIs logll QhatAll gammahatAll nIter;\n", + "# MATLAB L6800: installPath = which('nSTAT_Install');\n", + "_matlab(\"installPath = which('nSTAT_Install');\")\n", + "# MATLAB L6801: if isempty(installPath)\n", + "_matlab('if isempty(installPath)')\n", + "# MATLAB L6802: error('nSTATPaperExamples:MissingInstallPath', ...\n", + "_matlab(\"error('nSTATPaperExamples:MissingInstallPath', ...\")\n", + "# MATLAB L6803: 'Could not locate nSTAT_Install.m on MATLAB path.');\n", + "_matlab(\"'Could not locate nSTAT_Install.m on MATLAB path.');\")\n", + "# MATLAB L6804: end\n", + "_matlab('end')\n", + "# MATLAB L6805: nstatRoot = fileparts(installPath);\n", + "_matlab('nstatRoot = fileparts(installPath);')\n", + "# MATLAB L6806: if exist(nstatRoot,'dir') == 7 && ~strcmp(pwd,nstatRoot)\n", + "_matlab(\"if exist(nstatRoot,'dir') == 7 && ~strcmp(pwd,nstatRoot)\")\n", + "# MATLAB L6807: cd(nstatRoot);\n", + "_matlab('cd(nstatRoot);')\n", + "# MATLAB L6808: end\n", + "_matlab('end')\n", + "# MATLAB L6809: addpath(nstatRoot,'-begin');\n", + "_matlab(\"addpath(nstatRoot,'-begin');\")\n", + "# MATLAB L6810: load(fullfile(nstatRoot,'data','SSGLMExampleData.mat'));\n", + "_matlab(\"load(fullfile(nstatRoot,'data','SSGLMExampleData.mat'));\")\n", + "# MATLAB L6811: fitResults = FitResult.fromStructure(fR);\n", + "_matlab('fitResults = FitResult.fromStructure(fR);')\n", + "# MATLAB L6812: psthResult = FitResult.fromStructure(psthR);\n", + "_matlab('psthResult = FitResult.fromStructure(psthR);')\n", + "# MATLAB L7000: t=psthResult.mergeResults(fitResults);\n", + "_matlab('t=psthResult.mergeResults(fitResults);')\n", + "# MATLAB L7001: %t.plotResults; %Compare the results with the PSTH Model\n", + "# t.plotResults; %Compare the results with the PSTH Model\n", + "# MATLAB L7002: t.lambda.setDataLabels({'\\lambda_{PSTH}','\\lambda_{SSGLM}'});\n", + "_matlab(\"t.lambda.setDataLabels({'\\\\lambda_{PSTH}','\\\\lambda_{SSGLM}'});\")\n", + "# MATLAB L7003: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L7004: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", + "__tracker.new_figure(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])\")\n", + "_matlab(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", + "# MATLAB L7005: subplot(2,2,1); t.KSPlot;\n", + "__tracker.annotate('subplot(2,2,1)')\n", + "__tracker.annotate('t.KSPlot')\n", + "_matlab('subplot(2,2,1); t.KSPlot;')\n", + "# MATLAB L7006: subplot(2,2,2); t.plotResidual;\n", + "__tracker.annotate('subplot(2,2,2)')\n", + "__tracker.annotate('t.plotResidual')\n", + "_matlab('subplot(2,2,2); t.plotResidual;')\n", + "# MATLAB L7007: subplot(2,2,3); t.plotInvGausTrans;\n", + "__tracker.annotate('subplot(2,2,3)')\n", + "_matlab('subplot(2,2,3); t.plotInvGausTrans;')\n", + "# MATLAB L7008: subplot(2,2,4); t.plotSeqCorr;\n", + "__tracker.annotate('subplot(2,2,4)')\n", + "_matlab('subplot(2,2,4); t.plotSeqCorr;')\n", + "# MATLAB L7009: \n", + "#\n", + "# MATLAB L7010: S=FitResSummary(t);\n", + "_matlab('S=FitResSummary(t);')\n", + "# MATLAB L7011: dAIC=diff(S.AIC)\n", + "_matlab('dAIC=diff(S.AIC)')\n", + "# MATLAB L7012: dBIC=diff(S.BIC)\n", + "_matlab('dBIC=diff(S.BIC)')\n", + "# MATLAB L7013: dKS =diff(S.KSStats);\n", + "_matlab('dKS =diff(S.KSStats);')\n", + "# MATLAB L7200: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L7201: % Generate the actual stimulus effect\n", + "# Generate the actual stimulus effect\n", + "# MATLAB L7202: minTime=0; maxTime = Tmax;\n", + "_matlab('minTime=0; maxTime = Tmax;')\n", + "# MATLAB L7203: stimData = stim.data*b1;\n", + "_matlab('stimData = stim.data*b1;')\n", + "# MATLAB L7204: if(strcmp(fitType,'poisson'))\n", + "_matlab(\"if(strcmp(fitType,'poisson'))\")\n", + "# MATLAB L7205: actStimEffect=exp(stimData + b0)./delta;\n", + "_matlab('actStimEffect=exp(stimData + b0)./delta;')\n", + "# MATLAB L7206: elseif(strcmp(fitType,'binomial'))\n", + "_matlab(\"elseif(strcmp(fitType,'binomial'))\")\n", + "# MATLAB L7207: actStimEffect=exp(stimData + b0)./(1+exp(stimData + b0))./delta;\n", + "_matlab('actStimEffect=exp(stimData + b0)./(1+exp(stimData + b0))./delta;')\n", + "# MATLAB L7208: end\n", + "_matlab('end')\n", + "# MATLAB L7209: %\n", + "#\n", + "# MATLAB L7210: \n", + "#\n", + "# MATLAB L7211: % Generate the basis function so that the estimated effect can be plotted\n", + "# Generate the basis function so that the estimated effect can be plotted\n", + "# MATLAB L7212: % at the same temporal resolution as the theoretical effect\n", + "# at the same temporal resolution as the theoretical effect\n", + "# MATLAB L7213: if(~isempty(numBasis))\n", + "_matlab('if(~isempty(numBasis))')\n", + "# MATLAB L7214: basisWidth = (maxTime-minTime)/numBasis;\n", + "_matlab('basisWidth = (maxTime-minTime)/numBasis;')\n", + "# MATLAB L7215: sampleRate=1/delta;\n", + "_matlab('sampleRate=1/delta;')\n", + "# MATLAB L7216: unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,minTime,...\n", + "_matlab('unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,minTime,...')\n", + "# MATLAB L7217: maxTime,sampleRate);\n", + "_matlab('maxTime,sampleRate);')\n", + "# MATLAB L7218: basisMat = unitPulseBasis.data;\n", + "_matlab('basisMat = unitPulseBasis.data;')\n", + "# MATLAB L7219: end\n", + "_matlab('end')\n", + "# MATLAB L7220: \n", + "#\n", + "# MATLAB L7221: % Generate the estimated stimulus effect\n", + "# Generate the estimated stimulus effect\n", + "# MATLAB L7222: if(strcmp(fitType,'poisson'))\n", + "_matlab(\"if(strcmp(fitType,'poisson'))\")\n", + "# MATLAB L7223: estStimEffect=exp(basisMat*xK)./delta;\n", + "_matlab('estStimEffect=exp(basisMat*xK)./delta;')\n", + "# MATLAB L7224: elseif(strcmp(fitType,'binomial'))\n", + "_matlab(\"elseif(strcmp(fitType,'binomial'))\")\n", + "# MATLAB L7225: estStimEffect=exp(basisMat*xK)./(1+exp(basisMat*xK))./delta;\n", + "_matlab('estStimEffect=exp(basisMat*xK)./(1+exp(basisMat*xK))./delta;')\n", + "# MATLAB L7226: end\n", + "_matlab('end')\n", + "# MATLAB L7227: \n", + "#\n", + "# MATLAB L7228: \n", + "#\n", + "# MATLAB L7229: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L7230: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\n", + "__tracker.new_figure(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8])\")\n", + "_matlab(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\")\n", + "# MATLAB L7231: \n", + "#\n", + "# MATLAB L7232: % Plot the actual and estimated stimulus effect as a function of trial and\n", + "# Plot the actual and estimated stimulus effect as a function of trial and\n", + "# MATLAB L7233: % time\n", + "# time\n", + "# MATLAB L7234: subplot(3,1,[1 2 3]);\n", + "__tracker.annotate('subplot(3,1,[1 2 3])')\n", + "_matlab('subplot(3,1,[1 2 3]);')\n", + "# MATLAB L7235: lighting gouraud\n", + "_matlab('lighting gouraud')\n", + "# MATLAB L7236: surf((1:length(b1))',stim.time,actStimEffect,'FaceAlpha',0.1,...\n", + "__tracker.annotate(\"surf((1:length(b1))',stim.time,actStimEffect,'FaceAlpha',0.1,...\")\n", + "_matlab(\"surf((1:length(b1))',stim.time,actStimEffect,'FaceAlpha',0.1,...\")\n", + "# MATLAB L7237: 'EdgeAlpha',0.1,'AlphaData',0.1);\n", + "_matlab(\"'EdgeAlpha',0.1,'AlphaData',0.1);\")\n", + "# MATLAB L7238: hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\n", + "_matlab(\"hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\")\n", + "# MATLAB L7239: hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\n", + "_matlab(\"hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\")\n", + "# MATLAB L7240: set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L7241: \n", + "#\n", + "# MATLAB L7242: surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),...\n", + "__tracker.annotate(\"surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),...\")\n", + "_matlab(\"surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),...\")\n", + "# MATLAB L7243: 'FaceAlpha',0.5,'EdgeAlpha',0.1,'AlphaData',0.5); %xlabel('Trial [k]'); ylabel('time [s]'); zlabel('Stimulus Effect');\n", + "_matlab(\"'FaceAlpha',0.5,'EdgeAlpha',0.1,'AlphaData',0.5); %xlabel('Trial [k]'); ylabel('time [s]'); zlabel('Stimulus Effect');\")\n", + "# MATLAB L7244: set(gca,'YDir','reverse');\n", + "_matlab(\"set(gca,'YDir','reverse');\")\n", + "# MATLAB L7245: set(gca,'ytick',0:.1:Tmax,'ytickLabel',0:.1:Tmax);\n", + "_matlab(\"set(gca,'ytick',0:.1:Tmax,'ytickLabel',0:.1:Tmax);\")\n", + "# MATLAB L7246: \n", + "#\n", + "# MATLAB L7247: title('SSGLM Estimated vs. Actual Stimulus Effect','FontWeight','bold',...\n", + "_matlab(\"title('SSGLM Estimated vs. Actual Stimulus Effect','FontWeight','bold',...\")\n", + "# MATLAB L7248: 'Fontsize',14,...\n", + "_matlab(\"'Fontsize',14,...\")\n", + "# MATLAB L7249: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L7250: \n", + "#\n", + "# MATLAB L7251: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L7252: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\n", + "__tracker.new_figure(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8])\")\n", + "_matlab(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);\")\n", + "# MATLAB L7253: \n", + "#\n", + "# MATLAB L7254: % The actual stimulus effect\n", + "# The actual stimulus effect\n", + "# MATLAB L7255: subplot(3,1,1);\n", + "__tracker.annotate('subplot(3,1,1)')\n", + "_matlab('subplot(3,1,1);')\n", + "# MATLAB L7256: lighting gouraud\n", + "_matlab('lighting gouraud')\n", + "# MATLAB L7257: mesh((1:length(b1))',stim.time,actStimEffect);\n", + "_matlab(\"mesh((1:length(b1))',stim.time,actStimEffect);\")\n", + "# MATLAB L7258: hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\n", + "_matlab(\"hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\")\n", + "# MATLAB L7259: zlabel('Stimulus Effect [spikes/sec]'); hold all;\n", + "_matlab(\"zlabel('Stimulus Effect [spikes/sec]'); hold all;\")\n", + "# MATLAB L7260: set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L7261: % title('True Stimulus Effect');\n", + "# title('True Stimulus Effect');\n", + "# MATLAB L7262: title('True Stimulus Effect','FontWeight','bold',...\n", + "_matlab(\"title('True Stimulus Effect','FontWeight','bold',...\")\n", + "# MATLAB L7263: 'Fontsize',14,...\n", + "_matlab(\"'Fontsize',14,...\")\n", + "# MATLAB L7264: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L7265: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L7266: set(gca,'ytick',[],'ytickLabel',[]);\n", + "_matlab(\"set(gca,'ytick',[],'ytickLabel',[]);\")\n", + "# MATLAB L7267: CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];\n", + "_matlab('CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];')\n", + "# MATLAB L7268: view(gca,[90 -90]);\n", + "_matlab('view(gca,[90 -90]);')\n", + "# MATLAB L7269: \n", + "#\n", + "# MATLAB L7270: \n", + "#\n", + "# MATLAB L7271: \n", + "#\n", + "# MATLAB L7272: % The PSTH estimate\n", + "# The PSTH estimate\n", + "# MATLAB L7273: subplot(3,1,2);\n", + "__tracker.annotate('subplot(3,1,2)')\n", + "_matlab('subplot(3,1,2);')\n", + "# MATLAB L7274: lighting gouraud\n", + "_matlab('lighting gouraud')\n", + "# MATLAB L7275: mesh((1:length(b1))',stim.time,repmat(psthSig.data, [1 numRealizations]));\n", + "_matlab(\"mesh((1:length(b1))',stim.time,repmat(psthSig.data, [1 numRealizations]));\")\n", + "# MATLAB L7276: hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\n", + "_matlab(\"hx=xlabel('Trial [k]'); hy=ylabel('time [s]');\")\n", + "# MATLAB L7277: hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\n", + "_matlab(\"hz=zlabel('Stimulus Effect [spikes/sec]'); hold all;\")\n", + "# MATLAB L7278: set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L7279: % title('PSTH Estimated Stimulus Effect');\n", + "# title('PSTH Estimated Stimulus Effect');\n", + "# MATLAB L7280: title('PSTH Estimated Stimulus Effect','FontWeight','bold',...\n", + "_matlab(\"title('PSTH Estimated Stimulus Effect','FontWeight','bold',...\")\n", + "# MATLAB L7281: 'Fontsize',14,...\n", + "_matlab(\"'Fontsize',14,...\")\n", + "# MATLAB L7282: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L7283: \n", + "#\n", + "# MATLAB L7284: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L7285: set(gca,'ytick',[],'ytickLabel',[]);\n", + "_matlab(\"set(gca,'ytick',[],'ytickLabel',[]);\")\n", + "# MATLAB L7286: CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];\n", + "_matlab('CLIM = [min(min(stimData./delta)) max(max(stimData./delta))];')\n", + "# MATLAB L7287: view(gca,[90 -90]);\n", + "_matlab('view(gca,[90 -90]);')\n", + "# MATLAB L7288: \n", + "#\n", + "# MATLAB L7289: % The SSGLM estimated stimulus effect\n", + "# The SSGLM estimated stimulus effect\n", + "# MATLAB L7290: subplot(3,1,3);\n", + "__tracker.annotate('subplot(3,1,3)')\n", + "_matlab('subplot(3,1,3);')\n", + "# MATLAB L7291: lighting gouraud\n", + "_matlab('lighting gouraud')\n", + "# MATLAB L7292: mesh((1:length(b1))',stim.time,estStimEffect);\n", + "_matlab(\"mesh((1:length(b1))',stim.time,estStimEffect);\")\n", + "# MATLAB L7293: xlabel('Trial [k]'); ylabel('time [s]');\n", + "plt.xlabel('Trial [k]')\n", + "plt.ylabel('time [s]')\n", + "# MATLAB L7294: zlabel('Stimulus Effect [spikes/sec]'); hold all;\n", + "_matlab(\"zlabel('Stimulus Effect [spikes/sec]'); hold all;\")\n", + "# MATLAB L7295: hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); hz=get(gca,'ZLabel');\n", + "_matlab(\"hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); hz=get(gca,'ZLabel');\")\n", + "# MATLAB L7296: set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L7297: \n", + "#\n", + "# MATLAB L7298: % title('SSGLM Estimated Stimulus Efferct');\n", + "# title('SSGLM Estimated Stimulus Efferct');\n", + "# MATLAB L7299: title('SSGLM Estimated Stimulus Effect','FontWeight','bold',...\n", + "_matlab(\"title('SSGLM Estimated Stimulus Effect','FontWeight','bold',...\")\n", + "# MATLAB L7300: 'Fontsize',14,...\n", + "_matlab(\"'Fontsize',14,...\")\n", + "# MATLAB L7301: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L7302: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L7303: set(gca,'ytick',[],'ytickLabel',[]);\n", + "_matlab(\"set(gca,'ytick',[],'ytickLabel',[]);\")\n", + "# MATLAB L7304: set(gca, 'YDir','normal')\n", + "_matlab(\"set(gca, 'YDir','normal')\")\n", + "# MATLAB L7305: view(gca,[90 -90]);\n", + "_matlab('view(gca,[90 -90]);')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a6d7400", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 18: Compare differences across trials\n", + "# MATLAB L7500: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L7501: minTime=0; maxTime = Tmax;\n", + "_matlab('minTime=0; maxTime = Tmax;')\n", + "# MATLAB L7502: % Generate the basis function so that the estimated effect can be plotted\n", + "# Generate the basis function so that the estimated effect can be plotted\n", + "# MATLAB L7503: % at the same temporal resolution as the theoretical effect\n", + "# at the same temporal resolution as the theoretical effect\n", + "# MATLAB L7504: if(~isempty(numBasis))\n", + "_matlab('if(~isempty(numBasis))')\n", + "# MATLAB L7505: basisWidth = (maxTime-minTime)/numBasis;\n", + "_matlab('basisWidth = (maxTime-minTime)/numBasis;')\n", + "# MATLAB L7506: sampleRate=1/delta;\n", + "_matlab('sampleRate=1/delta;')\n", + "# MATLAB L7507: unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,...\n", + "_matlab('unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,...')\n", + "# MATLAB L7508: minTime,maxTime,sampleRate);\n", + "_matlab('minTime,maxTime,sampleRate);')\n", + "# MATLAB L7509: basisMat = unitPulseBasis.data;\n", + "_matlab('basisMat = unitPulseBasis.data;')\n", + "# MATLAB L7510: end\n", + "_matlab('end')\n", + "# MATLAB L7511: \n", + "#\n", + "# MATLAB L7512: \n", + "#\n", + "# MATLAB L7513: % close all;\n", + "# close all;\n", + "# MATLAB L7514: \n", + "#\n", + "# MATLAB L7515: t0=0; tf=Tmax;\n", + "_matlab('t0=0; tf=Tmax;')\n", + "# MATLAB L7516: [spikeRateBinom, ProbMat,sigMat]=DecodingAlgorithms.computeSpikeRateCIs(xK,...\n", + "_matlab('[spikeRateBinom, ProbMat,sigMat]=DecodingAlgorithms.computeSpikeRateCIs(xK,...')\n", + "# MATLAB L7517: WkuFinal,dN,t0,tf,fitType,delta,gammahat,windowTimes);\n", + "_matlab('WkuFinal,dN,t0,tf,fitType,delta,gammahat,windowTimes);')\n", + "# MATLAB L7518: \n", + "#\n", + "# MATLAB L7519: lt=find(sigMat(1,:)==1,1,'first');\n", + "_matlab(\"lt=find(sigMat(1,:)==1,1,'first');\")\n", + "# MATLAB L7520: display(['The learning trial (compared to the first trial) is trial #' ...\n", + "_matlab(\"display(['The learning trial (compared to the first trial) is trial #' ...\")\n", + "# MATLAB L7521: num2str(find(sigMat(1,:)==1,1,'first'))]);\n", + "_matlab(\"num2str(find(sigMat(1,:)==1,1,'first'))]);\")\n", + "# MATLAB L7522: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L7523: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\n", + "__tracker.new_figure(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])\")\n", + "_matlab(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);\")\n", + "# MATLAB L7524: \n", + "#\n", + "# MATLAB L7525: subplot(2,3,1);\n", + "__tracker.annotate('subplot(2,3,1)')\n", + "_matlab('subplot(2,3,1);')\n", + "# MATLAB L7526: spikeRateBinom.setName(['(' num2str(Tmax) '-0)^-1*\\Lambda(0,' ...\n", + "_matlab(\"spikeRateBinom.setName(['(' num2str(Tmax) '-0)^-1*\\\\Lambda(0,' ...\")\n", + "# MATLAB L7527: num2str(Tmax) ')']);\n", + "_matlab(\"num2str(Tmax) ')']);\")\n", + "# MATLAB L7528: spikeRateBinom.plot([],{{' ''k'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"spikeRateBinom.plot([],{{' ''k'',''Linewidth'',4'}})\")\n", + "_matlab(\"spikeRateBinom.plot([],{{' ''k'',''Linewidth'',4'}});\")\n", + "# MATLAB L7529: % e = Events(lt,{''});\n", + "# e = Events(lt,{''});\n", + "# MATLAB L7530: % e.plot;\n", + "# e.plot;\n", + "# MATLAB L7531: v=axis;\n", + "_matlab('v=axis;')\n", + "# MATLAB L7532: plot(lt*[1;1],v(3:4),'r','Linewidth',2);\n", + "__tracker.annotate('plot(lt*[1')\n", + "_matlab(\"plot(lt*[1;1],v(3:4),'r','Linewidth',2);\")\n", + "# MATLAB L7533: hx=xlabel('Trial [k]','Interpreter','none'); hold all;\n", + "_matlab(\"hx=xlabel('Trial [k]','Interpreter','none'); hold all;\")\n", + "# MATLAB L7534: hy=ylabel('Average Firing Rate [spikes/sec]','Interpreter','none');\n", + "_matlab(\"hy=ylabel('Average Firing Rate [spikes/sec]','Interpreter','none');\")\n", + "# MATLAB L7535: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L7536: title(['Learning Trial:' num2str(lt)],'FontWeight','bold',...\n", + "_matlab(\"title(['Learning Trial:' num2str(lt)],'FontWeight','bold',...\")\n", + "# MATLAB L7537: 'Fontsize',12,...\n", + "_matlab(\"'Fontsize',12,...\")\n", + "# MATLAB L7538: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L7539: \n", + "#\n", + "# MATLAB L7540: \n", + "#\n", + "# MATLAB L7541: \n", + "#\n", + "# MATLAB L7542: h=subplot(2,3,[2 3 5 6]);\n", + "__tracker.annotate('h=subplot(2,3,[2 3 5 6])')\n", + "_matlab('h=subplot(2,3,[2 3 5 6]);')\n", + "# MATLAB L7543: K=size(dN,1);\n", + "_matlab('K=size(dN,1);')\n", + "# MATLAB L7544: colormap(flipud(gray));\n", + "_matlab('colormap(flipud(gray));')\n", + "# MATLAB L7545: imagesc(ProbMat); hold on;\n", + "__tracker.annotate('imagesc(ProbMat)')\n", + "_matlab('imagesc(ProbMat); hold on;')\n", + "# MATLAB L7546: for k=1:K\n", + "_matlab('for k=1:K')\n", + "# MATLAB L7547: for m=(k+1):K\n", + "_matlab('for m=(k+1):K')\n", + "# MATLAB L7548: if(sigMat(k,m)==1)\n", + "_matlab('if(sigMat(k,m)==1)')\n", + "# MATLAB L7549: plot3(m,k,1,'r*'); hold on;\n", + "__tracker.annotate(\"plot3(m,k,1,'r*')\")\n", + "_matlab(\"plot3(m,k,1,'r*'); hold on;\")\n", + "# MATLAB L7550: end\n", + "_matlab('end')\n", + "# MATLAB L7551: end\n", + "_matlab('end')\n", + "# MATLAB L7552: end\n", + "_matlab('end')\n", + "# MATLAB L7553: %\n", + "#\n", + "# MATLAB L7554: set(h,'XAxisLocation','top','YAxisLocation','right');\n", + "_matlab(\"set(h,'XAxisLocation','top','YAxisLocation','right');\")\n", + "# MATLAB L7555: hx=xlabel('Trial Number','Interpreter','none'); hold all;\n", + "_matlab(\"hx=xlabel('Trial Number','Interpreter','none'); hold all;\")\n", + "# MATLAB L7556: hy=ylabel('Trial Number','Interpreter','none');\n", + "_matlab(\"hy=ylabel('Trial Number','Interpreter','none');\")\n", + "# MATLAB L7557: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L7558: \n", + "#\n", + "# MATLAB L7559: subplot(2,3,4)\n", + "__tracker.annotate('subplot(2,3,4)')\n", + "_matlab('subplot(2,3,4)')\n", + "# MATLAB L7560: stim1 = Covariate(time, basisMat*stimulus(:,1),'Trial1','time','s',...\n", + "_matlab(\"stim1 = Covariate(time, basisMat*stimulus(:,1),'Trial1','time','s',...\")\n", + "# MATLAB L7561: 'spikes/sec');\n", + "_matlab(\"'spikes/sec');\")\n", + "# MATLAB L7562: temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,1,:)));\n", + "_matlab('temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,1,:)));')\n", + "# MATLAB L7563: stim1.setConfInterval(temp);\n", + "_matlab('stim1.setConfInterval(temp);')\n", + "# MATLAB L7564: stimlt = Covariate(time, basisMat*stimulus(:,lt),'Trial1','time','s',...\n", + "_matlab(\"stimlt = Covariate(time, basisMat*stimulus(:,lt),'Trial1','time','s',...\")\n", + "# MATLAB L7565: 'spikes/sec');\n", + "_matlab(\"'spikes/sec');\")\n", + "# MATLAB L7566: temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt,:)));\n", + "_matlab('temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt,:)));')\n", + "# MATLAB L7567: temp.setColor('r');\n", + "_matlab(\"temp.setColor('r');\")\n", + "# MATLAB L7568: stimlt.setConfInterval(temp);\n", + "_matlab('stimlt.setConfInterval(temp);')\n", + "# MATLAB L7569: stimltm1 = Covariate(time, basisMat*stimulus(:,lt-1),'Trial1','time','s',...\n", + "_matlab(\"stimltm1 = Covariate(time, basisMat*stimulus(:,lt-1),'Trial1','time','s',...\")\n", + "# MATLAB L7570: 'spikes/sec');\n", + "_matlab(\"'spikes/sec');\")\n", + "# MATLAB L7571: temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt-1,:)));\n", + "_matlab('temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt-1,:)));')\n", + "# MATLAB L7572: temp.setColor('r');\n", + "_matlab(\"temp.setColor('r');\")\n", + "# MATLAB L7573: stimltm1.setConfInterval(temp);\n", + "_matlab('stimltm1.setConfInterval(temp);')\n", + "# MATLAB L7574: \n", + "#\n", + "# MATLAB L7575: % figure;\n", + "# figure;\n", + "# MATLAB L7576: h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}}); hold all;\n", + "__tracker.annotate(\"h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}})\")\n", + "_matlab(\"h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}}); hold all;\")\n", + "# MATLAB L7577: h2=stimlt.plot([],{{' ''r'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"h2=stimlt.plot([],{{' ''r'',''Linewidth'',4'}})\")\n", + "_matlab(\"h2=stimlt.plot([],{{' ''r'',''Linewidth'',4'}});\")\n", + "# MATLAB L7578: hx=xlabel('time [s]','Interpreter','none'); hold all;\n", + "_matlab(\"hx=xlabel('time [s]','Interpreter','none'); hold all;\")\n", + "# MATLAB L7579: hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\n", + "_matlab(\"hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\")\n", + "# MATLAB L7580: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L7581: \n", + "#\n", + "# MATLAB L7582: title({'Learning Trial Vs. Baseline Trial';'with 95% CIs'},'FontWeight','bold',...\n", + "_matlab(\"title({'Learning Trial Vs. Baseline Trial';'with 95% CIs'},'FontWeight','bold',...\")\n", + "# MATLAB L7583: 'Fontsize',12,...\n", + "_matlab(\"'Fontsize',12,...\")\n", + "# MATLAB L7584: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L7585: h_legend=legend([h1(1) h2(1)],'\\lambda_{1}(t)',['\\lambda_{' num2str(lt) '}(t)']);\n", + "_matlab(\"h_legend=legend([h1(1) h2(1)],'\\\\lambda_{1}(t)',['\\\\lambda_{' num2str(lt) '}(t)']);\")\n", + "# MATLAB L7586: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L7587: set(h_legend, 'position',[pos(1)+.03 pos(2)+.01 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)+.03 pos(2)+.01 pos(3:4)]);\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "578ba515", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 19: Example 4 - HIPPOCAMPAL PLACE CELL - RECEPTIVE FIELD ESTIMATION\n", + "# MATLAB L7800: % Estimation of receptive fields of neurons is a very common data analysis problem in neuroscience. Here we use the nSTAT software to perform an estimation of the receptive fields of hippocampal place cells using a bivariate Gaussian model and Zernike polynomials. The number of zernike polynomials is based on \"An Analysis of Hippocampal Spatio-Temporal Representations Using a Bayesian Algorithm for Neural Spike Train Decoding\" Barbieri et. al 2005. The data used herein in was provided by Dr. Ricardo Barbieri on 2/28/2011.\n", + "# Estimation of receptive fields of neurons is a very common data analysis problem in neuroscience. Here we use the nSTAT software to perform an estimation of the receptive fields of hippocampal place cells using a bivariate Gaussian model and Zernike polynomials. The number of zernike polynomials is based on \"An Analysis of Hippocampal Spatio-Temporal Representations Using a Bayesian Algorithm for Neural Spike Train Decoding\" Barbieri et. al 2005. The data used herein in was provided by Dr. Ricardo Barbieri on 2/28/2011.\n", + "# MATLAB L7900: % Author: Iahn Cajigas\n", + "# Author: Iahn Cajigas\n", + "# MATLAB L8000: % Date: 3/1/2011\n", + "# Date: 3/1/2011\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80618678", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 20: Example Data\n", + "# MATLAB L8300: % The x and y coordinates of a freely foraging rat in a circular environment (70cm in diameter and 30cm high walls) and a fixed visual cue. The x and y coordinates at the time when a spike was observed are marked in red. The position coordinates have been normalized to be between -1 and 1 to allow to simplify the analysis.\n", + "# The x and y coordinates of a freely foraging rat in a circular environment (70cm in diameter and 30cm high walls) and a fixed visual cue. The x and y coordinates at the time when a spike was observed are marked in red. The position coordinates have been normalized to be between -1 and 1 to allow to simplify the analysis.\n", + "# MATLAB L8400: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L8401: load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\n", + "_matlab(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", + "# MATLAB L8402: exampleCell = [2 21 25 49];\n", + "_matlab('exampleCell = [2 21 25 49];')\n", + "# MATLAB L8403: % exampleCell = 1:length(neuron);\n", + "# exampleCell = 1:length(neuron);\n", + "# MATLAB L8404: % figure(1);\n", + "# figure(1);\n", + "# MATLAB L8405: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L8406: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9]);\n", + "__tracker.new_figure(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9])\")\n", + "_matlab(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9]);\")\n", + "# MATLAB L8407: \n", + "#\n", + "# MATLAB L8408: for i=1:length(exampleCell)\n", + "_matlab('for i=1:length(exampleCell)')\n", + "# MATLAB L8409: subplot(2,2,i);\n", + "__tracker.annotate('subplot(2,2,i)')\n", + "_matlab('subplot(2,2,i);')\n", + "# MATLAB L8410: h1=plot(x,y,'b','Linewidth',.5); hold on;\n", + "__tracker.annotate(\"h1=plot(x,y,'b','Linewidth',.5)\")\n", + "_matlab(\"h1=plot(x,y,'b','Linewidth',.5); hold on;\")\n", + "# MATLAB L8411: h2=plot(neuron{exampleCell(i)}.xN,neuron{exampleCell(i)}.yN,'r.',...\n", + "__tracker.annotate(\"h2=plot(neuron{exampleCell(i)}.xN,neuron{exampleCell(i)}.yN,'r.',...\")\n", + "_matlab(\"h2=plot(neuron{exampleCell(i)}.xN,neuron{exampleCell(i)}.yN,'r.',...\")\n", + "# MATLAB L8412: 'MarkerSize',7);\n", + "_matlab(\"'MarkerSize',7);\")\n", + "# MATLAB L8413: hx=xlabel('X Position'); hy=ylabel('Y Position');\n", + "_matlab(\"hx=xlabel('X Position'); hy=ylabel('Y Position');\")\n", + "# MATLAB L8414: % title(['Animal#1, Cell#' num2str(exampleCell(i))]);\n", + "# title(['Animal#1, Cell#' num2str(exampleCell(i))]);\n", + "# MATLAB L8415: title(['Cell#' num2str(exampleCell(i))],'FontWeight','bold',...\n", + "_matlab(\"title(['Cell#' num2str(exampleCell(i))],'FontWeight','bold',...\")\n", + "# MATLAB L8416: 'Fontsize',12,'FontName','Arial');\n", + "_matlab(\"'Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L8417: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L8418: set(gca,'xTick',-1:.5:1,'yTick',-1:.5:1); axis square;\n", + "_matlab(\"set(gca,'xTick',-1:.5:1,'yTick',-1:.5:1); axis square;\")\n", + "# MATLAB L8419: if(i==4)\n", + "_matlab('if(i==4)')\n", + "# MATLAB L8420: h_legend = legend([h1 h2],'Animal Path',...\n", + "_matlab(\"h_legend = legend([h1 h2],'Animal Path',...\")\n", + "# MATLAB L8421: 'Location at time of spike');\n", + "_matlab(\"'Location at time of spike');\")\n", + "# MATLAB L8422: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L8423: set(h_legend, 'position',[pos(1)+.09 pos(2)+.06 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)+.09 pos(2)+.06 pos(3:4)]);\")\n", + "# MATLAB L8424: end\n", + "_matlab('end')\n", + "# MATLAB L8425: end\n", + "_matlab('end')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b61d521c", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 21: Analyze All Cells\n", + "# MATLAB L8700: numAnimals=2;\n", + "numAnimals = 2\n", + "# MATLAB L8701: CompilingHelpFile=1;\n", + "CompilingHelpFile = 1\n", + "# MATLAB L8702: if(~CompilingHelpFile)\n", + "_matlab('if(~CompilingHelpFile)')\n", + "# MATLAB L8703: for n=1:numAnimals\n", + "_matlab('for n=1:numAnimals')\n", + "# MATLAB L8704: % load the data\n", + "# load the data\n", + "# MATLAB L8705: clear x y neuron time nst tc tcc z;\n", + "pass\n", + "# MATLAB L8706: load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\n", + "_matlab(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", + "# MATLAB L8707: \n", + "#\n", + "# MATLAB L8708: % Create the spikeTrains for each cell\n", + "# Create the spikeTrains for each cell\n", + "# MATLAB L8709: for i=1:length(neuron)\n", + "_matlab('for i=1:length(neuron)')\n", + "# MATLAB L8710: nst{i} = nspikeTrain(neuron{i}.spikeTimes);\n", + "_matlab('nst{i} = nspikeTrain(neuron{i}.spikeTimes);')\n", + "# MATLAB L8711: end\n", + "_matlab('end')\n", + "# MATLAB L8712: \n", + "#\n", + "# MATLAB L8713: \n", + "#\n", + "# MATLAB L8714: % Convert to polar coordinates\n", + "# Convert to polar coordinates\n", + "# MATLAB L8715: [theta,r] = cart2pol(x,y);\n", + "_matlab('[theta,r] = cart2pol(x,y);')\n", + "# MATLAB L8716: \n", + "#\n", + "# MATLAB L8717: \n", + "#\n", + "# MATLAB L8718: % Evaluate the Zernike Polynomials\n", + "# Evaluate the Zernike Polynomials\n", + "# MATLAB L8719: % Number of polynomials from \"An Analysis of Hippocampal\n", + "# Number of polynomials from \"An Analysis of Hippocampal\n", + "# MATLAB L8720: % Spatio-Temporal Representations Using a Bayesian Algorithm for Neural\n", + "# Spatio-Temporal Representations Using a Bayesian Algorithm for Neural\n", + "# MATLAB L8721: % Spike Train Decoding\" Barbieri et. al 2005\n", + "# Spike Train Decoding\" Barbieri et. al 2005\n", + "# MATLAB L8722: cnt=0;\n", + "cnt = 0\n", + "# MATLAB L8723: for l=0:3\n", + "_matlab('for l=0:3')\n", + "# MATLAB L8724: for m=-l:l\n", + "_matlab('for m=-l:l')\n", + "# MATLAB L8725: if(~any(mod(l-m,2))) % otherwise the polynomial = 0\n", + "_matlab('if(~any(mod(l-m,2))) % otherwise the polynomial = 0')\n", + "# MATLAB L8726: cnt = cnt+1;\n", + "_matlab('cnt = cnt+1;')\n", + "# MATLAB L8727: z(:,cnt) = zernfun(l,m,r,theta,'norm');\n", + "_matlab(\"z(:,cnt) = zernfun(l,m,r,theta,'norm');\")\n", + "# MATLAB L8728: % zernfun by Paul Fricker\n", + "# zernfun by Paul Fricker\n", + "# MATLAB L8729: % http://www.mathworks.com/matlabcentral/fileexchange/7687\n", + "# http://www.mathworks.com/matlabcentral/fileexchange/7687\n", + "# MATLAB L8730: end\n", + "_matlab('end')\n", + "# MATLAB L8731: end\n", + "_matlab('end')\n", + "# MATLAB L8732: end\n", + "_matlab('end')\n", + "# MATLAB L8733: \n", + "#\n", + "# MATLAB L8734: % Data sampled at 30 Hz but just to be sure\n", + "# Data sampled at 30 Hz but just to be sure\n", + "# MATLAB L8735: delta=min(diff(time));\n", + "_matlab('delta=min(diff(time));')\n", + "# MATLAB L8736: sampleRate = round(1/delta);\n", + "_matlab('sampleRate = round(1/delta);')\n", + "# MATLAB L8737: % Define Covariates for the analysis\n", + "# Define Covariates for the analysis\n", + "# MATLAB L8738: baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...\")\n", + "# MATLAB L8739: {'mu'});\n", + "_matlab(\"{'mu'});\")\n", + "# MATLAB L8740: zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\n", + "_matlab(\"zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',...\")\n", + "# MATLAB L8741: 'z4','z5','z6','z7','z8','z9','z10'});\n", + "_matlab(\"'z4','z5','z6','z7','z8','z9','z10'});\")\n", + "# MATLAB L8742: gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\n", + "_matlab(\"gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',...\")\n", + "# MATLAB L8743: 's','m',{'x','y','x^2','y^2','x*y'});\n", + "_matlab(\"'s','m',{'x','y','x^2','y^2','x*y'});\")\n", + "# MATLAB L8744: covarColl = CovColl({baseline,gaussian,zernike});\n", + "_matlab('covarColl = CovColl({baseline,gaussian,zernike});')\n", + "# MATLAB L8745: \n", + "#\n", + "# MATLAB L8746: % Create the trial structure\n", + "# Create the trial structure\n", + "# MATLAB L8747: spikeColl = nstColl(nst);\n", + "_matlab('spikeColl = nstColl(nst);')\n", + "# MATLAB L8748: trial = Trial(spikeColl,covarColl);\n", + "_matlab('trial = Trial(spikeColl,covarColl);')\n", + "# MATLAB L8749: \n", + "#\n", + "# MATLAB L8750: \n", + "#\n", + "# MATLAB L8751: % Define how we want to analyze the data\n", + "# Define how we want to analyze the data\n", + "# MATLAB L8752: tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\n", + "_matlab(\"tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...\")\n", + "# MATLAB L8753: 'x','y','x^2','y^2','x*y'}},sampleRate,[]);\n", + "_matlab(\"'x','y','x^2','y^2','x*y'}},sampleRate,[]);\")\n", + "# MATLAB L8754: tc{1}.setName('Gaussian');\n", + "_matlab(\"tc{1}.setName('Gaussian');\")\n", + "# MATLAB L8755: tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\n", + "_matlab(\"tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',...\")\n", + "# MATLAB L8756: 'z7','z8','z9','z10'}},sampleRate,[]);\n", + "_matlab(\"'z7','z8','z9','z10'}},sampleRate,[]);\")\n", + "# MATLAB L8757: tc{2}.setName('Zernike');\n", + "_matlab(\"tc{2}.setName('Zernike');\")\n", + "# MATLAB L8758: tcc = ConfigColl(tc);\n", + "_matlab('tcc = ConfigColl(tc);')\n", + "# MATLAB L8759: \n", + "#\n", + "# MATLAB L8760: % Perform Analysis (Commented to since data already saved)\n", + "# Perform Analysis (Commented to since data already saved)\n", + "# MATLAB L8761: results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\n", + "_matlab('results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);')\n", + "# MATLAB L8762: \n", + "#\n", + "# MATLAB L8763: % Save results\n", + "# Save results\n", + "# MATLAB L8764: resStruct =FitResult.CellArrayToStructure(results);\n", + "_matlab('resStruct =FitResult.CellArrayToStructure(results);')\n", + "# MATLAB L8765: filename = fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results']);\n", + "_matlab(\"filename = fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results']);\")\n", + "# MATLAB L8766: save(filename,'resStruct');\n", + "_matlab(\"save(filename,'resStruct');\")\n", + "# MATLAB L8767: end\n", + "_matlab('end')\n", + "# MATLAB L8768: end\n", + "_matlab('end')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ddf98823", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 22: View Summary Statistics\n", + "# MATLAB L9000: % Note the Zernike Polynomials yield better fits in terms of decreased KS Statistics (less deviation from the 45 degree line), reduced AIC and reduced BIC across the majority of cells and for both animals\n", + "# Note the Zernike Polynomials yield better fits in terms of decreased KS Statistics (less deviation from the 45 degree line), reduced AIC and reduced BIC across the majority of cells and for both animals\n", + "# MATLAB L9100: clear Summary;\n", + "pass\n", + "# MATLAB L9101: numAnimals =2;\n", + "numAnimals = 2\n", + "# MATLAB L9102: \n", + "#\n", + "# MATLAB L9103: for n=1:numAnimals\n", + "_matlab('for n=1:numAnimals')\n", + "# MATLAB L9104: resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\n", + "_matlab(\"resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", + "# MATLAB L9105: results = FitResult.fromStructure(resData.resStruct);\n", + "_matlab('results = FitResult.fromStructure(resData.resStruct);')\n", + "# MATLAB L9106: Summary{n} = FitResSummary(results);\n", + "_matlab('Summary{n} = FitResSummary(results);')\n", + "# MATLAB L9107: % Summary{n}.plotSummary;\n", + "# Summary{n}.plotSummary;\n", + "# MATLAB L9108: end\n", + "_matlab('end')\n", + "# MATLAB L9300: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L9301: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L9302: h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5]);\n", + "__tracker.new_figure(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5])\")\n", + "_matlab(\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5]);\")\n", + "# MATLAB L9303: subplot(1,3,1);\n", + "__tracker.annotate('subplot(1,3,1)')\n", + "_matlab('subplot(1,3,1);')\n", + "# MATLAB L9304: maxLength = max([Summary{1}.numNeurons,Summary{2}.numNeurons]);\n", + "_matlab('maxLength = max([Summary{1}.numNeurons,Summary{2}.numNeurons]);')\n", + "# MATLAB L9305: dKS = nan(maxLength, 2);\n", + "_matlab('dKS = nan(maxLength, 2);')\n", + "# MATLAB L9306: dKS(1:Summary{1}.numNeurons,1) = (Summary{1}.KSStats(:,1)-Summary{1}.KSStats(:,2)) ;\n", + "_matlab('dKS(1:Summary{1}.numNeurons,1) = (Summary{1}.KSStats(:,1)-Summary{1}.KSStats(:,2)) ;')\n", + "# MATLAB L9307: dKS(1:Summary{2}.numNeurons,2) = (Summary{2}.KSStats(:,1)-Summary{2}.KSStats(:,2)) ;\n", + "_matlab('dKS(1:Summary{2}.numNeurons,2) = (Summary{2}.KSStats(:,1)-Summary{2}.KSStats(:,2)) ;')\n", + "# MATLAB L9308: \n", + "#\n", + "# MATLAB L9309: boxplot(dKS ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\n", + "_matlab(\"boxplot(dKS ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\")\n", + "# MATLAB L9310: title('\\Delta KS Statistic','FontWeight','bold','FontSize',14,...\n", + "_matlab(\"title('\\\\Delta KS Statistic','FontWeight','bold','FontSize',14,...\")\n", + "# MATLAB L9311: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L9312: \n", + "#\n", + "# MATLAB L9313: \n", + "#\n", + "# MATLAB L9314: subplot(1,3,2);\n", + "__tracker.annotate('subplot(1,3,2)')\n", + "_matlab('subplot(1,3,2);')\n", + "# MATLAB L9315: dAIC = nan(maxLength, 2);\n", + "_matlab('dAIC = nan(maxLength, 2);')\n", + "# MATLAB L9316: dAIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffAIC(1);\n", + "_matlab('dAIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffAIC(1);')\n", + "# MATLAB L9317: dAIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffAIC(1);\n", + "_matlab('dAIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffAIC(1);')\n", + "# MATLAB L9318: \n", + "#\n", + "# MATLAB L9319: boxplot(dAIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\n", + "_matlab(\"boxplot(dAIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline');\")\n", + "# MATLAB L9320: title('\\Delta AIC','FontWeight','bold','FontSize',14,'FontName','Arial');\n", + "_matlab(\"title('\\\\Delta AIC','FontWeight','bold','FontSize',14,'FontName','Arial');\")\n", + "# MATLAB L9321: \n", + "#\n", + "# MATLAB L9322: \n", + "#\n", + "# MATLAB L9323: subplot(1,3,3);\n", + "__tracker.annotate('subplot(1,3,3)')\n", + "_matlab('subplot(1,3,3);')\n", + "# MATLAB L9324: dBIC = nan(maxLength, 2);\n", + "_matlab('dBIC = nan(maxLength, 2);')\n", + "# MATLAB L9325: dBIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffBIC(1);\n", + "_matlab('dBIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffBIC(1);')\n", + "# MATLAB L9326: dBIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffBIC(1);\n", + "_matlab('dBIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffBIC(1);')\n", + "# MATLAB L9327: \n", + "#\n", + "# MATLAB L9328: boxplot(dBIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline'); %ylabel('\\Delta BIC'); %xticklabel_rotate([],45,[],'Fontsize',6);\n", + "_matlab(\"boxplot(dBIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline'); %ylabel('\\\\Delta BIC'); %xticklabel_rotate([],45,[],'Fontsize',6);\")\n", + "# MATLAB L9329: title('\\Delta BIC','FontWeight','bold','FontSize',14,'FontName','Arial');\n", + "_matlab(\"title('\\\\Delta BIC','FontWeight','bold','FontSize',14,'FontName','Arial');\")\n", + "# MATLAB L9330: \n", + "#\n", + "# MATLAB L9331: % close all;\n", + "# close all;\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d23dd4f4", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 23: Visualize the results\n", + "# MATLAB L9600: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L9601: % Define a grid\n", + "# Define a grid\n", + "# MATLAB L9602: [x_new,y_new]=meshgrid(-1:.01:1); %define new x and y\n", + "_matlab('[x_new,y_new]=meshgrid(-1:.01:1); %define new x and y')\n", + "# MATLAB L9603: y_new = flipud(y_new); x_new = fliplr(x_new);\n", + "_matlab('y_new = flipud(y_new); x_new = fliplr(x_new);')\n", + "# MATLAB L9604: [theta_new,r_new] = cart2pol(x_new,y_new);\n", + "_matlab('[theta_new,r_new] = cart2pol(x_new,y_new);')\n", + "# MATLAB L9605: \n", + "#\n", + "# MATLAB L9606: %Data for the gaussian fit\n", + "# Data for the gaussian fit\n", + "# MATLAB L9607: newData{1} =ones(size(x_new));\n", + "_matlab('newData{1} =ones(size(x_new));')\n", + "# MATLAB L9608: newData{2} =x_new; newData{3} =y_new;\n", + "_matlab('newData{2} =x_new; newData{3} =y_new;')\n", + "# MATLAB L9609: newData{4} =x_new.^2; newData{5} =y_new.^2;\n", + "_matlab('newData{4} =x_new.^2; newData{5} =y_new.^2;')\n", + "# MATLAB L9610: newData{6} =x_new.*y_new;\n", + "_matlab('newData{6} =x_new.*y_new;')\n", + "# MATLAB L9611: \n", + "#\n", + "# MATLAB L9612: \n", + "#\n", + "# MATLAB L9613: % Zernike polynomials only defined on the unit disk\n", + "# Zernike polynomials only defined on the unit disk\n", + "# MATLAB L9614: idx = r_new<=1;\n", + "_matlab('idx = r_new<=1;')\n", + "# MATLAB L9615: zpoly = cell(1,10);\n", + "_matlab('zpoly = cell(1,10);')\n", + "# MATLAB L9616: cnt=0;\n", + "cnt = 0\n", + "# MATLAB L9617: for l=0:3\n", + "_matlab('for l=0:3')\n", + "# MATLAB L9618: for m=-l:l\n", + "_matlab('for m=-l:l')\n", + "# MATLAB L9619: if(~any(mod(l-m,2)))\n", + "_matlab('if(~any(mod(l-m,2)))')\n", + "# MATLAB L9620: cnt = cnt+1;\n", + "_matlab('cnt = cnt+1;')\n", + "# MATLAB L9621: temp = nan(size(x_new));\n", + "_matlab('temp = nan(size(x_new));')\n", + "# MATLAB L9622: temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\n", + "_matlab(\"temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');\")\n", + "# MATLAB L9623: zpoly{cnt} = temp;\n", + "_matlab('zpoly{cnt} = temp;')\n", + "# MATLAB L9624: end\n", + "_matlab('end')\n", + "# MATLAB L9625: end\n", + "_matlab('end')\n", + "# MATLAB L9626: end\n", + "_matlab('end')\n", + "# MATLAB L9627: \n", + "#\n", + "# MATLAB L9628: \n", + "#\n", + "# MATLAB L9629: \n", + "#\n", + "# MATLAB L9630: for n=1:numAnimals\n", + "_matlab('for n=1:numAnimals')\n", + "# MATLAB L9631: \n", + "#\n", + "# MATLAB L9632: clear lambdaGaussian lambdaZernike;\n", + "pass\n", + "# MATLAB L9633: load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\n", + "_matlab(\"load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));\")\n", + "# MATLAB L9634: resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\n", + "_matlab(\"resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat']));\")\n", + "# MATLAB L9635: results = FitResult.fromStructure(resData.resStruct);\n", + "_matlab('results = FitResult.fromStructure(resData.resStruct);')\n", + "# MATLAB L9636: \n", + "#\n", + "# MATLAB L9637: for i=1:length(neuron)\n", + "_matlab('for i=1:length(neuron)')\n", + "# MATLAB L9638: % Evaluate our fits using the new data and the estimated parameters\n", + "# Evaluate our fits using the new data and the estimated parameters\n", + "# MATLAB L9639: lambdaGaussian{i} = results{i}.evalLambda(1,newData);\n", + "_matlab('lambdaGaussian{i} = results{i}.evalLambda(1,newData);')\n", + "# MATLAB L9640: lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\n", + "_matlab('lambdaZernike{i} = results{i}.evalLambda(2,zpoly);')\n", + "# MATLAB L9641: end\n", + "_matlab('end')\n", + "# MATLAB L9642: \n", + "#\n", + "# MATLAB L9643: \n", + "#\n", + "# MATLAB L9644: \n", + "#\n", + "# MATLAB L9645: \n", + "#\n", + "# MATLAB L9646: % Plot the receptive fields\n", + "# Plot the receptive fields\n", + "# MATLAB L9647: for i=1:length(neuron)\n", + "_matlab('for i=1:length(neuron)')\n", + "# MATLAB L9648: % 3d plot of an example place field\n", + "# 3d plot of an example place field\n", + "# MATLAB L9649: \n", + "#\n", + "# MATLAB L9650: \n", + "#\n", + "# MATLAB L9651: % 2d plot of all the cell's fields\n", + "# 2d plot of all the cell's fields\n", + "# MATLAB L9652: if(n==1)\n", + "_matlab('if(n==1)')\n", + "# MATLAB L9653: h4=figure(4);\n", + "__tracker.new_figure('h4=figure(4)')\n", + "_matlab('h4=figure(4);')\n", + "# MATLAB L9654: colormap('jet');\n", + "_matlab(\"colormap('jet');\")\n", + "# MATLAB L9655: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L9656: tb=annotation(h4,'textbox',...\n", + "_matlab(\"tb=annotation(h4,'textbox',...\")\n", + "# MATLAB L9657: [0.283261904761904 0.928571428571418 ...\n", + "_matlab('[0.283261904761904 0.928571428571418 ...')\n", + "# MATLAB L9658: 0.392857142857143 0.0595238095238095],...\n", + "_matlab('0.392857142857143 0.0595238095238095],...')\n", + "# MATLAB L9659: 'String',{['Gaussian Place Fields - Animal#' ...\n", + "_matlab(\"'String',{['Gaussian Place Fields - Animal#' ...\")\n", + "# MATLAB L9660: num2str(n)]},'FitBoxToText','on','Fontsize',11,...\n", + "_matlab(\"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\")\n", + "# MATLAB L9661: 'FontName','Arial','FontWeight','bold','LineStyle',...\n", + "_matlab(\"'FontName','Arial','FontWeight','bold','LineStyle',...\")\n", + "# MATLAB L9662: 'none','HorizontalAlignment','center'); hold on;\n", + "_matlab(\"'none','HorizontalAlignment','center'); hold on;\")\n", + "# MATLAB L9663: end\n", + "_matlab('end')\n", + "# MATLAB L9664: subplot(7,7,i);\n", + "__tracker.annotate('subplot(7,7,i)')\n", + "_matlab('subplot(7,7,i);')\n", + "# MATLAB L9665: elseif(n==2)\n", + "_matlab('elseif(n==2)')\n", + "# MATLAB L9666: h6=figure(6);\n", + "__tracker.new_figure('h6=figure(6)')\n", + "_matlab('h6=figure(6);')\n", + "# MATLAB L9667: colormap('jet');\n", + "_matlab(\"colormap('jet');\")\n", + "# MATLAB L9668: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L9669: annotation(h6,'textbox',...\n", + "_matlab(\"annotation(h6,'textbox',...\")\n", + "# MATLAB L9670: [0.283261904761904 0.928571428571418 ...\n", + "_matlab('[0.283261904761904 0.928571428571418 ...')\n", + "# MATLAB L9671: 0.392857142857143 0.0595238095238095],...\n", + "_matlab('0.392857142857143 0.0595238095238095],...')\n", + "# MATLAB L9672: 'String',{['Gaussian Place Fields - Animal#' ...\n", + "_matlab(\"'String',{['Gaussian Place Fields - Animal#' ...\")\n", + "# MATLAB L9673: num2str(n)]},'FitBoxToText','on','Fontsize',11,...\n", + "_matlab(\"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\")\n", + "# MATLAB L9674: 'FontName','Arial','FontWeight','bold','LineStyle',...\n", + "_matlab(\"'FontName','Arial','FontWeight','bold','LineStyle',...\")\n", + "# MATLAB L9675: 'none','HorizontalAlignment','center'); hold on;\n", + "_matlab(\"'none','HorizontalAlignment','center'); hold on;\")\n", + "# MATLAB L9676: end\n", + "_matlab('end')\n", + "# MATLAB L9677: subplot(6,7,i);\n", + "__tracker.annotate('subplot(6,7,i)')\n", + "_matlab('subplot(6,7,i);')\n", + "# MATLAB L9678: end\n", + "_matlab('end')\n", + "# MATLAB L9679: pcolor(x_new,y_new,lambdaGaussian{i}), shading interp\n", + "__tracker.annotate('pcolor(x_new,y_new,lambdaGaussian{i}), shading interp')\n", + "_matlab('pcolor(x_new,y_new,lambdaGaussian{i}), shading interp')\n", + "# MATLAB L9680: axis square; set(gca,'xtick',[],'ytick',[]);\n", + "_matlab(\"axis square; set(gca,'xtick',[],'ytick',[]);\")\n", + "# MATLAB L9681: set(gca, 'Box' , 'off');\n", + "_matlab(\"set(gca, 'Box' , 'off');\")\n", + "# MATLAB L9682: \n", + "#\n", + "# MATLAB L9683: if(n==1)\n", + "_matlab('if(n==1)')\n", + "# MATLAB L9684: h5=figure(5);\n", + "__tracker.new_figure('h5=figure(5)')\n", + "_matlab('h5=figure(5);')\n", + "# MATLAB L9685: colormap('jet');\n", + "_matlab(\"colormap('jet');\")\n", + "# MATLAB L9686: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L9687: annotation(h5,'textbox',...\n", + "_matlab(\"annotation(h5,'textbox',...\")\n", + "# MATLAB L9688: [0.303261904761904 0.928571428571418 ...\n", + "_matlab('[0.303261904761904 0.928571428571418 ...')\n", + "# MATLAB L9689: 0.392857142857143 0.0595238095238095],...\n", + "_matlab('0.392857142857143 0.0595238095238095],...')\n", + "# MATLAB L9690: 'String',{['Zernike Place Fields - Animal#' ...\n", + "_matlab(\"'String',{['Zernike Place Fields - Animal#' ...\")\n", + "# MATLAB L9691: num2str(n)]},'FitBoxToText','on','Fontsize',11,...\n", + "_matlab(\"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\")\n", + "# MATLAB L9692: 'FontName','Arial','FontWeight','bold','LineStyle','none'); hold on;\n", + "_matlab(\"'FontName','Arial','FontWeight','bold','LineStyle','none'); hold on;\")\n", + "# MATLAB L9693: \n", + "#\n", + "# MATLAB L9694: end\n", + "_matlab('end')\n", + "# MATLAB L9695: subplot(7,7,i);\n", + "__tracker.annotate('subplot(7,7,i)')\n", + "_matlab('subplot(7,7,i);')\n", + "# MATLAB L9696: elseif(n==2)\n", + "_matlab('elseif(n==2)')\n", + "# MATLAB L9697: h7=figure(7);\n", + "__tracker.new_figure('h7=figure(7)')\n", + "_matlab('h7=figure(7);')\n", + "# MATLAB L9698: colormap('jet');\n", + "_matlab(\"colormap('jet');\")\n", + "# MATLAB L9699: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L9700: annotation(h7,'textbox',...\n", + "_matlab(\"annotation(h7,'textbox',...\")\n", + "# MATLAB L9701: [0.303261904761904 0.928571428571418 ...\n", + "_matlab('[0.303261904761904 0.928571428571418 ...')\n", + "# MATLAB L9702: 0.392857142857143 0.0595238095238095],...\n", + "_matlab('0.392857142857143 0.0595238095238095],...')\n", + "# MATLAB L9703: 'String',{['Zernike Place Fields - Animal#' ...\n", + "_matlab(\"'String',{['Zernike Place Fields - Animal#' ...\")\n", + "# MATLAB L9704: num2str(n)]},'FitBoxToText','on','Fontsize',11,...\n", + "_matlab(\"num2str(n)]},'FitBoxToText','on','Fontsize',11,...\")\n", + "# MATLAB L9705: 'FontName','Arial','FontWeight','bold','LineStyle',...\n", + "_matlab(\"'FontName','Arial','FontWeight','bold','LineStyle',...\")\n", + "# MATLAB L9706: 'none','HorizontalAlignment','center'); hold on;\n", + "_matlab(\"'none','HorizontalAlignment','center'); hold on;\")\n", + "# MATLAB L9707: end\n", + "_matlab('end')\n", + "# MATLAB L9708: subplot(6,7,i);\n", + "__tracker.annotate('subplot(6,7,i)')\n", + "_matlab('subplot(6,7,i);')\n", + "# MATLAB L9709: end\n", + "_matlab('end')\n", + "# MATLAB L9710: pcolor(x_new,y_new,lambdaZernike{i}), shading interp\n", + "__tracker.annotate('pcolor(x_new,y_new,lambdaZernike{i}), shading interp')\n", + "_matlab('pcolor(x_new,y_new,lambdaZernike{i}), shading interp')\n", + "# MATLAB L9711: axis square;\n", + "_matlab('axis square;')\n", + "# MATLAB L9712: set(gca,'xtick',[],'ytick',[]);\n", + "_matlab(\"set(gca,'xtick',[],'ytick',[]);\")\n", + "# MATLAB L9713: set(gca, 'Box' , 'off');\n", + "_matlab(\"set(gca, 'Box' , 'off');\")\n", + "# MATLAB L9714: end\n", + "_matlab('end')\n", + "# MATLAB L9715: \n", + "#\n", + "# MATLAB L9716: \n", + "#\n", + "# MATLAB L9717: end\n", + "_matlab('end')\n", + "# MATLAB L9800: clear lambdaGaussian lambdaZernike;\n", + "pass\n", + "# MATLAB L9801: load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\n", + "_matlab(\"load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));\")\n", + "# MATLAB L9802: resData = load(fullfile(dataDir,'PlaceCellAnimal1Results.mat'));\n", + "_matlab(\"resData = load(fullfile(dataDir,'PlaceCellAnimal1Results.mat'));\")\n", + "# MATLAB L9803: results = FitResult.fromStructure(resData.resStruct);\n", + "_matlab('results = FitResult.fromStructure(resData.resStruct);')\n", + "# MATLAB L9804: \n", + "#\n", + "# MATLAB L9805: for i=1:length(neuron)\n", + "_matlab('for i=1:length(neuron)')\n", + "# MATLAB L9806: % Evaluate our fits using the new data and the estimated parameters\n", + "# Evaluate our fits using the new data and the estimated parameters\n", + "# MATLAB L9807: lambdaGaussian{i} = results{i}.evalLambda(1,newData);\n", + "_matlab('lambdaGaussian{i} = results{i}.evalLambda(1,newData);')\n", + "# MATLAB L9808: lambdaZernike{i} = results{i}.evalLambda(2,zpoly);\n", + "_matlab('lambdaZernike{i} = results{i}.evalLambda(2,zpoly);')\n", + "# MATLAB L9809: end\n", + "_matlab('end')\n", + "# MATLAB L9810: \n", + "#\n", + "# MATLAB L9811: \n", + "#\n", + "# MATLAB L9812: \n", + "#\n", + "# MATLAB L9813: % h1=plot(x,y,'b');\n", + "# h1=plot(x,y,'b');\n", + "# MATLAB L9814: % h2=plot(x,y,'g');\n", + "# h2=plot(x,y,'g');\n", + "# MATLAB L9815: %\n", + "#\n", + "# MATLAB L9816: exampleCell = 25;\n", + "exampleCell = 25\n", + "# MATLAB L9817: % figure(8);\n", + "# figure(8);\n", + "# MATLAB L9818: % plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", + "# plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", + "# MATLAB L9819: % xlabel('x'); ylabel('y');\n", + "# xlabel('x'); ylabel('y');\n", + "# MATLAB L9820: % title(['Animal#1, Cell#' num2str(exampleCell)]);\n", + "# title(['Animal#1, Cell#' num2str(exampleCell)]);\n", + "# MATLAB L9821: %\n", + "#\n", + "# MATLAB L9822: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L9823: h9=figure(9);\n", + "__tracker.new_figure('h9=figure(9)')\n", + "_matlab('h9=figure(9);')\n", + "# MATLAB L9824: h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\n", + "_matlab(\"h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);\")\n", + "# MATLAB L9825: get(h_mesh,'AlphaData');\n", + "_matlab(\"get(h_mesh,'AlphaData');\")\n", + "# MATLAB L9826: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\n", + "_matlab(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b');\")\n", + "# MATLAB L9827: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L9828: h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\n", + "_matlab(\"h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);\")\n", + "# MATLAB L9829: get(h_mesh,'AlphaData');\n", + "_matlab(\"get(h_mesh,'AlphaData');\")\n", + "# MATLAB L9830: set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\n", + "_matlab(\"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g');\")\n", + "# MATLAB L9831: \n", + "#\n", + "# MATLAB L9832: \n", + "#\n", + "# MATLAB L9833: % h_legend=legend('\\lambda_{Gaussian}','\\lambda_{Zernike}');\n", + "# h_legend=legend('\\lambda_{Gaussian}','\\lambda_{Zernike}');\n", + "# MATLAB L9834: % set(h_legend,'FontSize',20);\n", + "# set(h_legend,'FontSize',20);\n", + "# MATLAB L9835: plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\n", + "__tracker.annotate(\"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')\")\n", + "_matlab(\"plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');\")\n", + "# MATLAB L9836: axis tight square;\n", + "ax = plt.gca()\n", + "ax.relim()\n", + "ax.autoscale_view(tight=True)\n", + "ax.set_aspect('equal', adjustable='box')\n", + "ax.tick_params(top=True, right=True, direction='in')\n", + "# MATLAB L9837: xlabel('x position'); ylabel('y position');\n", + "plt.xlabel('x position')\n", + "plt.ylabel('y position')\n", + "# MATLAB L9838: title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...\n", + "_matlab(\"title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...\")\n", + "# MATLAB L9839: 'Fontsize',12,'FontName','Arial');\n", + "_matlab(\"'Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L9840: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", + "_matlab(\"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\")\n", + "# MATLAB L9841: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13eada6c", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 24: Example 5 - STIMULUS DECODING\n", + "# MATLAB L10100: % In this example we show how to decode a univariate and a bivariate stimulus based on a point process observations using nSTAT. Even though due to the simulated nature of the data, we know the exact condition intensity function, we estimate the parameters before moving on to the decoding stage.\n", + "# In this example we show how to decode a univariate and a bivariate stimulus based on a point process observations using nSTAT. Even though due to the simulated nature of the data, we know the exact condition intensity function, we estimate the parameters before moving on to the decoding stage.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c8d3823", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 25: Generate the conditional Intensity Function\n", + "# MATLAB L10300: close all; clear all;\n", + "plt.close(\"all\")\n", + "# MATLAB L10301: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", + "_matlab('[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...')\n", + "# MATLAB L10302: getPaperDataDirs();\n", + "_matlab('getPaperDataDirs();')\n", + "# MATLAB L10303: delta = 0.001; Tmax = 1;\n", + "_matlab('delta = 0.001; Tmax = 1;')\n", + "# MATLAB L10304: time = 0:delta:Tmax;\n", + "_matlab('time = 0:delta:Tmax;')\n", + "# MATLAB L10305: numRealizations = 20;\n", + "numRealizations = 20\n", + "# MATLAB L10306: f=2; b1=randn(numRealizations,1);b0=log(10*delta)+randn(numRealizations,1);\n", + "_matlab('f=2; b1=randn(numRealizations,1);b0=log(10*delta)+randn(numRealizations,1);')\n", + "# MATLAB L10307: x = sin(2*pi*f*time);\n", + "_matlab('x = sin(2*pi*f*time);')\n", + "# MATLAB L10308: clear nst;\n", + "pass\n", + "# MATLAB L10309: for i=1:numRealizations\n", + "_matlab('for i=1:numRealizations')\n", + "# MATLAB L10310: expData = exp(b1(i)*x+b0(i));\n", + "_matlab('expData = exp(b1(i)*x+b0(i));')\n", + "# MATLAB L10311: lambdaData = expData./(1+expData);\n", + "_matlab('lambdaData = expData./(1+expData);')\n", + "# MATLAB L10312: \n", + "#\n", + "# MATLAB L10313: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L10314: lambda = Covariate(time,lambdaData./delta, ...\n", + "_matlab('lambda = Covariate(time,lambdaData./delta, ...')\n", + "# MATLAB L10315: '\\Lambda(t)','time','s','spikes/sec',{'\\lambda_{1}'},...\n", + "_matlab(\"'\\\\Lambda(t)','time','s','spikes/sec',{'\\\\lambda_{1}'},...\")\n", + "# MATLAB L10316: {{' ''b'', ''LineWidth'' ,2'}});\n", + "_matlab(\"{{' ''b'', ''LineWidth'' ,2'}});\")\n", + "# MATLAB L10317: else\n", + "_matlab('else')\n", + "# MATLAB L10318: tempLambda = Covariate(time,lambdaData./delta, ...\n", + "_matlab('tempLambda = Covariate(time,lambdaData./delta, ...')\n", + "# MATLAB L10319: '\\Lambda(t)','time','s','spikes/sec',{'\\lambda_{1}'},...\n", + "_matlab(\"'\\\\Lambda(t)','time','s','spikes/sec',{'\\\\lambda_{1}'},...\")\n", + "# MATLAB L10320: {{' ''b'', ''LineWidth'' ,2'}});\n", + "_matlab(\"{{' ''b'', ''LineWidth'' ,2'}});\")\n", + "# MATLAB L10321: lambda = lambda.merge(tempLambda);\n", + "_matlab('lambda = lambda.merge(tempLambda);')\n", + "# MATLAB L10322: end\n", + "_matlab('end')\n", + "# MATLAB L10323: \n", + "#\n", + "# MATLAB L10324: spikeColl = CIF.simulateCIFByThinningFromLambda(...\n", + "_matlab('spikeColl = CIF.simulateCIFByThinningFromLambda(...')\n", + "# MATLAB L10325: lambda.getSubSignal(i),1);\n", + "_matlab('lambda.getSubSignal(i),1);')\n", + "# MATLAB L10326: nst{i} = spikeColl.getNST(1);\n", + "_matlab('nst{i} = spikeColl.getNST(1);')\n", + "# MATLAB L10327: end\n", + "_matlab('end')\n", + "# MATLAB L10328: spikeColl = nstColl(nst);scrsz = get(0,'ScreenSize');\n", + "_matlab(\"spikeColl = nstColl(nst);scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L10329: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...\n", + "__tracker.new_figure(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", + "_matlab(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", + "# MATLAB L10330: scrsz(3)*.6 scrsz(4)*.8]);\n", + "_matlab('scrsz(3)*.6 scrsz(4)*.8]);')\n", + "# MATLAB L10331: % figure;\n", + "# figure;\n", + "# MATLAB L10332: subplot(3,1,1); plot(time,x,'k');\n", + "__tracker.annotate('subplot(3,1,1)')\n", + "__tracker.annotate(\"plot(time,x,'k')\")\n", + "_matlab(\"subplot(3,1,1); plot(time,x,'k');\")\n", + "# MATLAB L10333: set(gca,'xtick',[],'xtickLabel',[]); ylabel('Stimulus');\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]); ylabel('Stimulus');\")\n", + "# MATLAB L10334: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", + "_matlab(\"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\")\n", + "# MATLAB L10335: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L10336: title('Driving Stimulus','FontWeight','bold',...\n", + "_matlab(\"title('Driving Stimulus','FontWeight','bold',...\")\n", + "# MATLAB L10337: 'FontSize',14,'FontName','Arial');\n", + "_matlab(\"'FontSize',14,'FontName','Arial');\")\n", + "# MATLAB L10338: subplot(3,1,2); lambda.plot([],{{' ''k'',''Linewidth'',1'}});\n", + "__tracker.annotate('subplot(3,1,2)')\n", + "__tracker.annotate(\"lambda.plot([],{{' ''k'',''Linewidth'',1'}})\")\n", + "_matlab(\"subplot(3,1,2); lambda.plot([],{{' ''k'',''Linewidth'',1'}});\")\n", + "# MATLAB L10339: legend off;\n", + "_matlab('legend off;')\n", + "# MATLAB L10340: hy=ylabel('Firing Rate [spikes/sec]', 'Interpreter','none');\n", + "_matlab(\"hy=ylabel('Firing Rate [spikes/sec]', 'Interpreter','none');\")\n", + "# MATLAB L10341: hx=xlabel('','Interpreter','none');\n", + "_matlab(\"hx=xlabel('','Interpreter','none');\")\n", + "# MATLAB L10342: set([hx, hy],'FontName', 'Arial','FontSize',12,...\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,...\")\n", + "# MATLAB L10343: 'FontWeight','bold');\n", + "_matlab(\"'FontWeight','bold');\")\n", + "# MATLAB L10344: set(gca,'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtickLabel',[]);\")\n", + "# MATLAB L10345: title('Conditional Intensity Functions','FontWeight',...\n", + "_matlab(\"title('Conditional Intensity Functions','FontWeight',...\")\n", + "# MATLAB L10346: 'bold','FontSize',14,'FontName','Arial');\n", + "_matlab(\"'bold','FontSize',14,'FontName','Arial');\")\n", + "# MATLAB L10347: \n", + "#\n", + "# MATLAB L10348: subplot(3,1,3); spikeColl.plot;\n", + "__tracker.annotate('subplot(3,1,3)')\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('subplot(3,1,3); spikeColl.plot;')\n", + "# MATLAB L10349: set(gca,'ytick',0:10:numRealizations,'ytickLabel',...\n", + "_matlab(\"set(gca,'ytick',0:10:numRealizations,'ytickLabel',...\")\n", + "# MATLAB L10350: 0:10:numRealizations);\n", + "_matlab('0:10:numRealizations);')\n", + "# MATLAB L10351: xlabel('time [s]','Interpreter','none');\n", + "_matlab(\"xlabel('time [s]','Interpreter','none');\")\n", + "# MATLAB L10352: ylabel('Cell Number','Interpreter','none');\n", + "_matlab(\"ylabel('Cell Number','Interpreter','none');\")\n", + "# MATLAB L10353: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", + "_matlab(\"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\")\n", + "# MATLAB L10354: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L10355: title('Point Process Sample Paths','FontWeight',...\n", + "_matlab(\"title('Point Process Sample Paths','FontWeight',...\")\n", + "# MATLAB L10356: 'bold','FontSize',14,'FontName','Arial');\n", + "_matlab(\"'bold','FontSize',14,'FontName','Arial');\")\n", + "# MATLAB L10357: \n", + "#\n", + "# MATLAB L10358: stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\n", + "_matlab(\"stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});\")\n", + "# MATLAB L10359: baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\n", + "_matlab(\"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\")\n", + "# MATLAB L10360: {'constant'});\n", + "_matlab(\"{'constant'});\")\n", + "# MATLAB L10361: \n", + "#\n", + "# MATLAB L10362: % close all;\n", + "# close all;\n", + "# MATLAB L10500: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L10501: \n", + "#\n", + "# MATLAB L10502: clear lambdaCIF;\n", + "pass\n", + "# MATLAB L10503: spikeColl.resample(1/delta);\n", + "_matlab('spikeColl.resample(1/delta);')\n", + "# MATLAB L10504: dN=spikeColl.dataToMatrix;\n", + "_matlab('dN=spikeColl.dataToMatrix;')\n", + "# MATLAB L10505: \n", + "#\n", + "# MATLAB L10506: % Make noise according to the dynamic range of the stimulus\n", + "# Make noise according to the dynamic range of the stimulus\n", + "# MATLAB L10507: Q=std(stim.data(2:end)-stim.data(1:end-1));\n", + "_matlab('Q=std(stim.data(2:end)-stim.data(1:end-1));')\n", + "# MATLAB L10508: Px0=.1; A=1;\n", + "_matlab('Px0=.1; A=1;')\n", + "# MATLAB L10509: x0 = x(:,1); yT=x(:,end);\n", + "_matlab('x0 = x(:,1); yT=x(:,end);')\n", + "# MATLAB L10510: Pi0 = eps*eye(size(x0,1),size(x0,1));\n", + "_matlab('Pi0 = eps*eye(size(x0,1),size(x0,1));')\n", + "# MATLAB L10511: PiT = eps*eye(size(x0,1),size(x0,1));\n", + "_matlab('PiT = eps*eye(size(x0,1),size(x0,1));')\n", + "# MATLAB L10512: \n", + "#\n", + "# MATLAB L10513: \n", + "#\n", + "# MATLAB L10514: [x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, ...\n", + "_matlab('[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, ...')\n", + "# MATLAB L10515: Q, dN',b0,b1','binomial',delta);\n", + "_matlab(\"Q, dN',b0,b1','binomial',delta);\")\n", + "# MATLAB L10516: %\n", + "#\n", + "# MATLAB L10517: h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]);\n", + "__tracker.new_figure(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6])\")\n", + "_matlab(\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]);\")\n", + "# MATLAB L10518: zVal=1.96;\n", + "zVal = 1.96\n", + "# MATLAB L10519: ciLower = min(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\n", + "_matlab(\"ciLower = min(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\")\n", + "# MATLAB L10520: x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\n", + "_matlab(\"x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\")\n", + "# MATLAB L10521: ciUpper = max(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\n", + "_matlab(\"ciUpper = max(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',...\")\n", + "# MATLAB L10522: x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\n", + "_matlab(\"x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))'));\")\n", + "# MATLAB L10523: \n", + "#\n", + "# MATLAB L10524: estimatedStimulus = Covariate(time,x_u(1:end),'\\hat{x}(t)','time','s','');\n", + "_matlab(\"estimatedStimulus = Covariate(time,x_u(1:end),'\\\\hat{x}(t)','time','s','');\")\n", + "# MATLAB L10525: CI= ConfidenceInterval(time,[ciLower', ciUpper'],'\\hat{x}(t)','time','s','');\n", + "_matlab(\"CI= ConfidenceInterval(time,[ciLower', ciUpper'],'\\\\hat{x}(t)','time','s','');\")\n", + "# MATLAB L10526: estimatedStimulus.setConfInterval(CI);\n", + "_matlab('estimatedStimulus.setConfInterval(CI);')\n", + "# MATLAB L10527: \n", + "#\n", + "# MATLAB L10528: % hold all;\n", + "# hold all;\n", + "# MATLAB L10529: % hEst=plot(time,x_u(1:end),'b','Linewidth',2); hold on;\n", + "# hEst=plot(time,x_u(1:end),'b','Linewidth',2); hold on;\n", + "# MATLAB L10530: % plot(time, [ciUpper', ciLower'],'b');\n", + "# plot(time, [ciUpper', ciLower'],'b');\n", + "# MATLAB L10531: \n", + "#\n", + "# MATLAB L10532: hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}})\")\n", + "_matlab(\"hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}});\")\n", + "# MATLAB L10533: hStim=stim.plot([],{{' ''b'',''Linewidth'',4'}});\n", + "__tracker.annotate(\"hStim=stim.plot([],{{' ''b'',''Linewidth'',4'}})\")\n", + "_matlab(\"hStim=stim.plot([],{{' ''b'',''Linewidth'',4'}});\")\n", + "# MATLAB L10534: legend off;\n", + "_matlab('legend off;')\n", + "# MATLAB L10535: h_legend=legend([hEst(1) hStim],'Decoded','Actual');\n", + "_matlab(\"h_legend=legend([hEst(1) hStim],'Decoded','Actual');\")\n", + "# MATLAB L10536: set(h_legend,'Interpreter','none');\n", + "_matlab(\"set(h_legend,'Interpreter','none');\")\n", + "# MATLAB L10537: set(h_legend,'FontSize',22);\n", + "_matlab(\"set(h_legend,'FontSize',22);\")\n", + "# MATLAB L10538: title(['Decoded Stimulus +/- 95% CIs with ' num2str(numRealizations) ' cells'],...\n", + "_matlab(\"title(['Decoded Stimulus +/- 95% CIs with ' num2str(numRealizations) ' cells'],...\")\n", + "# MATLAB L10539: 'FontWeight','bold','Fontsize',22,'FontName','Arial');\n", + "_matlab(\"'FontWeight','bold','Fontsize',22,'FontName','Arial');\")\n", + "# MATLAB L10540: xlabel('time [s]','Interpreter','none');\n", + "_matlab(\"xlabel('time [s]','Interpreter','none');\")\n", + "# MATLAB L10541: ylabel('Stimulus','Interpreter','none');\n", + "_matlab(\"ylabel('Stimulus','Interpreter','none');\")\n", + "# MATLAB L10542: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", + "_matlab(\"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\")\n", + "# MATLAB L10543: set([hx, hy],'FontName', 'Arial','FontSize',22,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',22,'FontWeight','bold');\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0272ba98", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 26: Example 5b - Arm reaching to target Simulation\n", + "# MATLAB L10800: % See L. Srinivasan, U. T. Eden, A. S. Willsky, and E. N. Brown, \"A state-space analysis for reconstruction of goal-directed movements using neural signals.,\" Neural computation, vol. 18, no. 10, pp. 2465?2494, Oct. 2006.\n", + "# See L. Srinivasan, U. T. Eden, A. S. Willsky, and E. N. Brown, \"A state-space analysis for reconstruction of goal-directed movements using neural signals.,\" Neural computation, vol. 18, no. 10, pp. 2465?2494, Oct. 2006.\n", + "# MATLAB L10900: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L10901: clear all;\n", + "pass\n", + "# MATLAB L10902: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", + "_matlab('[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...')\n", + "# MATLAB L10903: getPaperDataDirs();\n", + "_matlab('getPaperDataDirs();')\n", + "# MATLAB L10904: %Process noise covariance only drives the movement velocity\n", + "# Process noise covariance only drives the movement velocity\n", + "# MATLAB L10905: q=1e-4;\n", + "q = 1e-4\n", + "# MATLAB L10906: Q=diag([1e-12 1e-12 q q]);\n", + "_matlab('Q=diag([1e-12 1e-12 q q]);')\n", + "# MATLAB L10907: \n", + "#\n", + "# MATLAB L10908: delta = .001; % Time increment\n", + "delta = .001\n", + "# MATLAB L10909: r=1e-6; % in meters^2\n", + "r = 1e-6\n", + "# MATLAB L10910: p=1e-6; % in meters^2/s^2\n", + "p = 1e-6\n", + "# MATLAB L10911: PiT=diag([r r p p]); % Uncertainty in the target state\n", + "_matlab('PiT=diag([r r p p]); % Uncertainty in the target state')\n", + "# MATLAB L10912: Pi0=PiT;\n", + "_matlab('Pi0=PiT;')\n", + "# MATLAB L10913: T=2; % Reach Duration\n", + "T = 2\n", + "# MATLAB L10914: \n", + "#\n", + "# MATLAB L10915: x0 = [0;0;0;0]; % Initial Position and velocities (states)\n", + "_matlab('x0 = [0;0;0;0]; % Initial Position and velocities (states)')\n", + "# MATLAB L10916: xT = [-.35;.2; 0;0];% Final Target\n", + "_matlab('xT = [-.35;.2; 0;0];% Final Target')\n", + "# MATLAB L10917: time=0:delta:T; % time vector\n", + "_matlab('time=0:delta:T; % time vector')\n", + "# MATLAB L10918: \n", + "#\n", + "# MATLAB L10919: A=[1 0 delta 0 ; %State transition matrix\n", + "_matlab('A=[1 0 delta 0 ; %State transition matrix')\n", + "# MATLAB L10920: 0 1 0 delta;\n", + "_matlab('0 1 0 delta;')\n", + "# MATLAB L10921: 0 0 1 0 ;\n", + "_matlab('0 0 1 0 ;')\n", + "# MATLAB L10922: 0 0 0 1 ];\n", + "_matlab('0 0 0 1 ];')\n", + "# MATLAB L10923: \n", + "#\n", + "# MATLAB L10924: x=zeros(4,length(time));\n", + "_matlab('x=zeros(4,length(time));')\n", + "# MATLAB L10925: \n", + "#\n", + "# MATLAB L10926: \n", + "#\n", + "# MATLAB L10927: % Simulate a reach trajectory\n", + "# Simulate a reach trajectory\n", + "# MATLAB L10928: % Differs from reference by multiplication by delta instead of division so\n", + "# Differs from reference by multiplication by delta instead of division so\n", + "# MATLAB L10929: % that the velocity has units of meters per second\n", + "# that the velocity has units of meters per second\n", + "# MATLAB L10930: R=chol(Q);\n", + "_matlab('R=chol(Q);')\n", + "# MATLAB L10931: L=chol(PiT);\n", + "_matlab('L=chol(PiT);')\n", + "# MATLAB L10932: for k=1:length(time)\n", + "_matlab('for k=1:length(time)')\n", + "# MATLAB L10933: if(k==1)\n", + "_matlab('if(k==1)')\n", + "# MATLAB L10934: x(:,k)=x0;\n", + "_matlab('x(:,k)=x0;')\n", + "# MATLAB L10935: else\n", + "_matlab('else')\n", + "# MATLAB L10936: x(:,k)=A*x(:,k-1)+...\n", + "_matlab('x(:,k)=A*x(:,k-1)+...')\n", + "# MATLAB L10937: delta/(2)*(pi/T)^2*cos(pi*time(k)/T)*[0;0;...\n", + "_matlab('delta/(2)*(pi/T)^2*cos(pi*time(k)/T)*[0;0;...')\n", + "# MATLAB L10938: xT(1)-x0(1);xT(2)-x0(2)]; %Reach to target model\n", + "_matlab('xT(1)-x0(1);xT(2)-x0(2)]; %Reach to target model')\n", + "# MATLAB L10939: %x(:,k)=A*x(:,k-1)+R*randn(size(x,1),1); %Random walk model\n", + "# x(:,k)=A*x(:,k-1)+R*randn(size(x,1),1); %Random walk model\n", + "# MATLAB L10940: end\n", + "_matlab('end')\n", + "# MATLAB L10941: \n", + "#\n", + "# MATLAB L10942: end\n", + "_matlab('end')\n", + "# MATLAB L10943: xT =x(:,end); % The target generated by the model\n", + "_matlab('xT =x(:,end); % The target generated by the model')\n", + "# MATLAB L10944: yT=xT; % Assume we have observed the actual target position with uncertainty PiT\n", + "_matlab('yT=xT; % Assume we have observed the actual target position with uncertainty PiT')\n", + "# MATLAB L10945: \n", + "#\n", + "# MATLAB L10946: %Define Q according to the dynamic range of the movement above\n", + "# Define Q according to the dynamic range of the movement above\n", + "# MATLAB L10947: Q=diag(var(diff(x,[],2),[],2))*100;\n", + "_matlab('Q=diag(var(diff(x,[],2),[],2))*100;')\n", + "# MATLAB L10948: \n", + "#\n", + "# MATLAB L10949: % Plot the movement trajectories and the hand path\n", + "# Plot the movement trajectories and the hand path\n", + "# MATLAB L10950: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L10951: fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\n", + "__tracker.new_figure(\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", + "_matlab(\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", + "# MATLAB L10952: scrsz(3)*.8 scrsz(4)*.8]);\n", + "_matlab('scrsz(3)*.8 scrsz(4)*.8]);')\n", + "# MATLAB L10953: %Plot The movement path\n", + "# Plot The movement path\n", + "# MATLAB L10954: subplot(4,2,[1 3]);\n", + "__tracker.annotate('subplot(4,2,[1 3])')\n", + "_matlab('subplot(4,2,[1 3]);')\n", + "# MATLAB L10955: plot(100*x(1,:),100*x(2,:),'k','Linewidth',2);\n", + "__tracker.annotate(\"plot(100*x(1,:),100*x(2,:),'k','Linewidth',2)\")\n", + "_matlab(\"plot(100*x(1,:),100*x(2,:),'k','Linewidth',2);\")\n", + "# MATLAB L10956: xlabel('X Position [cm]'); ylabel('Y Position [cm]');\n", + "plt.xlabel('X Position [cm]')\n", + "plt.ylabel('Y Position [cm]')\n", + "# MATLAB L10957: hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\n", + "_matlab(\"hx=get(gca,'XLabel'); hy=get(gca,'YLabel');\")\n", + "# MATLAB L10958: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L10959: title('Reach Path','FontWeight','bold','Fontsize',14,'FontName','Arial');\n", + "_matlab(\"title('Reach Path','FontWeight','bold','Fontsize',14,'FontName','Arial');\")\n", + "# MATLAB L10960: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L10961: axis([sort([100*x0(1)+5, 100*xT(1)-5]), sort([100*x0(2)-5, 100*xT(2)+5])]);\n", + "_matlab('axis([sort([100*x0(1)+5, 100*xT(1)-5]), sort([100*x0(2)-5, 100*xT(2)+5])]);')\n", + "# MATLAB L10962: h1=plot(100*x(1,1),100*x(2,1),'bo','MarkerSize',14);\n", + "__tracker.annotate(\"h1=plot(100*x(1,1),100*x(2,1),'bo','MarkerSize',14)\")\n", + "_matlab(\"h1=plot(100*x(1,1),100*x(2,1),'bo','MarkerSize',14);\")\n", + "# MATLAB L10963: h2=plot(100*x(1,end),100*x(2,end),'ro','MarkerSize',14);\n", + "__tracker.annotate(\"h2=plot(100*x(1,end),100*x(2,end),'ro','MarkerSize',14)\")\n", + "_matlab(\"h2=plot(100*x(1,end),100*x(2,end),'ro','MarkerSize',14);\")\n", + "# MATLAB L10964: legend([h1 h2],'Start','Finish','Location','NorthEast');\n", + "_matlab(\"legend([h1 h2],'Start','Finish','Location','NorthEast');\")\n", + "# MATLAB L10965: \n", + "#\n", + "# MATLAB L10966: \n", + "#\n", + "# MATLAB L10967: subplot(4,2,5); h1=plot(time,100*x(1,:),'k','Linewidth',2); hold on;\n", + "__tracker.annotate('subplot(4,2,5)')\n", + "__tracker.annotate(\"h1=plot(time,100*x(1,:),'k','Linewidth',2)\")\n", + "_matlab(\"subplot(4,2,5); h1=plot(time,100*x(1,:),'k','Linewidth',2); hold on;\")\n", + "# MATLAB L10968: h2=plot(time,100*x(2,:),'k-.','Linewidth',2);\n", + "__tracker.annotate(\"h2=plot(time,100*x(2,:),'k-.','Linewidth',2)\")\n", + "_matlab(\"h2=plot(time,100*x(2,:),'k-.','Linewidth',2);\")\n", + "# MATLAB L10969: h_legend=legend([h1,h2],'x','y','Location','NorthEast');\n", + "_matlab(\"h_legend=legend([h1,h2],'x','y','Location','NorthEast');\")\n", + "# MATLAB L10970: set(h_legend,'FontSize',14)\n", + "_matlab(\"set(h_legend,'FontSize',14)\")\n", + "# MATLAB L10971: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L10972: set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\")\n", + "# MATLAB L10973: hx=xlabel('time [s]'); hy=ylabel('Position [cm]');\n", + "_matlab(\"hx=xlabel('time [s]'); hy=ylabel('Position [cm]');\")\n", + "# MATLAB L10974: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L10975: % Plot the velocity profiles\n", + "# Plot the velocity profiles\n", + "# MATLAB L10976: \n", + "#\n", + "# MATLAB L10977: subplot(4,2,7);\n", + "__tracker.annotate('subplot(4,2,7)')\n", + "_matlab('subplot(4,2,7);')\n", + "# MATLAB L10978: h1=plot(time,100*x(3,:),'k','Linewidth',2); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*x(3,:),'k','Linewidth',2)\")\n", + "_matlab(\"h1=plot(time,100*x(3,:),'k','Linewidth',2); hold on;\")\n", + "# MATLAB L10979: h2=plot(time,100*x(4,:),'k-.','Linewidth',2);\n", + "__tracker.annotate(\"h2=plot(time,100*x(4,:),'k-.','Linewidth',2)\")\n", + "_matlab(\"h2=plot(time,100*x(4,:),'k-.','Linewidth',2);\")\n", + "# MATLAB L10980: h_legend=legend([h1 h2],'v_x','v_y','Location','NorthEast');\n", + "_matlab(\"h_legend=legend([h1 h2],'v_x','v_y','Location','NorthEast');\")\n", + "# MATLAB L10981: xlabel('time [s]');\n", + "_matlab(\"xlabel('time [s]');\")\n", + "# MATLAB L10982: set(h_legend,'FontSize',14);\n", + "_matlab(\"set(h_legend,'FontSize',14);\")\n", + "# MATLAB L10983: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L10984: set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]);\")\n", + "# MATLAB L10985: hx=xlabel('time [s]'); hy=ylabel('Velocity [cm/s]');\n", + "_matlab(\"hx=xlabel('time [s]'); hy=ylabel('Velocity [cm/s]');\")\n", + "# MATLAB L10986: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L10987: %\n", + "#\n", + "# MATLAB L10988: \n", + "#\n", + "# MATLAB L10989: gamma=0;\n", + "gamma = 0\n", + "# MATLAB L10990: windowTimes=[0, 0.001];\n", + "_matlab('windowTimes=[0, 0.001];')\n", + "# MATLAB L10991: \n", + "#\n", + "# MATLAB L10992: \n", + "#\n", + "# MATLAB L10993: % Simulate neural responses\n", + "# Simulate neural responses\n", + "# MATLAB L10994: % logit(lambda_i*delta) = mu_i + b_x_i*v_x + b_y_i*v_y\n", + "# logit(lambda_i*delta) = mu_i + b_x_i*v_x + b_y_i*v_y\n", + "# MATLAB L10995: % logit(lambda_i*delta) = X_i*beta_i;\n", + "# logit(lambda_i*delta) = X_i*beta_i;\n", + "# MATLAB L10996: numCells = 20;\n", + "numCells = 20\n", + "# MATLAB L10997: bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);\n", + "_matlab('bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);')\n", + "# MATLAB L10998: phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell\n", + "_matlab('phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell')\n", + "# MATLAB L10999: phiMaxNorm = (phiMax+pi)./(2*pi);\n", + "_matlab('phiMaxNorm = (phiMax+pi)./(2*pi);')\n", + "# MATLAB L11000: meanMu = log(10*delta); % baseline firing rate -10Hz\n", + "_matlab('meanMu = log(10*delta); % baseline firing rate -10Hz')\n", + "# MATLAB L11001: MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)\n", + "_matlab('MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)')\n", + "# MATLAB L11002: \n", + "#\n", + "# MATLAB L11003: dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\n", + "_matlab(\"dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\")\n", + "# MATLAB L11004: coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta\n", + "_matlab('coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta')\n", + "# MATLAB L11005: fitType='binomial';\n", + "_matlab(\"fitType='binomial';\")\n", + "# MATLAB L11006: clear nst;\n", + "pass\n", + "# MATLAB L11007: for i=1:numCells\n", + "_matlab('for i=1:numCells')\n", + "# MATLAB L11008: tempData = exp(dataMat*coeffs(i,:)');\n", + "_matlab(\"tempData = exp(dataMat*coeffs(i,:)');\")\n", + "# MATLAB L11009: \n", + "#\n", + "# MATLAB L11010: if(strcmp(fitType,'poisson'))\n", + "_matlab(\"if(strcmp(fitType,'poisson'))\")\n", + "# MATLAB L11011: lambdaData = tempData;\n", + "_matlab('lambdaData = tempData;')\n", + "# MATLAB L11012: else\n", + "_matlab('else')\n", + "# MATLAB L11013: lambdaData = tempData./(1+tempData); % Conditional Intensity Function for ith cell\n", + "_matlab('lambdaData = tempData./(1+tempData); % Conditional Intensity Function for ith cell')\n", + "# MATLAB L11014: end\n", + "_matlab('end')\n", + "# MATLAB L11015: lambda{i}=Covariate(time,lambdaData./delta, ...\n", + "_matlab('lambda{i}=Covariate(time,lambdaData./delta, ...')\n", + "# MATLAB L11016: '\\Lambda(t)','time','s','spikes/sec',...\n", + "_matlab(\"'\\\\Lambda(t)','time','s','spikes/sec',...\")\n", + "# MATLAB L11017: {strcat('\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\n", + "_matlab(\"{strcat('\\\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\")\n", + "# MATLAB L11018: lambda{i}=lambda{i}.resample(1/delta);\n", + "_matlab('lambda{i}=lambda{i}.resample(1/delta);')\n", + "# MATLAB L11019: \n", + "#\n", + "# MATLAB L11020: % Generate CIF representation in case we want to use the symbolic\n", + "# Generate CIF representation in case we want to use the symbolic\n", + "# MATLAB L11021: % versions of the PPDecodeFilter (i.e. not PPDecodeFilterLinear\n", + "# versions of the PPDecodeFilter (i.e. not PPDecodeFilterLinear\n", + "# MATLAB L11022: lambdaCIF{i} = CIF([MuCoeffs(i) 0 0 bCoeffs(i,:)],...\n", + "_matlab('lambdaCIF{i} = CIF([MuCoeffs(i) 0 0 bCoeffs(i,:)],...')\n", + "# MATLAB L11023: {'1','x','y','vx','vy'},{'x','y','vx','vy'},fitType);\n", + "_matlab(\"{'1','x','y','vx','vy'},{'x','y','vx','vy'},fitType);\")\n", + "# MATLAB L11024: % generate one realization for each cell\n", + "# generate one realization for each cell\n", + "# MATLAB L11025: tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1); nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization\n", + "_matlab('tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1); nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization')\n", + "# MATLAB L11026: nst{i}.setName(num2str(i)); % give each cell a unique name\n", + "_matlab('nst{i}.setName(num2str(i)); % give each cell a unique name')\n", + "# MATLAB L11027: subplot(4,2,[6 8]);\n", + "__tracker.annotate('subplot(4,2,[6 8])')\n", + "_matlab('subplot(4,2,[6 8]);')\n", + "# MATLAB L11028: h2=lambda{i}.plot([],{{' ''k'', ''LineWidth'' ,.5'}});\n", + "__tracker.annotate(\"h2=lambda{i}.plot([],{{' ''k'', ''LineWidth'' ,.5'}})\")\n", + "_matlab(\"h2=lambda{i}.plot([],{{' ''k'', ''LineWidth'' ,.5'}});\")\n", + "# MATLAB L11029: legend off; hold all; % Plot the CIF\n", + "_matlab('legend off; hold all; % Plot the CIF')\n", + "# MATLAB L11030: \n", + "#\n", + "# MATLAB L11031: \n", + "#\n", + "# MATLAB L11032: \n", + "#\n", + "# MATLAB L11033: end\n", + "_matlab('end')\n", + "# MATLAB L11034: title('Neural Conditional Intensity Functions','FontWeight',...\n", + "_matlab(\"title('Neural Conditional Intensity Functions','FontWeight',...\")\n", + "# MATLAB L11035: 'bold','Fontsize',14,'FontName','Arial');\n", + "_matlab(\"'bold','Fontsize',14,'FontName','Arial');\")\n", + "# MATLAB L11036: hx=xlabel('time [s]','Interpreter','none');\n", + "_matlab(\"hx=xlabel('time [s]','Interpreter','none');\")\n", + "# MATLAB L11037: hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\n", + "_matlab(\"hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none');\")\n", + "# MATLAB L11038: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L11039: spikeColl = nstColl(nst); % Create a neural spike train collection\n", + "_matlab('spikeColl = nstColl(nst); % Create a neural spike train collection')\n", + "# MATLAB L11040: \n", + "#\n", + "# MATLAB L11041: subplot(4,2,[2,4]); spikeColl.plot;\n", + "__tracker.annotate('subplot(4,2,[2,4])')\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('subplot(4,2,[2,4]); spikeColl.plot;')\n", + "# MATLAB L11042: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L11043: title('Neural Raster','FontWeight','bold','Fontsize',14,...\n", + "_matlab(\"title('Neural Raster','FontWeight','bold','Fontsize',14,...\")\n", + "# MATLAB L11044: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L11045: hx=xlabel('time [s]','Interpreter','none');\n", + "_matlab(\"hx=xlabel('time [s]','Interpreter','none');\")\n", + "# MATLAB L11046: hy=ylabel('Cell Number','Interpreter','none');\n", + "_matlab(\"hy=ylabel('Cell Number','Interpreter','none');\")\n", + "# MATLAB L11047: set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold');\")\n", + "# MATLAB L11048: \n", + "#\n", + "# MATLAB L11049: % close all;\n", + "# close all;\n", + "# MATLAB L11100: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L11101: numExamples=20;\n", + "numExamples = 20\n", + "# MATLAB L11102: scrsz = get(0,'ScreenSize');\n", + "_matlab(\"scrsz = get(0,'ScreenSize');\")\n", + "# MATLAB L11103: fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\n", + "__tracker.new_figure(\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", + "_matlab(\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...\")\n", + "# MATLAB L11104: scrsz(3)*.6 scrsz(4)*.9]);\n", + "_matlab('scrsz(3)*.6 scrsz(4)*.9]);')\n", + "# MATLAB L11105: for k=1:numExamples\n", + "_matlab('for k=1:numExamples')\n", + "# MATLAB L11106: bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);\n", + "_matlab('bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5);')\n", + "# MATLAB L11107: phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell\n", + "_matlab('phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell')\n", + "# MATLAB L11108: phiMaxNorm = (phiMax+pi)./(2*pi);\n", + "_matlab('phiMaxNorm = (phiMax+pi)./(2*pi);')\n", + "# MATLAB L11109: meanMu = log(10*delta); % baseline firing rate\n", + "_matlab('meanMu = log(10*delta); % baseline firing rate')\n", + "# MATLAB L11110: MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)\n", + "_matlab('MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1)')\n", + "# MATLAB L11111: \n", + "#\n", + "# MATLAB L11112: dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\n", + "_matlab(\"dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (\")\n", + "# MATLAB L11113: coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta\n", + "_matlab('coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta')\n", + "# MATLAB L11114: fitType='binomial';\n", + "_matlab(\"fitType='binomial';\")\n", + "# MATLAB L11115: clear nst lambda;\n", + "pass\n", + "# MATLAB L11116: \n", + "#\n", + "# MATLAB L11117: \n", + "#\n", + "# MATLAB L11118: for i=1:numCells\n", + "_matlab('for i=1:numCells')\n", + "# MATLAB L11119: tempData = exp(dataMat*coeffs(i,:)');\n", + "_matlab(\"tempData = exp(dataMat*coeffs(i,:)');\")\n", + "# MATLAB L11120: if(strcmp(fitType,'poisson'))\n", + "_matlab(\"if(strcmp(fitType,'poisson'))\")\n", + "# MATLAB L11121: lambdaData = tempData;\n", + "_matlab('lambdaData = tempData;')\n", + "# MATLAB L11122: else\n", + "_matlab('else')\n", + "# MATLAB L11123: % Conditional Intensity Function for ith cell\n", + "# Conditional Intensity Function for ith cell\n", + "# MATLAB L11124: lambdaData = tempData./(1+tempData);\n", + "_matlab('lambdaData = tempData./(1+tempData);')\n", + "# MATLAB L11125: end\n", + "_matlab('end')\n", + "# MATLAB L11126: lambda{i}=Covariate(time,lambdaData./delta, ...\n", + "_matlab('lambda{i}=Covariate(time,lambdaData./delta, ...')\n", + "# MATLAB L11127: '\\Lambda(t)','time','s','spikes/sec',...\n", + "_matlab(\"'\\\\Lambda(t)','time','s','spikes/sec',...\")\n", + "# MATLAB L11128: {strcat('\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\n", + "_matlab(\"{strcat('\\\\lambda_{',num2str(i),'}')},{{' ''b'' '}});\")\n", + "# MATLAB L11129: lambda{i}=lambda{i}.resample(1/delta);\n", + "_matlab('lambda{i}=lambda{i}.resample(1/delta);')\n", + "# MATLAB L11130: \n", + "#\n", + "# MATLAB L11131: % Generate CIF representation in case we want to use the symbolic\n", + "# Generate CIF representation in case we want to use the symbolic\n", + "# MATLAB L11132: % versions of the PPDecodeFilter (i.e. not PPDecodeFilterLinear\n", + "# versions of the PPDecodeFilter (i.e. not PPDecodeFilterLinear\n", + "# MATLAB L11133: % generate one realization for each cell\n", + "# generate one realization for each cell\n", + "# MATLAB L11134: tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);\n", + "_matlab('tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);')\n", + "# MATLAB L11135: nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization\n", + "_matlab('nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization')\n", + "# MATLAB L11136: nst{i}.setName(num2str(i)); % give each cell a unique name\n", + "_matlab('nst{i}.setName(num2str(i)); % give each cell a unique name')\n", + "# MATLAB L11137: \n", + "#\n", + "# MATLAB L11138: end\n", + "_matlab('end')\n", + "# MATLAB L11139: \n", + "#\n", + "# MATLAB L11140: % Plot the neural raster across all the cells\n", + "# Plot the neural raster across all the cells\n", + "# MATLAB L11141: spikeColl = nstColl(nst); % Create a neural spike train collection\n", + "_matlab('spikeColl = nstColl(nst); % Create a neural spike train collection')\n", + "# MATLAB L11142: \n", + "#\n", + "# MATLAB L11143: % Based on the temporal resolution defined by delta, bin the data and get\n", + "# Based on the temporal resolution defined by delta, bin the data and get\n", + "# MATLAB L11144: % a matrix representation of the neural firing\n", + "# a matrix representation of the neural firing\n", + "# MATLAB L11145: dN=spikeColl.dataToMatrix';\n", + "_matlab(\"dN=spikeColl.dataToMatrix';\")\n", + "# MATLAB L11146: dN(dN>1)=1; % more than one spike per bin will be treated as one spike. In\n", + "_matlab('dN(dN>1)=1; % more than one spike per bin will be treated as one spike. In')\n", + "# MATLAB L11147: % general we should pick delta small enough so that there is\n", + "# general we should pick delta small enough so that there is\n", + "# MATLAB L11148: % only one spike per bin\n", + "# only one spike per bin\n", + "# MATLAB L11149: \n", + "#\n", + "# MATLAB L11150: [C,N] = size(dN); % N time samples, C cells\n", + "_matlab('[C,N] = size(dN); % N time samples, C cells')\n", + "# MATLAB L11151: \n", + "#\n", + "# MATLAB L11152: beta=[zeros(2,numCells); bCoeffs'];\n", + "_matlab(\"beta=[zeros(2,numCells); bCoeffs'];\")\n", + "# MATLAB L11153: \n", + "#\n", + "# MATLAB L11154: \n", + "#\n", + "# MATLAB L11155: %Use the Goal Directed Movement Version of the Point Process adaptive\n", + "# Use the Goal Directed Movement Version of the Point Process adaptive\n", + "# MATLAB L11156: %Filter\n", + "# Filter\n", + "# MATLAB L11157: [x_p, W_p, x_u, W_u,x_uT,W_uT,x_pT,W_pT] = ...\n", + "_matlab('[x_p, W_p, x_u, W_u,x_uT,W_uT,x_pT,W_pT] = ...')\n", + "# MATLAB L11158: DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...\n", + "_matlab('DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...')\n", + "# MATLAB L11159: MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0, Pi0, yT,PiT,0);\n", + "_matlab('MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0, Pi0, yT,PiT,0);')\n", + "# MATLAB L11160: \n", + "#\n", + "# MATLAB L11161: %Use the Free Movement Version of the Point Process adaptive\n", + "# Use the Free Movement Version of the Point Process adaptive\n", + "# MATLAB L11162: %Filter\n", + "# Filter\n", + "# MATLAB L11163: [x_pf, W_pf, x_uf, W_uf] = ...\n", + "_matlab('[x_pf, W_pf, x_uf, W_uf] = ...')\n", + "# MATLAB L11164: DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...\n", + "_matlab('DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,...')\n", + "# MATLAB L11165: MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0);\n", + "_matlab('MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0);')\n", + "# MATLAB L11166: \n", + "#\n", + "# MATLAB L11167: \n", + "#\n", + "# MATLAB L11168: if(k==numExamples)\n", + "_matlab('if(k==numExamples)')\n", + "# MATLAB L11169: subplot(4,2,1:4);h1=plot(100*x(1,:),100*x(2,:),'k','LineWidth',3);\n", + "__tracker.annotate('subplot(4,2,1:4)')\n", + "__tracker.annotate(\"h1=plot(100*x(1,:),100*x(2,:),'k','LineWidth',3)\")\n", + "_matlab(\"subplot(4,2,1:4);h1=plot(100*x(1,:),100*x(2,:),'k','LineWidth',3);\")\n", + "# MATLAB L11170: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L11171: axis([sort([100*x0(1)+5, 100*xT(1)-5]), ...\n", + "_matlab('axis([sort([100*x0(1)+5, 100*xT(1)-5]), ...')\n", + "# MATLAB L11172: sort([100*x0(2)-5, 100*xT(2)+5])]);\n", + "_matlab('sort([100*x0(2)-5, 100*xT(2)+5])]);')\n", + "# MATLAB L11173: title('Estimated vs. Actual Reach Paths',...\n", + "_matlab(\"title('Estimated vs. Actual Reach Paths',...\")\n", + "# MATLAB L11174: 'FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"'FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L11175: end\n", + "_matlab('end')\n", + "# MATLAB L11176: subplot(4,2,1:4);h2=plot(100*x_u(1,:)',100*x_u(2,:)','b'); hold all;\n", + "__tracker.annotate('subplot(4,2,1:4)')\n", + "__tracker.annotate(\"h2=plot(100*x_u(1,:)',100*x_u(2,:)','b')\")\n", + "_matlab(\"subplot(4,2,1:4);h2=plot(100*x_u(1,:)',100*x_u(2,:)','b'); hold all;\")\n", + "# MATLAB L11177: subplot(4,2,1:4);h3=plot(100*x_uf(1,:)',100*x_uf(2,:)','g');\n", + "__tracker.annotate('subplot(4,2,1:4)')\n", + "__tracker.annotate(\"h3=plot(100*x_uf(1,:)',100*x_uf(2,:)','g')\")\n", + "_matlab(\"subplot(4,2,1:4);h3=plot(100*x_uf(1,:)',100*x_uf(2,:)','g');\")\n", + "# MATLAB L11178: hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\n", + "_matlab(\"hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\")\n", + "# MATLAB L11179: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L11180: h1=plot(100*x0(1),100*x0(2),'bo','MarkerSize',10); hold on;\n", + "__tracker.annotate(\"h1=plot(100*x0(1),100*x0(2),'bo','MarkerSize',10)\")\n", + "_matlab(\"h1=plot(100*x0(1),100*x0(2),'bo','MarkerSize',10); hold on;\")\n", + "# MATLAB L11181: h2=plot(100*xT(1),100*xT(2),'ro','MarkerSize',10);\n", + "__tracker.annotate(\"h2=plot(100*xT(1),100*xT(2),'ro','MarkerSize',10)\")\n", + "_matlab(\"h2=plot(100*xT(1),100*xT(2),'ro','MarkerSize',10);\")\n", + "# MATLAB L11182: legend([h1 h2],'Start','Finish','Location','NorthEast');\n", + "_matlab(\"legend([h1 h2],'Start','Finish','Location','NorthEast');\")\n", + "# MATLAB L11183: \n", + "#\n", + "# MATLAB L11184: \n", + "#\n", + "# MATLAB L11185: subplot(4,2,5);\n", + "__tracker.annotate('subplot(4,2,5)')\n", + "_matlab('subplot(4,2,5);')\n", + "# MATLAB L11186: h1=plot(time,100*x(1,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*x(1,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*x(1,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L11187: h2=plot(time,100*x_u(1,:)','b');\n", + "__tracker.annotate(\"h2=plot(time,100*x_u(1,:)','b');\")\n", + "_matlab(\"h2=plot(time,100*x_u(1,:)','b');\")\n", + "# MATLAB L11188: h3=plot(time,100*x_uf(1,:)','g');\n", + "__tracker.annotate(\"h3=plot(time,100*x_uf(1,:)','g');\")\n", + "_matlab(\"h3=plot(time,100*x_uf(1,:)','g');\")\n", + "# MATLAB L11189: hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L11190: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L11191: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L11192: title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L11193: \n", + "#\n", + "# MATLAB L11194: subplot(4,2,6);\n", + "__tracker.annotate('subplot(4,2,6)')\n", + "_matlab('subplot(4,2,6);')\n", + "# MATLAB L11195: h1=plot(time,100*x(2,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*x(2,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*x(2,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L11196: h2=plot(time,100*x_u(2,:)','b');\n", + "__tracker.annotate(\"h2=plot(time,100*x_u(2,:)','b');\")\n", + "_matlab(\"h2=plot(time,100*x_u(2,:)','b');\")\n", + "# MATLAB L11197: h3=plot(time,100*x_uf(2,:)','g');\n", + "__tracker.annotate(\"h3=plot(time,100*x_uf(2,:)','g');\")\n", + "_matlab(\"h3=plot(time,100*x_uf(2,:)','g');\")\n", + "# MATLAB L11198: h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\n", + "_matlab(\"h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\")\n", + "# MATLAB L11199: 'PPAF','Location','SouthEast');\n", + "_matlab(\"'PPAF','Location','SouthEast');\")\n", + "# MATLAB L11200: hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L11201: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L11202: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L11203: title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L11204: set(h_legend,'FontSize',10)\n", + "_matlab(\"set(h_legend,'FontSize',10)\")\n", + "# MATLAB L11205: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L11206: set(h_legend, 'position',[pos(1)-.63 pos(2)+.23 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)-.63 pos(2)+.23 pos(3:4)]);\")\n", + "# MATLAB L11207: \n", + "#\n", + "# MATLAB L11208: subplot(4,2,7);\n", + "__tracker.annotate('subplot(4,2,7)')\n", + "_matlab('subplot(4,2,7);')\n", + "# MATLAB L11209: h1=plot(time,100*x(3,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*x(3,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*x(3,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L11210: h2=plot(time,100*x_u(3,:)','b');\n", + "__tracker.annotate(\"h2=plot(time,100*x_u(3,:)','b');\")\n", + "_matlab(\"h2=plot(time,100*x_u(3,:)','b');\")\n", + "# MATLAB L11211: h3=plot(time,100*x_uf(3,:)','g');\n", + "__tracker.annotate(\"h3=plot(time,100*x_uf(3,:)','g');\")\n", + "_matlab(\"h3=plot(time,100*x_uf(3,:)','g');\")\n", + "# MATLAB L11212: hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L11213: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L11214: title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L11215: \n", + "#\n", + "# MATLAB L11216: subplot(4,2,8);\n", + "__tracker.annotate('subplot(4,2,8)')\n", + "_matlab('subplot(4,2,8);')\n", + "# MATLAB L11217: h1=plot(time,100*x(4,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*x(4,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*x(4,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L11218: h2=plot(time,100*x_u(4,:)','b');\n", + "__tracker.annotate(\"h2=plot(time,100*x_u(4,:)','b');\")\n", + "_matlab(\"h2=plot(time,100*x_u(4,:)','b');\")\n", + "# MATLAB L11219: h3=plot(time,100*x_uf(4,:)','g');\n", + "__tracker.annotate(\"h3=plot(time,100*x_uf(4,:)','g');\")\n", + "_matlab(\"h3=plot(time,100*x_uf(4,:)','g');\")\n", + "# MATLAB L11220: hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L11221: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L11222: title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L11223: \n", + "#\n", + "# MATLAB L11224: \n", + "#\n", + "# MATLAB L11225: end\n", + "_matlab('end')\n", + "# MATLAB L11226: \n", + "#\n", + "# MATLAB L11227: % close all;\n", + "# close all;\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6895763f", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 27: Experiment 6 - Hybrid Point Process Filter Example\n", + "# MATLAB L11400: % NOTE THIS EXAMPLE WAS NOT INCLUDED IN THE FINAL VERSION OF THE PAPER This example is based on an implementation of the Hybrid Point Process filter described in General-purpose filter design for neural prosthetic devices by Srinivasan L, Eden UT, Mitter SK, Brown EN in J Neurophysiol. 2007 Oct, 98(4):2456-75.\n", + "# NOTE THIS EXAMPLE WAS NOT INCLUDED IN THE FINAL VERSION OF THE PAPER This example is based on an implementation of the Hybrid Point Process filter described in General-purpose filter design for neural prosthetic devices by Srinivasan L, Eden UT, Mitter SK, Brown EN in J Neurophysiol. 2007 Oct, 98(4):2456-75.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5680cbc", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 28: Problem Statement\n", + "# MATLAB L11600: % Suppose that a process of interest can be modeled as consisting of several discrete states where the evolution of the system under each state can be modeled as a linear state space model. The observations of both the state and the continuous dynamics are not direct, but rather observed through how the continuous and discrete states affect the firing of a population of neurons. The goal of the hybrid filter is to estimate both the continuous dynamics and the underlying system state from only the neural population firing (point process observations).\n", + "# Suppose that a process of interest can be modeled as consisting of several discrete states where the evolution of the system under each state can be modeled as a linear state space model. The observations of both the state and the continuous dynamics are not direct, but rather observed through how the continuous and discrete states affect the firing of a population of neurons. The goal of the hybrid filter is to estimate both the continuous dynamics and the underlying system state from only the neural population firing (point process observations).\n", + "# MATLAB L11700: % To illustrate the use of this filter, we consider a reaching task. We assume two underlying system states s=1=\"Not Moving\"=NM and s=2=\"Moving\"=M. Under the \"Not Moving\" the position of the arm remain constant, whereas in the \"Moving\" state, the position and velocities evolved based on the arm acceleration that is modeled as a gaussian white noise process.\n", + "# To illustrate the use of this filter, we consider a reaching task. We assume two underlying system states s=1=\"Not Moving\"=NM and s=2=\"Moving\"=M. Under the \"Not Moving\" the position of the arm remain constant, whereas in the \"Moving\" state, the position and velocities evolved based on the arm acceleration that is modeled as a gaussian white noise process.\n", + "# MATLAB L11800: % Under both the \"Moving\" and \"Not Moving\" states, the arm evolution state vector is\n", + "# Under both the \"Moving\" and \"Not Moving\" states, the arm evolution state vector is\n", + "# MATLAB L11900: % {\\bf{x}} = {[x,y,{v_x},{v_y},{a_x},{a_y}]^T}\n", + "# {\\bf{x}} = {[x,y,{v_x},{v_y},{a_x},{a_y}]^T}\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28f51ba1", + "metadata": {}, + "outputs": [], + "source": [ + "# SECTION 29: Generated Simulated Arm Reach\n", + "# MATLAB L12100: clear all;\n", + "pass\n", + "# MATLAB L12101: [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", + "_matlab('[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...')\n", + "# MATLAB L12102: getPaperDataDirs();\n", + "_matlab('getPaperDataDirs();')\n", + "# MATLAB L12103: close all;\n", + "plt.close(\"all\")\n", + "# MATLAB L12104: delta=0.001;\n", + "delta = 0.001\n", + "# MATLAB L12105: Tmax=2;\n", + "Tmax = 2\n", + "# MATLAB L12106: time=0:delta:Tmax;\n", + "_matlab('time=0:delta:Tmax;')\n", + "# MATLAB L12107: A{2} = [1 0 delta 0 delta^2/2 0;\n", + "_matlab('A{2} = [1 0 delta 0 delta^2/2 0;')\n", + "# MATLAB L12108: 0 1 0 delta 0 delta^2/2;\n", + "_matlab('0 1 0 delta 0 delta^2/2;')\n", + "# MATLAB L12109: 0 0 1 0 delta 0;\n", + "_matlab('0 0 1 0 delta 0;')\n", + "# MATLAB L12110: 0 0 0 1 0 delta;\n", + "_matlab('0 0 0 1 0 delta;')\n", + "# MATLAB L12111: 0 0 0 0 1 0;\n", + "_matlab('0 0 0 0 1 0;')\n", + "# MATLAB L12112: 0 0 0 0 0 1];\n", + "_matlab('0 0 0 0 0 1];')\n", + "# MATLAB L12113: \n", + "#\n", + "# MATLAB L12114: A{1} = [1 0 0 0 0 0;\n", + "_matlab('A{1} = [1 0 0 0 0 0;')\n", + "# MATLAB L12115: 0 1 0 0 0 0;\n", + "_matlab('0 1 0 0 0 0;')\n", + "# MATLAB L12116: 0 0 0 0 0 0;\n", + "_matlab('0 0 0 0 0 0;')\n", + "# MATLAB L12117: 0 0 0 0 0 0;\n", + "_matlab('0 0 0 0 0 0;')\n", + "# MATLAB L12118: 0 0 0 0 0 0;\n", + "_matlab('0 0 0 0 0 0;')\n", + "# MATLAB L12119: 0 0 0 0 0 0];\n", + "_matlab('0 0 0 0 0 0];')\n", + "# MATLAB L12120: A{1} = [1 0;\n", + "_matlab('A{1} = [1 0;')\n", + "# MATLAB L12121: 0 1];\n", + "_matlab('0 1];')\n", + "# MATLAB L12122: \n", + "#\n", + "# MATLAB L12123: Px0{2} =1e-6*eye(6,6);\n", + "_matlab('Px0{2} =1e-6*eye(6,6);')\n", + "# MATLAB L12124: Px0{1} =1e-6*eye(2,2);\n", + "_matlab('Px0{1} =1e-6*eye(2,2);')\n", + "# MATLAB L12125: \n", + "#\n", + "# MATLAB L12126: minCovVal = 1e-12;\n", + "minCovVal = 1e-12\n", + "# MATLAB L12127: covVal = 1e-3;\n", + "covVal = 1e-3\n", + "# MATLAB L12128: \n", + "#\n", + "# MATLAB L12129: \n", + "#\n", + "# MATLAB L12130: \n", + "#\n", + "# MATLAB L12131: Q{2}=[minCovVal 0 0 0 0 0;\n", + "_matlab('Q{2}=[minCovVal 0 0 0 0 0;')\n", + "# MATLAB L12132: 0 minCovVal 0 0 0 0;\n", + "_matlab('0 minCovVal 0 0 0 0;')\n", + "# MATLAB L12133: 0 0 minCovVal 0 0 0;\n", + "_matlab('0 0 minCovVal 0 0 0;')\n", + "# MATLAB L12134: 0 0 0 minCovVal 0 0;\n", + "_matlab('0 0 0 minCovVal 0 0;')\n", + "# MATLAB L12135: 0 0 0 0 covVal 0;\n", + "_matlab('0 0 0 0 covVal 0;')\n", + "# MATLAB L12136: 0 0 0 0 0 covVal];\n", + "_matlab('0 0 0 0 0 covVal];')\n", + "# MATLAB L12137: \n", + "#\n", + "# MATLAB L12138: Q{1}=minCovVal*eye(2,2);\n", + "_matlab('Q{1}=minCovVal*eye(2,2);')\n", + "# MATLAB L12139: \n", + "#\n", + "# MATLAB L12140: mstate = zeros(1,length(time));\n", + "_matlab('mstate = zeros(1,length(time));')\n", + "# MATLAB L12141: ind{1}=1:2;\n", + "_matlab('ind{1}=1:2;')\n", + "# MATLAB L12142: ind{2}=1:6;\n", + "_matlab('ind{2}=1:6;')\n", + "# MATLAB L12143: \n", + "#\n", + "# MATLAB L12144: % Acceleration model\n", + "# Acceleration model\n", + "# MATLAB L12145: X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));\n", + "_matlab('X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));')\n", + "# MATLAB L12146: p_ij = [.998 .002;\n", + "_matlab('p_ij = [.998 .002;')\n", + "# MATLAB L12147: .001 .999];\n", + "_matlab('.001 .999];')\n", + "# MATLAB L12148: \n", + "#\n", + "# MATLAB L12149: for i = 1:length(time)\n", + "_matlab('for i = 1:length(time)')\n", + "# MATLAB L12150: \n", + "#\n", + "# MATLAB L12151: if(i==1)\n", + "_matlab('if(i==1)')\n", + "# MATLAB L12152: mstate(i) = 1;\n", + "_matlab('mstate(i) = 1;')\n", + "# MATLAB L12153: else\n", + "_matlab('else')\n", + "# MATLAB L12154: if(rand(1,1)1)=1; %Avoid more than 1 spike per bin.\n", + "_matlab('dN(dN>1)=1; %Avoid more than 1 spike per bin.')\n", + "# MATLAB L12754: \n", + "#\n", + "# MATLAB L12755: % Starting states are equally probable\n", + "# Starting states are equally probable\n", + "# MATLAB L12756: Mu0=.5*ones(size(p_ij,1),1);\n", + "_matlab('Mu0=.5*ones(size(p_ij,1),1);')\n", + "# MATLAB L12757: clear x0 yT clear Pi0 PiT;\n", + "pass\n", + "# MATLAB L12758: x0{1} = X(ind{1},1);\n", + "_matlab('x0{1} = X(ind{1},1);')\n", + "# MATLAB L12759: yT{1} = X(ind{1},end);\n", + "_matlab('yT{1} = X(ind{1},end);')\n", + "# MATLAB L12760: Pi0 = Px0;\n", + "_matlab('Pi0 = Px0;')\n", + "# MATLAB L12761: PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));\n", + "_matlab('PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1));')\n", + "# MATLAB L12762: \n", + "#\n", + "# MATLAB L12763: x0{2} = X(ind{2},1);\n", + "_matlab('x0{2} = X(ind{2},1);')\n", + "# MATLAB L12764: yT{2} = X(ind{2},end);\n", + "_matlab('yT{2} = X(ind{2},end);')\n", + "# MATLAB L12765: PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));\n", + "_matlab('PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1));')\n", + "# MATLAB L12766: \n", + "#\n", + "# MATLAB L12767: \n", + "#\n", + "# MATLAB L12768: % Run the Hybrid Point Process Filter\n", + "# Run the Hybrid Point Process Filter\n", + "# MATLAB L12769: [S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...\n", + "_matlab('[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...')\n", + "# MATLAB L12770: DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\n", + "_matlab(\"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\")\n", + "# MATLAB L12771: coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\n", + "_matlab(\"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT);\")\n", + "# MATLAB L12772: [S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...\n", + "_matlab('[S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=...')\n", + "# MATLAB L12773: DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\n", + "_matlab(\"DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',...\")\n", + "# MATLAB L12774: coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0);\n", + "_matlab(\"coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0);\")\n", + "# MATLAB L12775: \n", + "#\n", + "# MATLAB L12776: %Store the results for computing relevant statistics later\n", + "# Store the results for computing relevant statistics later\n", + "# MATLAB L12777: X_estAll(:,:,n) = X_est;\n", + "_matlab('X_estAll(:,:,n) = X_est;')\n", + "# MATLAB L12778: X_estNTAll(:,:,n) = X_estNT;\n", + "_matlab('X_estNTAll(:,:,n) = X_estNT;')\n", + "# MATLAB L12779: S_estAll(n,:)=S_est;\n", + "_matlab('S_estAll(n,:)=S_est;')\n", + "# MATLAB L12780: S_estNTAll(n,:)=S_estNT;\n", + "_matlab('S_estNTAll(n,:)=S_estNT;')\n", + "# MATLAB L12781: MU_estAll(:,:,n)=MU_est;\n", + "_matlab('MU_estAll(:,:,n)=MU_est;')\n", + "# MATLAB L12782: MU_estNTAll(:,:,n) = MU_estNT;\n", + "_matlab('MU_estNTAll(:,:,n) = MU_estNT;')\n", + "# MATLAB L12783: \n", + "#\n", + "# MATLAB L12784: \n", + "#\n", + "# MATLAB L12785: %State Estimate\n", + "# State Estimate\n", + "# MATLAB L12786: subplot(4,3,[1 4]);\n", + "__tracker.annotate('subplot(4,3,[1 4])')\n", + "_matlab('subplot(4,3,[1 4]);')\n", + "# MATLAB L12787: plot(time,mstate,'k','LineWidth',3); hold all;\n", + "__tracker.annotate(\"plot(time,mstate,'k','LineWidth',3)\")\n", + "_matlab(\"plot(time,mstate,'k','LineWidth',3); hold all;\")\n", + "# MATLAB L12788: plot(time,S_est,'b-.','Linewidth',.5);\n", + "__tracker.annotate(\"plot(time,S_est,'b-.','Linewidth',.5)\")\n", + "_matlab(\"plot(time,S_est,'b-.','Linewidth',.5);\")\n", + "# MATLAB L12789: plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\n", + "__tracker.annotate(\"plot(time,S_estNT,'g-.','Linewidth',.5)\")\n", + "_matlab(\"plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis;\")\n", + "# MATLAB L12790: axis([v(1) v(2) 0.5 2.5]);\n", + "_matlab('axis([v(1) v(2) 0.5 2.5]);')\n", + "# MATLAB L12791: \n", + "#\n", + "# MATLAB L12792: %Movement State Probability (Non-movement State probability is 1-Pr(Movement))\n", + "# Movement State Probability (Non-movement State probability is 1-Pr(Movement))\n", + "# MATLAB L12793: subplot(4,3,[7 10]);\n", + "__tracker.annotate('subplot(4,3,[7 10])')\n", + "_matlab('subplot(4,3,[7 10]);')\n", + "# MATLAB L12794: plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\n", + "__tracker.annotate(\"plot(time,MU_est(2,:),'b-.','Linewidth',.5)\")\n", + "_matlab(\"plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on;\")\n", + "# MATLAB L12795: plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\n", + "__tracker.annotate(\"plot(time,MU_estNT(2,:),'g-.','Linewidth',.5)\")\n", + "_matlab(\"plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on;\")\n", + "# MATLAB L12796: axis([min(time) max(time) 0 1.1]);\n", + "_matlab('axis([min(time) max(time) 0 1.1]);')\n", + "# MATLAB L12797: \n", + "#\n", + "# MATLAB L12798: %The movement path\n", + "# The movement path\n", + "# MATLAB L12799: subplot(4,3,[2 3 5 6]);\n", + "__tracker.annotate('subplot(4,3,[2 3 5 6])')\n", + "_matlab('subplot(4,3,[2 3 5 6]);')\n", + "# MATLAB L12800: h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\n", + "__tracker.annotate(\"h1=plot(100*X(1,:)',100*X(2,:)','k')\")\n", + "_matlab(\"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\")\n", + "# MATLAB L12801: h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\n", + "__tracker.annotate(\"h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.')\")\n", + "_matlab(\"h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all;\")\n", + "# MATLAB L12802: h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.')\")\n", + "_matlab(\"h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.');\")\n", + "# MATLAB L12803: \n", + "#\n", + "# MATLAB L12804: %X-Position\n", + "# X-Position\n", + "# MATLAB L12805: subplot(4,3,8);\n", + "__tracker.annotate('subplot(4,3,8)')\n", + "_matlab('subplot(4,3,8);')\n", + "# MATLAB L12806: h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(1,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L12807: h2=plot(time,100*X_est(1,:)','b-.');\n", + "__tracker.annotate(\"h2=plot(time,100*X_est(1,:)','b-.');\")\n", + "_matlab(\"h2=plot(time,100*X_est(1,:)','b-.');\")\n", + "# MATLAB L12808: h3=plot(time,100*X_estNT(1,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(time,100*X_estNT(1,:)','g-.');\")\n", + "_matlab(\"h3=plot(time,100*X_estNT(1,:)','g-.');\")\n", + "# MATLAB L12809: \n", + "#\n", + "# MATLAB L12810: %Y-Position\n", + "# Y-Position\n", + "# MATLAB L12811: subplot(4,3,9);\n", + "__tracker.annotate('subplot(4,3,9)')\n", + "_matlab('subplot(4,3,9);')\n", + "# MATLAB L12812: h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(2,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L12813: h2=plot(time,100*X_est(2,:)','b-.');\n", + "__tracker.annotate(\"h2=plot(time,100*X_est(2,:)','b-.');\")\n", + "_matlab(\"h2=plot(time,100*X_est(2,:)','b-.');\")\n", + "# MATLAB L12814: h3=plot(time,100*X_estNT(2,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(time,100*X_estNT(2,:)','g-.');\")\n", + "_matlab(\"h3=plot(time,100*X_estNT(2,:)','g-.');\")\n", + "# MATLAB L12815: \n", + "#\n", + "# MATLAB L12816: %X-Velocity\n", + "# X-Velocity\n", + "# MATLAB L12817: subplot(4,3,11);\n", + "__tracker.annotate('subplot(4,3,11)')\n", + "_matlab('subplot(4,3,11);')\n", + "# MATLAB L12818: h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(3,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L12819: h2=plot(time,100*X_est(3,:)','b-.');\n", + "__tracker.annotate(\"h2=plot(time,100*X_est(3,:)','b-.');\")\n", + "_matlab(\"h2=plot(time,100*X_est(3,:)','b-.');\")\n", + "# MATLAB L12820: h3=plot(time,100*X_estNT(3,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(time,100*X_estNT(3,:)','g-.');\")\n", + "_matlab(\"h3=plot(time,100*X_estNT(3,:)','g-.');\")\n", + "# MATLAB L12821: \n", + "#\n", + "# MATLAB L12822: subplot(4,3,12);\n", + "__tracker.annotate('subplot(4,3,12)')\n", + "_matlab('subplot(4,3,12);')\n", + "# MATLAB L12823: h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(4,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L12824: h2=plot(time,100*X_est(4,:)','b-.');\n", + "__tracker.annotate(\"h2=plot(time,100*X_est(4,:)','b-.');\")\n", + "_matlab(\"h2=plot(time,100*X_est(4,:)','b-.');\")\n", + "# MATLAB L12825: h3=plot(time,100*X_estNT(4,:)','g-.');\n", + "__tracker.annotate(\"h3=plot(time,100*X_estNT(4,:)','g-.');\")\n", + "_matlab(\"h3=plot(time,100*X_estNT(4,:)','g-.');\")\n", + "# MATLAB L12826: \n", + "#\n", + "# MATLAB L12827: \n", + "#\n", + "# MATLAB L12828: \n", + "#\n", + "# MATLAB L12829: \n", + "#\n", + "# MATLAB L12830: end\n", + "_matlab('end')\n", + "# MATLAB L12831: \n", + "#\n", + "# MATLAB L12832: %\n", + "#\n", + "# MATLAB L12833: % Save all the example Data\n", + "# Save all the example Data\n", + "# MATLAB L12834: % save Experiment6ReachExamples X_estAll X_estNTAll S_estAll ...\n", + "# save Experiment6ReachExamples X_estAll X_estNTAll S_estAll ...\n", + "# MATLAB L12835: % S_estNTAll MU_estAll MU_estNTAll;\n", + "# S_estNTAll MU_estAll MU_estNTAll;\n", + "# MATLAB L12836: %\n", + "#\n", + "# MATLAB L12837: % load Experiment6ReachExamples;\n", + "# load Experiment6ReachExamples;\n", + "# MATLAB L12838: \n", + "#\n", + "# MATLAB L12839: % Mean Discrete State Estimate\n", + "# Mean Discrete State Estimate\n", + "# MATLAB L12840: subplot(4,3,[1 4]);\n", + "__tracker.annotate('subplot(4,3,[1 4])')\n", + "_matlab('subplot(4,3,[1 4]);')\n", + "# MATLAB L12841: hold all;\n", + "_matlab('hold all;')\n", + "# MATLAB L12842: plot(time,mstate,'k','LineWidth',3);\n", + "__tracker.annotate(\"plot(time,mstate,'k','LineWidth',3)\")\n", + "_matlab(\"plot(time,mstate,'k','LineWidth',3);\")\n", + "# MATLAB L12843: plot(time,mean(S_estAll),'b','LineWidth',3);\n", + "__tracker.annotate(\"plot(time,mean(S_estAll),'b','LineWidth',3)\")\n", + "_matlab(\"plot(time,mean(S_estAll),'b','LineWidth',3);\")\n", + "# MATLAB L12844: plot(time,mean(S_estNTAll),'g','LineWidth',3);\n", + "__tracker.annotate(\"plot(time,mean(S_estNTAll),'g','LineWidth',3)\")\n", + "_matlab(\"plot(time,mean(S_estNTAll),'g','LineWidth',3);\")\n", + "# MATLAB L12845: set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\n", + "_matlab(\"set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'});\")\n", + "# MATLAB L12846: hy=ylabel('state'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('state'); hx=xlabel('time [s]');\")\n", + "# MATLAB L12847: set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\n", + "_matlab(\"set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',...\")\n", + "# MATLAB L12848: 'Interpreter','none');\n", + "_matlab(\"'Interpreter','none');\")\n", + "# MATLAB L12849: title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\n", + "_matlab(\"title('Estimated vs. Actual State','FontWeight','bold','Fontsize',...\")\n", + "# MATLAB L12850: 12,'FontName','Arial');\n", + "_matlab(\"12,'FontName','Arial');\")\n", + "# MATLAB L12851: \n", + "#\n", + "# MATLAB L12852: \n", + "#\n", + "# MATLAB L12853: \n", + "#\n", + "# MATLAB L12854: \n", + "#\n", + "# MATLAB L12855: % Mean State Movement State Probability\n", + "# Mean State Movement State Probability\n", + "# MATLAB L12856: subplot(4,3,[7 10]);\n", + "__tracker.annotate('subplot(4,3,[7 10])')\n", + "_matlab('subplot(4,3,[7 10]);')\n", + "# MATLAB L12857: plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\n", + "__tracker.annotate(\"plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3)\")\n", + "_matlab(\"plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3);\")\n", + "# MATLAB L12858: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L12859: plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\n", + "__tracker.annotate(\"plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3)\")\n", + "_matlab(\"plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3);\")\n", + "# MATLAB L12860: hold on;\n", + "_matlab('hold on;')\n", + "# MATLAB L12861: axis([min(time) max(time) 0 1.1]);\n", + "_matlab('axis([min(time) max(time) 0 1.1]);')\n", + "# MATLAB L12862: hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\n", + "_matlab(\"hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)');\")\n", + "# MATLAB L12863: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L12864: title('Probability of State','FontWeight','bold','Fontsize',12,...\n", + "_matlab(\"title('Probability of State','FontWeight','bold','Fontsize',12,...\")\n", + "# MATLAB L12865: 'FontName','Arial');\n", + "_matlab(\"'FontName','Arial');\")\n", + "# MATLAB L12866: \n", + "#\n", + "# MATLAB L12867: % Mean movement path\n", + "# Mean movement path\n", + "# MATLAB L12868: subplot(4,3,[2 3 5 6]);\n", + "__tracker.annotate('subplot(4,3,[2 3 5 6])')\n", + "_matlab('subplot(4,3,[2 3 5 6]);')\n", + "# MATLAB L12869: h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\n", + "__tracker.annotate(\"h1=plot(100*X(1,:)',100*X(2,:)','k')\")\n", + "_matlab(\"h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all;\")\n", + "# MATLAB L12870: mXestAll=mean(100*X_estAll,3);\n", + "_matlab('mXestAll=mean(100*X_estAll,3);')\n", + "# MATLAB L12871: mXestNTAll=mean(100*X_estNTAll,3);\n", + "_matlab('mXestNTAll=mean(100*X_estNTAll,3);')\n", + "# MATLAB L12872: plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\n", + "__tracker.annotate(\"plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3)\")\n", + "_matlab(\"plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3);\")\n", + "# MATLAB L12873: plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\n", + "__tracker.annotate(\"plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3)\")\n", + "_matlab(\"plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3);\")\n", + "# MATLAB L12874: hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\n", + "_matlab(\"hx=xlabel('x [cm]'); hy=ylabel('y [cm]');\")\n", + "# MATLAB L12875: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L12876: \n", + "#\n", + "# MATLAB L12877: h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\n", + "__tracker.annotate(\"h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14)\")\n", + "_matlab(\"h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;\")\n", + "# MATLAB L12878: h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\n", + "__tracker.annotate(\"h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14)\")\n", + "_matlab(\"h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14);\")\n", + "# MATLAB L12879: legend([h1 h2],'Start','Finish','Location','NorthEast');\n", + "_matlab(\"legend([h1 h2],'Start','Finish','Location','NorthEast');\")\n", + "# MATLAB L12880: title('Estimated vs. Actual Reach Path','FontWeight','bold',...\n", + "_matlab(\"title('Estimated vs. Actual Reach Path','FontWeight','bold',...\")\n", + "# MATLAB L12881: 'Fontsize',12,'FontName','Arial');\n", + "_matlab(\"'Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L12882: \n", + "#\n", + "# MATLAB L12883: \n", + "#\n", + "# MATLAB L12884: % Mean X-Positon\n", + "# Mean X-Positon\n", + "# MATLAB L12885: subplot(4,3,8);\n", + "__tracker.annotate('subplot(4,3,8)')\n", + "_matlab('subplot(4,3,8);')\n", + "# MATLAB L12886: h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(1,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L12887: h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h2=plot(time,mXestAll(1,:),'b','LineWidth',3)\")\n", + "_matlab(\"h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on;\")\n", + "# MATLAB L12888: h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3)\")\n", + "_matlab(\"h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on;\")\n", + "# MATLAB L12889: hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L12890: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L12891: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L12892: title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L12893: \n", + "#\n", + "# MATLAB L12894: % Mean Y-Position\n", + "# Mean Y-Position\n", + "# MATLAB L12895: subplot(4,3,9);\n", + "__tracker.annotate('subplot(4,3,9)')\n", + "_matlab('subplot(4,3,9);')\n", + "# MATLAB L12896: h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(2,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L12897: h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h2=plot(time,mXestAll(2,:),'b','LineWidth',3)\")\n", + "_matlab(\"h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on;\")\n", + "# MATLAB L12898: h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3)\")\n", + "_matlab(\"h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on;\")\n", + "# MATLAB L12899: h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\n", + "_matlab(\"h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',...\")\n", + "# MATLAB L12900: 'PPAF','Location','SouthEast');\n", + "_matlab(\"'PPAF','Location','SouthEast');\")\n", + "# MATLAB L12901: hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L12902: set(gca,'xtick',[],'xtickLabel',[]);\n", + "_matlab(\"set(gca,'xtick',[],'xtickLabel',[]);\")\n", + "# MATLAB L12903: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L12904: title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L12905: set(h_legend,'FontSize',10)\n", + "_matlab(\"set(h_legend,'FontSize',10)\")\n", + "# MATLAB L12906: pos = get(h_legend,'position');\n", + "_matlab(\"pos = get(h_legend,'position');\")\n", + "# MATLAB L12907: set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\n", + "_matlab(\"set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]);\")\n", + "# MATLAB L12908: \n", + "#\n", + "# MATLAB L12909: % Mean X-Velocity\n", + "# Mean X-Velocity\n", + "# MATLAB L12910: subplot(4,3,11);\n", + "__tracker.annotate('subplot(4,3,11)')\n", + "_matlab('subplot(4,3,11);')\n", + "# MATLAB L12911: h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(3,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L12912: h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h2=plot(time,mXestAll(3,:),'b','LineWidth',3)\")\n", + "_matlab(\"h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on;\")\n", + "# MATLAB L12913: h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3)\")\n", + "_matlab(\"h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on;\")\n", + "# MATLAB L12914: hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L12915: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L12916: title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L12917: \n", + "#\n", + "# MATLAB L12918: % Mean Y-Velocity\n", + "# Mean Y-Velocity\n", + "# MATLAB L12919: subplot(4,3,12);\n", + "__tracker.annotate('subplot(4,3,12)')\n", + "_matlab('subplot(4,3,12);')\n", + "# MATLAB L12920: h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h1=plot(time,100*X(4,:),'k','LineWidth',3)\")\n", + "_matlab(\"h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on;\")\n", + "# MATLAB L12921: h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h2=plot(time,mXestAll(4,:),'b','LineWidth',3)\")\n", + "_matlab(\"h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on;\")\n", + "# MATLAB L12922: h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\n", + "__tracker.annotate(\"h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3)\")\n", + "_matlab(\"h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on;\")\n", + "# MATLAB L12923: hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\n", + "_matlab(\"hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]');\")\n", + "# MATLAB L12924: set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\n", + "_matlab(\"set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold');\")\n", + "# MATLAB L12925: title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\n", + "_matlab(\"title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial');\")\n", + "# MATLAB L12926: \n", + "#\n", + "# MATLAB L12927: function [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...\n", + "_matlab('function [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...')\n", + "# MATLAB L12928: getPaperDataDirs()\n", + "_matlab('getPaperDataDirs()')\n", + "# MATLAB L12929: % Resolve local data folders robustly when Live Editor executes from a temp\n", + "# Resolve local data folders robustly when Live Editor executes from a temp\n", + "# MATLAB L12930: % location (e.g., /private/var/.../T).\n", + "# location (e.g., /private/var/.../T).\n", + "# MATLAB L12931: candidateRoots = {};\n", + "_matlab('candidateRoots = {};')\n", + "# MATLAB L12932: \n", + "#\n", + "# MATLAB L12933: scriptPath = mfilename('fullpath');\n", + "_matlab(\"scriptPath = mfilename('fullpath');\")\n", + "# MATLAB L12934: if ~isempty(scriptPath)\n", + "_matlab('if ~isempty(scriptPath)')\n", + "# MATLAB L12935: candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(scriptPath)));\n", + "_matlab('candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(scriptPath)));')\n", + "# MATLAB L12936: end\n", + "_matlab('end')\n", + "# MATLAB L12937: \n", + "#\n", + "# MATLAB L12938: paperPath = which('nSTATPaperExamples');\n", + "_matlab(\"paperPath = which('nSTATPaperExamples');\")\n", + "# MATLAB L12939: if ~isempty(paperPath)\n", + "_matlab('if ~isempty(paperPath)')\n", + "# MATLAB L12940: candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(paperPath)));\n", + "_matlab('candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(paperPath)));')\n", + "# MATLAB L12941: end\n", + "_matlab('end')\n", + "# MATLAB L12942: \n", + "#\n", + "# MATLAB L12943: installPath = which('nSTAT_Install');\n", + "_matlab(\"installPath = which('nSTAT_Install');\")\n", + "# MATLAB L12944: if ~isempty(installPath)\n", + "_matlab('if ~isempty(installPath)')\n", + "# MATLAB L12945: candidateRoots = appendCandidateRoot(candidateRoots, fileparts(installPath));\n", + "_matlab('candidateRoots = appendCandidateRoot(candidateRoots, fileparts(installPath));')\n", + "# MATLAB L12946: end\n", + "_matlab('end')\n", + "# MATLAB L12947: \n", + "#\n", + "# MATLAB L12948: try\n", + "_matlab('try')\n", + "# MATLAB L12949: activeFile = matlab.desktop.editor.getActiveFilename;\n", + "_matlab('activeFile = matlab.desktop.editor.getActiveFilename;')\n", + "# MATLAB L12950: catch\n", + "_matlab('catch')\n", + "# MATLAB L12951: activeFile = '';\n", + "_matlab(\"activeFile = '';\")\n", + "# MATLAB L12952: end\n", + "_matlab('end')\n", + "# MATLAB L12953: if ~isempty(activeFile)\n", + "_matlab('if ~isempty(activeFile)')\n", + "# MATLAB L12954: candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(activeFile)));\n", + "_matlab('candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(activeFile)));')\n", + "# MATLAB L12955: end\n", + "_matlab('end')\n", + "# MATLAB L12956: \n", + "#\n", + "# MATLAB L12957: candidateRoots = appendCandidateRoot(candidateRoots, pwd);\n", + "_matlab('candidateRoots = appendCandidateRoot(candidateRoots, pwd);')\n", + "# MATLAB L12958: \n", + "#\n", + "# MATLAB L12959: nSTATDir = '';\n", + "_matlab(\"nSTATDir = '';\")\n", + "# MATLAB L12960: for iRoot = 1:numel(candidateRoots)\n", + "_matlab('for iRoot = 1:numel(candidateRoots)')\n", + "# MATLAB L12961: candidateDataDir = fullfile(candidateRoots{iRoot}, 'data');\n", + "_matlab(\"candidateDataDir = fullfile(candidateRoots{iRoot}, 'data');\")\n", + "# MATLAB L12962: if exist(candidateDataDir, 'dir') == 7\n", + "_matlab(\"if exist(candidateDataDir, 'dir') == 7\")\n", + "# MATLAB L12963: nSTATDir = candidateRoots{iRoot};\n", + "_matlab('nSTATDir = candidateRoots{iRoot};')\n", + "# MATLAB L12964: break;\n", + "_matlab('break;')\n", + "# MATLAB L12965: end\n", + "_matlab('end')\n", + "# MATLAB L12966: end\n", + "_matlab('end')\n", + "# MATLAB L12967: \n", + "#\n", + "# MATLAB L12968: if isempty(nSTATDir)\n", + "_matlab('if isempty(nSTATDir)')\n", + "# MATLAB L12969: error('nSTATPaperExamples:MissingInstallPath', ...\n", + "_matlab(\"error('nSTATPaperExamples:MissingInstallPath', ...\")\n", + "# MATLAB L12970: ['Could not resolve the nSTAT root path. Checked roots derived from ', ...\n", + "_matlab(\"['Could not resolve the nSTAT root path. Checked roots derived from ', ...\")\n", + "# MATLAB L12971: 'mfilename, which(''nSTATPaperExamples''), which(''nSTAT_Install''), ', ...\n", + "_matlab(\"'mfilename, which(''nSTATPaperExamples''), which(''nSTAT_Install''), ', ...\")\n", + "# MATLAB L12972: 'the active editor file, and pwd.']);\n", + "_matlab(\"'the active editor file, and pwd.']);\")\n", + "# MATLAB L12973: end\n", + "_matlab('end')\n", + "# MATLAB L12974: \n", + "#\n", + "# MATLAB L12975: dataDir = fullfile(nSTATDir,'data');\n", + "_matlab(\"dataDir = fullfile(nSTATDir,'data');\")\n", + "# MATLAB L12976: mEPSCDir = fullfile(dataDir,'mEPSCs');\n", + "_matlab(\"mEPSCDir = fullfile(dataDir,'mEPSCs');\")\n", + "# MATLAB L12977: explicitStimulusDir = fullfile(dataDir,'Explicit Stimulus');\n", + "_matlab(\"explicitStimulusDir = fullfile(dataDir,'Explicit Stimulus');\")\n", + "# MATLAB L12978: psthDir = fullfile(dataDir,'PSTH');\n", + "_matlab(\"psthDir = fullfile(dataDir,'PSTH');\")\n", + "# MATLAB L12979: placeCellDataDir = fullfile(dataDir,'Place Cells');\n", + "_matlab(\"placeCellDataDir = fullfile(dataDir,'Place Cells');\")\n", + "# MATLAB L12980: \n", + "#\n", + "# MATLAB L12981: if exist(dataDir,'dir') ~= 7\n", + "_matlab(\"if exist(dataDir,'dir') ~= 7\")\n", + "# MATLAB L12982: error('nSTATPaperExamples:MissingDataDir', ...\n", + "_matlab(\"error('nSTATPaperExamples:MissingDataDir', ...\")\n", + "# MATLAB L12983: 'Could not find local nSTAT data folder at %s', dataDir);\n", + "_matlab(\"'Could not find local nSTAT data folder at %s', dataDir);\")\n", + "# MATLAB L12984: end\n", + "_matlab('end')\n", + "# MATLAB L12985: end\n", + "_matlab('end')\n", + "# MATLAB L12986: \n", + "#\n", + "# MATLAB L12987: function roots = appendCandidateRoot(roots, startDir)\n", + "_matlab('function roots = appendCandidateRoot(roots, startDir)')\n", + "# MATLAB L12988: if isempty(startDir)\n", + "_matlab('if isempty(startDir)')\n", + "# MATLAB L12989: return;\n", + "_matlab('return;')\n", + "# MATLAB L12990: end\n", + "_matlab('end')\n", + "# MATLAB L12991: \n", + "#\n", + "# MATLAB L12992: thisDir = startDir;\n", + "_matlab('thisDir = startDir;')\n", + "# MATLAB L12993: while true\n", + "_matlab('while true')\n", + "# MATLAB L12994: if ~any(strcmp(roots, thisDir))\n", + "_matlab('if ~any(strcmp(roots, thisDir))')\n", + "# MATLAB L12995: roots{end+1} = thisDir; %#ok\n", + "_matlab('roots{end+1} = thisDir; %#ok')\n", + "# MATLAB L12996: end\n", + "_matlab('end')\n", + "# MATLAB L12997: parentDir = fileparts(thisDir);\n", + "_matlab('parentDir = fileparts(thisDir);')\n", + "# MATLAB L12998: if strcmp(parentDir, thisDir)\n", + "_matlab('if strcmp(parentDir, thisDir)')\n", + "# MATLAB L12999: break;\n", + "_matlab('break;')\n", + "# MATLAB L13000: end\n", + "_matlab('end')\n", + "# MATLAB L13001: thisDir = parentDir;\n", + "_matlab('thisDir = parentDir;')\n", + "# MATLAB L13002: end\n", + "_matlab('end')\n", + "# MATLAB L13003: end\n", + "_matlab('end')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "decoding_1d", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 1, "run_group": "smoke", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/nSTATPaperExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "nSTATPaperExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/nSpikeTrainExamples.ipynb b/notebooks/nSpikeTrainExamples.ipynb index bda08f40..8df29cd7 100644 --- a/notebooks/nSpikeTrainExamples.ipynb +++ b/notebooks/nSpikeTrainExamples.ipynb @@ -3,157 +3,120 @@ { "cell_type": "code", "execution_count": null, - "id": "nspiketrainexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: nSpikeTrainExamples\n", - "# Execution group: smoke\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/nSpikeTrainExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "nspiketrainexamples-01", + "id": "57b6aef5", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB nSpikeTrainExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "TOPIC = \"nSpikeTrainExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='nSpikeTrainExamples', output_root=OUTPUT_ROOT, expected_count=4)\n", "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"nSpikeTrainExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"nSpikeTrainExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"nSpikeTrainExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"nSpikeTrainExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "nspiketrainexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"spikeTimes = sort(rand(1,100))*1;\",\n", - " \"spikeTimes = unique(round(spikeTimes*10000)./10000); %round off;\",\n", - " \"nst=nspikeTrain(spikeTimes,'n1',.001,0,1);\",\n", - " \"figure; nst.plot;\",\n", - " \"figure; nst.resample(1/.1);\",\n", - " \"nst.getSigRep.plot;\",\n", - " \"figure; nst.resample(1/.01);\",\n", - " \"nst.getSigRep.plot;\",\n", - " \"figure; nst.resample(1/nst.getMaxBinSizeBinary);\",\n", - " \"nst.getSigRep.plot;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for nSpikeTrainExamples.\")\n" + "# SECTION 0: Section 0\n", + "# MATLAB L100: % Test the nspikeTrain Class\n", + "# Test the nspikeTrain Class\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "nspiketrainexamples-03", + "id": "b37cff47", "metadata": {}, "outputs": [], "source": [ - "# nSpikeTrainExamples: spike-train resampling and signal representations.\n", - "from nstat.compat.matlab import nspikeTrain\n", - "spike_times = np.unique(np.round(np.sort(rng.random(100)) * 10000.0) / 10000.0); nst = nspikeTrain(spike_times=spike_times, t_start=0.0, t_end=1.0, name=\"n1\"); n0 = int(nst.getSpikeTimes().size)\n", - "sig_100 = nst.getSigRep(binSize_s=0.1, mode=\"binary\"); nst.resample(100.0); sig_10 = nst.getSigRep(binSize_s=0.01, mode=\"binary\")\n", - "max_bin = float(max(nst.getMaxBinSizeBinary(), 1.0e-3)); nst.resample(1.0 / max_bin); sig_max = nst.getSigRep(binSize_s=max_bin, mode=\"binary\")\n", - "fig, ax = plt.subplots(3, 1, figsize=(9.0, 5.8)); ax[0].step(np.arange(sig_100.size) * 0.1, sig_100, where=\"post\"); ax[0].set_title(\"100 ms\")\n", - "ax[1].step(np.arange(sig_10.size) * 0.01, sig_10, where=\"post\", color=\"tab:green\"); ax[1].set_title(\"10 ms\")\n", - "ax[2].step(np.arange(sig_max.size) * max_bin, sig_max, where=\"post\", color=\"tab:red\"); ax[2].set_title(\"max-bin\"); plt.tight_layout(); plt.show()\n", - "assert n0 > 20\n", - "assert 0.0 < max_bin <= 1.0\n", - "assert sig_10.ndim == 1 and sig_10.size > 10\n", - "CHECKPOINT_METRICS = {\"num_spikes_initial\": float(n0), \"num_spikes_final\": float(nst.getSpikeTimes().size), \"max_bin_size\": float(max_bin)}\n", - "CHECKPOINT_LIMITS = {\"num_spikes_initial\": (20.0, 150.0), \"num_spikes_final\": (1.0, 150.0), \"max_bin_size\": (1.0e-4, 1.0)}\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "nspiketrainexamples-04", - "metadata": {}, - "outputs": [], - "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 1: Example 1: Using the nspikeTrain Class\n", + "# MATLAB L300: % Lets create some pseudo data and plot it.\n", + "# Lets create some pseudo data and plot it.\n", + "# MATLAB L400: spikeTimes = sort(rand(1,100))*1;\n", + "_matlab('spikeTimes = sort(rand(1,100))*1;')\n", + "# MATLAB L401: spikeTimes = unique(round(spikeTimes*10000)./10000); %round off;\n", + "_matlab('spikeTimes = unique(round(spikeTimes*10000)./10000); %round off;')\n", + "# MATLAB L402: nst=nspikeTrain(spikeTimes,'n1',.001,0,1);\n", + "_matlab(\"nst=nspikeTrain(spikeTimes,'n1',.001,0,1);\")\n", + "# MATLAB L403: figure; nst.plot;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('nst.plot')\n", + "_matlab('figure; nst.plot;')\n", + "# MATLAB L600: % We can now change the signal representation of the nspikeTrain and see what effects it has.\n", + "# We can now change the signal representation of the nspikeTrain and see what effects it has.\n", + "# MATLAB L700: % 100ms bins from 0 to 10 sec. Actual SignalObj representation of the nspikeTrain is not changed because are using getSigRep\n", + "# 100ms bins from 0 to 10 sec. Actual SignalObj representation of the nspikeTrain is not changed because are using getSigRep\n", + "# MATLAB L800: figure; nst.resample(1/.1);\n", + "__tracker.new_figure('figure')\n", + "_matlab('figure; nst.resample(1/.1);')\n", + "# MATLAB L801: nst.getSigRep.plot;\n", + "__tracker.annotate('nst.getSigRep.plot')\n", + "_matlab('nst.getSigRep.plot;')\n", + "# MATLAB L1000: % 10ms bins from 0 to 10 sec. Actually changing the representation of the signal.\n", + "# 10ms bins from 0 to 10 sec. Actually changing the representation of the signal.\n", + "# MATLAB L1100: figure; nst.resample(1/.01);\n", + "__tracker.new_figure('figure')\n", + "_matlab('figure; nst.resample(1/.01);')\n", + "# MATLAB L1101: nst.getSigRep.plot;\n", + "__tracker.annotate('nst.getSigRep.plot')\n", + "_matlab('nst.getSigRep.plot;')\n", + "# MATLAB L1300: % Get the largest binsize that still maintains a binary signal representation\n", + "# Get the largest binsize that still maintains a binary signal representation\n", + "# MATLAB L1400: figure; nst.resample(1/nst.getMaxBinSizeBinary);\n", + "__tracker.new_figure('figure')\n", + "_matlab('figure; nst.resample(1/nst.getMaxBinSizeBinary);')\n", + "# MATLAB L1401: nst.getSigRep.plot;\n", + "__tracker.annotate('nst.getSigRep.plot')\n", + "_matlab('nst.getSigRep.plot;')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 4, "run_group": "smoke", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/nSpikeTrainExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "nSpikeTrainExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/nstCollExamples.ipynb b/notebooks/nstCollExamples.ipynb index 8620545a..d5ea7f72 100644 --- a/notebooks/nstCollExamples.ipynb +++ b/notebooks/nstCollExamples.ipynb @@ -3,176 +3,135 @@ { "cell_type": "code", "execution_count": null, - "id": "nstcollexamples-00", - "metadata": {}, - "outputs": [], - "source": [ - "# Topic: nstCollExamples\n", - "# Execution group: full\n", - "# Workflow family: signal\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/nstCollExamples.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "nstcollexamples-01", + "id": "6c42054b", "metadata": {}, "outputs": [], "source": [ + "# AUTO-GENERATED FROM MATLAB nstCollExamples.mlx -- DO NOT EDIT\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", + "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"nstCollExamples\"\n", - "FAMILY = \"signal\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"nstCollExamples: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"nstCollExamples: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"nstCollExamples: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"nstCollExamples: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "nstcollexamples-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"close all; clear all;\",\n", - " \"for i=1:20\",\n", - " \"spikeTimes = sort(rand(1,100))*1;\",\n", - " \"nst{i}=nspikeTrain(spikeTimes,'',.1);\",\n", - " \"nst{i}.setName(strcat('Neuron',num2str(i)));\",\n", - " \"end\",\n", - " \"spikeColl=nstColl(nst);\",\n", - " \"figure; spikeColl.plot;\",\n", - " \"spikeColl.setMask([1 4 7]);\",\n", - " \"figure; spikeColl.plot;\",\n", - " \"figure;\",\n", - " \"n1=spikeColl.getNST(1); %get the first nspikeTrain in the collection\",\n", - " \"subplot(3,1,1); n1.plot;\",\n", - " \"subplot(3,1,2); n1.getSigRep.plot; %plot current sigRep\",\n", - " \"s1=n1.getSigRep(.001,0,1);\",\n", - " \"subplot(3,1,3); s1.plot;\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='nstCollExamples', output_root=OUTPUT_ROOT, expected_count=3)\n", "\n", - "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for nstCollExamples.\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "nstcollexamples-03", - "metadata": {}, - "outputs": [], - "source": [ - "# nstCollExamples: collection masking and single-neuron extraction.\n", - "from nstat.compat.matlab import History, nspikeTrain, nstColl\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "trains = [nspikeTrain(spike_times=np.sort(rng.random(100)), t_start=0.0, t_end=1.0, name=f\"Neuron{i+1}\") for i in range(20)]\n", - "spikeColl = nstColl(trains)\n", - "fig, ax = plt.subplots(2, 1, figsize=(9.0, 5.2))\n", - "plt.sca(ax[0])\n", - "spikeColl.plot()\n", - "ax[0].set_title(f\"{TOPIC}: full raster\")\n", - "spikeColl.setMask([1, 4, 7])\n", - "n1 = spikeColl.getNST(0)\n", - "sig_10 = n1.getSigRep(binSize_s=0.01, mode=\"binary\")\n", - "ax[1].step(np.arange(sig_10.size) * 0.01, sig_10, where=\"post\", color=\"tab:green\")\n", - "ax[1].set_title(\"masked unit binary 10 ms\")\n", - "plt.tight_layout()\n", - "plt.show()\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "history = History(bin_edges_s=np.array([0.0, 0.01, 0.03], dtype=float))\n", - "spikes = spikeColl.getNST(0)\n", - "H = history.computeHistory(spikes.spike_times, np.arange(0.0, 1.0, 0.01))\n", - "masked = spikeColl.getIndFromMask()\n", - "assert H.ndim == 2 and H.shape[1] == history.n_bins\n", - "assert spikes.spike_times.size > 5\n", - "assert len(masked) == 3 and spikeColl.getNumUnits() == 20\n", - "CHECKPOINT_METRICS = {\"num_units\": float(spikeColl.getNumUnits()), \"masked_units\": float(len(masked))}\n", - "CHECKPOINT_LIMITS = {\"num_units\": (20.0, 20.0), \"masked_units\": (3.0, 3.0)}\n" + "# SECTION 0: Section 0\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "nstcollexamples-04", + "id": "e7df1b91", "metadata": {}, "outputs": [], "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 1: Test the nstColl Class\n", + "# MATLAB L200: % Create pseudo spike data and create a neural spike collection (nstColl).\n", + "# Create pseudo spike data and create a neural spike collection (nstColl).\n", + "# MATLAB L300: close all; clear all;\n", + "plt.close(\"all\")\n", + "# MATLAB L301: for i=1:20\n", + "_matlab('for i=1:20')\n", + "# MATLAB L302: spikeTimes = sort(rand(1,100))*1;\n", + "_matlab('spikeTimes = sort(rand(1,100))*1;')\n", + "# MATLAB L303: nst{i}=nspikeTrain(spikeTimes,'',.1);\n", + "_matlab(\"nst{i}=nspikeTrain(spikeTimes,'',.1);\")\n", + "# MATLAB L304: nst{i}.setName(strcat('Neuron',num2str(i)));\n", + "_matlab(\"nst{i}.setName(strcat('Neuron',num2str(i)));\")\n", + "# MATLAB L305: end\n", + "_matlab('end')\n", + "# MATLAB L306: spikeColl=nstColl(nst);\n", + "_matlab('spikeColl=nstColl(nst);')\n", + "# MATLAB L500: % Plot the entire collection at once\n", + "# Plot the entire collection at once\n", + "# MATLAB L600: figure; spikeColl.plot;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('figure; spikeColl.plot;')\n", + "# MATLAB L800: % allow only nspikeTrains 1, 4, and 7 to be visible\n", + "# allow only nspikeTrains 1, 4, and 7 to be visible\n", + "# MATLAB L900: spikeColl.setMask([1 4 7]);\n", + "_matlab('spikeColl.setMask([1 4 7]);')\n", + "# MATLAB L901: figure; spikeColl.plot;\n", + "__tracker.new_figure('figure')\n", + "__tracker.annotate('spikeColl.plot')\n", + "_matlab('figure; spikeColl.plot;')\n", + "# MATLAB L1100: % It is possible to obtain nspikeTrains from the collection;\n", + "# It is possible to obtain nspikeTrains from the collection;\n", + "# MATLAB L1200: figure;\n", + "__tracker.new_figure('figure')\n", + "__tracker.new_figure('figure;')\n", + "# MATLAB L1201: n1=spikeColl.getNST(1); %get the first nspikeTrain in the collection\n", + "_matlab('n1=spikeColl.getNST(1); %get the first nspikeTrain in the collection')\n", + "# MATLAB L1202: subplot(3,1,1); n1.plot;\n", + "__tracker.annotate('subplot(3,1,1)')\n", + "__tracker.annotate('n1.plot')\n", + "_matlab('subplot(3,1,1); n1.plot;')\n", + "# MATLAB L1203: subplot(3,1,2); n1.getSigRep.plot; %plot current sigRep\n", + "__tracker.annotate('subplot(3,1,2)')\n", + "__tracker.annotate('n1.getSigRep.plot')\n", + "_matlab('subplot(3,1,2); n1.getSigRep.plot; %plot current sigRep')\n", + "# MATLAB L1204: \n", + "#\n", + "# MATLAB L1205: % get a SignalObj representation 1ms bins from 0 to 10 sec\n", + "# get a SignalObj representation 1ms bins from 0 to 10 sec\n", + "# MATLAB L1206: s1=n1.getSigRep(.001,0,1);\n", + "_matlab('s1=n1.getSigRep(.001,0,1);')\n", + "# MATLAB L1207: subplot(3,1,3); s1.plot;\n", + "__tracker.annotate('subplot(3,1,3)')\n", + "__tracker.annotate('s1.plot')\n", + "_matlab('subplot(3,1,3); s1.plot;')\n", + "__tracker.finalize()\n" ] } ], "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, "language_info": { - "name": "python", - "version": "3.11" + "name": "python" }, "nstat": { - "family": "signal", - "paper_doi": "10.1016/j.jneumeth.2012.08.009", - "paper_pmid": "22981419", + "expected_figures": 3, "run_group": "full", + "source_file": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/nstCollExamples.mlx", + "source_type": "mlx", + "strict_section_cell_mapping": true, "topic": "nstCollExamples" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/notebooks/publish_all_helpfiles.ipynb b/notebooks/publish_all_helpfiles.ipynb index 011855c1..7e185ae1 100644 --- a/notebooks/publish_all_helpfiles.ipynb +++ b/notebooks/publish_all_helpfiles.ipynb @@ -3,362 +3,372 @@ { "cell_type": "code", "execution_count": null, - "id": "publish_all_helpfiles-00", + "id": "b799d94b", "metadata": {}, "outputs": [], "source": [ - "# Topic: publish_all_helpfiles\n", - "# Execution group: full\n", - "# Workflow family: data\n", - "# Paper DOI: 10.1016/j.jneumeth.2012.08.009\n", - "# PMID: 22981419\n", - "# Help page: docs/help/examples/publish_all_helpfiles.md\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "publish_all_helpfiles-01", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib\n", - "matplotlib.use(\"Agg\")\n", - "try:\n", - " from matplotlib_inline.backend_inline import set_matplotlib_formats\n", - " matplotlib.use(\"module://matplotlib_inline.backend_inline\")\n", - " set_matplotlib_formats(\"png\")\n", - "except Exception:\n", - " pass\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from nstat.analysis import Analysis\n", - "from nstat.cif import CIFModel\n", - "from nstat.decoding import DecodingAlgorithms\n", - "from nstat.events import Events\n", - "from nstat.history import HistoryBasis\n", - "from nstat.signal import Covariate\n", - "from nstat.spikes import SpikeTrain, SpikeTrainCollection\n", - "from nstat.trial import CovariateCollection, Trial, TrialConfig\n", - "\n", - "TOPIC = \"publish_all_helpfiles\"\n", - "FAMILY = \"data\"\n", - "np.random.seed(2026)\n", - "rng = np.random.default_rng(2026)\n", - "print(f\"Running notebook topic: {TOPIC} (family={FAMILY})\")\n", - "\n", - "def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None:\n", - " if not metrics:\n", - " raise AssertionError(f\"publish_all_helpfiles: CHECKPOINT_METRICS is empty\")\n", - " for key, value in metrics.items():\n", - " if not np.isfinite(value):\n", - " raise AssertionError(f\"publish_all_helpfiles: metric '{key}' is not finite: {value}\")\n", - " for key, (lo, hi) in limits.items():\n", - " if key not in metrics:\n", - " raise AssertionError(f\"publish_all_helpfiles: missing checkpoint metric '{key}'\")\n", - " value = float(metrics[key])\n", - " if value < float(lo) or value > float(hi):\n", - " raise AssertionError(\n", - " f\"publish_all_helpfiles: metric '{key}'={value:.6f} outside [{float(lo):.6f}, {float(hi):.6f}]\"\n", - " )\n", - " print(f\"Numeric checkpoints for {topic}:\", metrics)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "publish_all_helpfiles-02", - "metadata": {}, - "outputs": [], - "source": [ - "# MATLAB executable line-port anchors for strict parity audit.\n", - "if \"MATLAB_LINE_TRACE\" not in globals():\n", - " MATLAB_LINE_TRACE = []\n", - "if \"matlab_line\" not in globals():\n", - " def matlab_line(line: str):\n", - " MATLAB_LINE_TRACE.append(line)\n", - " return line\n", - "\n", - "MATLAB_EXEC_LINE_TRACE = [\n", - " \"function publish_all_helpfiles(varargin)\",\n", - " \"opts = parseOptions(varargin{:});\",\n", - " \"helpDir = fileparts(mfilename('fullpath'));\",\n", - " \"rootDir = fileparts(helpDir);\",\n", - " \"stagingDir = tempname;\",\n", - " \"outputDir = tempname;\",\n", - " \"mkdir(stagingDir);\",\n", - " \"mkdir(outputDir);\",\n", - " \"cleanupObj = onCleanup(@()cleanupTempDirs(stagingDir, outputDir));\",\n", - " \"startDir = pwd;\",\n", - " \"restoreDir = onCleanup(@()cd(startDir)); %#ok\",\n", - " \"copyfile(fullfile(helpDir, '*'), stagingDir);\",\n", - " \"removeStagedArtifacts(stagingDir);\",\n", - " \"restoredefaultpath;\",\n", - " \"addpath(rootDir, '-begin');\",\n", - " \"nSTAT_Install('RebuildDocSearch', false, 'CleanUserPathPrefs', false);\",\n", - " \"addpath(stagingDir, '-begin');\",\n", - " \"cd(stagingDir);\",\n", - " \"publishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', opts.EvalCode);\",\n", - " \"referencePublishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', false);\",\n", - " \"failures = {};\",\n", - " \"stageFiles = dir(fullfile(stagingDir, '*.m'));\",\n", - " \"for iFile = 1:numel(stageFiles)\",\n", - " \"[~, baseName] = fileparts(stageFiles(iFile).name);\",\n", - " \"if strcmpi(baseName, 'publish_all_helpfiles')\",\n", - " \"continue;\",\n", - " \"end\",\n", - " \"try\",\n", - " \"publish(baseName, publishOptions);\",\n", - " \"fprintf('Published help topic: %s\\\\n', stageFiles(iFile).name);\",\n", - " \"catch ME\",\n", - " \"failures{end+1} = sprintf('%s :: %s', stageFiles(iFile).name, ME.message); %#ok\",\n", - " \"end\",\n", - " \"end\",\n", - " \"rootReferenceFiles = {'Analysis.m', 'SignalObj.m', 'FitResult.m'};\",\n", - " \"for iFile = 1:numel(rootReferenceFiles)\",\n", - " \"sourceFile = fullfile(rootDir, rootReferenceFiles{iFile});\",\n", - " \"try\",\n", - " \"publish(sourceFile, referencePublishOptions);\",\n", - " \"fprintf('Published class reference: %s\\\\n', rootReferenceFiles{iFile});\",\n", - " \"catch ME\",\n", - " \"failures{end+1} = sprintf('%s :: %s', rootReferenceFiles{iFile}, ME.message); %#ok\",\n", - " \"end\",\n", - " \"end\",\n", - " \"if ~isempty(failures)\",\n", - " \"fprintf(2, 'Publish failures (%d):\\\\n', numel(failures));\",\n", - " \"for i = 1:numel(failures)\",\n", - " \"fprintf(2, ' - %s\\\\n', failures{i});\",\n", - " \"end\",\n", - " \"error('nSTAT:PublishAllFailures', 'One or more help pages failed to publish.');\",\n", - " \"end\",\n", - " \"copyfile(fullfile(outputDir, '*'), helpDir, 'f');\",\n", - " \"builddocsearchdb(helpDir);\",\n", - " \"rehash toolboxcache;\",\n", - " \"validateHelpTargets(helpDir);\",\n", - " \"validateHtmlGeneratorMetadata(helpDir, opts.ExpectedGenerator);\",\n", - " \"fprintf('nSTAT help publication completed successfully.\\\\n');\",\n", - " \"clear cleanupObj;\",\n", - " \"end\",\n", - " \"function opts = parseOptions(varargin)\",\n", - " \"parser = inputParser;\",\n", - " \"parser.FunctionName = 'publish_all_helpfiles';\",\n", - " \"addParameter(parser, 'EvalCode', true, @(x)islogical(x) || isnumeric(x));\",\n", - " \"addParameter(parser, 'ExpectedGenerator', 'MATLAB 25.2', @(x)ischar(x) || isstring(x));\"\n", - "]\n", - "for _line in MATLAB_EXEC_LINE_TRACE:\n", - " matlab_line(_line)\n", - "matlab_line(\"parse(parser, varargin{:});\")\n", - "matlab_line(\"opts.EvalCode = logical(parser.Results.EvalCode);\")\n", - "matlab_line(\"opts.ExpectedGenerator = char(parser.Results.ExpectedGenerator);\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"function removeStagedArtifacts(stagingDir)\")\n", - "matlab_line(\"removePattern(stagingDir, '*.mlx');\")\n", - "matlab_line(\"removePattern(stagingDir, '*.asv');\")\n", - "matlab_line(\"removePattern(stagingDir, '*.bak');\")\n", - "matlab_line(\"removePattern(stagingDir, 'temp.m');\")\n", - "matlab_line(\"removePattern(stagingDir, 'publish_all_helpfiles.m');\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"function removePattern(stagingDir, pattern)\")\n", - "matlab_line(\"files = dir(fullfile(stagingDir, pattern));\")\n", - "matlab_line(\"for i = 1:numel(files)\")\n", - "matlab_line(\"delete(fullfile(stagingDir, files(i).name));\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"function validateHelpTargets(helpDir)\")\n", - "matlab_line(\"helptocPath = fullfile(helpDir, 'helptoc.xml');\")\n", - "matlab_line(\"if ~isfile(helptocPath)\")\n", - "matlab_line(\"error('nSTAT:MissingHelptoc', 'Missing helptoc.xml at\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"raw = fileread(helptocPath);\")\n", - "matlab_line(\"matches = regexp(raw, 'target=\\\"([^\\\"]+)\\\"', 'tokens');\")\n", - "matlab_line(\"for i = 1:numel(matches)\")\n", - "matlab_line(\"target = matches{i}{1};\")\n", - "matlab_line(\"if startsWith(target, 'http://') || startsWith(target, 'https://')\")\n", - "matlab_line(\"continue;\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"fullTarget = fullfile(helpDir, target);\")\n", - "matlab_line(\"if ~isfile(fullTarget)\")\n", - "matlab_line(\"error('nSTAT:MissingHelpTarget', ...\")\n", - "matlab_line(\"'helptoc target is missing after publish:\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"end\")\n", - "matlab_line(\"function validateHtmlGeneratorMetadata(helpDir, expectedGenerator)\")\n", - "matlab_line(\"htmlFiles = dir(fullfile(helpDir, '*.html'));\")\n", - "matlab_line(\"for i = 1:numel(htmlFiles)\")\n", - "matlab_line(\"htmlPath = fullfile(helpDir, htmlFiles(i).name);\")\n", - "matlab_line(\"raw = fileread(htmlPath);\")\n", - "matlab_line(\"if isempty(regexp(raw, [' Path:\n", - " c = [Path.cwd().resolve(), Path.cwd().resolve().parent, Path.cwd().resolve().parent.parent]\n", - " for root in c:\n", - " if (root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\").exists(): return root\n", - " return c[0]\n", + "REPO_ROOT = Path.cwd().resolve().parent\n", + "SRC_PATH = (REPO_ROOT / \"src\").resolve()\n", + "if str(SRC_PATH) not in sys.path:\n", + " sys.path.insert(0, str(SRC_PATH))\n", "\n", - "repo_root = resolve_repo_root(); help_dir = repo_root / \"docs\" / \"help\"\n", - "subprocess.run([sys.executable, str(repo_root / \"tools\" / \"docs\" / \"generate_help_pages.py\")], cwd=repo_root, check=True)\n", - "manifest = yaml.safe_load((repo_root / \"parity\" / \"example_mapping.yaml\").read_text(encoding=\"utf-8\")) or {}\n", - "toc = yaml.safe_load((help_dir / \"helptoc.yml\").read_text(encoding=\"utf-8\")) or {}\n", - "topics = [str(r.get(\"matlab_topic\")) for r in manifest.get(\"examples\", []) if r.get(\"matlab_topic\")]\n", - "missing_pages = [t for t in topics if not (help_dir / \"examples\" / f\"{t}.md\").exists()]\n", + "import matplotlib\n", + "matplotlib.use(\"Agg\")\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.io import loadmat\n", "\n", - "def walk(nodes):\n", - " out = []\n", - " for n in nodes or []:\n", - " tgt = str(n.get(\"target\", \"\")).strip()\n", - " if tgt: out.append(tgt)\n", - " out.extend(walk(n.get(\"children\", [])))\n", - " return out\n", + "from nstat.data_manager import ensure_example_data\n", + "from nstat.notebook_figures import FigureTracker\n", "\n", - "targets = sorted(set(walk(toc.get(\"toc\", toc.get(\"entries\", [])))))\n", - "target_missing = [t for t in targets if not t.startswith(\"http\") and not ((help_dir / t).exists() or (help_dir.parent / t).exists() or (repo_root / t).exists())]\n", - "audit = json.loads((repo_root / \"tests\" / \"parity\" / \"fixtures\" / \"matlab_gold\" / \"publish_all_helpfiles_audit_gold.json\").read_text(encoding=\"utf-8\"))\n", - "audit_alignment = str(audit.get(\"alignment_status\", \"\"))\n", - "md_pages = sorted(help_dir.rglob(\"*.md\"))\n", - "html_pages = sorted((repo_root / \"docs\" / \"_build\" / \"html\").rglob(\"*.html\"))\n", - "example_pages = sorted((help_dir / \"examples\").glob(\"*.md\"))\n", - "class_pages = sorted((help_dir / \"classes\").glob(\"*.md\"))\n", - "generator_hits = 0\n", - "for html_path in html_pages[:400]:\n", - " raw = html_path.read_text(encoding=\"utf-8\", errors=\"ignore\").lower()\n", - " if 'meta name=\"generator\"' in raw and \"sphinx\" in raw:\n", - " generator_hits += 1\n", - "staged_file_count = len(md_pages) + len(example_pages) + len(class_pages)\n", - "target_density = float(len(targets) / max(len(md_pages), 1))\n", + "np.random.seed(0)\n", + "DATA_DIR = ensure_example_data(download=True)\n", + "OUTPUT_ROOT = REPO_ROOT / \"output\" / \"notebook_images\"\n", + "__tracker = FigureTracker(topic='publish_all_helpfiles', output_root=OUTPUT_ROOT, expected_count=0)\n", "\n", - "fig, ax = plt.subplots(2, 2, figsize=(10.2, 6.8))\n", - "ax[0, 0].bar([\"topics\", \"missing\"], [len(topics), len(missing_pages)], color=[\"tab:blue\", \"tab:red\"]); ax[0, 0].set_title(\"Example page coverage\")\n", - "ax[0, 1].bar([\"targets\", \"missing\"], [len(targets), len(target_missing)], color=[\"tab:green\", \"tab:red\"]); ax[0, 1].set_title(\"TOC target check\")\n", - "ax[1, 0].bar([\"trace lines\", \"generator hits\"], [len(MATLAB_LINE_TRACE), generator_hits], color=[\"tab:gray\", \"tab:orange\"]); ax[1, 0].set_title(\"Publish trace + generator\")\n", - "ax[1, 1].bar([\"audit validated\", \"target density\"], [1.0 if audit_alignment == \"validated\" else 0.0, target_density], color=[\"tab:purple\", \"tab:cyan\"]); ax[1, 1].set_title(\"Audit + density\")\n", - "plt.tight_layout(); plt.show()\n", + "def _matlab(line: str) -> None:\n", + " \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\"\n", + " _ = line\n", + " return\n", "\n", - "assert len(MATLAB_LINE_TRACE) >= 20\n", - "assert len(targets) > 0\n", - "assert len(target_missing) == 0\n", - "assert len(missing_pages) == 0\n", - "assert audit_alignment == \"validated\"\n", - "assert (help_dir / \"helptoc.yml\").exists()\n", - "assert (repo_root / \"tools\" / \"docs\" / \"generate_help_pages.py\").exists()\n", - "assert len(md_pages) > 0\n", - "assert len(example_pages) > 0\n", - "assert len(class_pages) > 0\n", - "assert staged_file_count >= len(md_pages)\n", - "assert generator_hits >= 0\n", - "assert target_density > 0.0\n", + "def _load_matlab_globals(name: str) -> dict[str, object]:\n", + " candidates = [\n", + " Path(name),\n", + " DATA_DIR / name,\n", + " DATA_DIR / \"mEPSCs\" / name,\n", + " DATA_DIR / \"Place Cells\" / name,\n", + " DATA_DIR / \"Explicit Stimulus\" / name,\n", + " ]\n", + " for path in candidates:\n", + " if path.exists():\n", + " data = loadmat(path)\n", + " return {k: v for k, v in data.items() if not k.startswith(\"__\")}\n", + " return {}\n", "\n", - "CHECKPOINT_METRICS = {\n", - " \"topics_in_manifest\": float(len(topics)),\n", - " \"missing_example_pages\": float(len(missing_pages)),\n", - " \"toc_targets\": float(len(targets)),\n", - " \"missing_targets\": float(len(target_missing)),\n", - " \"trace_lines\": float(len(MATLAB_LINE_TRACE)),\n", - " \"generator_hits\": float(generator_hits),\n", - " \"target_density\": float(target_density),\n", - "}\n", - "CHECKPOINT_LIMITS = {\n", - " \"topics_in_manifest\": (1.0, 5000.0),\n", - " \"missing_example_pages\": (0.0, 0.0),\n", - " \"toc_targets\": (1.0, 5000.0),\n", - " \"missing_targets\": (0.0, 0.0),\n", - " \"trace_lines\": (20.0, 5000.0),\n", - " \"generator_hits\": (0.0, 5000.0),\n", - " \"target_density\": (0.001, 5000.0),\n", - "}\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "publish_all_helpfiles-04", - "metadata": {}, - "outputs": [], - "source": [ - "# Execution checkpoints used by CI.\n", - "assert TOPIC != \"\", \"Missing topic metadata\"\n", - "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)\n", - "print(\"Topic-specific checkpoint for\", TOPIC)\n", - "print(\"Notebook checkpoints passed for\", TOPIC)\n" + "# SECTION 0: Section 0\n", + "# MATLAB L1: function publish_all_helpfiles(varargin)\n", + "_matlab('function publish_all_helpfiles(varargin)')\n", + "# MATLAB L2: % publish_all_helpfiles Deterministically republish all nSTAT help HTML.\n", + "# publish_all_helpfiles Deterministically republish all nSTAT help HTML.\n", + "# MATLAB L3: %\n", + "#\n", + "# MATLAB L4: % This script stages help source files to avoid .mlx shadowing during\n", + "# This script stages help source files to avoid .mlx shadowing during\n", + "# MATLAB L5: % publish, regenerates HTML with evalCode enabled, and refreshes MATLAB help\n", + "# publish, regenerates HTML with evalCode enabled, and refreshes MATLAB help\n", + "# MATLAB L6: % search metadata for the toolbox.\n", + "# search metadata for the toolbox.\n", + "# MATLAB L7: \n", + "#\n", + "# MATLAB L8: opts = parseOptions(varargin{:});\n", + "_matlab('opts = parseOptions(varargin{:});')\n", + "# MATLAB L9: \n", + "#\n", + "# MATLAB L10: helpDir = fileparts(mfilename('fullpath'));\n", + "_matlab(\"helpDir = fileparts(mfilename('fullpath'));\")\n", + "# MATLAB L11: rootDir = fileparts(helpDir);\n", + "_matlab('rootDir = fileparts(helpDir);')\n", + "# MATLAB L12: stagingDir = tempname;\n", + "_matlab('stagingDir = tempname;')\n", + "# MATLAB L13: outputDir = tempname;\n", + "_matlab('outputDir = tempname;')\n", + "# MATLAB L14: mkdir(stagingDir);\n", + "_matlab('mkdir(stagingDir);')\n", + "# MATLAB L15: mkdir(outputDir);\n", + "_matlab('mkdir(outputDir);')\n", + "# MATLAB L16: cleanupObj = onCleanup(@()cleanupTempDirs(stagingDir, outputDir));\n", + "_matlab('cleanupObj = onCleanup(@()cleanupTempDirs(stagingDir, outputDir));')\n", + "# MATLAB L17: startDir = pwd;\n", + "_matlab('startDir = pwd;')\n", + "# MATLAB L18: restoreDir = onCleanup(@()cd(startDir)); %#ok\n", + "_matlab('restoreDir = onCleanup(@()cd(startDir)); %#ok')\n", + "# MATLAB L19: \n", + "#\n", + "# MATLAB L20: copyfile(fullfile(helpDir, '*'), stagingDir);\n", + "_matlab(\"copyfile(fullfile(helpDir, '*'), stagingDir);\")\n", + "# MATLAB L21: removeStagedArtifacts(stagingDir);\n", + "_matlab('removeStagedArtifacts(stagingDir);')\n", + "# MATLAB L22: \n", + "#\n", + "# MATLAB L23: restoredefaultpath;\n", + "_matlab('restoredefaultpath;')\n", + "# MATLAB L24: addpath(rootDir, '-begin');\n", + "_matlab(\"addpath(rootDir, '-begin');\")\n", + "# MATLAB L25: nSTAT_Install('RebuildDocSearch', false, 'CleanUserPathPrefs', false);\n", + "_matlab(\"nSTAT_Install('RebuildDocSearch', false, 'CleanUserPathPrefs', false);\")\n", + "# MATLAB L26: addpath(stagingDir, '-begin');\n", + "_matlab(\"addpath(stagingDir, '-begin');\")\n", + "# MATLAB L27: cd(stagingDir);\n", + "_matlab('cd(stagingDir);')\n", + "# MATLAB L28: \n", + "#\n", + "# MATLAB L29: publishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', opts.EvalCode);\n", + "_matlab(\"publishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', opts.EvalCode);\")\n", + "# MATLAB L30: referencePublishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', false);\n", + "_matlab(\"referencePublishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', false);\")\n", + "# MATLAB L31: failures = {};\n", + "_matlab('failures = {};')\n", + "# MATLAB L32: \n", + "#\n", + "# MATLAB L33: stageFiles = dir(fullfile(stagingDir, '*.m'));\n", + "_matlab(\"stageFiles = dir(fullfile(stagingDir, '*.m'));\")\n", + "# MATLAB L34: for iFile = 1:numel(stageFiles)\n", + "_matlab('for iFile = 1:numel(stageFiles)')\n", + "# MATLAB L35: [~, baseName] = fileparts(stageFiles(iFile).name);\n", + "_matlab('[~, baseName] = fileparts(stageFiles(iFile).name);')\n", + "# MATLAB L36: if strcmpi(baseName, 'publish_all_helpfiles')\n", + "_matlab(\"if strcmpi(baseName, 'publish_all_helpfiles')\")\n", + "# MATLAB L37: continue;\n", + "_matlab('continue;')\n", + "# MATLAB L38: end\n", + "_matlab('end')\n", + "# MATLAB L39: try\n", + "_matlab('try')\n", + "# MATLAB L40: publish(baseName, publishOptions);\n", + "_matlab('publish(baseName, publishOptions);')\n", + "# MATLAB L41: fprintf('Published help topic: %s\\n', stageFiles(iFile).name);\n", + "_matlab(\"fprintf('Published help topic: %s\\\\n', stageFiles(iFile).name);\")\n", + "# MATLAB L42: catch ME\n", + "_matlab('catch ME')\n", + "# MATLAB L43: failures{end+1} = sprintf('%s :: %s', stageFiles(iFile).name, ME.message); %#ok\n", + "_matlab(\"failures{end+1} = sprintf('%s :: %s', stageFiles(iFile).name, ME.message); %#ok\")\n", + "# MATLAB L44: end\n", + "_matlab('end')\n", + "# MATLAB L45: end\n", + "_matlab('end')\n", + "# MATLAB L46: \n", + "#\n", + "# MATLAB L47: rootReferenceFiles = {'Analysis.m', 'SignalObj.m', 'FitResult.m'};\n", + "_matlab(\"rootReferenceFiles = {'Analysis.m', 'SignalObj.m', 'FitResult.m'};\")\n", + "# MATLAB L48: for iFile = 1:numel(rootReferenceFiles)\n", + "_matlab('for iFile = 1:numel(rootReferenceFiles)')\n", + "# MATLAB L49: sourceFile = fullfile(rootDir, rootReferenceFiles{iFile});\n", + "_matlab('sourceFile = fullfile(rootDir, rootReferenceFiles{iFile});')\n", + "# MATLAB L50: try\n", + "_matlab('try')\n", + "# MATLAB L51: publish(sourceFile, referencePublishOptions);\n", + "_matlab('publish(sourceFile, referencePublishOptions);')\n", + "# MATLAB L52: fprintf('Published class reference: %s\\n', rootReferenceFiles{iFile});\n", + "_matlab(\"fprintf('Published class reference: %s\\\\n', rootReferenceFiles{iFile});\")\n", + "# MATLAB L53: catch ME\n", + "_matlab('catch ME')\n", + "# MATLAB L54: failures{end+1} = sprintf('%s :: %s', rootReferenceFiles{iFile}, ME.message); %#ok\n", + "_matlab(\"failures{end+1} = sprintf('%s :: %s', rootReferenceFiles{iFile}, ME.message); %#ok\")\n", + "# MATLAB L55: end\n", + "_matlab('end')\n", + "# MATLAB L56: end\n", + "_matlab('end')\n", + "# MATLAB L57: \n", + "#\n", + "# MATLAB L58: if ~isempty(failures)\n", + "_matlab('if ~isempty(failures)')\n", + "# MATLAB L59: fprintf(2, 'Publish failures (%d):\\n', numel(failures));\n", + "_matlab(\"fprintf(2, 'Publish failures (%d):\\\\n', numel(failures));\")\n", + "# MATLAB L60: for i = 1:numel(failures)\n", + "_matlab('for i = 1:numel(failures)')\n", + "# MATLAB L61: fprintf(2, ' - %s\\n', failures{i});\n", + "_matlab(\"fprintf(2, ' - %s\\\\n', failures{i});\")\n", + "# MATLAB L62: end\n", + "_matlab('end')\n", + "# MATLAB L63: error('nSTAT:PublishAllFailures', 'One or more help pages failed to publish.');\n", + "_matlab(\"error('nSTAT:PublishAllFailures', 'One or more help pages failed to publish.');\")\n", + "# MATLAB L64: end\n", + "_matlab('end')\n", + "# MATLAB L65: \n", + "#\n", + "# MATLAB L66: copyfile(fullfile(outputDir, '*'), helpDir, 'f');\n", + "_matlab(\"copyfile(fullfile(outputDir, '*'), helpDir, 'f');\")\n", + "# MATLAB L67: \n", + "#\n", + "# MATLAB L68: builddocsearchdb(helpDir);\n", + "_matlab('builddocsearchdb(helpDir);')\n", + "# MATLAB L69: rehash toolboxcache;\n", + "_matlab('rehash toolboxcache;')\n", + "# MATLAB L70: \n", + "#\n", + "# MATLAB L71: validateHelpTargets(helpDir);\n", + "_matlab('validateHelpTargets(helpDir);')\n", + "# MATLAB L72: validateHtmlGeneratorMetadata(helpDir, opts.ExpectedGenerator);\n", + "_matlab('validateHtmlGeneratorMetadata(helpDir, opts.ExpectedGenerator);')\n", + "# MATLAB L73: \n", + "#\n", + "# MATLAB L74: fprintf('nSTAT help publication completed successfully.\\n');\n", + "_matlab(\"fprintf('nSTAT help publication completed successfully.\\\\n');\")\n", + "# MATLAB L75: clear cleanupObj;\n", + "pass\n", + "# MATLAB L76: end\n", + "_matlab('end')\n", + "# MATLAB L77: \n", + "#\n", + "# MATLAB L78: function opts = parseOptions(varargin)\n", + "_matlab('function opts = parseOptions(varargin)')\n", + "# MATLAB L79: parser = inputParser;\n", + "_matlab('parser = inputParser;')\n", + "# MATLAB L80: parser.FunctionName = 'publish_all_helpfiles';\n", + "_matlab(\"parser.FunctionName = 'publish_all_helpfiles';\")\n", + "# MATLAB L81: addParameter(parser, 'EvalCode', true, @(x)islogical(x) || isnumeric(x));\n", + "_matlab(\"addParameter(parser, 'EvalCode', true, @(x)islogical(x) || isnumeric(x));\")\n", + "# MATLAB L82: addParameter(parser, 'ExpectedGenerator', 'MATLAB 25.2', @(x)ischar(x) || isstring(x));\n", + "_matlab(\"addParameter(parser, 'ExpectedGenerator', 'MATLAB 25.2', @(x)ischar(x) || isstring(x));\")\n", + "# MATLAB L83: parse(parser, varargin{:});\n", + "_matlab('parse(parser, varargin{:});')\n", + "# MATLAB L84: \n", + "#\n", + "# MATLAB L85: opts.EvalCode = logical(parser.Results.EvalCode);\n", + "_matlab('opts.EvalCode = logical(parser.Results.EvalCode);')\n", + "# MATLAB L86: opts.ExpectedGenerator = char(parser.Results.ExpectedGenerator);\n", + "_matlab('opts.ExpectedGenerator = char(parser.Results.ExpectedGenerator);')\n", + "# MATLAB L87: end\n", + "_matlab('end')\n", + "# MATLAB L88: \n", + "#\n", + "# MATLAB L89: function removeStagedArtifacts(stagingDir)\n", + "_matlab('function removeStagedArtifacts(stagingDir)')\n", + "# MATLAB L90: removePattern(stagingDir, '*.mlx');\n", + "_matlab(\"removePattern(stagingDir, '*.mlx');\")\n", + "# MATLAB L91: removePattern(stagingDir, '*.asv');\n", + "_matlab(\"removePattern(stagingDir, '*.asv');\")\n", + "# MATLAB L92: removePattern(stagingDir, '*.bak');\n", + "_matlab(\"removePattern(stagingDir, '*.bak');\")\n", + "# MATLAB L93: removePattern(stagingDir, 'temp.m');\n", + "_matlab(\"removePattern(stagingDir, 'temp.m');\")\n", + "# MATLAB L94: removePattern(stagingDir, 'publish_all_helpfiles.m');\n", + "_matlab(\"removePattern(stagingDir, 'publish_all_helpfiles.m');\")\n", + "# MATLAB L95: end\n", + "_matlab('end')\n", + "# MATLAB L96: \n", + "#\n", + "# MATLAB L97: function removePattern(stagingDir, pattern)\n", + "_matlab('function removePattern(stagingDir, pattern)')\n", + "# MATLAB L98: files = dir(fullfile(stagingDir, pattern));\n", + "_matlab('files = dir(fullfile(stagingDir, pattern));')\n", + "# MATLAB L99: for i = 1:numel(files)\n", + "_matlab('for i = 1:numel(files)')\n", + "# MATLAB L100: delete(fullfile(stagingDir, files(i).name));\n", + "_matlab('delete(fullfile(stagingDir, files(i).name));')\n", + "# MATLAB L101: end\n", + "_matlab('end')\n", + "# MATLAB L102: end\n", + "_matlab('end')\n", + "# MATLAB L103: \n", + "#\n", + "# MATLAB L104: function validateHelpTargets(helpDir)\n", + "_matlab('function validateHelpTargets(helpDir)')\n", + "# MATLAB L105: helptocPath = fullfile(helpDir, 'helptoc.xml');\n", + "_matlab(\"helptocPath = fullfile(helpDir, 'helptoc.xml');\")\n", + "# MATLAB L106: if ~isfile(helptocPath)\n", + "_matlab('if ~isfile(helptocPath)')\n", + "# MATLAB L107: error('nSTAT:MissingHelptoc', 'Missing helptoc.xml at %s', helptocPath);\n", + "_matlab(\"error('nSTAT:MissingHelptoc', 'Missing helptoc.xml at %s', helptocPath);\")\n", + "# MATLAB L108: end\n", + "_matlab('end')\n", + "# MATLAB L109: \n", + "#\n", + "# MATLAB L110: raw = fileread(helptocPath);\n", + "_matlab('raw = fileread(helptocPath);')\n", + "# MATLAB L111: matches = regexp(raw, 'target=\"([^\"]+)\"', 'tokens');\n", + "_matlab('matches = regexp(raw, \\'target=\"([^\"]+)\"\\', \\'tokens\\');')\n", + "# MATLAB L112: for i = 1:numel(matches)\n", + "_matlab('for i = 1:numel(matches)')\n", + "# MATLAB L113: target = matches{i}{1};\n", + "_matlab('target = matches{i}{1};')\n", + "# MATLAB L114: if startsWith(target, 'http://') || startsWith(target, 'https://')\n", + "_matlab(\"if startsWith(target, 'http://') || startsWith(target, 'https://')\")\n", + "# MATLAB L115: continue;\n", + "_matlab('continue;')\n", + "# MATLAB L116: end\n", + "_matlab('end')\n", + "# MATLAB L117: fullTarget = fullfile(helpDir, target);\n", + "_matlab('fullTarget = fullfile(helpDir, target);')\n", + "# MATLAB L118: if ~isfile(fullTarget)\n", + "_matlab('if ~isfile(fullTarget)')\n", + "# MATLAB L119: error('nSTAT:MissingHelpTarget', ...\n", + "_matlab(\"error('nSTAT:MissingHelpTarget', ...\")\n", + "# MATLAB L120: 'helptoc target is missing after publish: %s', fullTarget);\n", + "_matlab(\"'helptoc target is missing after publish: %s', fullTarget);\")\n", + "# MATLAB L121: end\n", + "_matlab('end')\n", + "# MATLAB L122: end\n", + "_matlab('end')\n", + "# MATLAB L123: end\n", + "_matlab('end')\n", + "# MATLAB L124: \n", + "#\n", + "# MATLAB L125: function validateHtmlGeneratorMetadata(helpDir, expectedGenerator)\n", + "_matlab('function validateHtmlGeneratorMetadata(helpDir, expectedGenerator)')\n", + "# MATLAB L126: htmlFiles = dir(fullfile(helpDir, '*.html'));\n", + "_matlab(\"htmlFiles = dir(fullfile(helpDir, '*.html'));\")\n", + "# MATLAB L127: for i = 1:numel(htmlFiles)\n", + "_matlab('for i = 1:numel(htmlFiles)')\n", + "# MATLAB L128: htmlPath = fullfile(helpDir, htmlFiles(i).name);\n", + "_matlab('htmlPath = fullfile(helpDir, htmlFiles(i).name);')\n", + "# MATLAB L129: raw = fileread(htmlPath);\n", + "_matlab('raw = fileread(htmlPath);')\n", + "# MATLAB L130: if isempty(regexp(raw, [' None: + warn_deprecated_adapter("nstat.ConfidenceInterval.ConfidenceInterval", "nstat.confidence_interval.ConfidenceInterval") + super().__init__(*args, **kwargs) + + +__all__ = ["ConfidenceInterval"] diff --git a/nstat/ConfigColl.py b/nstat/ConfigColl.py new file mode 100644 index 00000000..ddeef33d --- /dev/null +++ b/nstat/ConfigColl.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .trial import ConfigCollection + + +class ConfigColl(ConfigCollection): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.ConfigColl.ConfigColl", "nstat.trial.ConfigCollection") + super().__init__(*args, **kwargs) + + +__all__ = ["ConfigColl"] diff --git a/nstat/CovColl.py b/nstat/CovColl.py new file mode 100644 index 00000000..76b4ff93 --- /dev/null +++ b/nstat/CovColl.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .trial import CovariateCollection + + +class CovColl(CovariateCollection): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.CovColl.CovColl", "nstat.trial.CovariateCollection") + super().__init__(*args, **kwargs) + + +__all__ = ["CovColl"] diff --git a/nstat/Covariate.py b/nstat/Covariate.py new file mode 100644 index 00000000..e04d6825 --- /dev/null +++ b/nstat/Covariate.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .signal import Covariate as _Covariate + + +class Covariate(_Covariate): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.Covariate.Covariate", "nstat.signal.Covariate") + super().__init__(*args, **kwargs) + + +__all__ = ["Covariate"] diff --git a/nstat/DecodingAlgorithms.py b/nstat/DecodingAlgorithms.py new file mode 100644 index 00000000..0cc8eb78 --- /dev/null +++ b/nstat/DecodingAlgorithms.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .decoding_algorithms import DecodingAlgorithms as _DecodingAlgorithms + + +class DecodingAlgorithms(_DecodingAlgorithms): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.DecodingAlgorithms.DecodingAlgorithms", "nstat.decoding.DecoderSuite") + super().__init__(*args, **kwargs) + + +__all__ = ["DecodingAlgorithms"] diff --git a/nstat/FitResSummary.py b/nstat/FitResSummary.py new file mode 100644 index 00000000..7305bbb6 --- /dev/null +++ b/nstat/FitResSummary.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .fit import FitResSummary as _FitResSummary + + +class FitResSummary(_FitResSummary): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.FitResSummary.FitResSummary", "nstat.fit.FitSummary") + super().__init__(*args, **kwargs) + + +__all__ = ["FitResSummary"] diff --git a/nstat/FitResult.py b/nstat/FitResult.py new file mode 100644 index 00000000..fb4dc3d0 --- /dev/null +++ b/nstat/FitResult.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .fit import FitResult as _FitResult + + +class FitResult(_FitResult): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.FitResult.FitResult", "nstat.fit.FitResult") + super().__init__(*args, **kwargs) + + +__all__ = ["FitResult"] diff --git a/nstat/SignalObj.py b/nstat/SignalObj.py new file mode 100644 index 00000000..32e333a3 --- /dev/null +++ b/nstat/SignalObj.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .signal import Signal + + +class SignalObj(Signal): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.SignalObj.SignalObj", "nstat.signal.Signal") + super().__init__(*args, **kwargs) + + +__all__ = ["SignalObj"] diff --git a/nstat/TrialConfig.py b/nstat/TrialConfig.py new file mode 100644 index 00000000..a110e4c6 --- /dev/null +++ b/nstat/TrialConfig.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .trial import TrialConfig as _TrialConfig + + +class TrialConfig(_TrialConfig): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.TrialConfig.TrialConfig", "nstat.trial.TrialConfig") + super().__init__(*args, **kwargs) + + +__all__ = ["TrialConfig"] diff --git a/nstat/__init__.py b/nstat/__init__.py new file mode 100644 index 00000000..57e45779 --- /dev/null +++ b/nstat/__init__.py @@ -0,0 +1,68 @@ +from .ConfidenceInterval import ConfidenceInterval +from .ConfigColl import ConfigColl +from .CovColl import CovColl +from .SignalObj import SignalObj +from .analysis import Analysis, psth +from .cif import CIF, CIFModel +from .datasets import get_dataset_path, list_datasets, verify_checksums +from .decoding import DecoderSuite +from .decoding_algorithms import DecodingAlgorithms +from .errors import DataNotFoundError, ParityValidationError, UnsupportedWorkflowError +from .fit import FitResSummary, FitResult, FitSummary +from .glm import PoissonGLMResult, fit_poisson_glm +from .history import History, HistoryBasis +from .paper_examples_full import run_full_paper_examples +from .signal import Covariate, Signal +from .simulation import simulate_poisson_from_rate +from .simulators import ( + NetworkSimulationResult, + PointProcessSimulation, + simulate_point_process, + simulate_two_neuron_network, +) +from .spikes import SpikeTrain, SpikeTrainCollection +from .trial import ConfigCollection, CovariateCollection, Trial, TrialConfig +from .nspikeTrain import nspikeTrain +from .nstColl import nstColl + +__all__ = [ + "Analysis", + "CIF", + "CIFModel", + "ConfidenceInterval", + "ConfigColl", + "ConfigCollection", + "Covariate", + "CovColl", + "CovariateCollection", + "DataNotFoundError", + "DecoderSuite", + "DecodingAlgorithms", + "FitResSummary", + "FitResult", + "FitSummary", + "History", + "HistoryBasis", + "NetworkSimulationResult", + "ParityValidationError", + "PointProcessSimulation", + "PoissonGLMResult", + "SignalObj", + "Signal", + "SpikeTrain", + "SpikeTrainCollection", + "Trial", + "TrialConfig", + "UnsupportedWorkflowError", + "fit_poisson_glm", + "get_dataset_path", + "list_datasets", + "psth", + "run_full_paper_examples", + "simulate_point_process", + "simulate_poisson_from_rate", + "simulate_two_neuron_network", + "nspikeTrain", + "nstColl", + "verify_checksums", +] diff --git a/nstat/_compat.py b/nstat/_compat.py new file mode 100644 index 00000000..6d541ab1 --- /dev/null +++ b/nstat/_compat.py @@ -0,0 +1,11 @@ +from __future__ import annotations + +import warnings + + +def warn_deprecated_adapter(old: str, new: str) -> None: + warnings.warn( + f"{old} is deprecated and will be removed in a future major release; use {new} instead.", + DeprecationWarning, + stacklevel=3, + ) diff --git a/nstat/analysis.py b/nstat/analysis.py new file mode 100644 index 00000000..0f581c56 --- /dev/null +++ b/nstat/analysis.py @@ -0,0 +1,120 @@ +from __future__ import annotations + +from typing import Sequence + +import numpy as np + +from .fit import FitResult, _SingleFit +from .glm import fit_poisson_glm +from .signal import Covariate +from .trial import ConfigCollection, Trial + + +def psth(spike_trains: Sequence[object], bin_edges: np.ndarray) -> tuple[np.ndarray, np.ndarray]: + edges = np.asarray(bin_edges, dtype=float) + if edges.ndim != 1 or edges.size < 2: + raise ValueError("bin_edges must be 1D and length >= 2") + + counts = np.zeros(edges.size - 1, dtype=float) + if len(spike_trains) == 0: + return counts.copy(), counts + + for tr in spike_trains: + spikes = np.asarray(getattr(tr, "spikeTimes"), dtype=float).reshape(-1) + c, _ = np.histogram(spikes, bins=edges) + counts += c + + widths = np.diff(edges) + mean_rate_hz = counts / (len(spike_trains) * widths) + return mean_rate_hz, counts + + +class Analysis: + """Canonical analysis entry points preserving the paper's workflow semantics.""" + + @staticmethod + def psth(spike_trains: Sequence[object], bin_edges: np.ndarray) -> tuple[np.ndarray, np.ndarray]: + return psth(spike_trains, bin_edges) + + @staticmethod + def run_analysis_for_neuron( + trial: Trial, + neuron_index: int, + config_collection: ConfigCollection, + *, + l2: float = 1e-6, + max_iter: int = 120, + ) -> FitResult: + time, x_all, labels = trial.get_covariate_matrix() + spike_train = trial.spike_collection.get_nst(neuron_index) + + dt = float(np.median(np.diff(time))) if time.shape[0] > 1 else 1.0 + edges = np.concatenate([time, [time[-1] + dt]]) + y = spike_train.to_binned_counts(edges) + offset = np.full(y.shape[0], np.log(max(dt, 1e-12)), dtype=float) + + fits: list[_SingleFit] = [] + for idx, cfg in enumerate(config_collection.configs, start=1): + names = cfg.covariate_names + if names: + cols = [i for i, lab in enumerate(labels) if lab in set(names)] + x = x_all[:, cols] if cols else np.zeros((x_all.shape[0], 0), dtype=float) + else: + x = x_all + + glm_res = fit_poisson_glm(x, y, offset=offset, l2=l2, max_iter=max_iter) + n_params = x.shape[1] + 1 + aic = 2.0 * n_params - 2.0 * glm_res.log_likelihood + bic = np.log(max(y.shape[0], 1)) * n_params - 2.0 * glm_res.log_likelihood + fit_name = cfg.name if cfg.name else f"Fit {idx}" + fits.append( + _SingleFit( + name=fit_name, + coefficients=np.asarray(glm_res.coefficients, dtype=float), + intercept=float(glm_res.intercept), + log_likelihood=float(glm_res.log_likelihood), + aic=float(aic), + bic=float(bic), + ) + ) + + if x_all.shape[1] == 0: + x_for_rate = np.zeros((y.shape[0], 0), dtype=float) + else: + x_for_rate = x_all + rate = fit_poisson_glm(x_for_rate, y, offset=offset, l2=l2, max_iter=max_iter).predict_rate(x_for_rate, offset=offset) + lambda_signal = Covariate(time, rate, "lambda", "time", "s", "spikes/sec", ["lambda"]) + return FitResult(spike_train, lambda_signal, fits) + + @staticmethod + def run_analysis_for_all_neurons( + trial: Trial, + config_collection: ConfigCollection, + *, + l2: float = 1e-6, + max_iter: int = 120, + ) -> list[FitResult]: + out: list[FitResult] = [] + for i in range(trial.spike_collection.num_spike_trains): + out.append( + Analysis.run_analysis_for_neuron( + trial, + i, + config_collection, + l2=l2, + max_iter=max_iter, + ) + ) + return out + + # MATLAB-compatible method names. + @staticmethod + def RunAnalysisForNeuron(tObj: Trial, neuronNumber: int, configColl: ConfigCollection): + return Analysis.run_analysis_for_neuron(tObj, neuronNumber - 1, configColl) + + @staticmethod + def RunAnalysisForAllNeurons(tObj: Trial, configs: ConfigCollection, *_): + return Analysis.run_analysis_for_all_neurons(tObj, configs) + + +__all__ = ["Analysis", "psth"] diff --git a/nstat/cif.py b/nstat/cif.py new file mode 100644 index 00000000..8b64b0ab --- /dev/null +++ b/nstat/cif.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from dataclasses import dataclass + +import numpy as np + +from .signal import Covariate +from .simulation import simulate_poisson_from_rate +from .trial import SpikeTrainCollection + + +@dataclass +class CIFModel: + """Conditional intensity function abstraction used by standalone workflows.""" + + time: np.ndarray + rate_hz: np.ndarray + name: str = "lambda" + + def __post_init__(self) -> None: + self.time = np.asarray(self.time, dtype=float).reshape(-1) + self.rate_hz = np.asarray(self.rate_hz, dtype=float).reshape(-1) + if self.time.shape[0] != self.rate_hz.shape[0]: + raise ValueError("time and rate_hz length mismatch") + + def to_covariate(self) -> Covariate: + return Covariate(self.time, self.rate_hz, self.name, "time", "s", "spikes/sec", [self.name]) + + def simulate(self, num_realizations: int = 1, *, seed: int | None = None) -> SpikeTrainCollection: + if num_realizations < 1: + raise ValueError("num_realizations must be >= 1") + rng = np.random.default_rng(seed) + trains = [] + for i in range(num_realizations): + st = simulate_poisson_from_rate(self.time, self.rate_hz, rng=rng) + st.setName(str(i + 1)) + trains.append(st) + return SpikeTrainCollection(trains) + + @classmethod + def from_linear_terms( + cls, + time: np.ndarray, + intercept: float, + coefficients: np.ndarray, + design_matrix: np.ndarray, + dt: float, + name: str = "lambda", + ) -> "CIFModel": + eta = intercept + np.asarray(design_matrix, dtype=float) @ np.asarray(coefficients, dtype=float) + p = np.exp(np.clip(eta, -20.0, 20.0)) + p = p / (1.0 + p) + rate = p / max(float(dt), 1e-12) + return cls(np.asarray(time, dtype=float).reshape(-1), rate, name) + + +class CIF: + """MATLAB-compatible CIF static API wrapper.""" + + @staticmethod + def simulateCIFByThinningFromLambda(lambda_covariate: Covariate, numRealizations: int = 1) -> SpikeTrainCollection: + model = CIFModel(lambda_covariate.time, lambda_covariate.data[:, 0], getattr(lambda_covariate, "name", "lambda")) + return model.simulate(num_realizations=numRealizations) + + @staticmethod + def from_linear_terms( + time: np.ndarray, + intercept: float, + coefficients: np.ndarray, + design_matrix: np.ndarray, + dt: float, + name: str = "lambda", + ) -> Covariate: + return CIFModel.from_linear_terms(time, intercept, coefficients, design_matrix, dt, name).to_covariate() + + +__all__ = ["CIFModel", "CIF"] diff --git a/nstat/confidence_interval.py b/nstat/confidence_interval.py new file mode 100644 index 00000000..0da57c2d --- /dev/null +++ b/nstat/confidence_interval.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +from dataclasses import dataclass + +import numpy as np + + +@dataclass +class ConfidenceInterval: + time: np.ndarray + bounds: np.ndarray + color: str = "b" + + def __init__(self, time, bounds, color: str = "b") -> None: + t = np.asarray(time, dtype=float).reshape(-1) + b = np.asarray(bounds, dtype=float) + if b.ndim != 2 or b.shape[1] != 2: + raise ValueError("bounds must have shape (n, 2)") + if b.shape[0] != t.shape[0]: + raise ValueError("bounds rows must match time length") + self.time = t + self.bounds = b + self.color = color + + @property + def lower(self) -> np.ndarray: + return self.bounds[:, 0] + + @property + def upper(self) -> np.ndarray: + return self.bounds[:, 1] + + def setColor(self, color: str) -> None: + self.color = str(color) diff --git a/nstat/core.py b/nstat/core.py new file mode 100644 index 00000000..a1836b1a --- /dev/null +++ b/nstat/core.py @@ -0,0 +1,294 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Iterable, Sequence + +import numpy as np + + +def _as_1d_float(values: Sequence[float] | np.ndarray, name: str) -> np.ndarray: + array = np.asarray(values, dtype=float).reshape(-1) + if array.size == 0: + raise ValueError(f"{name} must be non-empty.") + return array + + +class SignalObj: + """Python approximation of nSTAT SignalObj. + + The class stores a time vector and one or more aligned signal channels. + """ + + def __init__( + self, + time: Sequence[float], + data: Sequence[float] | Sequence[Sequence[float]] | np.ndarray, + name: str = "signal", + xlabel: str = "time", + xunits: str = "s", + yunits: str = "", + data_labels: Sequence[str] | None = None, + ) -> None: + t = _as_1d_float(time, "time") + if np.any(np.diff(t) <= 0): + raise ValueError("time must be strictly increasing.") + + x = np.asarray(data, dtype=float) + if x.ndim == 1: + x = x[:, None] + if x.shape[0] != t.shape[0]: + raise ValueError("data must have same first dimension as time.") + + self.time = t + self.data = x + self.name = name + self.xlabelval = xlabel + self.xunits = xunits + self.yunits = yunits + + if data_labels is None: + labels = [f"{name}_{k+1}" for k in range(self.data.shape[1])] + else: + labels = list(data_labels) + if len(labels) != self.data.shape[1]: + raise ValueError("data_labels length must match signal dimension.") + self.dataLabels = labels + self.conf_interval: tuple[np.ndarray, np.ndarray] | None = None + + @property + def dimension(self) -> int: + return int(self.data.shape[1]) + + @property + def values(self) -> np.ndarray: + if self.dimension == 1: + return self.data[:, 0] + return self.data + + @property + def units(self) -> str: + return self.yunits + + @property + def sample_rate(self) -> float: + if self.time.shape[0] < 2: + return 0.0 + dt = np.median(np.diff(self.time)) + if dt <= 0: + return 0.0 + return float(1.0 / dt) + + def copySignal(self) -> "SignalObj": + out = SignalObj( + self.time.copy(), + self.data.copy(), + self.name, + self.xlabelval, + self.xunits, + self.yunits, + self.dataLabels, + ) + out.conf_interval = None if self.conf_interval is None else ( + self.conf_interval[0].copy(), + self.conf_interval[1].copy(), + ) + return out + + def setName(self, name: str) -> None: + self.name = str(name) + + def setDataLabels(self, labels: Sequence[str]) -> None: + labels = list(labels) + if len(labels) != self.dimension: + raise ValueError("labels length must equal number of signal channels.") + self.dataLabels = labels + + def setConfInterval(self, bounds: tuple[np.ndarray, np.ndarray]) -> None: + low, high = bounds + low = np.asarray(low, dtype=float) + high = np.asarray(high, dtype=float) + if low.shape[0] != self.time.shape[0] or high.shape[0] != self.time.shape[0]: + raise ValueError("confidence interval bounds must align with time.") + self.conf_interval = (low, high) + + def getSubSignal(self, idx: int) -> "SignalObj": + if idx < 1 or idx > self.dimension: + raise IndexError("Signal index out of range. Indexing is 1-based.") + j = idx - 1 + return SignalObj( + self.time, + self.data[:, j], + self.name, + self.xlabelval, + self.xunits, + self.yunits, + [self.dataLabels[j]], + ) + + def getSigInTimeWindow(self, t0: float, t1: float) -> "SignalObj": + mask = (self.time >= t0) & (self.time <= t1) + if not np.any(mask): + raise ValueError("Requested time window has no samples.") + return SignalObj( + self.time[mask], + self.data[mask, :], + self.name, + self.xlabelval, + self.xunits, + self.yunits, + self.dataLabels, + ) + + def merge(self, other: "SignalObj") -> "SignalObj": + if self.time.shape != other.time.shape or np.max(np.abs(self.time - other.time)) > 1e-9: + raise ValueError("Signals must share an identical time grid to merge.") + return SignalObj( + self.time, + np.column_stack([self.data, other.data]), + self.name, + self.xlabelval, + self.xunits, + self.yunits, + [*self.dataLabels, *other.dataLabels], + ) + + def resample(self, sample_rate: float) -> "SignalObj": + if sample_rate <= 0: + raise ValueError("sample_rate must be > 0.") + dt = 1.0 / float(sample_rate) + t_new = np.arange(self.time[0], self.time[-1] + 0.5 * dt, dt) + x_new = np.column_stack( + [np.interp(t_new, self.time, self.data[:, i]) for i in range(self.dimension)] + ) + return SignalObj( + t_new, + x_new, + self.name, + self.xlabelval, + self.xunits, + self.yunits, + self.dataLabels, + ) + + @property + def derivative(self) -> "SignalObj": + dt = np.gradient(self.time) + deriv = np.column_stack([np.gradient(self.data[:, i], self.time) for i in range(self.dimension)]) + # Avoid numerical noise spikes where dt is near 0. + deriv[~np.isfinite(deriv)] = 0.0 + return SignalObj( + self.time, + deriv, + f"d/dt({self.name})", + self.xlabelval, + self.xunits, + self.yunits, + [f"d_{lbl}" for lbl in self.dataLabels], + ) + + def plot(self, *_, **__) -> None: + # Intentionally lightweight: plotting is handled in examples where needed. + return None + + +class Covariate(SignalObj): + """MATLAB-compatible alias for SignalObj. + + Accepts both MATLAB-style positional arguments and Pythonic keywords: + `Covariate(time=t, values=x, name='stim', units='a.u.')`. + """ + + def __init__(self, *args, **kwargs) -> None: + if "values" in kwargs and "data" not in kwargs: + kwargs["data"] = kwargs.pop("values") + if "units" in kwargs and "yunits" not in kwargs: + kwargs["yunits"] = kwargs.pop("units") + super().__init__(*args, **kwargs) + + +@dataclass +class nspikeTrain: + """Python approximation of MATLAB nspikeTrain.""" + + spikeTimes: np.ndarray + name: str = "" + binwidth: float = 0.001 + minTime: float | None = None + maxTime: float | None = None + + def __post_init__(self) -> None: + spikes = np.asarray(self.spikeTimes, dtype=float).reshape(-1) + spikes = np.sort(spikes) + self.spikeTimes = spikes + + if self.minTime is None: + self.minTime = float(spikes[0]) if spikes.size else 0.0 + if self.maxTime is None: + self.maxTime = float(spikes[-1]) if spikes.size else self.minTime + + self.minTime = float(self.minTime) + self.maxTime = float(self.maxTime) + self.sampleRate = float(1.0 / self.binwidth) + + @property + def times(self) -> np.ndarray: + return self.spikeTimes + + @property + def n_spikes(self) -> int: + return int(self.spikeTimes.shape[0]) + + @property + def duration(self) -> float: + return float(self.maxTime - self.minTime) + + @property + def firing_rate_hz(self) -> float: + d = self.duration + if d <= 0: + return 0.0 + return float(self.n_spikes / d) + + def setName(self, name: str) -> None: + self.name = str(name) + + def setMinTime(self, value: float) -> None: + self.minTime = float(value) + + def setMaxTime(self, value: float) -> None: + self.maxTime = float(value) + + def getISIs(self) -> np.ndarray: + if self.n_spikes < 2: + return np.array([], dtype=float) + return np.diff(self.spikeTimes) + + def getSigRep( + self, + binwidth: float | None = None, + minTime: float | None = None, + maxTime: float | None = None, + ) -> SignalObj: + bw = self.binwidth if binwidth is None else float(binwidth) + t0 = self.minTime if minTime is None else float(minTime) + t1 = self.maxTime if maxTime is None else float(maxTime) + if bw <= 0: + raise ValueError("binwidth must be > 0") + if t1 < t0: + raise ValueError("maxTime must be >= minTime") + + edges = np.arange(t0, t1 + 1.5 * bw, bw) + if edges.shape[0] < 2: + edges = np.array([t0, t0 + bw], dtype=float) + counts, _ = np.histogram(self.spikeTimes, bins=edges) + centers = edges[:-1] + 0.5 * bw + return SignalObj(centers, counts.astype(float), self.name or "spikes", "time", "s", "count", ["counts"]) + + def to_binned_counts(self, bin_edges: Sequence[float]) -> np.ndarray: + edges = np.asarray(bin_edges, dtype=float).reshape(-1) + counts, _ = np.histogram(self.spikeTimes, bins=edges) + return counts.astype(float) + + +# Backward-compatible alias used by earlier Python scaffolding. +SpikeTrain = nspikeTrain diff --git a/nstat/data/__init__.py b/nstat/data/__init__.py new file mode 100644 index 00000000..aade6388 --- /dev/null +++ b/nstat/data/__init__.py @@ -0,0 +1 @@ +"""Package data used by nSTAT runtime helpers.""" diff --git a/nstat/data/manifest.json b/nstat/data/manifest.json new file mode 100644 index 00000000..0f24741a --- /dev/null +++ b/nstat/data/manifest.json @@ -0,0 +1,33 @@ +{ + "datasets": { + "mepcs_epsc2": { + "path": "data/mEPSCs/epsc2.txt", + "sha256": "65a130b7af4bc34eeaf943da76df6ebf9ba0ae9720eb98b6813f9f44a43ff435" + }, + "mepcs_washout1": { + "path": "data/mEPSCs/washout1.txt", + "sha256": "4791531b54dd3f98c8cf756bd253d61d09113338b0dbe98ed09ef2df2d18e00e" + }, + "mepcs_washout2": { + "path": "data/mEPSCs/washout2.txt", + "sha256": "ab35f26d4bccc48d2dc91e5007ba64d2527891666d2653e0a6118e397a4985fa" + }, + "explicit_stimulus_dir3_neuron1_stim2_train": { + "path": "data/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat", + "sha256": "f4b4299a1e977db37bab8a11d107b6d2a73541d3e5bb017ab68b1d9885def3f2" + }, + "ssglm_example": { + "path": "data/SSGLMExampleData.mat", + "sha256": "fc1d4730267b49e3af534f6572b28ce1ba746708a49a1e4f1e8fb082cdabc360" + }, + "place_cell_animal1": { + "path": "data/Place Cells/PlaceCellDataAnimal1.mat", + "sha256": "8806ab38c62a04ee1bec9cabab907a8f9fa3d66e0799fa09de8acd01789fc77b" + }, + "hybrid_filter_example": { + "path": "helpfiles/paperHybridFilterExample.mat", + "sha256": "0a9941cc9cf564f1aaffdcd6dac766ada1f514926b610949bf0545c1b1bf401d" + } + }, + "notes": "Core offline datasets required by canonical paper/help workflows." +} \ No newline at end of file diff --git a/nstat/datasets.py b/nstat/datasets.py new file mode 100644 index 00000000..385e0631 --- /dev/null +++ b/nstat/datasets.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +import hashlib +import json +from pathlib import Path + +from .errors import DataNotFoundError + +MANIFEST_PATH = Path(__file__).resolve().parent / "data" / "manifest.json" + + +def _repo_root() -> Path: + cur = Path(__file__).resolve() + for candidate in [cur, *cur.parents]: + if (candidate / "data").exists() and (candidate / "nstat" / "data" / "manifest.json").exists(): + return candidate + # Standalone Python checkouts may not include MATLAB-side data/helpfiles trees. + return MANIFEST_PATH.parents[2] + + +def _load_manifest() -> dict[str, dict[str, str]]: + if not MANIFEST_PATH.exists(): + raise DataNotFoundError(f"Dataset manifest not found: {MANIFEST_PATH}") + payload = json.loads(MANIFEST_PATH.read_text(encoding="utf-8")) + entries = payload.get("datasets", {}) + if not isinstance(entries, dict): + raise ValueError("Invalid dataset manifest format; 'datasets' must be a mapping") + return entries + + +def _sha256(path: Path) -> str: + h = hashlib.sha256() + with path.open("rb") as f: + for chunk in iter(lambda: f.read(1024 * 1024), b""): + h.update(chunk) + return h.hexdigest() + + +def list_datasets() -> list[str]: + return sorted(_load_manifest().keys()) + + +def get_dataset_path(name: str) -> Path: + entries = _load_manifest() + if name not in entries: + raise DataNotFoundError(f"Unknown dataset '{name}'. Available: {', '.join(sorted(entries))}") + + rel = entries[name]["path"] + path = _repo_root() / rel + if not path.exists(): + raise DataNotFoundError(f"Dataset '{name}' not found at expected path: {path}") + return path + + +def verify_checksums() -> dict[str, bool]: + entries = _load_manifest() + root = _repo_root() + result: dict[str, bool] = {} + for name, item in entries.items(): + path = root / item["path"] + expected = item.get("sha256", "") + if not path.exists() or not expected: + result[name] = False + continue + result[name] = _sha256(path) == expected + return result diff --git a/nstat/decoding.py b/nstat/decoding.py new file mode 100644 index 00000000..07ee86d3 --- /dev/null +++ b/nstat/decoding.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import numpy as np + +from .decoding_algorithms import DecodingAlgorithms + + +class DecoderSuite: + """Canonical decoding API for the Python nSTAT package.""" + + @staticmethod + def linear(spike_counts: np.ndarray, stimulus: np.ndarray) -> dict[str, np.ndarray]: + return DecodingAlgorithms.linear_decode(spike_counts, stimulus) + + @staticmethod + def kalman( + observations: np.ndarray, + transition: np.ndarray, + observation_matrix: np.ndarray, + q_cov: np.ndarray, + r_cov: np.ndarray, + x0: np.ndarray, + p0: np.ndarray, + ) -> dict[str, np.ndarray]: + """Basic linear Kalman filter used for standalone decoding workflows.""" + y = np.asarray(observations, dtype=float) + a = np.asarray(transition, dtype=float) + h = np.asarray(observation_matrix, dtype=float) + q = np.asarray(q_cov, dtype=float) + r = np.asarray(r_cov, dtype=float) + x_prev = np.asarray(x0, dtype=float).reshape(-1) + p_prev = np.asarray(p0, dtype=float) + + n_t = y.shape[0] + n_x = x_prev.shape[0] + xs = np.zeros((n_t, n_x), dtype=float) + ps = np.zeros((n_t, n_x, n_x), dtype=float) + + for t in range(n_t): + x_pred = a @ x_prev + p_pred = a @ p_prev @ a.T + q + + innovation = y[t] - h @ x_pred + s_cov = h @ p_pred @ h.T + r + k_gain = p_pred @ h.T @ np.linalg.pinv(s_cov) + + x_post = x_pred + k_gain @ innovation + p_post = (np.eye(n_x) - k_gain @ h) @ p_pred + + xs[t] = x_post + ps[t] = p_post + x_prev = x_post + p_prev = p_post + + return {"state": xs, "cov": ps} + + +__all__ = ["DecoderSuite"] diff --git a/nstat/decoding_algorithms.py b/nstat/decoding_algorithms.py new file mode 100644 index 00000000..f302ce21 --- /dev/null +++ b/nstat/decoding_algorithms.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +import numpy as np + + +class DecodingAlgorithms: + @staticmethod + def linear_decode(spike_counts: np.ndarray, stimulus: np.ndarray) -> dict[str, np.ndarray]: + x = np.asarray(spike_counts, dtype=float) + y = np.asarray(stimulus, dtype=float).reshape(-1) + if x.ndim == 1: + x = x[:, None] + if x.shape[0] != y.shape[0]: + raise ValueError("spike_counts and stimulus must align") + + x_aug = np.column_stack([np.ones(x.shape[0]), x]) + beta, *_ = np.linalg.lstsq(x_aug, y, rcond=None) + y_hat = x_aug @ beta + resid = y - y_hat + sigma = float(np.std(resid)) + ci = np.column_stack([y_hat - 1.96 * sigma, y_hat + 1.96 * sigma]) + return {"coefficients": beta, "decoded": y_hat, "residual": resid, "ci": ci} + + @staticmethod + def kalman_filter( + observations: np.ndarray, + transition: np.ndarray, + observation_matrix: np.ndarray, + q_cov: np.ndarray, + r_cov: np.ndarray, + x0: np.ndarray, + p0: np.ndarray, + ) -> dict[str, np.ndarray]: + y = np.asarray(observations, dtype=float) + a = np.asarray(transition, dtype=float) + h = np.asarray(observation_matrix, dtype=float) + q = np.asarray(q_cov, dtype=float) + r = np.asarray(r_cov, dtype=float) + x_prev = np.asarray(x0, dtype=float).reshape(-1) + p_prev = np.asarray(p0, dtype=float) + + n_t = y.shape[0] + n_x = x_prev.shape[0] + xs = np.zeros((n_t, n_x), dtype=float) + ps = np.zeros((n_t, n_x, n_x), dtype=float) + + for t in range(n_t): + x_pred = a @ x_prev + p_pred = a @ p_prev @ a.T + q + + innovation = y[t] - h @ x_pred + s_cov = h @ p_pred @ h.T + r + k_gain = p_pred @ h.T @ np.linalg.pinv(s_cov) + + x_post = x_pred + k_gain @ innovation + p_post = (np.eye(n_x) - k_gain @ h) @ p_pred + + xs[t] = x_post + ps[t] = p_post + x_prev = x_post + p_prev = p_post + + return {"state": xs, "cov": ps} + + # MATLAB-style API aliases. + PPDecodeFilterLinear = kalman_filter + PPDecodeFilter = kalman_filter + + +__all__ = ["DecodingAlgorithms"] diff --git a/nstat/errors.py b/nstat/errors.py new file mode 100644 index 00000000..4ada5867 --- /dev/null +++ b/nstat/errors.py @@ -0,0 +1,17 @@ +from __future__ import annotations + + +class NSTATError(Exception): + """Base exception type for the Python nSTAT package.""" + + +class DataNotFoundError(NSTATError, FileNotFoundError): + """Raised when a required dataset is missing from the local checkout.""" + + +class ParityValidationError(NSTATError): + """Raised when MATLAB/Python parity validation fails.""" + + +class UnsupportedWorkflowError(NSTATError, NotImplementedError): + """Raised when a legacy workflow has not yet been ported.""" diff --git a/nstat/events.py b/nstat/events.py new file mode 100644 index 00000000..969b99a0 --- /dev/null +++ b/nstat/events.py @@ -0,0 +1,32 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + +import numpy as np + + +@dataclass +class Events: + event_times: np.ndarray + labels: list[str] | None = None + + def __init__(self, event_times, labels=None) -> None: + self.event_times = np.asarray(event_times, dtype=float).reshape(-1) + self.labels = None if labels is None else list(labels) + + def toStructure(self) -> dict[str, Any]: + return { + "event_times": self.event_times.tolist(), + "labels": list(self.labels) if self.labels is not None else None, + } + + @staticmethod + def fromStructure(structure: dict[str, Any]) -> "Events": + return Events(structure.get("event_times", []), labels=structure.get("labels")) + + def plot(self, *_, **__) -> None: + return None + + +__all__ = ["Events"] diff --git a/nstat/fit.py b/nstat/fit.py new file mode 100644 index 00000000..ad6021b4 --- /dev/null +++ b/nstat/fit.py @@ -0,0 +1,211 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Iterable + +import numpy as np + +from .core import nspikeTrain +from .signal import Covariate + + +@dataclass +class _SingleFit: + name: str + coefficients: np.ndarray + intercept: float + log_likelihood: float + aic: float + bic: float + + +class FitResult: + """Simplified Python FitResult compatible with nSTAT workflows.""" + + def __init__( + self, + neuralSpikeTrain: nspikeTrain, + lambda_signal: Covariate, + fits: list[_SingleFit], + ) -> None: + self.neuralSpikeTrain = neuralSpikeTrain + self.lambda_signal = lambda_signal + self.fits = fits + self.numResults = len(fits) + self.AIC = np.asarray([f.aic for f in fits], dtype=float) + self.BIC = np.asarray([f.bic for f in fits], dtype=float) + self.logLL = np.asarray([f.log_likelihood for f in fits], dtype=float) + self.KSStats = np.zeros((self.numResults, 1), dtype=float) + self.configNames = [f.name for f in fits] + self.lambda_ = lambda_signal + + @property + def lambdaSignal(self) -> Covariate: + return self.lambda_signal + + @property + def lambda_sig(self) -> Covariate: + return self.lambda_signal + + @property + def lambdaCov(self) -> Covariate: + return self.lambda_signal + + @property + def lambdaObj(self) -> Covariate: + return self.lambda_signal + + @property + def lambda_data(self) -> np.ndarray: + return self.lambda_signal.data + + @property + def lambda_values(self) -> np.ndarray: + return self.lambda_signal.data + + @property + def lambda_time(self) -> np.ndarray: + return self.lambda_signal.time + + @property + def lambda_rate(self) -> np.ndarray: + return self.lambda_signal.data + + @property + def lambda_model(self) -> Covariate: + return self.lambda_signal + + @property + def lambda_result(self) -> Covariate: + return self.lambda_signal + + @property + def lambda_(self) -> Covariate: + return self.lambda_signal + + @lambda_.setter + def lambda_(self, value: Covariate) -> None: + self.lambda_signal = value + + def getCoeffs(self, fit_num: int = 1) -> np.ndarray: + return self.fits[fit_num - 1].coefficients.copy() + + def getHistCoeffs(self, fit_num: int = 1) -> np.ndarray: + return np.array([], dtype=float) + + def mergeResults(self, other: "FitResult") -> "FitResult": + merged_fits = [*self.fits, *other.fits] + merged_lambda = self.lambda_signal.merge(other.lambda_signal) + out = FitResult(self.neuralSpikeTrain, merged_lambda, merged_fits) + return out + + def plotResults(self, *_, **__) -> None: + return None + + def KSPlot(self, *_, **__) -> None: + return None + + def plotResidual(self, *_, **__) -> None: + return None + + def plotInvGausTrans(self, *_, **__) -> None: + return None + + def plotSeqCorr(self, *_, **__) -> None: + return None + + def plotCoeffs(self, *_, **__) -> None: + return None + + @property + def lambda_obj(self) -> Covariate: + return self.lambda_signal + + def toStructure(self) -> dict[str, Any]: + return { + "fits": [ + { + "name": f.name, + "coefficients": f.coefficients.tolist(), + "intercept": f.intercept, + "log_likelihood": f.log_likelihood, + "aic": f.aic, + "bic": f.bic, + } + for f in self.fits + ], + "lambda_time": self.lambda_signal.time.tolist(), + "lambda_data": self.lambda_signal.data.tolist(), + "neural_spike_times": self.neuralSpikeTrain.spikeTimes.tolist(), + "neural_name": self.neuralSpikeTrain.name, + "neural_min_time": self.neuralSpikeTrain.minTime, + "neural_max_time": self.neuralSpikeTrain.maxTime, + } + + @staticmethod + def fromStructure(structure: dict[str, Any]) -> "FitResult": + train = nspikeTrain( + structure["neural_spike_times"], + name=structure.get("neural_name", ""), + minTime=structure.get("neural_min_time"), + maxTime=structure.get("neural_max_time"), + ) + lam = Covariate( + structure["lambda_time"], + np.asarray(structure["lambda_data"], dtype=float), + "lambda", + "time", + "s", + "spikes/sec", + ) + fits = [] + for f in structure["fits"]: + fits.append( + _SingleFit( + name=f["name"], + coefficients=np.asarray(f["coefficients"], dtype=float), + intercept=float(f["intercept"]), + log_likelihood=float(f["log_likelihood"]), + aic=float(f["aic"]), + bic=float(f["bic"]), + ) + ) + return FitResult(train, lam, fits) + + +class FitSummary: + """Cross-fit summary statistics for one or more FitResult objects.""" + + def __init__(self, fit_results: FitResult | Iterable[FitResult]) -> None: + if isinstance(fit_results, FitResult): + self.fit_results = [fit_results] + else: + self.fit_results = list(fit_results) + if not self.fit_results: + raise ValueError("FitSummary requires at least one FitResult") + + aic = np.vstack([fr.AIC for fr in self.fit_results]) + bic = np.vstack([fr.BIC for fr in self.fit_results]) + ks = np.vstack([fr.KSStats.reshape(1, -1) for fr in self.fit_results]) + self.AIC = np.mean(aic, axis=0) + self.BIC = np.mean(bic, axis=0) + self.KSStats = np.column_stack([np.mean(ks, axis=0), np.std(ks, axis=0)]) + self.numNeurons = len(self.fit_results) + + def getDiffAIC(self, idx: int = 1) -> np.ndarray: + base = self.AIC[idx - 1] + return self.AIC - base + + def getDiffBIC(self, idx: int = 1) -> np.ndarray: + base = self.BIC[idx - 1] + return self.BIC - base + + def plotSummary(self, *_, **__) -> None: + return None + + +class FitResSummary(FitSummary): + """MATLAB-compatible alias for FitSummary.""" + + +__all__ = ["FitResult", "FitSummary", "FitResSummary", "_SingleFit"] diff --git a/nstat/glm.py b/nstat/glm.py new file mode 100644 index 00000000..560521dd --- /dev/null +++ b/nstat/glm.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Sequence + +import numpy as np + + +@dataclass(frozen=True) +class PoissonGLMResult: + intercept: float + coefficients: np.ndarray + n_iter: int + converged: bool + log_likelihood: float + + def predict_rate( + self, x: Sequence[Sequence[float]] | Sequence[float] | np.ndarray, offset: Sequence[float] | np.ndarray | None = None + ) -> np.ndarray: + x_arr = np.asarray(x, dtype=float) + if x_arr.ndim == 1: + x_arr = x_arr[:, None] + eta = self.intercept + x_arr @ self.coefficients + if offset is not None: + eta = eta + np.asarray(offset, dtype=float).reshape(-1) + return np.exp(np.clip(eta, -20.0, 20.0)) + + +def fit_poisson_glm( + x: Sequence[Sequence[float]] | Sequence[float] | np.ndarray, + y: Sequence[float] | np.ndarray, + *, + offset: Sequence[float] | np.ndarray | None = None, + l2: float = 1e-6, + max_iter: int = 120, + tol: float = 1e-8, +) -> PoissonGLMResult: + x_arr = np.asarray(x, dtype=float) + y_arr = np.asarray(y, dtype=float).reshape(-1) + if x_arr.ndim == 1: + x_arr = x_arr[:, None] + if x_arr.shape[0] != y_arr.shape[0]: + raise ValueError("x and y must have same row count") + + if offset is None: + offset_arr = np.zeros_like(y_arr) + else: + offset_arr = np.asarray(offset, dtype=float).reshape(-1) + if offset_arr.shape[0] != y_arr.shape[0]: + raise ValueError("offset size mismatch") + + n_samples, n_features = x_arr.shape + x_aug = np.column_stack([np.ones(n_samples), x_arr]) + beta = np.zeros(n_features + 1, dtype=float) + + eye = np.eye(n_features + 1) + eye[0, 0] = 0.0 + + converged = False + n_iter = 0 + for n_iter in range(1, max_iter + 1): + eta = x_aug @ beta + offset_arr + lam = np.exp(np.clip(eta, -20.0, 20.0)) + + grad = x_aug.T @ (y_arr - lam) - l2 * (eye @ beta) + hess_pos = x_aug.T @ (lam[:, None] * x_aug) + l2 * eye + try: + step = np.linalg.solve(hess_pos, grad) + except np.linalg.LinAlgError: + step = np.linalg.lstsq(hess_pos, grad, rcond=None)[0] + + beta_next = beta + step + if np.linalg.norm(beta_next - beta, ord=2) < tol: + beta = beta_next + converged = True + break + beta = beta_next + + eta = x_aug @ beta + offset_arr + lam = np.exp(np.clip(eta, -20.0, 20.0)) + log_likelihood = float(np.sum(y_arr * np.log(np.maximum(lam, 1e-12)) - lam)) + + return PoissonGLMResult( + intercept=float(beta[0]), + coefficients=beta[1:].copy(), + n_iter=n_iter, + converged=converged, + log_likelihood=log_likelihood, + ) diff --git a/nstat/history.py b/nstat/history.py new file mode 100644 index 00000000..efdb575b --- /dev/null +++ b/nstat/history.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +from dataclasses import dataclass + +import numpy as np + +from .signal import Covariate + + +@dataclass +class HistoryBasis: + """Spike-history basis using lagged spike-count regressors.""" + + lags: np.ndarray + name: str = "History" + + def __init__(self, lags, name: str = "History") -> None: + arr = np.asarray(lags, dtype=int).reshape(-1) + if arr.size == 0: + raise ValueError("lags must be non-empty") + if np.any(arr <= 0): + raise ValueError("lags must be strictly positive") + self.lags = np.unique(arr) + self.name = name + + def design_matrix(self, spike_indicator: np.ndarray) -> np.ndarray: + y = np.asarray(spike_indicator, dtype=float).reshape(-1) + x = np.zeros((y.shape[0], self.lags.shape[0]), dtype=float) + for j, lag in enumerate(self.lags): + x[lag:, j] = y[:-lag] + return x + + def compute_history(self, spike_indicator: np.ndarray, time: np.ndarray) -> Covariate: + x = self.design_matrix(spike_indicator) + labels = [f"hist_lag_{int(l)}" for l in self.lags] + return Covariate(time, x, self.name, "time", "s", "count", labels) + + # MATLAB-compatible method names. + def computeHistory(self, nst) -> Covariate: + y = np.asarray(getattr(nst, "getSigRep")().data[:, 0], dtype=float) + t = np.asarray(getattr(nst, "getSigRep")().time, dtype=float) + return self.compute_history(y, t) + + +# Backward-compatible alias. +History = HistoryBasis + + +__all__ = ["HistoryBasis", "History"] diff --git a/nstat/nspikeTrain.py b/nstat/nspikeTrain.py new file mode 100644 index 00000000..f6e54d8a --- /dev/null +++ b/nstat/nspikeTrain.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .spikes import SpikeTrain + + +class nspikeTrain(SpikeTrain): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.nspikeTrain.nspikeTrain", "nstat.spikes.SpikeTrain") + super().__init__(*args, **kwargs) + + +__all__ = ["nspikeTrain"] diff --git a/nstat/nstColl.py b/nstat/nstColl.py new file mode 100644 index 00000000..1e1cb96a --- /dev/null +++ b/nstat/nstColl.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from ._compat import warn_deprecated_adapter +from .spikes import SpikeTrainCollection + + +class nstColl(SpikeTrainCollection): + def __init__(self, *args, **kwargs) -> None: + warn_deprecated_adapter("nstat.nstColl.nstColl", "nstat.spikes.SpikeTrainCollection") + super().__init__(*args, **kwargs) + + +__all__ = ["nstColl"] diff --git a/nstat/nstat_install.py b/nstat/nstat_install.py new file mode 100644 index 00000000..d34dd7b6 --- /dev/null +++ b/nstat/nstat_install.py @@ -0,0 +1,8 @@ +from __future__ import annotations + +from pathlib import Path + + +def nSTAT_Install() -> Path: + """Return Python package root path (MATLAB nSTAT_Install analogue).""" + return Path(__file__).resolve().parents[1] diff --git a/nstat/paper_examples.py b/nstat/paper_examples.py new file mode 100644 index 00000000..7c213d22 --- /dev/null +++ b/nstat/paper_examples.py @@ -0,0 +1,464 @@ +from __future__ import annotations + +import argparse +import json +from pathlib import Path +from typing import Any + +import numpy as np +from scipy.io import loadmat + +from .analysis import psth +from .decoding_algorithms import DecodingAlgorithms +from .glm import fit_poisson_glm +from .simulation import simulate_poisson_from_rate + + +Summary = dict[str, float] +Payload = dict[str, Any] +Results = dict[str, Summary] +PlotPayloads = dict[str, Payload] + + +def _default_repo_root() -> Path: + cur = Path(__file__).resolve() + for candidate in [cur, *cur.parents]: + if (candidate / "nstat").exists() and (candidate / "data").exists(): + return candidate + return cur.parents[1] + + +def _aic_bic(log_likelihood: float, n_obs: int, n_params: int) -> tuple[float, float]: + aic = 2.0 * n_params - 2.0 * log_likelihood + bic = np.log(max(n_obs, 1)) * n_params - 2.0 * log_likelihood + return float(aic), float(bic) + + +def _history_matrix(y: np.ndarray, lags: tuple[int, ...]) -> np.ndarray: + x = np.zeros((y.shape[0], len(lags)), dtype=float) + for j, lag in enumerate(lags): + x[lag:, j] = y[:-lag] + return x + + +def _bin_mean(values: np.ndarray, samples_per_bin: int) -> np.ndarray: + n_bins = values.shape[0] // samples_per_bin + if n_bins < 1: + return np.asarray([], dtype=float) + trimmed = values[: n_bins * samples_per_bin] + return trimmed.reshape(n_bins, samples_per_bin).mean(axis=1) + + +def _bin_sum(values: np.ndarray, samples_per_bin: int) -> np.ndarray: + n_bins = values.shape[0] // samples_per_bin + if n_bins < 1: + return np.asarray([], dtype=float) + trimmed = values[: n_bins * samples_per_bin] + return trimmed.reshape(n_bins, samples_per_bin).sum(axis=1) + + +def run_experiment2(data_dir: Path, *, return_payload: bool = False) -> Summary | tuple[Summary, Payload]: + mat_path = data_dir / "Explicit Stimulus" / "Dir3" / "Neuron1" / "Stim2" / "trngdataBis.mat" + d = loadmat(mat_path, squeeze_me=True, struct_as_record=False) + + stim_raw = np.asarray(d["t"], dtype=float).reshape(-1) + y = np.asarray(d["y"], dtype=float).reshape(-1) + + dt = 0.001 + stim = stim_raw / 10.0 + stim_vel = np.gradient(stim, dt) + hist = _history_matrix(y, lags=(1, 2, 3, 4, 5)) + + x1 = np.zeros((y.shape[0], 0), dtype=float) + x2 = np.column_stack([stim, stim_vel]) + x3 = np.column_stack([stim, stim_vel, hist]) + offset = np.full(y.shape[0], np.log(dt), dtype=float) + + m1 = fit_poisson_glm(x1, y, offset=offset) + m2 = fit_poisson_glm(x2, y, offset=offset) + m3 = fit_poisson_glm(x3, y, offset=offset) + + aic1, bic1 = _aic_bic(m1.log_likelihood, y.shape[0], 1) + aic2, bic2 = _aic_bic(m2.log_likelihood, y.shape[0], 3) + aic3, bic3 = _aic_bic(m3.log_likelihood, y.shape[0], 8) + + summary: Summary = { + "n_samples": float(y.shape[0]), + "model1_aic": aic1, + "model2_aic": aic2, + "model3_aic": aic3, + "model1_bic": bic1, + "model2_bic": bic2, + "model3_bic": bic3, + } + if not return_payload: + return summary + + rate1_hz = m1.predict_rate(x1, offset=offset) + rate2_hz = m2.predict_rate(x2, offset=offset) + rate3_hz = m3.predict_rate(x3, offset=offset) + + samples_per_bin = 50 # 50 ms bins. + t_binned = np.arange(y.shape[0] // samples_per_bin, dtype=float) * dt * samples_per_bin + obs_rate_hz = _bin_sum(y, samples_per_bin) / (dt * samples_per_bin) + stim_binned = _bin_mean(stim, samples_per_bin) + rate1_binned_hz = _bin_mean(rate1_hz, samples_per_bin) + rate2_binned_hz = _bin_mean(rate2_hz, samples_per_bin) + rate3_binned_hz = _bin_mean(rate3_hz, samples_per_bin) + + payload: Payload = { + "time_binned_s": t_binned, + "stimulus_binned": stim_binned, + "obs_rate_hz": obs_rate_hz, + "rate1_binned_hz": rate1_binned_hz, + "rate2_binned_hz": rate2_binned_hz, + "rate3_binned_hz": rate3_binned_hz, + "aic": np.asarray([aic1, aic2, aic3], dtype=float), + "bic": np.asarray([bic1, bic2, bic3], dtype=float), + } + return summary, payload + + +def run_experiment3(seed: int = 7, *, return_payload: bool = False) -> Summary | tuple[Summary, Payload]: + rng = np.random.default_rng(seed) + dt = 0.001 + tmax = 1.0 + time = np.arange(0.0, tmax + dt, dt) + + f = 2.0 + mu = -3.0 + linear = np.sin(2.0 * np.pi * f * time) + mu + p = np.exp(linear) + p = p / (1.0 + p) + rate_hz = p / dt + + trains = [simulate_poisson_from_rate(time, rate_hz, rng=rng) for _ in range(20)] + bin_edges = np.arange(0.0, tmax + 0.05, 0.05) + psth_rate_hz, counts = psth(trains, bin_edges) + + summary: Summary = { + "num_trials": float(len(trains)), + "psth_peak_hz": float(np.max(psth_rate_hz)), + "psth_mean_hz": float(np.mean(psth_rate_hz)), + "total_spikes": float(np.sum(counts)), + } + if not return_payload: + return summary + + payload: Payload = { + "time_s": time, + "true_rate_hz": rate_hz, + "psth_bin_centers_s": 0.5 * (bin_edges[:-1] + bin_edges[1:]), + "psth_rate_hz": psth_rate_hz, + "raster_spike_times": [np.asarray(train.spikeTimes, dtype=float) for train in trains], + } + return summary, payload + + +def _spike_indicator_from_times(time: np.ndarray, spike_times: np.ndarray) -> np.ndarray: + y = np.zeros(time.shape[0], dtype=float) + idx = np.searchsorted(time, spike_times, side="left") + idx = idx[(idx >= 0) & (idx < time.shape[0])] + if idx.size: + y[idx] = 1.0 + return y + + +def _zernike_like_basis(x: np.ndarray, y: np.ndarray) -> np.ndarray: + theta = np.arctan2(y, x) + r = np.sqrt(x * x + y * y) + return np.column_stack( + [ + np.ones_like(r), + r, + r**2, + np.cos(theta), + np.sin(theta), + r * np.cos(theta), + r * np.sin(theta), + r**2 * np.cos(2.0 * theta), + r**2 * np.sin(2.0 * theta), + r**3, + ] + ) + + +def run_experiment4(data_dir: Path, *, return_payload: bool = False) -> Summary | tuple[Summary, Payload]: + mat_path = data_dir / "Place Cells" / "PlaceCellDataAnimal1.mat" + d = loadmat(mat_path, squeeze_me=True, struct_as_record=False) + + x = np.asarray(d["x"], dtype=float).reshape(-1) + y = np.asarray(d["y"], dtype=float).reshape(-1) + time = np.asarray(d["time"], dtype=float).reshape(-1) + neurons = np.asarray(d["neuron"], dtype=object).reshape(-1) + + dt = float(np.median(np.diff(time))) + offset = np.full(time.shape[0], np.log(max(dt, 1e-12)), dtype=float) + + x_gauss = np.column_stack([x, y, x * x, y * y, x * y]) + x_zern = _zernike_like_basis(x, y) + + n_eval = int(min(8, neurons.shape[0])) + delta_aic = [] + delta_bic = [] + for i in range(n_eval): + spike_times = np.asarray(neurons[i].spikeTimes, dtype=float).reshape(-1) + y_spike = _spike_indicator_from_times(time, spike_times) + + m_g = fit_poisson_glm(x_gauss, y_spike, offset=offset) + m_z = fit_poisson_glm(x_zern, y_spike, offset=offset) + + aic_g, bic_g = _aic_bic(m_g.log_likelihood, y_spike.shape[0], x_gauss.shape[1] + 1) + aic_z, bic_z = _aic_bic(m_z.log_likelihood, y_spike.shape[0], x_zern.shape[1] + 1) + delta_aic.append(aic_g - aic_z) + delta_bic.append(bic_g - bic_z) + + summary: Summary = { + "num_cells_fit": float(n_eval), + "mean_delta_aic_gaussian_minus_zernike": float(np.mean(delta_aic)), + "mean_delta_bic_gaussian_minus_zernike": float(np.mean(delta_bic)), + } + if not return_payload: + return summary + + first_cell_spikes = np.asarray(neurons[0].spikeTimes, dtype=float).reshape(-1) + payload: Payload = { + "time_s": time, + "x_pos": x, + "y_pos": y, + "first_cell_spike_times_s": first_cell_spikes, + "delta_aic": np.asarray(delta_aic, dtype=float), + "delta_bic": np.asarray(delta_bic, dtype=float), + } + return summary, payload + + +def run_experiment5(seed: int = 11, *, return_payload: bool = False) -> Summary | tuple[Summary, Payload]: + rng = np.random.default_rng(seed) + + dt = 0.001 + time = np.arange(0.0, 1.0 + dt, dt) + stim = np.sin(2.0 * np.pi * 2.0 * time) + + n_cells = 20 + spikes = np.zeros((time.shape[0], n_cells), dtype=float) + for i in range(n_cells): + b1 = rng.normal(1.0, 0.5) + b0 = np.log(10.0 * dt) + rng.normal(0.0, 0.3) + eta = b1 * stim + b0 + p = np.exp(eta) + p = p / (1.0 + p) + spikes[:, i] = (rng.random(time.shape[0]) < p).astype(float) + + decoded = DecodingAlgorithms.linear_decode(spikes, stim) + rmse = float(np.sqrt(np.mean((decoded["decoded"] - stim) ** 2))) + + summary: Summary = { + "num_cells": float(n_cells), + "decode_rmse": rmse, + } + if not return_payload: + return summary + + payload: Payload = { + "time_s": time, + "stimulus": stim, + "decoded": np.asarray(decoded["decoded"], dtype=float), + "ci_low": np.asarray(decoded["ci"][:, 0], dtype=float), + "ci_high": np.asarray(decoded["ci"][:, 1], dtype=float), + } + return summary, payload + + +def run_paper_examples( + repo_root: Path, *, return_plot_data: bool = False +) -> Results | tuple[Results, PlotPayloads]: + data_dir = repo_root / "data" + if not data_dir.exists(): + raise FileNotFoundError(f"Could not locate data directory: {data_dir}") + + if not return_plot_data: + return { + "experiment2": run_experiment2(data_dir), # type: ignore[arg-type] + "experiment3": run_experiment3(), + "experiment4": run_experiment4(data_dir), # type: ignore[arg-type] + "experiment5": run_experiment5(), + } + + exp2_summary, exp2_payload = run_experiment2(data_dir, return_payload=True) # type: ignore[misc] + exp3_summary, exp3_payload = run_experiment3(return_payload=True) # type: ignore[misc] + exp4_summary, exp4_payload = run_experiment4(data_dir, return_payload=True) # type: ignore[misc] + exp5_summary, exp5_payload = run_experiment5(return_payload=True) # type: ignore[misc] + + results: Results = { + "experiment2": exp2_summary, + "experiment3": exp3_summary, + "experiment4": exp4_summary, + "experiment5": exp5_summary, + } + plot_payloads: PlotPayloads = { + "experiment2": exp2_payload, + "experiment3": exp3_payload, + "experiment4": exp4_payload, + "experiment5": exp5_payload, + } + return results, plot_payloads + + +def _save_paper_example_plots(plot_payloads: PlotPayloads, plots_dir: Path) -> list[Path]: + import matplotlib + + matplotlib.use("Agg") + import matplotlib.pyplot as plt + + plots_dir.mkdir(parents=True, exist_ok=True) + saved_paths: list[Path] = [] + + # Experiment 2: explicit stimulus + model comparison. + e2 = plot_payloads["experiment2"] + fig, (ax_rate, ax_metrics) = plt.subplots(2, 1, figsize=(11, 8), constrained_layout=True) + ax_rate.plot(e2["time_binned_s"], e2["obs_rate_hz"], label="Observed spike rate", color="tab:blue", lw=1.5) + ax_rate.plot(e2["time_binned_s"], e2["rate1_binned_hz"], label="Model 1 rate", color="tab:orange", lw=1.2) + ax_rate.plot(e2["time_binned_s"], e2["rate2_binned_hz"], label="Model 2 rate", color="tab:green", lw=1.2) + ax_rate.plot(e2["time_binned_s"], e2["rate3_binned_hz"], label="Model 3 rate", color="tab:red", lw=1.2) + ax_rate.set_title("Experiment 2: Stimulus and GLM Rate Fits") + ax_rate.set_xlabel("Time (s)") + ax_rate.set_ylabel("Rate (Hz)") + ax_rate.grid(alpha=0.3) + + ax_stim = ax_rate.twinx() + ax_stim.plot(e2["time_binned_s"], e2["stimulus_binned"], color="black", alpha=0.25, lw=1.0, label="Stimulus") + ax_stim.set_ylabel("Stimulus (a.u.)") + + handles1, labels1 = ax_rate.get_legend_handles_labels() + handles2, labels2 = ax_stim.get_legend_handles_labels() + ax_rate.legend(handles1 + handles2, labels1 + labels2, loc="upper right", fontsize=8) + + xloc = np.arange(3) + ax_metrics.bar(xloc - 0.175, e2["aic"], width=0.35, label="AIC", color="tab:purple") + ax_metrics.bar(xloc + 0.175, e2["bic"], width=0.35, label="BIC", color="tab:brown") + ax_metrics.set_xticks(xloc, ["Model 1", "Model 2", "Model 3"]) + ax_metrics.set_ylabel("Information Criterion") + ax_metrics.set_title("Experiment 2: Model Comparison") + ax_metrics.grid(alpha=0.3, axis="y") + ax_metrics.legend() + + out = plots_dir / "experiment2_stimulus_glm_comparison.png" + fig.savefig(out, dpi=180) + plt.close(fig) + saved_paths.append(out) + + # Experiment 3: true CIF and PSTH with raster. + e3 = plot_payloads["experiment3"] + fig, (ax_rate, ax_raster) = plt.subplots(2, 1, figsize=(11, 8), constrained_layout=True) + ax_rate.plot(e3["time_s"], e3["true_rate_hz"], color="tab:gray", lw=1.5, label="True rate") + ax_rate.step( + e3["psth_bin_centers_s"], + e3["psth_rate_hz"], + where="mid", + color="tab:blue", + lw=2.0, + label="Estimated PSTH", + ) + ax_rate.set_title("Experiment 3: Simulated CIF and Estimated PSTH") + ax_rate.set_xlabel("Time (s)") + ax_rate.set_ylabel("Rate (Hz)") + ax_rate.grid(alpha=0.3) + ax_rate.legend(loc="upper right") + + n_show = min(10, len(e3["raster_spike_times"])) + for row, spikes in enumerate(e3["raster_spike_times"][:n_show], start=1): + if len(spikes) > 0: + ax_raster.vlines(spikes, row - 0.4, row + 0.4, color="black", lw=0.6) + ax_raster.set_ylim(0.5, n_show + 0.5) + ax_raster.set_title("Experiment 3: Spike Raster (first 10 trials)") + ax_raster.set_xlabel("Time (s)") + ax_raster.set_ylabel("Trial") + ax_raster.grid(alpha=0.2) + + out = plots_dir / "experiment3_psth_and_raster.png" + fig.savefig(out, dpi=180) + plt.close(fig) + saved_paths.append(out) + + # Experiment 4: trajectory and model deltas. + e4 = plot_payloads["experiment4"] + fig, (ax_traj, ax_delta) = plt.subplots(1, 2, figsize=(13, 5.5), constrained_layout=True) + ax_traj.plot(e4["x_pos"], e4["y_pos"], color="tab:blue", alpha=0.45, lw=0.8, label="Trajectory") + spike_x = np.interp(e4["first_cell_spike_times_s"], e4["time_s"], e4["x_pos"]) + spike_y = np.interp(e4["first_cell_spike_times_s"], e4["time_s"], e4["y_pos"]) + ax_traj.scatter(spike_x, spike_y, s=8, color="tab:red", alpha=0.6, label="Cell 1 spikes") + ax_traj.set_title("Experiment 4: Place Trajectory and Cell 1 Spikes") + ax_traj.set_xlabel("X position") + ax_traj.set_ylabel("Y position") + ax_traj.set_aspect("equal", adjustable="box") + ax_traj.grid(alpha=0.3) + ax_traj.legend(loc="upper right", fontsize=8) + + cells = np.arange(1, len(e4["delta_aic"]) + 1) + ax_delta.plot(cells, e4["delta_aic"], marker="o", lw=1.5, color="tab:purple", label="Delta AIC") + ax_delta.plot(cells, e4["delta_bic"], marker="s", lw=1.5, color="tab:green", label="Delta BIC") + ax_delta.axhline(0.0, color="black", lw=1.0, alpha=0.5) + ax_delta.set_title("Experiment 4: Gaussian - Zernike Model Delta") + ax_delta.set_xlabel("Cell index") + ax_delta.set_ylabel("Score difference") + ax_delta.grid(alpha=0.3) + ax_delta.legend(loc="upper right") + + out = plots_dir / "experiment4_placecell_model_comparison.png" + fig.savefig(out, dpi=180) + plt.close(fig) + saved_paths.append(out) + + # Experiment 5: decode quality with confidence bounds. + e5 = plot_payloads["experiment5"] + fig, ax = plt.subplots(1, 1, figsize=(11, 4.5), constrained_layout=True) + ax.plot(e5["time_s"], e5["stimulus"], color="tab:blue", lw=1.8, label="True stimulus") + ax.plot(e5["time_s"], e5["decoded"], color="tab:orange", lw=1.5, label="Decoded stimulus") + ax.fill_between(e5["time_s"], e5["ci_low"], e5["ci_high"], color="tab:orange", alpha=0.2, label="95% CI") + ax.set_title("Experiment 5: Linear Decoding of Simulated Stimulus") + ax.set_xlabel("Time (s)") + ax.set_ylabel("Stimulus (a.u.)") + ax.grid(alpha=0.3) + ax.legend(loc="upper right") + + out = plots_dir / "experiment5_stimulus_decoding.png" + fig.savefig(out, dpi=180) + plt.close(fig) + saved_paths.append(out) + + return saved_paths + + +def main() -> int: + parser = argparse.ArgumentParser(description="Python nSTAT paper examples equivalent") + parser.add_argument("--repo-root", type=Path, default=_default_repo_root()) + parser.add_argument("--no-plots", action="store_true", help="Run metrics only without generating plots") + parser.add_argument("--plots-dir", type=Path, default=None, help="Directory for generated PNG plots") + parser.add_argument("--output-json", type=Path, default=None) + args = parser.parse_args() + + repo_root = args.repo_root.resolve() + default_plots_dir = repo_root / "plots" / "nstat_paper_examples" + plots_dir = (args.plots_dir or default_plots_dir).resolve() + + if args.no_plots: + results = run_paper_examples(repo_root) + saved_plots: list[Path] = [] + else: + results, payloads = run_paper_examples(repo_root, return_plot_data=True) + saved_plots = _save_paper_example_plots(payloads, plots_dir) + + if args.output_json is not None: + args.output_json.write_text(json.dumps(results, indent=2), encoding="utf-8") + + print(json.dumps(results, indent=2)) + if saved_plots: + print("\nGenerated plots:") + for path in saved_plots: + print(str(path)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/nstat/paper_examples_full.py b/nstat/paper_examples_full.py new file mode 100644 index 00000000..89501d86 --- /dev/null +++ b/nstat/paper_examples_full.py @@ -0,0 +1,460 @@ +from __future__ import annotations + +import argparse +import json +import os +from pathlib import Path + +import numpy as np +from scipy.io import loadmat + +from .analysis import psth +from .decoding_algorithms import DecodingAlgorithms +from .glm import fit_poisson_glm +from .simulation import simulate_poisson_from_rate + + +def _default_repo_root() -> Path: + cur = Path(__file__).resolve() + for candidate in [cur, *cur.parents]: + if (candidate / "nstat").exists() and (candidate / "data").exists(): + return candidate + return cur.parents[1] + + +def _allow_synthetic_data() -> bool: + return os.environ.get("NSTAT_ALLOW_SYNTHETIC_DATA", "").strip().lower() in {"1", "true", "yes", "on"} + + +def _is_lfs_pointer(path: Path) -> bool: + try: + head = path.read_bytes()[:200] + except OSError: + return False + return head.startswith(b"version https://git-lfs.github.com/spec/v1") + + +def _loadmat_checked(path: Path): + if path.exists() and not _is_lfs_pointer(path): + return loadmat(path, squeeze_me=True, struct_as_record=False) + if _allow_synthetic_data(): + return None + if not path.exists(): + raise FileNotFoundError(f"Missing MAT file: {path}") + if _is_lfs_pointer(path): + raise RuntimeError( + f"MAT file is a Git LFS pointer, not dataset content: {path}. " + "Fetch LFS assets or set NSTAT_ALLOW_SYNTHETIC_DATA=1 for synthetic CI fallback." + ) + raise RuntimeError(f"Unable to load MAT file: {path}") + + +def _aic_bic(log_likelihood: float, n_obs: int, n_params: int) -> tuple[float, float]: + aic = 2.0 * n_params - 2.0 * log_likelihood + bic = np.log(max(n_obs, 1)) * n_params - 2.0 * log_likelihood + return float(aic), float(bic) + + +def _history_matrix(y: np.ndarray, lags: list[int]) -> np.ndarray: + out = np.zeros((y.shape[0], len(lags)), dtype=float) + for j, lag in enumerate(lags): + out[lag:, j] = y[:-lag] + return out + + +def _load_mepsc_times_seconds(path: Path) -> np.ndarray: + arr = np.loadtxt(path, skiprows=1) + return np.asarray(arr[:, 1], dtype=float).reshape(-1) / 1000.0 + + +def _bin_spike_times(spikes: np.ndarray, t0: float, t1: float, dt: float) -> tuple[np.ndarray, np.ndarray]: + n_bins = int(np.floor((t1 - t0) / dt)) + 1 + edges = t0 + np.arange(n_bins + 1, dtype=float) * dt + counts, _ = np.histogram(spikes, bins=edges) + return edges[:-1], counts.astype(float) + + +def run_experiment1(data_dir: Path) -> dict[str, float]: + mepsc_dir = data_dir / "mEPSCs" + epsc2 = _load_mepsc_times_seconds(mepsc_dir / "epsc2.txt") + washout1 = _load_mepsc_times_seconds(mepsc_dir / "washout1.txt") + washout2 = _load_mepsc_times_seconds(mepsc_dir / "washout2.txt") + + dt_const = 0.01 + _, y_const = _bin_spike_times(epsc2, 0.0, float(np.max(epsc2)), dt_const) + off_const = np.full(y_const.shape[0], np.log(dt_const), dtype=float) + m_const = fit_poisson_glm(np.zeros((y_const.shape[0], 0), dtype=float), y_const, offset=off_const, max_iter=80) + aic_const, bic_const = _aic_bic(m_const.log_likelihood, y_const.shape[0], 1) + + spikes = np.concatenate([260.0 + washout1, np.sort(washout2) + 745.0]) + dt = 0.01 + t, y = _bin_spike_times(spikes, 260.0, float(np.max(spikes)), dt) + off = np.full(y.shape[0], np.log(dt), dtype=float) + + seg2 = ((t >= 495.0) & (t < 765.0)).astype(float) + seg3 = (t >= 765.0).astype(float) + x_piece = np.column_stack([seg2, seg3]) + hist = _history_matrix(y, [1, 2, 3, 4, 5, 7, 10, 14, 20, 30]) + x_piece_hist = np.column_stack([x_piece, hist]) + + m_piece = fit_poisson_glm(x_piece, y, offset=off, max_iter=100) + m_piece_hist = fit_poisson_glm(x_piece_hist, y, offset=off, max_iter=120) + aic_piece, bic_piece = _aic_bic(m_piece.log_likelihood, y.shape[0], x_piece.shape[1] + 1) + aic_piece_hist, bic_piece_hist = _aic_bic(m_piece_hist.log_likelihood, y.shape[0], x_piece_hist.shape[1] + 1) + + return { + "const_condition_spikes": float(np.sum(y_const)), + "const_model_aic": aic_const, + "const_model_bic": bic_const, + "decreasing_condition_spikes": float(np.sum(y)), + "piecewise_model_aic": aic_piece, + "piecewise_model_bic": bic_piece, + "piecewise_history_model_aic": aic_piece_hist, + "piecewise_history_model_bic": bic_piece_hist, + "dt_seconds": dt, + } + + +def run_experiment2(data_dir: Path) -> dict[str, float]: + path = data_dir / "Explicit Stimulus" / "Dir3" / "Neuron1" / "Stim2" / "trngdataBis.mat" + d = _loadmat_checked(path) + if d is None: + rng = np.random.default_rng(2002) + n = 5000 + t = np.linspace(0.0, 2.0 * np.pi, n, dtype=float) + stim_raw = np.sin(1.8 * t) + 0.25 * np.sin(0.4 * t + 0.2) + p = np.clip(0.015 + 0.02 * np.maximum(stim_raw, 0.0), 1e-4, 0.35) + y = (rng.random(n) < p).astype(float) + else: + stim_raw = np.asarray(d["t"], dtype=float).reshape(-1) + y = np.asarray(d["y"], dtype=float).reshape(-1) + + dt = 0.001 + stim = stim_raw / 10.0 + stim_vel = np.gradient(stim, dt) + hist = _history_matrix(y, [1, 2, 3, 4, 5]) + + x1 = np.zeros((y.shape[0], 0), dtype=float) + x2 = np.column_stack([stim, stim_vel]) + x3 = np.column_stack([stim, stim_vel, hist]) + offset = np.full(y.shape[0], np.log(dt), dtype=float) + + m1 = fit_poisson_glm(x1, y, offset=offset) + m2 = fit_poisson_glm(x2, y, offset=offset) + m3 = fit_poisson_glm(x3, y, offset=offset) + + aic1, bic1 = _aic_bic(m1.log_likelihood, y.shape[0], 1) + aic2, bic2 = _aic_bic(m2.log_likelihood, y.shape[0], 3) + aic3, bic3 = _aic_bic(m3.log_likelihood, y.shape[0], 8) + + return { + "n_samples": float(y.shape[0]), + "model1_aic": aic1, + "model2_aic": aic2, + "model3_aic": aic3, + "model1_bic": bic1, + "model2_bic": bic2, + "model3_bic": bic3, + } + + +def run_experiment3(seed: int = 7) -> dict[str, float]: + rng = np.random.default_rng(seed) + dt = 0.001 + tmax = 1.0 + time = np.arange(0.0, tmax + dt, dt) + + linear = np.sin(2.0 * np.pi * 2.0 * time) - 3.0 + p = np.exp(linear) + p = p / (1.0 + p) + rate_hz = p / dt + + trains = [simulate_poisson_from_rate(time, rate_hz, rng=rng) for _ in range(20)] + edges = np.arange(0.0, tmax + 0.05, 0.05) + psth_rate_hz, counts = psth(trains, edges) + + return { + "num_trials": float(len(trains)), + "psth_peak_hz": float(np.max(psth_rate_hz)), + "psth_mean_hz": float(np.mean(psth_rate_hz)), + "total_spikes": float(np.sum(counts)), + } + + +def run_experiment3b(data_dir: Path) -> dict[str, float]: + path = data_dir / "SSGLMExampleData.mat" + d = _loadmat_checked(path) + if d is None: + rng = np.random.default_rng(3003) + stimulus = rng.normal(0.0, 1.0, size=(15, 250)) + xk = stimulus + rng.normal(0.0, 0.2, size=stimulus.shape) + ci_half = np.abs(rng.normal(0.35, 0.08, size=stimulus.shape)) + stim_cis = np.stack([xk - ci_half, xk + ci_half], axis=-1) + qhat = np.abs(rng.normal(0.12, 0.03, size=stimulus.shape[0])) + gammahat = np.abs(rng.normal(0.08, 0.02, size=stimulus.shape[0])) + logll = float(-np.mean((xk - stimulus) ** 2) * stimulus.size) + else: + stimulus = np.asarray(d["stimulus"], dtype=float) + xk = np.asarray(d["xK"], dtype=float) + stim_cis = np.asarray(d["stimCIs"], dtype=float) + qhat = np.asarray(d["Qhat"], dtype=float).reshape(-1) + gammahat = np.asarray(d["gammahat"], dtype=float).reshape(-1) + logll = float(np.asarray(d["logll"], dtype=float).reshape(-1)[0]) + + coverage = np.mean((stimulus >= stim_cis[:, :, 0]) & (stimulus <= stim_cis[:, :, 1])) + rmse = np.sqrt(np.mean((xk - stimulus) ** 2)) + + return { + "num_trials": float(stimulus.shape[0]), + "num_time_bins": float(stimulus.shape[1]), + "state_rmse": float(rmse), + "ci_coverage": float(coverage), + "mean_qhat": float(np.mean(qhat)), + "mean_gammahat": float(np.mean(gammahat)), + "log_likelihood": logll, + } + + +def _spike_indicator(time: np.ndarray, spike_times: np.ndarray) -> np.ndarray: + y = np.zeros(time.shape[0], dtype=float) + idx = np.searchsorted(time, spike_times, side="left") + idx = idx[(idx >= 0) & (idx < time.shape[0])] + if idx.size > 0: + y[idx] = 1.0 + return y + + +def _zernike_like_basis(x: np.ndarray, y: np.ndarray) -> np.ndarray: + theta = np.arctan2(y, x) + r = np.sqrt(x * x + y * y) + return np.column_stack([ + np.ones_like(r), + r, + r**2, + np.cos(theta), + np.sin(theta), + r * np.cos(theta), + r * np.sin(theta), + r**2 * np.cos(2.0 * theta), + r**2 * np.sin(2.0 * theta), + r**3, + ]) + + +def run_experiment4(data_dir: Path) -> dict[str, float]: + path = data_dir / "Place Cells" / "PlaceCellDataAnimal1.mat" + d = _loadmat_checked(path) + if d is None: + rng = np.random.default_rng(4004) + time = np.linspace(0.0, 20.0, 2400, dtype=float) + x = 0.8 * np.sin(0.6 * time) + 0.2 * np.sin(1.7 * time + 0.5) + y = 0.7 * np.cos(0.5 * time + 0.3) + n_cells = 8 + neurons = [] + for _ in range(n_cells): + field = np.exp(-((x - rng.uniform(-0.5, 0.5)) ** 2 + (y - rng.uniform(-0.5, 0.5)) ** 2) / 0.2) + p = np.clip(0.001 + 0.03 * field, 1e-6, 0.25) + spikes = time[rng.random(time.shape[0]) < p] + neurons.append(type("N", (), {"spikeTimes": spikes})()) + neurons = np.asarray(neurons, dtype=object) + else: + x = np.asarray(d["x"], dtype=float).reshape(-1) + y = np.asarray(d["y"], dtype=float).reshape(-1) + time = np.asarray(d["time"], dtype=float).reshape(-1) + neurons = np.asarray(d["neuron"], dtype=object).reshape(-1) + + dt = float(np.median(np.diff(time))) + offset = np.full(time.shape[0], np.log(max(dt, 1e-12)), dtype=float) + x_gauss = np.column_stack([x, y, x * x, y * y, x * y]) + x_zern = _zernike_like_basis(x, y) + + d_aic = [] + d_bic = [] + n_eval = int(min(8, neurons.shape[0])) + for i in range(n_eval): + spike_times = np.asarray(neurons[i].spikeTimes, dtype=float).reshape(-1) + y_spike = _spike_indicator(time, spike_times) + mg = fit_poisson_glm(x_gauss, y_spike, offset=offset) + mz = fit_poisson_glm(x_zern, y_spike, offset=offset) + aicg, bicg = _aic_bic(mg.log_likelihood, y_spike.shape[0], x_gauss.shape[1] + 1) + aicz, bicz = _aic_bic(mz.log_likelihood, y_spike.shape[0], x_zern.shape[1] + 1) + d_aic.append(aicg - aicz) + d_bic.append(bicg - bicz) + + return { + "num_cells_fit": float(n_eval), + "mean_delta_aic_gaussian_minus_zernike": float(np.mean(d_aic)), + "mean_delta_bic_gaussian_minus_zernike": float(np.mean(d_bic)), + } + + +def run_experiment5(seed: int = 11, n_cells: int = 20) -> dict[str, float]: + rng = np.random.default_rng(seed) + dt = 0.001 + time = np.arange(0.0, 1.0 + dt, dt) + stim = np.sin(2.0 * np.pi * 2.0 * time) + + n_cells = int(n_cells) + if n_cells < 1: + raise ValueError("n_cells must be >= 1") + spikes = np.zeros((time.shape[0], n_cells), dtype=float) + for i in range(n_cells): + b1 = rng.normal(1.0, 0.5) + b0 = np.log(10.0 * dt) + rng.normal(0.0, 0.3) + eta = b1 * stim + b0 + p = np.exp(eta) + p = p / (1.0 + p) + spikes[:, i] = (rng.random(time.shape[0]) < p).astype(float) + + decoded = DecodingAlgorithms.linear_decode(spikes, stim) + rmse = float(np.sqrt(np.mean((decoded["decoded"] - stim) ** 2))) + return {"num_cells": float(n_cells), "decode_rmse": rmse} + + +def run_experiment5b(seed: int = 19, n_cells: int = 30) -> dict[str, float]: + rng = np.random.default_rng(seed) + + dt = 0.01 + time = np.arange(0.0, 20.0 + dt, dt) + x_true = 0.25 * np.sin(2.0 * np.pi * 0.15 * time) + y_true = 0.20 * np.cos(2.0 * np.pi * 0.10 * time) + vx = np.gradient(x_true, dt) + vy = np.gradient(y_true, dt) + + n_cells = int(n_cells) + if n_cells < 1: + raise ValueError("n_cells must be >= 1") + spikes = np.zeros((time.shape[0], n_cells), dtype=float) + for i in range(n_cells): + wx = rng.normal(0.0, 1.0) + wy = rng.normal(0.0, 1.0) + b0 = -3.0 + rng.normal(0.0, 0.2) + eta = b0 + 3.0 * wx * vx + 3.0 * wy * vy + p = 1.0 / (1.0 + np.exp(-np.clip(eta, -20.0, 20.0))) + spikes[:, i] = (rng.random(time.shape[0]) < p).astype(float) + + dx = DecodingAlgorithms.linear_decode(spikes, x_true)["decoded"] + dy = DecodingAlgorithms.linear_decode(spikes, y_true)["decoded"] + return { + "num_cells": float(n_cells), + "num_samples": float(time.shape[0]), + "decode_rmse_x": float(np.sqrt(np.mean((dx - x_true) ** 2))), + "decode_rmse_y": float(np.sqrt(np.mean((dy - y_true) ** 2))), + } + + +def _simulate_hybrid_spikes(x: np.ndarray, mstate: np.ndarray, dt: float, n_cells: int, seed: int): + rng = np.random.default_rng(seed) + vx = x[2, :] + vy = x[3, :] + wvx = rng.normal(0.0, 1.0, size=n_cells) + wvy = rng.normal(0.0, 1.0, size=n_cells) + b1 = rng.normal(-3.8, 0.2, size=n_cells) + b2 = rng.normal(-2.8, 0.2, size=n_cells) + + spikes = np.zeros((x.shape[1], n_cells), dtype=float) + for t in range(x.shape[1]): + base = b1 if int(mstate[t]) == 1 else b2 + eta = base + 1.2 * wvx * vx[t] + 1.2 * wvy * vy[t] + lam = np.exp(np.clip(eta, -15.0, 15.0)) + p = 1.0 - np.exp(-lam * dt) + spikes[t, :] = (rng.random(n_cells) < p).astype(float) + return spikes, wvx, wvy, b1, b2 + + +def _hybrid_state_filter(spikes: np.ndarray, x: np.ndarray, dt: float, p_ij: np.ndarray, wvx: np.ndarray, wvy: np.ndarray, b1: np.ndarray, b2: np.ndarray) -> np.ndarray: + n_t, _ = spikes.shape + post = np.zeros((n_t, 2), dtype=float) + post[0, :] = [0.5, 0.5] + vx = x[2, :] + vy = x[3, :] + + for t in range(1, n_t): + eta1 = b1 + 1.2 * wvx * vx[t] + 1.2 * wvy * vy[t] + eta2 = b2 + 1.2 * wvx * vx[t] + 1.2 * wvy * vy[t] + p1 = np.clip(1.0 - np.exp(-np.exp(np.clip(eta1, -15.0, 15.0)) * dt), 1e-6, 1.0 - 1e-6) + p2 = np.clip(1.0 - np.exp(-np.exp(np.clip(eta2, -15.0, 15.0)) * dt), 1e-6, 1.0 - 1e-6) + k = spikes[t, :] + ll1 = np.sum(k * np.log(p1) + (1.0 - k) * np.log(1.0 - p1)) + ll2 = np.sum(k * np.log(p2) + (1.0 - k) * np.log(1.0 - p2)) + pred0 = max(post[t - 1, 0] * p_ij[0, 0] + post[t - 1, 1] * p_ij[1, 0], 1e-15) + pred1 = max(post[t - 1, 0] * p_ij[0, 1] + post[t - 1, 1] * p_ij[1, 1], 1e-15) + logs = np.array([np.log(pred0) + ll1, np.log(pred1) + ll2], dtype=float) + logs = logs - np.max(logs) + un = np.exp(logs) + post[t, :] = un / np.sum(un) + return post + + +def run_experiment6(repo_root: Path, seed: int = 37) -> dict[str, float]: + path = repo_root / "helpfiles" / "paperHybridFilterExample.mat" + d = _loadmat_checked(path) + if d is None: + rng = np.random.default_rng(seed) + dt = 0.01 + t = np.arange(0.0, 30.0, dt, dtype=float) + x_pos = 0.3 * np.sin(0.2 * t) + y_pos = 0.25 * np.cos(0.15 * t) + x_vel = np.gradient(x_pos, dt) + y_vel = np.gradient(y_pos, dt) + x = np.vstack([x_pos, y_pos, x_vel, y_vel]) + mstate = np.where(np.sin(0.05 * t + 0.4) > 0.0, 1, 2).astype(int) + # Add mild stochasticity so state filter is non-trivial. + flip = rng.random(t.shape[0]) < 0.02 + mstate[flip] = 3 - mstate[flip] + p_ij = np.array([[0.985, 0.015], [0.02, 0.98]], dtype=float) + else: + x = np.asarray(d["X"], dtype=float) + mstate = np.asarray(d["mstate"], dtype=int).reshape(-1) + p_ij = np.asarray(d["p_ij"], dtype=float) + dt = float(np.asarray(d["delta"], dtype=float).reshape(-1)[0]) + + n_cells = 24 + spikes, wvx, wvy, b1, b2 = _simulate_hybrid_spikes(x, mstate, dt, n_cells=n_cells, seed=seed) + post = _hybrid_state_filter(spikes, x, dt, p_ij, wvx, wvy, b1, b2) + state_hat = np.argmax(post, axis=1) + 1 + state_acc = np.mean(state_hat == mstate) + + dx = DecodingAlgorithms.linear_decode(spikes, x[0, :])["decoded"] + dy = DecodingAlgorithms.linear_decode(spikes, x[1, :])["decoded"] + return { + "num_samples": float(x.shape[1]), + "num_cells": float(n_cells), + "state_accuracy": float(state_acc), + "decode_rmse_x": float(np.sqrt(np.mean((dx - x[0, :]) ** 2))), + "decode_rmse_y": float(np.sqrt(np.mean((dy - x[1, :]) ** 2))), + } + + +def run_full_paper_examples(repo_root: Path) -> dict[str, dict[str, float]]: + data_dir = repo_root / "data" + if not data_dir.exists(): + raise FileNotFoundError(f"Could not locate data directory: {data_dir}") + + return { + "experiment1": run_experiment1(data_dir), + "experiment2": run_experiment2(data_dir), + "experiment3": run_experiment3(), + "experiment3b": run_experiment3b(data_dir), + "experiment4": run_experiment4(data_dir), + "experiment5": run_experiment5(), + "experiment5b": run_experiment5b(), + "experiment6": run_experiment6(repo_root), + } + + +def main() -> int: + parser = argparse.ArgumentParser(description="Native Python approximation of nSTATPaperExamples.m") + parser.add_argument("--repo-root", type=Path, default=_default_repo_root()) + parser.add_argument("--output-json", type=Path, default=None) + args = parser.parse_args() + + results = run_full_paper_examples(args.repo_root.resolve()) + if args.output_json is not None: + args.output_json.write_text(json.dumps(results, indent=2), encoding="utf-8") + print(json.dumps(results, indent=2)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/nstat/signal.py b/nstat/signal.py new file mode 100644 index 00000000..11be2dc4 --- /dev/null +++ b/nstat/signal.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from typing import Sequence + +import numpy as np + +from .core import Covariate as _LegacyCovariate +from .core import SignalObj as _LegacySignalObj + + +class Signal(_LegacySignalObj): + """Canonical Pythonic signal abstraction for nSTAT.""" + + def copy(self) -> "Signal": + copied = self.copySignal() + return Signal( + copied.time, + copied.data, + copied.name, + copied.xlabelval, + copied.xunits, + copied.yunits, + copied.dataLabels, + ) + + def sub_signal(self, index: int) -> "Signal": + """Return one channel as a new signal. + + Uses zero-based indexing in Python, unlike MATLAB's one-based indexing. + """ + if index < 0 or index >= self.dimension: + raise IndexError("Signal channel index out of range.") + out = self.getSubSignal(index + 1) + return Signal( + out.time, + out.data, + out.name, + out.xlabelval, + out.xunits, + out.yunits, + out.dataLabels, + ) + + def window(self, start: float, stop: float) -> "Signal": + out = self.getSigInTimeWindow(start, stop) + return Signal( + out.time, + out.data, + out.name, + out.xlabelval, + out.xunits, + out.yunits, + out.dataLabels, + ) + + def as_array(self) -> np.ndarray: + return np.asarray(self.data, dtype=float) + + +class Covariate(_LegacyCovariate): + """Canonical covariate type for model design matrices.""" + + def standardize(self) -> "Covariate": + data = np.asarray(self.data, dtype=float) + mu = np.mean(data, axis=0, keepdims=True) + sigma = np.std(data, axis=0, keepdims=True) + sigma[sigma == 0.0] = 1.0 + z = (data - mu) / sigma + return Covariate( + self.time, + z, + self.name, + self.xlabelval, + self.xunits, + self.yunits, + self.dataLabels, + ) + + @classmethod + def from_values( + cls, + time: Sequence[float], + values: Sequence[float] | Sequence[Sequence[float]] | np.ndarray, + *, + name: str = "covariate", + units: str = "", + ) -> "Covariate": + return cls(time=time, values=values, name=name, units=units) diff --git a/nstat/simulation.py b/nstat/simulation.py new file mode 100644 index 00000000..863bd604 --- /dev/null +++ b/nstat/simulation.py @@ -0,0 +1,35 @@ +from __future__ import annotations + +import numpy as np + +from .core import nspikeTrain + + +# Backward-compatible alias used by earlier Python code. +SpikeTrain = nspikeTrain + + +def simulate_poisson_from_rate( + time: np.ndarray, + rate_hz: np.ndarray, + rng: np.random.Generator | None = None, +) -> nspikeTrain: + t = np.asarray(time, dtype=float).reshape(-1) + r = np.asarray(rate_hz, dtype=float).reshape(-1) + if t.shape[0] != r.shape[0]: + raise ValueError("time and rate_hz length mismatch") + if t.shape[0] < 2: + return nspikeTrain(np.asarray([], dtype=float)) + + if rng is None: + rng = np.random.default_rng() + + dt = np.diff(t) + dt = np.concatenate([dt, [dt[-1]]]) + p = 1.0 - np.exp(-np.clip(r, 0.0, np.inf) * dt) + p = np.clip(p, 0.0, 1.0) + keep = rng.random(t.shape[0]) < p + return nspikeTrain(spikeTimes=t[keep]) + + +__all__ = ["SpikeTrain", "simulate_poisson_from_rate"] diff --git a/nstat/simulators.py b/nstat/simulators.py new file mode 100644 index 00000000..fb88990b --- /dev/null +++ b/nstat/simulators.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +from dataclasses import dataclass + +import numpy as np + +from .spikes import SpikeTrain, SpikeTrainCollection + + +@dataclass +class PointProcessSimulation: + time: np.ndarray + rate_hz: np.ndarray + spikes: SpikeTrain + + +@dataclass +class NetworkSimulationResult: + time: np.ndarray + latent_drive: np.ndarray + spikes: SpikeTrainCollection + + +def simulate_point_process(time: np.ndarray, rate_hz: np.ndarray, *, seed: int | None = None) -> PointProcessSimulation: + t = np.asarray(time, dtype=float).reshape(-1) + r = np.asarray(rate_hz, dtype=float).reshape(-1) + if t.shape[0] != r.shape[0]: + raise ValueError("time and rate_hz length mismatch") + if t.shape[0] < 2: + return PointProcessSimulation(t, r, SpikeTrain(np.array([], dtype=float))) + + dt = np.diff(t) + dt = np.concatenate([dt, [dt[-1]]]) + p = 1.0 - np.exp(-np.clip(r, 0.0, np.inf) * dt) + p = np.clip(p, 0.0, 1.0) + + rng = np.random.default_rng(seed) + keep = rng.random(t.shape[0]) < p + return PointProcessSimulation(t, r, SpikeTrain(t[keep])) + + +def simulate_two_neuron_network( + duration_s: float = 2.0, + dt: float = 0.001, + base_rate_hz: float = 8.0, + coupling: float = 1.2, + seed: int | None = 13, +) -> NetworkSimulationResult: + """Standalone Python replacement for Simulink-style 2-neuron network examples.""" + if duration_s <= 0 or dt <= 0: + raise ValueError("duration_s and dt must be > 0") + + time = np.arange(0.0, duration_s + dt, dt) + drive = np.sin(2.0 * np.pi * 2.0 * time) + + rng = np.random.default_rng(seed) + spikes = np.zeros((time.shape[0], 2), dtype=float) + for i in range(1, time.shape[0]): + prev = spikes[i - 1] + eta1 = np.log(base_rate_hz * dt) + 1.5 * drive[i] + coupling * (prev[1] - 0.1) + eta2 = np.log(base_rate_hz * dt) - 1.5 * drive[i] + coupling * (prev[0] - 0.1) + p1 = 1.0 / (1.0 + np.exp(-np.clip(eta1, -20.0, 20.0))) + p2 = 1.0 / (1.0 + np.exp(-np.clip(eta2, -20.0, 20.0))) + spikes[i, 0] = 1.0 if rng.random() < p1 else 0.0 + spikes[i, 1] = 1.0 if rng.random() < p2 else 0.0 + + t1 = time[spikes[:, 0] > 0.5] + t2 = time[spikes[:, 1] > 0.5] + coll = SpikeTrainCollection([SpikeTrain(t1, name="neuron_1"), SpikeTrain(t2, name="neuron_2")]) + return NetworkSimulationResult(time=time, latent_drive=drive, spikes=coll) + + +__all__ = ["PointProcessSimulation", "NetworkSimulationResult", "simulate_point_process", "simulate_two_neuron_network"] diff --git a/nstat/spikes.py b/nstat/spikes.py new file mode 100644 index 00000000..1670c0f1 --- /dev/null +++ b/nstat/spikes.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +from typing import Sequence + +import numpy as np + +from .core import nspikeTrain as _LegacySpikeTrain +from .simulation import simulate_poisson_from_rate +from .trial import nstColl as _LegacySpikeTrainCollection + + +class SpikeTrain(_LegacySpikeTrain): + """Canonical spike train type for point-process analyses.""" + + def inter_spike_intervals(self) -> np.ndarray: + return self.getISIs() + + def to_counts(self, bin_edges: Sequence[float]) -> np.ndarray: + return self.to_binned_counts(bin_edges) + + +class SpikeTrainCollection(_LegacySpikeTrainCollection): + """Collection of aligned spike trains for ensemble analyses.""" + + def __iter__(self): + for i in range(1, self.numSpikeTrains + 1): + yield self.getNST(i) + + def to_matrix(self, bin_edges: Sequence[float]) -> np.ndarray: + edges = np.asarray(bin_edges, dtype=float).reshape(-1) + if edges.ndim != 1 or edges.size < 2: + raise ValueError("bin_edges must be a 1D array with at least two entries") + rows = [np.asarray(train.to_binned_counts(edges), dtype=float) for train in self] + return np.vstack(rows) + + +__all__ = ["SpikeTrain", "SpikeTrainCollection", "simulate_poisson_from_rate"] diff --git a/nstat/trial.py b/nstat/trial.py new file mode 100644 index 00000000..8b336367 --- /dev/null +++ b/nstat/trial.py @@ -0,0 +1,266 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Iterable, Sequence + +import numpy as np + +from .core import nspikeTrain +from .events import Events +from .signal import Covariate + + +class CovariateCollection: + def __init__(self, covariates: Sequence[Covariate] | None = None) -> None: + self.covariates = list(covariates or []) + + @property + def names(self) -> list[str]: + return [cov.name for cov in self.covariates] + + def add(self, covariate: Covariate) -> None: + self.covariates.append(covariate) + + def addCovariate(self, covariate: Covariate) -> None: + self.add(covariate) + + def addToColl(self, covariate: Covariate) -> None: + self.add(covariate) + + def get(self, name: str) -> Covariate: + for cov in self.covariates: + if cov.name == name: + return cov + raise KeyError(f"Covariate '{name}' not found") + + def getCov(self, name: str) -> Covariate: + return self.get(name) + + def dataToMatrix(self, names: Sequence[str] | None = None) -> tuple[np.ndarray, np.ndarray, list[str]]: + if not self.covariates: + raise ValueError("CovariateCollection is empty") + selected = self.covariates + if names is not None: + keep = set(names) + selected = [cov for cov in self.covariates if cov.name in keep] + if not selected: + raise ValueError("No covariates matched requested names") + + base_time = selected[0].time + x_parts: list[np.ndarray] = [] + labels: list[str] = [] + for cov in selected: + if cov.time.shape != base_time.shape or np.max(np.abs(cov.time - base_time)) > 1e-9: + raise ValueError("All covariates must share the same time grid") + x_parts.append(np.asarray(cov.data, dtype=float)) + labels.extend(cov.dataLabels) + return base_time, np.hstack(x_parts), labels + + +class SpikeTrainCollection: + def __init__(self, trains: Sequence[nspikeTrain] | nspikeTrain) -> None: + if isinstance(trains, nspikeTrain): + trains = [trains] + self._trains = list(trains) + if len(self._trains) == 0: + raise ValueError("SpikeTrainCollection requires at least one spike train") + + self.minTime = float(min(s.minTime for s in self._trains)) + self.maxTime = float(max(s.maxTime for s in self._trains)) + rates = [s.sampleRate for s in self._trains if s.sampleRate > 0] + self.sampleRate = float(np.median(rates)) if rates else 1000.0 + + @property + def num_spike_trains(self) -> int: + return len(self._trains) + + @property + def numSpikeTrains(self) -> int: + return self.num_spike_trains + + def __iter__(self): + for tr in self._trains: + yield tr + + def get_nst(self, idx: int) -> nspikeTrain: + if idx < 0 or idx >= len(self._trains): + raise IndexError("SpikeTrainCollection index out of bounds (0-based indexing).") + return self._trains[idx] + + def getNST(self, idx: int) -> nspikeTrain: + if idx < 1 or idx > len(self._trains): + raise IndexError("nstColl index out of bounds (1-based indexing).") + return self._trains[idx - 1] + + def setMinTime(self, value: float) -> None: + self.minTime = float(value) + + def setMaxTime(self, value: float) -> None: + self.maxTime = float(value) + + def dataToMatrix(self, bin_edges: Sequence[float]) -> np.ndarray: + edges = np.asarray(bin_edges, dtype=float).reshape(-1) + if edges.ndim != 1 or edges.size < 2: + raise ValueError("bin_edges must be a 1D array with at least two points") + rows = [np.asarray(spk.to_binned_counts(edges), dtype=float) for spk in self._trains] + return np.vstack(rows) + + def plot(self, *_, **__) -> None: + return None + + def psth(self, binwidth: float) -> Covariate: + if binwidth <= 0: + raise ValueError("binwidth must be > 0") + min_time = float(self.minTime) + max_time = float(self.maxTime) + if max_time < min_time: + raise ValueError("maxTime must be >= minTime") + + # Match MATLAB nstColl.psth edge construction: + # windowTimes = minTime:binwidth:maxTime; + # if ~any(windowTimes==maxTime), append maxTime + span = max_time - min_time + n_full = int(np.floor((span / binwidth) + 1e-12)) + window_times = min_time + np.arange(n_full + 1, dtype=float) * float(binwidth) + if window_times.size == 0: + window_times = np.array([min_time, max_time], dtype=float) + if window_times[-1] < max_time - 1e-12: + window_times = np.append(window_times, max_time) + elif window_times[-1] > max_time + 1e-12: + window_times[-1] = max_time + if window_times.size < 2: + window_times = np.array([min_time, max_time], dtype=float) + if window_times[1] <= window_times[0]: + window_times[1] = window_times[0] + float(binwidth) + + # MATLAB histc-like counting produces one extra terminal bin for x==max; + # nstColl.psth discards that final bin before normalizing. + psth_hist = np.zeros(window_times.size, dtype=float) + for spk in self._trains: + spikes = np.asarray(spk.spikeTimes, dtype=float).reshape(-1) + if spikes.size == 0: + continue + valid = np.isfinite(spikes) & (spikes >= window_times[0]) & (spikes <= window_times[-1]) + if not np.any(valid): + continue + idx = np.searchsorted(window_times, spikes[valid], side="right") - 1 + idx = np.clip(idx, 0, window_times.size - 1) + psth_hist += np.bincount(idx, minlength=window_times.size).astype(float) + + rate = psth_hist[:-1] / binwidth / float(len(self._trains)) + centers = (window_times[1:] + window_times[:-1]) * 0.5 + return Covariate(centers, rate, "PSTH", "time", "s", "spikes/sec", ["psth"]) + + def psthGLM(self, binwidth: float): + psth_signal = self.psth(binwidth) + return psth_signal, None, None + + +@dataclass +class TrialConfig: + covMask: Sequence[Sequence[str]] | Sequence[str] + sampleRate: float + history: object | None = None + ensCovHist: object | None = None + covLag: object | None = None + name: str = "" + + def setName(self, name: str) -> None: + self.name = str(name) + + @property + def covariate_names(self) -> list[str]: + if not self.covMask: + return [] + names: list[str] = [] + for item in self.covMask: + if isinstance(item, str): + names.append(item) + else: + names.extend([str(v) for v in item]) + return names + + +class ConfigCollection: + def __init__(self, configs: Sequence[TrialConfig] | None = None) -> None: + self.configs: list[TrialConfig] = list(configs or []) + + @property + def numConfigs(self) -> int: + return len(self.configs) + + @property + def configArray(self) -> list[TrialConfig]: + return self.configs + + def add_config(self, cfg: TrialConfig) -> None: + self.configs.append(cfg) + + def addConfig(self, cfg: TrialConfig) -> None: + self.add_config(cfg) + + def get_config(self, idx: int) -> TrialConfig: + if idx < 0 or idx >= len(self.configs): + raise IndexError("ConfigCollection index out of bounds (0-based indexing).") + return self.configs[idx] + + def getConfig(self, idx: int) -> TrialConfig: + return self.configs[idx - 1] + + def getConfigNames(self, index: Sequence[int] | None = None) -> list[str]: + if index is None: + index = list(range(1, self.numConfigs + 1)) + out: list[str] = [] + for i in index: + cfg = self.configs[i - 1] + out.append(cfg.name if cfg.name else f"Fit {i}") + return out + + +class Trial: + def __init__( + self, + spike_collection: SpikeTrainCollection | None = None, + covariate_collection: CovariateCollection | None = None, + events: Events | None = None, + *, + spikeColl: SpikeTrainCollection | None = None, + covarColl: CovariateCollection | None = None, + ) -> None: + self.spike_collection = spike_collection if spike_collection is not None else spikeColl + self.covariate_collection = covariate_collection if covariate_collection is not None else covarColl + if self.spike_collection is None or self.covariate_collection is None: + raise ValueError("Trial requires both spike_collection and covariate_collection") + self.events = events + + @property + def spikeColl(self) -> SpikeTrainCollection: + return self.spike_collection + + @property + def covarColl(self) -> CovariateCollection: + return self.covariate_collection + + def get_covariate_matrix(self, selected_covariates: Sequence[str] | None = None) -> tuple[np.ndarray, np.ndarray, list[str]]: + return self.covariate_collection.dataToMatrix(selected_covariates) + + def getSpikeVector(self, bin_edges: Sequence[float], neuron_index: int = 1) -> np.ndarray: + return self.spike_collection.getNST(neuron_index).to_binned_counts(bin_edges) + + +# Backward-compatible MATLAB-style aliases. +CovColl = CovariateCollection +nstColl = SpikeTrainCollection +ConfigColl = ConfigCollection + + +__all__ = [ + "CovariateCollection", + "SpikeTrainCollection", + "TrialConfig", + "ConfigCollection", + "Trial", + "CovColl", + "nstColl", + "ConfigColl", +] diff --git a/parity/TIER1_PORT_BACKLOG.md b/parity/TIER1_PORT_BACKLOG.md deleted file mode 100644 index 843c889c..00000000 --- a/parity/TIER1_PORT_BACKLOG.md +++ /dev/null @@ -1,23 +0,0 @@ -# Tier-1 Port Backlog - -Generated from `parity/parity_gap_report.json`. - -| Priority | MATLAB Class | Missing Methods | Coverage | Next Implementation Focus | -|---|---:|---:|---:|---| -| P2 | `DecodingAlgorithms` | 0 | 1.000 | n/a | -| P2 | `Analysis` | 0 | 1.000 | n/a | -| P2 | `Trial` | 0 | 1.000 | n/a | -| P2 | `CovColl` | 0 | 1.000 | n/a | -| P2 | `nstColl` | 0 | 1.000 | n/a | -| P2 | `FitResult` | 0 | 1.000 | n/a | -| P2 | `FitResSummary` | 0 | 1.000 | n/a | - -## Implementation Order -1. `DecodingAlgorithms` and `Analysis` (numerical behavior parity) -2. `Trial` / `CovColl` / `nstColl` (data plumbing parity) -3. `FitResult` / `FitResSummary` (model diagnostics parity) - -## Acceptance for Each Tier-1 Class -- Implement method aliases in `nstat.compat.matlab`. -- Add numerical fixture checks when outputs are deterministic. -- Add unit tests for method signatures and key behavior. diff --git a/parity/class_contracts.yml b/parity/class_contracts.yml deleted file mode 100644 index 9821e09a..00000000 --- a/parity/class_contracts.yml +++ /dev/null @@ -1,180 +0,0 @@ -version: 1 -description: > - Class-level contract manifest tying MATLAB classes to Python counterparts, - MATLAB-gold fixtures, and critical method checkpoints. - -classes: - - matlab_class: SignalObj - python_class: nstat.signal.Signal - compat_class: nstat.compat.matlab.SignalObj - fixture_path: tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat - key_methods: - - copy - - resample - - periodogram - - get_sub_signal - - merge - - - matlab_class: Covariate - python_class: nstat.signal.Covariate - compat_class: nstat.compat.matlab.Covariate - fixture_path: tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat - key_methods: - - get_sub_signal - - data_to_matrix - - compute_mean_plus_ci - - to_structure - - from_structure - - - matlab_class: ConfidenceInterval - python_class: nstat.confidence.ConfidenceInterval - compat_class: nstat.compat.matlab.ConfidenceInterval - fixture_path: tests/parity/fixtures/matlab_gold/classes/ConfidenceInterval/basic.mat - key_methods: - - width - - contains - - set_color - - set_value - - from_structure - - - matlab_class: Events - python_class: nstat.events.Events - compat_class: nstat.compat.matlab.Events - fixture_path: tests/parity/fixtures/matlab_gold/EventsExamples_gold.mat - key_methods: - - subset - - merge - - shift - - to_structure - - from_structure - - - matlab_class: History - python_class: nstat.history.HistoryBasis - compat_class: nstat.compat.matlab.History - fixture_path: tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat - key_methods: - - design_matrix - - to_filter - - set_window - - to_structure - - from_structure - - - matlab_class: nspikeTrain - python_class: nstat.spikes.SpikeTrain - compat_class: nstat.compat.matlab.nspikeTrain - fixture_path: tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat - key_methods: - - firing_rate_hz - - bin_counts - - binarize - - shift_time - - copy - - - matlab_class: nstColl - python_class: nstat.spikes.SpikeTrainCollection - compat_class: nstat.compat.matlab.nstColl - fixture_path: tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat - key_methods: - - to_binned_matrix - - merge - - get_first_spike_time - - get_last_spike_time - - get_spike_times - - - matlab_class: CovColl - python_class: nstat.trial.CovariateCollection - compat_class: nstat.compat.matlab.CovColl - fixture_path: tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat - key_methods: - - design_matrix - - get_cov - - set_mask - - to_structure - - from_structure - - - matlab_class: TrialConfig - python_class: nstat.trial.TrialConfig - compat_class: nstat.compat.matlab.TrialConfig - fixture_path: tests/parity/fixtures/matlab_gold/classes/TrialConfig/basic.mat - key_methods: - - get_name - - set_name - - to_structure - - from_structure - - - matlab_class: ConfigColl - python_class: nstat.trial.ConfigCollection - compat_class: nstat.compat.matlab.ConfigColl - fixture_path: tests/parity/fixtures/matlab_gold/classes/ConfigColl/basic.mat - key_methods: - - get_config - - add_config - - get_config_names - - to_structure - - from_structure - - - matlab_class: Trial - python_class: nstat.trial.Trial - compat_class: nstat.compat.matlab.Trial - fixture_path: tests/parity/fixtures/matlab_gold/TrialExamples_gold.mat - key_methods: - - aligned_binned_observation - - get_design_matrix - - set_history - - set_trial_partition - - to_structure - - - matlab_class: CIF - python_class: nstat.cif.CIFModel - compat_class: nstat.compat.matlab.CIF - fixture_path: tests/parity/fixtures/matlab_gold/classes/CIF/basic.mat - key_methods: - - evaluate - - linear_predictor - - log_likelihood - - simulate_by_thinning - - simulateCIFByThinningFromLambda - - - matlab_class: Analysis - python_class: nstat.analysis.Analysis - compat_class: nstat.compat.matlab.Analysis - fixture_path: tests/parity/fixtures/matlab_gold/AnalysisExamples_gold.mat - key_methods: - - fit_glm - - fit_trial - - run_analysis_for_neuron - - run_analysis_for_all_neurons - - compute_hist_lag - - - matlab_class: FitResult - python_class: nstat.fit.FitResult - compat_class: nstat.compat.matlab.FitResult - fixture_path: tests/parity/fixtures/matlab_gold/classes/FitResult/basic.mat - key_methods: - - predict - - aic - - bic - - as_cif_model - - to_structure - - - matlab_class: FitResSummary - python_class: nstat.fit.FitSummary - compat_class: nstat.compat.matlab.FitResSummary - fixture_path: tests/parity/fixtures/matlab_gold/classes/FitResSummary/basic.mat - key_methods: - - best_by_aic - - best_by_bic - - diff_aic - - diff_bic - - to_structure - - - matlab_class: DecodingAlgorithms - python_class: nstat.decoding.DecodingAlgorithms - compat_class: nstat.compat.matlab.DecodingAlgorithms - fixture_path: tests/parity/fixtures/matlab_gold/DecodingExample_gold.mat - key_methods: - - compute_spike_rate_cis - - compute_spike_rate_diff_cis - - decode_weighted_center - - decode_state_posterior - - computeSpikeRateCIs diff --git a/parity/class_fixture_export_spec.yml b/parity/class_fixture_export_spec.yml deleted file mode 100644 index e39e1ebf..00000000 --- a/parity/class_fixture_export_spec.yml +++ /dev/null @@ -1,69 +0,0 @@ -version: 1 -description: > - Fixture export specification for per-class equivalence contracts. - This file is consumed by class-equivalence inventory/report tooling and - test harnesses; it is not referenced by the README. - -generators: - - name: topic_gold_exporter - script: tools/parity/export_matlab_gold_fixtures.py - command: >- - python tools/parity/export_matlab_gold_fixtures.py - --matlab-root - --out tests/parity/fixtures/matlab_gold - - name: class_gold_exporter - script: matlab/fixtures/export_class_equivalence_fixtures.m - command: >- - matlab -batch "addpath('matlab/fixtures'); - export_class_equivalence_fixtures('', - 'tests/parity/fixtures/matlab_gold/classes');" - -classes: - - matlab_class: SignalObj - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat - - matlab_class: Covariate - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat - - matlab_class: ConfidenceInterval - generator: class_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/classes/ConfidenceInterval/basic.mat - - matlab_class: Events - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/EventsExamples_gold.mat - - matlab_class: History - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat - - matlab_class: nspikeTrain - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat - - matlab_class: nstColl - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat - - matlab_class: CovColl - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat - - matlab_class: TrialConfig - generator: class_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/classes/TrialConfig/basic.mat - - matlab_class: ConfigColl - generator: class_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/classes/ConfigColl/basic.mat - - matlab_class: Trial - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/TrialExamples_gold.mat - - matlab_class: CIF - generator: class_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/classes/CIF/basic.mat - - matlab_class: Analysis - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/AnalysisExamples_gold.mat - - matlab_class: FitResult - generator: class_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/classes/FitResult/basic.mat - - matlab_class: FitResSummary - generator: class_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/classes/FitResSummary/basic.mat - - matlab_class: DecodingAlgorithms - generator: topic_gold_exporter - fixture_path: tests/parity/fixtures/matlab_gold/DecodingExample_gold.mat diff --git a/parity/example_mapping.yaml b/parity/example_mapping.yaml deleted file mode 100644 index 85b6b4b9..00000000 --- a/parity/example_mapping.yaml +++ /dev/null @@ -1,122 +0,0 @@ -version: 1 -examples: - - matlab_topic: AnalysisExamples - python_notebook: notebooks/helpfiles/AnalysisExamples.ipynb - python_help_page: docs/help/examples/AnalysisExamples.md - status: implemented - - matlab_topic: AnalysisExamples2 - python_notebook: notebooks/helpfiles/AnalysisExamples2.ipynb - python_help_page: docs/help/examples/AnalysisExamples2.md - status: implemented - - matlab_topic: ConfigCollExamples - python_notebook: notebooks/helpfiles/ConfigCollExamples.ipynb - python_help_page: docs/help/examples/ConfigCollExamples.md - status: implemented - - matlab_topic: CovCollExamples - python_notebook: notebooks/helpfiles/CovCollExamples.ipynb - python_help_page: docs/help/examples/CovCollExamples.md - status: implemented - - matlab_topic: CovariateExamples - python_notebook: notebooks/helpfiles/CovariateExamples.ipynb - python_help_page: docs/help/examples/CovariateExamples.md - status: implemented - - matlab_topic: DecodingExample - python_notebook: notebooks/helpfiles/DecodingExample.ipynb - python_help_page: docs/help/examples/DecodingExample.md - status: implemented - - matlab_topic: DecodingExampleWithHist - python_notebook: notebooks/helpfiles/DecodingExampleWithHist.ipynb - python_help_page: docs/help/examples/DecodingExampleWithHist.md - status: implemented - - matlab_topic: DocumentationSetup2025b - python_notebook: notebooks/helpfiles/DocumentationSetup2025b.ipynb - python_help_page: docs/help/examples/DocumentationSetup2025b.md - status: implemented - - matlab_topic: EventsExamples - python_notebook: notebooks/helpfiles/EventsExamples.ipynb - python_help_page: docs/help/examples/EventsExamples.md - status: implemented - - matlab_topic: ExplicitStimulusWhiskerData - python_notebook: notebooks/helpfiles/ExplicitStimulusWhiskerData.ipynb - python_help_page: docs/help/examples/ExplicitStimulusWhiskerData.md - status: implemented - - matlab_topic: FitResSummaryExamples - python_notebook: notebooks/helpfiles/FitResSummaryExamples.ipynb - python_help_page: docs/help/examples/FitResSummaryExamples.md - status: implemented - - matlab_topic: FitResultExamples - python_notebook: notebooks/helpfiles/FitResultExamples.ipynb - python_help_page: docs/help/examples/FitResultExamples.md - status: implemented - - matlab_topic: FitResultReference - python_notebook: notebooks/helpfiles/FitResultReference.ipynb - python_help_page: docs/help/examples/FitResultReference.md - status: implemented - - matlab_topic: HippocampalPlaceCellExample - python_notebook: notebooks/helpfiles/HippocampalPlaceCellExample.ipynb - python_help_page: docs/help/examples/HippocampalPlaceCellExample.md - status: implemented - - matlab_topic: HistoryExamples - python_notebook: notebooks/helpfiles/HistoryExamples.ipynb - python_help_page: docs/help/examples/HistoryExamples.md - status: implemented - - matlab_topic: HybridFilterExample - python_notebook: notebooks/helpfiles/HybridFilterExample.ipynb - python_help_page: docs/help/examples/HybridFilterExample.md - status: implemented - - matlab_topic: NetworkTutorial - python_notebook: notebooks/helpfiles/NetworkTutorial.ipynb - python_help_page: docs/help/examples/NetworkTutorial.md - status: implemented - - matlab_topic: PPSimExample - python_notebook: notebooks/helpfiles/PPSimExample.ipynb - python_help_page: docs/help/examples/PPSimExample.md - status: implemented - - matlab_topic: PPThinning - python_notebook: notebooks/helpfiles/PPThinning.ipynb - python_help_page: docs/help/examples/PPThinning.md - status: implemented - - matlab_topic: PSTHEstimation - python_notebook: notebooks/helpfiles/PSTHEstimation.ipynb - python_help_page: docs/help/examples/PSTHEstimation.md - status: implemented - - matlab_topic: SignalObjExamples - python_notebook: notebooks/helpfiles/SignalObjExamples.ipynb - python_help_page: docs/help/examples/SignalObjExamples.md - status: implemented - - matlab_topic: StimulusDecode2D - python_notebook: notebooks/helpfiles/StimulusDecode2D.ipynb - python_help_page: docs/help/examples/StimulusDecode2D.md - status: implemented - - matlab_topic: TrialConfigExamples - python_notebook: notebooks/helpfiles/TrialConfigExamples.ipynb - python_help_page: docs/help/examples/TrialConfigExamples.md - status: implemented - - matlab_topic: TrialExamples - python_notebook: notebooks/helpfiles/TrialExamples.ipynb - python_help_page: docs/help/examples/TrialExamples.md - status: implemented - - matlab_topic: ValidationDataSet - python_notebook: notebooks/helpfiles/ValidationDataSet.ipynb - python_help_page: docs/help/examples/ValidationDataSet.md - status: implemented - - matlab_topic: mEPSCAnalysis - python_notebook: notebooks/helpfiles/mEPSCAnalysis.ipynb - python_help_page: docs/help/examples/mEPSCAnalysis.md - status: implemented - - matlab_topic: nSTATPaperExamples - python_notebook: notebooks/helpfiles/nSTATPaperExamples.ipynb - python_help_page: docs/help/examples/nSTATPaperExamples.md - status: implemented - - matlab_topic: nSpikeTrainExamples - python_notebook: notebooks/helpfiles/nSpikeTrainExamples.ipynb - python_help_page: docs/help/examples/nSpikeTrainExamples.md - status: implemented - - matlab_topic: nstCollExamples - python_notebook: notebooks/helpfiles/nstCollExamples.ipynb - python_help_page: docs/help/examples/nstCollExamples.md - status: implemented - - matlab_topic: publish_all_helpfiles - python_notebook: notebooks/helpfiles/publish_all_helpfiles.ipynb - python_help_page: docs/help/examples/publish_all_helpfiles.md - status: implemented diff --git a/parity/example_output_spec.yml b/parity/example_output_spec.yml deleted file mode 100644 index d478e542..00000000 --- a/parity/example_output_spec.yml +++ /dev/null @@ -1,49 +0,0 @@ -version: 1 -policy_name: example_output_spec - -defaults: - min_python_code_lines: 20 - min_python_code_cells: 1 - min_assertion_count: 2 - require_topic_checkpoint: true - require_plot_call: true - min_matlab_reference_images: 0 - min_python_validation_images: 1 - enforce_validation_images: true - require_line_port_audit: true - min_line_port_coverage: 0.0 - min_line_port_function_recall: 0.0 - allowed_strict_line_statuses: - - line_port_verified - - line_port_partial - - line_port_gap - - matlab_doc_only - - doc_only - - missing_artifact - - missing_executable_content - allowed_alignment_statuses: - - validated - out_of_scope_allowed_alignment_statuses: - - validated - - matlab_doc_only - - doc_only - -out_of_scope_topics: - - DocumentationSetup2025b - - FitResSummaryExamples - - FitResultExamples - - FitResultReference - -topics: - TrialConfigExamples: - min_python_code_lines: 4 - ConfigCollExamples: - min_python_code_lines: 4 - CovCollExamples: - min_python_code_lines: 15 - EventsExamples: - min_python_code_lines: 8 - nSpikeTrainExamples: - min_python_code_lines: 12 - nstCollExamples: - min_python_code_lines: 12 diff --git a/parity/function_example_alignment_report.json b/parity/function_example_alignment_report.json deleted file mode 100644 index da5bbc58..00000000 --- a/parity/function_example_alignment_report.json +++ /dev/null @@ -1,12225 +0,0 @@ -{ - "example_line_alignment_audit": { - "summary": { - "doc_only_topics": 0, - "matlab_doc_only_topics": 4, - "missing_artifact_topics": 0, - "missing_executable_topics": 0, - "pending_manual_review_topics": 0, - "strict_line_gap_topics": 22, - "strict_line_partial_topics": 3, - "strict_line_verified_topics": 1, - "total_topics": 30, - "validated_topics": 26 - }, - "topic_rows": [ - { - "alignment_status": "validated", - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 39, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 59, - "line_port_matlab_function_count": 39, - "line_port_matlab_lines": 59, - "line_port_python_function_count": 86, - "line_port_python_lines": 224, - "matlab_code_blocks": [ - { - "end_line": 26, - "line_count": 9, - "preview": "close all;", - "start_line": 18 - }, - { - "end_line": 33, - "line_count": 4, - "preview": "figure;", - "start_line": 30 - }, - { - "end_line": 42, - "line_count": 6, - "preview": "[b,dev,stats] = glmfit([xN yN (xN.^2-mean(xN.^2)) (yN.^2-mean(yN.^2)) (xN.*yN-mean(xN.*yN))],spikes_binned,'poisson');", - "start_line": 37 - }, - { - "end_line": 50, - "line_count": 4, - "preview": "figure;", - "start_line": 47 - }, - { - "end_line": 54, - "line_count": 2, - "preview": "lambda = exp(b(1) + b(2)*x_new + b(3)*y_new + b(4)*x_new.^2 + b(5)*y_new.^2 + b(6)*x_new.*y_new);", - "start_line": 53 - }, - { - "end_line": 64, - "line_count": 8, - "preview": "h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);", - "start_line": 57 - }, - { - "end_line": 70, - "line_count": 2, - "preview": "[b_lin,dev_lin,stats_lin] = glmfit([xN yN],spikes_binned,'poisson');", - "start_line": 69 - }, - { - "end_line": 73, - "line_count": 2, - "preview": "lambdaEst_lin = exp( b_lin(1) + b_lin(2)*xN+b_lin(3)*yN); % based on our GLM model with the log \"link function\"", - "start_line": 72 - }, - { - "end_line": 109, - "line_count": 22, - "preview": "lambdaEst=[lambdaEst_lin, lambdaEst_quad];", - "start_line": 88 - } - ], - "matlab_code_lines": 59, - "matlab_file": "helpfiles/AnalysisExamples.m", - "matlab_reference_image_count": 5, - "matlab_reference_images": [ - "helpfiles/AnalysisExamples.png", - "helpfiles/AnalysisExamples_01.png", - "helpfiles/AnalysisExamples_02.png", - "helpfiles/AnalysisExamples_03.png", - "helpfiles/AnalysisExamples_04.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=30, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 4, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=38, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 5, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=47, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 6, - "line_count": 2, - "preview": "section_index = 6" - }, - { - "cell_index": 7, - "line_count": 148, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=103, matlab_snippet=\"figure;\")" - } - ], - "python_code_lines": 179, - "python_notebook": "notebooks/helpfiles/AnalysisExamples.ipynb", - "python_to_matlab_line_ratio": 3.0338983050847457, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/AnalysisExamples/AnalysisExamples_001.png" - ], - "strict_line_status": "line_port_gap", - "topic": "AnalysisExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 2, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 38, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 61, - "line_port_matlab_function_count": 38, - "line_port_matlab_lines": 61, - "line_port_python_function_count": 87, - "line_port_python_lines": 232, - "matlab_code_blocks": [ - { - "end_line": 14, - "line_count": 9, - "preview": "close all;", - "start_line": 6 - }, - { - "end_line": 20, - "line_count": 5, - "preview": "nst = nspikeTrain(spiketimes);", - "start_line": 16 - }, - { - "end_line": 30, - "line_count": 1, - "preview": "[values_at_spiketimes] =position.getValueAt(spiketimes);", - "start_line": 30 - }, - { - "end_line": 36, - "line_count": 1, - "preview": "[values_at_spiketimes] =position.resample(1/min(diff(spiketimes))).getValueAt(spiketimes);", - "start_line": 36 - }, - { - "end_line": 44, - "line_count": 5, - "preview": "figure;", - "start_line": 40 - }, - { - "end_line": 52, - "line_count": 5, - "preview": "spikeColl = nstColl({nst});", - "start_line": 48 - }, - { - "end_line": 56, - "line_count": 3, - "preview": "tc{1} = TrialConfig({{'Baseline','mu'},{'Radial','x','y'}},sampleRate,[]); tc{1}.setName('Linear');", - "start_line": 54 - }, - { - "end_line": 62, - "line_count": 3, - "preview": "tcc = ConfigColl(tc); makePlot=1; neuronNum=1;", - "start_line": 60 - }, - { - "end_line": 69, - "line_count": 4, - "preview": "figure;", - "start_line": 66 - }, - { - "end_line": 76, - "line_count": 5, - "preview": "newData{1} =ones(size(x_new));", - "start_line": 72 - }, - { - "end_line": 79, - "line_count": 1, - "preview": "for i=1:fitResults.numResults", - "start_line": 79 - }, - { - "end_line": 84, - "line_count": 4, - "preview": "lambda = fitResults.evalLambda(i,newData);", - "start_line": 81 - }, - { - "end_line": 92, - "line_count": 7, - "preview": "hold on;", - "start_line": 86 - }, - { - "end_line": 98, - "line_count": 2, - "preview": "[b,dev,stats] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');", - "start_line": 97 - }, - { - "end_line": 107, - "line_count": 5, - "preview": "sampleRate=1000; makePlot=1; neuronNum = 1;", - "start_line": 103 - }, - { - "end_line": 109, - "line_count": 1, - "preview": "[fitResults,tcc] = Analysis.computeHistLag(trial,neuronNum,windowTimes,covLabels,Algorithm,batchMode,sampleRate,makePlot);", - "start_line": 109 - } - ], - "matlab_code_lines": 61, - "matlab_file": "helpfiles/AnalysisExamples2.m", - "matlab_reference_image_count": 6, - "matlab_reference_images": [ - "helpfiles/AnalysisExamples2.png", - "helpfiles/AnalysisExamples2_01.png", - "helpfiles/AnalysisExamples2_02.png", - "helpfiles/AnalysisExamples2_03.png", - "helpfiles/AnalysisExamples2_04.png", - "helpfiles/AnalysisExamples2_05.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=40, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 5, - "line_count": 2, - "preview": "section_index = 5" - }, - { - "cell_index": 6, - "line_count": 2, - "preview": "section_index = 6" - }, - { - "cell_index": 7, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=66, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 8, - "line_count": 2, - "preview": "section_index = 8" - }, - { - "cell_index": 9, - "line_count": 159, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=102, matlab_snippet=\"" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 79, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=31, matlab_snippet=\"position.getSigRep.plot('all',plotProps); %same as p" - } - ], - "python_code_lines": 83, - "python_notebook": "notebooks/helpfiles/CovariateExamples.ipynb", - "python_to_matlab_line_ratio": 4.368421052631579, - "python_validation_image_count": 2, - "python_validation_images": [ - "baseline/validation/notebook_images/CovariateExamples/CovariateExamples_001.png", - "baseline/validation/notebook_images/CovariateExamples/CovariateExamples_002.png" - ], - "strict_line_status": "line_port_gap", - "topic": "CovariateExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 38, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 57, - "line_port_matlab_function_count": 38, - "line_port_matlab_lines": 57, - "line_port_python_function_count": 81, - "line_port_python_lines": 236, - "matlab_code_blocks": [ - { - "end_line": 15, - "line_count": 7, - "preview": "close all;", - "start_line": 9 - }, - { - "end_line": 17, - "line_count": 1, - "preview": "lambda = Covariate(time,lambdaData./delta, '\\Lambda(t)','time','s','Hz',{'\\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}});", - "start_line": 17 - }, - { - "end_line": 23, - "line_count": 5, - "preview": "numRealizations = 10;", - "start_line": 19 - }, - { - "end_line": 33, - "line_count": 7, - "preview": "stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});", - "start_line": 27 - }, - { - "end_line": 47, - "line_count": 13, - "preview": "clear c;", - "start_line": 35 - }, - { - "end_line": 50, - "line_count": 2, - "preview": "paramEst = squeeze(Summary.bAct(:,2,:));", - "start_line": 49 - }, - { - "end_line": 68, - "line_count": 4, - "preview": "clear lambdaCIF;", - "start_line": 65 - }, - { - "end_line": 72, - "line_count": 2, - "preview": "lambdaCIF{i} = CIF([b0(i) b1(i)],{'1','x'},{'x'},'binomial');", - "start_line": 71 - }, - { - "end_line": 75, - "line_count": 2, - "preview": "spikeColl.resample(1/delta);", - "start_line": 74 - }, - { - "end_line": 85, - "line_count": 9, - "preview": "Q=2*std(stim.data(2:end)-stim.data(1:end-1));", - "start_line": 77 - }, - { - "end_line": 91, - "line_count": 5, - "preview": "hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});", - "start_line": 87 - } - ], - "matlab_code_lines": 57, - "matlab_file": "helpfiles/DecodingExample.m", - "matlab_reference_image_count": 7, - "matlab_reference_images": [ - "helpfiles/DecodingExample.png", - "helpfiles/DecodingExample_01.png", - "helpfiles/DecodingExample_02.png", - "helpfiles/DecodingExample_03.png", - "helpfiles/DecodingExample_04.png", - "helpfiles/DecodingExample_05.png", - "helpfiles/DecodingExample_06.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=21, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 3, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=30, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 4, - "line_count": 166, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=80, matlab_snippet=\"figure;\")" - } - ], - "python_code_lines": 191, - "python_notebook": "notebooks/helpfiles/DecodingExample.ipynb", - "python_to_matlab_line_ratio": 3.3508771929824563, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/DecodingExample/DecodingExample_001.png" - ], - "strict_line_status": "line_port_gap", - "topic": "DecodingExample" - }, - { - "alignment_status": "validated", - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 28, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 55, - "line_port_matlab_function_count": 28, - "line_port_matlab_lines": 55, - "line_port_python_function_count": 74, - "line_port_python_lines": 202, - "matlab_code_blocks": [ - { - "end_line": 12, - "line_count": 1, - "preview": "close all;", - "start_line": 12 - }, - { - "end_line": 20, - "line_count": 7, - "preview": "delta = 0.001; Tmax = 1;", - "start_line": 14 - }, - { - "end_line": 32, - "line_count": 11, - "preview": "histCoeffs= [-2 -2 -4];", - "start_line": 22 - }, - { - "end_line": 36, - "line_count": 3, - "preview": "figure;", - "start_line": 34 - }, - { - "end_line": 39, - "line_count": 1, - "preview": "for i=1:numRealizations", - "start_line": 39 - }, - { - "end_line": 43, - "line_count": 1, - "preview": "lambdaCIF{i} = CIF([mu b1],{'1','x'},{'x'},'binomial',histCoeffs,histObj);", - "start_line": 43 - }, - { - "end_line": 46, - "line_count": 2, - "preview": "lambdaCIFNoHist{i} = CIF([mu b1],{'1','x'},{'x'},'binomial');", - "start_line": 45 - }, - { - "end_line": 52, - "line_count": 2, - "preview": "sC.resample(1/delta);", - "start_line": 51 - }, - { - "end_line": 55, - "line_count": 2, - "preview": "Q=2*std(stim.data(2:end)-stim.data(1:end-1));", - "start_line": 54 - }, - { - "end_line": 59, - "line_count": 2, - "preview": "[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta);", - "start_line": 58 - }, - { - "end_line": 69, - "line_count": 7, - "preview": "figure;", - "start_line": 63 - }, - { - "end_line": 75, - "line_count": 5, - "preview": "hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});", - "start_line": 71 - }, - { - "end_line": 82, - "line_count": 6, - "preview": "subplot(2,1,2);", - "start_line": 77 - }, - { - "end_line": 88, - "line_count": 5, - "preview": "hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}});", - "start_line": 84 - } - ], - "matlab_code_lines": 55, - "matlab_file": "helpfiles/DecodingExampleWithHist.m", - "matlab_reference_image_count": 3, - "matlab_reference_images": [ - "helpfiles/DecodingExampleWithHist.png", - "helpfiles/DecodingExampleWithHist_01.png", - "helpfiles/DecodingExampleWithHist_02.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 143, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=90, matlab_snippet=\"" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 65, - "preview": "from pathlib import Path" - } - ], - "python_code_lines": 71, - "python_notebook": "notebooks/helpfiles/DocumentationSetup2025b.ipynb", - "python_to_matlab_line_ratio": null, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/DocumentationSetup2025b/DocumentationSetup2025b_001.png" - ], - "strict_line_status": "matlab_doc_only", - "topic": "DocumentationSetup2025b" - }, - { - "alignment_status": "validated", - "assertion_count": 2, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 4, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 8, - "line_port_matlab_function_count": 4, - "line_port_matlab_lines": 8, - "line_port_python_function_count": 40, - "line_port_python_lines": 112, - "matlab_code_blocks": [ - { - "end_line": 9, - "line_count": 6, - "preview": "close all;", - "start_line": 4 - }, - { - "end_line": 14, - "line_count": 2, - "preview": "figure; e.plot([],'r'); %dont specify handle, use red; handel = gca;", - "start_line": 13 - } - ], - "matlab_code_lines": 8, - "matlab_file": "helpfiles/EventsExamples.m", - "matlab_reference_image_count": 5, - "matlab_reference_images": [ - "helpfiles/EventsExamples.png", - "helpfiles/EventsExamples_01.png", - "helpfiles/EventsExamples_02.png", - "helpfiles/EventsExamples_03.png", - "helpfiles/EventsExamples_04.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 67, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=13, matlab_snippet=\"figure; e.plot([],'r'); %dont specify handle, use re" - } - ], - "python_code_lines": 67, - "python_notebook": "notebooks/helpfiles/EventsExamples.ipynb", - "python_to_matlab_line_ratio": 8.375, - "python_validation_image_count": 4, - "python_validation_images": [ - "baseline/validation/notebook_images/EventsExamples/EventsExamples_001.png", - "baseline/validation/notebook_images/EventsExamples/EventsExamples_002.png", - "baseline/validation/notebook_images/EventsExamples/EventsExamples_003.png", - "baseline/validation/notebook_images/EventsExamples/EventsExamples_004.png" - ], - "strict_line_status": "line_port_gap", - "topic": "EventsExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 43, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 115, - "line_port_matlab_function_count": 43, - "line_port_matlab_lines": 115, - "line_port_python_function_count": 88, - "line_port_python_lines": 293, - "matlab_code_blocks": [ - { - "end_line": 9, - "line_count": 2, - "preview": "close all;", - "start_line": 8 - }, - { - "end_line": 14, - "line_count": 4, - "preview": "Direction=3; Neuron=1; Stim=2;", - "start_line": 11 - }, - { - "end_line": 18, - "line_count": 3, - "preview": "time=0:.001:(length(data.t)-1)*.001;", - "start_line": 16 - }, - { - "end_line": 22, - "line_count": 3, - "preview": "stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});", - "start_line": 20 - }, - { - "end_line": 28, - "line_count": 5, - "preview": "nst = nspikeTrain(spikeTimes);", - "start_line": 24 - }, - { - "end_line": 35, - "line_count": 6, - "preview": "figure;", - "start_line": 30 - }, - { - "end_line": 45, - "line_count": 6, - "preview": "clear c;", - "start_line": 40 - }, - { - "end_line": 51, - "line_count": 3, - "preview": "figure;", - "start_line": 49 - }, - { - "end_line": 56, - "line_count": 4, - "preview": "stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});", - "start_line": 53 - }, - { - "end_line": 61, - "line_count": 4, - "preview": "nst = nspikeTrain(spikeTimes);", - "start_line": 58 - }, - { - "end_line": 77, - "line_count": 11, - "preview": "clear c;", - "start_line": 67 - }, - { - "end_line": 87, - "line_count": 7, - "preview": "sampleRate=1000;", - "start_line": 81 - }, - { - "end_line": 102, - "line_count": 14, - "preview": "KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));", - "start_line": 89 - }, - { - "end_line": 111, - "line_count": 7, - "preview": "clear c;", - "start_line": 105 - }, - { - "end_line": 116, - "line_count": 4, - "preview": "figure;", - "start_line": 113 - }, - { - "end_line": 128, - "line_count": 11, - "preview": "set(gca,'xtick',[]);", - "start_line": 118 - }, - { - "end_line": 132, - "line_count": 3, - "preview": "for i=2:length(x)", - "start_line": 130 - }, - { - "end_line": 140, - "line_count": 7, - "preview": "figure;", - "start_line": 134 - }, - { - "end_line": 157, - "line_count": 11, - "preview": "c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,[],NeighborHist);", - "start_line": 147 - } - ], - "matlab_code_lines": 115, - "matlab_file": "helpfiles/ExplicitStimulusWhiskerData.m", - "matlab_reference_image_count": 10, - "matlab_reference_images": [ - "helpfiles/ExplicitStimulusWhiskerData.png", - "helpfiles/ExplicitStimulusWhiskerData_01.png", - "helpfiles/ExplicitStimulusWhiskerData_02.png", - "helpfiles/ExplicitStimulusWhiskerData_03.png", - "helpfiles/ExplicitStimulusWhiskerData_04.png", - "helpfiles/ExplicitStimulusWhiskerData_05.png", - "helpfiles/ExplicitStimulusWhiskerData_06.png", - "helpfiles/ExplicitStimulusWhiskerData_07.png", - "helpfiles/ExplicitStimulusWhiskerData_08.png", - "helpfiles/ExplicitStimulusWhiskerData_09.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=30, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 3, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=49, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 2, - "preview": "section_index = 5" - }, - { - "cell_index": 6, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=113, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 7, - "line_count": 210, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=143, matlab_snippet=\"" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=23, matlab_snippet=\"figure(1);\")" - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 2, - "preview": "section_index = 5" - }, - { - "cell_index": 6, - "line_count": 506, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=162, matlab_snippet=\"h4=figure(4);\")" - } - ], - "python_code_lines": 521, - "python_notebook": "notebooks/helpfiles/HippocampalPlaceCellExample.ipynb", - "python_to_matlab_line_ratio": 3.361290322580645, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/HippocampalPlaceCellExample/HippocampalPlaceCellExample_001.png" - ], - "strict_line_status": "line_port_gap", - "topic": "HippocampalPlaceCellExample" - }, - { - "alignment_status": "validated", - "assertion_count": 5, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 8, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 18, - "line_port_matlab_function_count": 8, - "line_port_matlab_lines": 18, - "line_port_python_function_count": 49, - "line_port_python_lines": 146, - "matlab_code_blocks": [ - { - "end_line": 10, - "line_count": 4, - "preview": "spikeTimes = sort(rand(1,100))*1;", - "start_line": 7 - }, - { - "end_line": 20, - "line_count": 4, - "preview": "histn1=h.computeHistory(nst);", - "start_line": 17 - }, - { - "end_line": 32, - "line_count": 4, - "preview": "clear nst;", - "start_line": 29 - }, - { - "end_line": 35, - "line_count": 2, - "preview": "end", - "start_line": 34 - }, - { - "end_line": 38, - "line_count": 2, - "preview": "windowTimes = [.001 .002 .01];", - "start_line": 37 - }, - { - "end_line": 44, - "line_count": 2, - "preview": "histColl = h.computeHistory(spikeColl);", - "start_line": 43 - } - ], - "matlab_code_lines": 18, - "matlab_file": "helpfiles/HistoryExamples.m", - "matlab_reference_image_count": 5, - "matlab_reference_images": [ - "helpfiles/HistoryExamples.png", - "helpfiles/HistoryExamples_01.png", - "helpfiles/HistoryExamples_02.png", - "helpfiles/HistoryExamples_03.png", - "helpfiles/HistoryExamples_04.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=18, matlab_snippet=\"figure; subplot(3,1,1); h.plot; ylabel('History Wind" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 81, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=44, matlab_snippet=\"figure; histColl.plot;\")" - } - ], - "python_code_lines": 101, - "python_notebook": "notebooks/helpfiles/HistoryExamples.ipynb", - "python_to_matlab_line_ratio": 5.611111111111111, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/HistoryExamples/HistoryExamples_001.png" - ], - "strict_line_status": "line_port_gap", - "topic": "HistoryExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 5, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 68, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 288, - "line_port_matlab_function_count": 68, - "line_port_matlab_lines": 288, - "line_port_python_function_count": 114, - "line_port_python_lines": 458, - "matlab_code_blocks": [ - { - "end_line": 44, - "line_count": 11, - "preview": "clear all;", - "start_line": 34 - }, - { - "end_line": 53, - "line_count": 8, - "preview": "A{1} = [1 0 0 0 0 0;", - "start_line": 46 - }, - { - "end_line": 56, - "line_count": 2, - "preview": "Px0{2} =1e-6*eye(6,6);", - "start_line": 55 - }, - { - "end_line": 59, - "line_count": 2, - "preview": "minCovVal = 1e-12;", - "start_line": 58 - }, - { - "end_line": 68, - "line_count": 6, - "preview": "Q{2}=[minCovVal 0 0 0 0 0;", - "start_line": 63 - }, - { - "end_line": 70, - "line_count": 1, - "preview": "Q{1}=minCovVal*eye(2,2);", - "start_line": 70 - }, - { - "end_line": 74, - "line_count": 3, - "preview": "mstate = zeros(1,length(time));", - "start_line": 72 - }, - { - "end_line": 79, - "line_count": 3, - "preview": "X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));", - "start_line": 77 - }, - { - "end_line": 81, - "line_count": 1, - "preview": "for i = 1:length(time)", - "start_line": 81 - }, - { - "end_line": 100, - "line_count": 18, - "preview": "if(i==1)", - "start_line": 83 - }, - { - "end_line": 102, - "line_count": 1, - "preview": "end", - "start_line": 102 - }, - { - "end_line": 120, - "line_count": 16, - "preview": "load paperHybridFilterExample;", - "start_line": 105 - }, - { - "end_line": 131, - "line_count": 8, - "preview": "subplot(4,2,[6 8]);", - "start_line": 124 - }, - { - "end_line": 141, - "line_count": 9, - "preview": "subplot(4,2,5);", - "start_line": 133 - }, - { - "end_line": 152, - "line_count": 9, - "preview": "subplot(4,2,7);", - "start_line": 144 - }, - { - "end_line": 157, - "line_count": 4, - "preview": "meanMu = log(10*delta); % baseline firing rate", - "start_line": 154 - }, - { - "end_line": 159, - "line_count": 1, - "preview": "dataMat = [ones(size(X,2),1),X(:,1:end)'];", - "start_line": 159 - }, - { - "end_line": 162, - "line_count": 2, - "preview": "clear lambda tempSpikeColl lambdaCIF n;", - "start_line": 161 - }, - { - "end_line": 186, - "line_count": 23, - "preview": "for i=1:numCells", - "start_line": 164 - }, - { - "end_line": 208, - "line_count": 12, - "preview": "nonMovingInd = intersect(find(X(5,:)==0),find(X(6,:)==0));", - "start_line": 197 - }, - { - "end_line": 214, - "line_count": 5, - "preview": "for n=1:numExamples", - "start_line": 210 - }, - { - "end_line": 219, - "line_count": 1, - "preview": "dataMat = [ones(size(X,2),1),X(:,1:end)'];", - "start_line": 219 - }, - { - "end_line": 222, - "line_count": 2, - "preview": "clear lambda tempSpikeColl lambdaCIF nst;", - "start_line": 221 - }, - { - "end_line": 239, - "line_count": 16, - "preview": "for i=1:numCells", - "start_line": 224 - }, - { - "end_line": 247, - "line_count": 4, - "preview": "spikeColl = nstColl(nst);", - "start_line": 244 - }, - { - "end_line": 255, - "line_count": 6, - "preview": "Mu0=.5*ones(size(p_ij,1),1);", - "start_line": 250 - }, - { - "end_line": 259, - "line_count": 3, - "preview": "x0{2} = X(ind{2},1);", - "start_line": 257 - }, - { - "end_line": 268, - "line_count": 6, - "preview": "[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...", - "start_line": 263 - }, - { - "end_line": 276, - "line_count": 6, - "preview": "X_estAll(:,:,n) = X_est;", - "start_line": 271 - }, - { - "end_line": 284, - "line_count": 5, - "preview": "subplot(4,3,[1 4]);", - "start_line": 280 - }, - { - "end_line": 290, - "line_count": 4, - "preview": "subplot(4,3,[7 10]);", - "start_line": 287 - }, - { - "end_line": 296, - "line_count": 4, - "preview": "subplot(4,3,[2 3 5 6]);", - "start_line": 293 - }, - { - "end_line": 302, - "line_count": 4, - "preview": "subplot(4,3,8);", - "start_line": 299 - }, - { - "end_line": 308, - "line_count": 4, - "preview": "subplot(4,3,9);", - "start_line": 305 - }, - { - "end_line": 314, - "line_count": 4, - "preview": "subplot(4,3,11);", - "start_line": 311 - }, - { - "end_line": 319, - "line_count": 4, - "preview": "subplot(4,3,12);", - "start_line": 316 - }, - { - "end_line": 324, - "line_count": 1, - "preview": "end", - "start_line": 324 - }, - { - "end_line": 344, - "line_count": 11, - "preview": "subplot(4,3,[1 4]);", - "start_line": 334 - }, - { - "end_line": 359, - "line_count": 10, - "preview": "subplot(4,3,[7 10]);", - "start_line": 350 - }, - { - "end_line": 369, - "line_count": 8, - "preview": "subplot(4,3,[2 3 5 6]);", - "start_line": 362 - }, - { - "end_line": 375, - "line_count": 5, - "preview": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;", - "start_line": 371 - }, - { - "end_line": 386, - "line_count": 8, - "preview": "subplot(4,3,8);", - "start_line": 379 - }, - { - "end_line": 401, - "line_count": 13, - "preview": "subplot(4,3,9);", - "start_line": 389 - }, - { - "end_line": 410, - "line_count": 7, - "preview": "subplot(4,3,11);", - "start_line": 404 - }, - { - "end_line": 419, - "line_count": 7, - "preview": "subplot(4,3,12);", - "start_line": 413 - } - ], - "matlab_code_lines": 288, - "matlab_file": "helpfiles/HybridFilterExample.m", - "matlab_reference_image_count": 3, - "matlab_reference_images": [ - "helpfiles/HybridFilterExample.png", - "helpfiles/HybridFilterExample_01.png", - "helpfiles/HybridFilterExample_02.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=110, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*." - }, - { - "cell_index": 6, - "line_count": 398, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=207, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*." - } - ], - "python_code_lines": 413, - "python_notebook": "notebooks/helpfiles/HybridFilterExample.ipynb", - "python_to_matlab_line_ratio": 1.4340277777777777, - "python_validation_image_count": 2, - "python_validation_images": [ - "baseline/validation/notebook_images/HybridFilterExample/HybridFilterExample_001.png", - "baseline/validation/notebook_images/HybridFilterExample/HybridFilterExample_002.png" - ], - "strict_line_status": "line_port_verified", - "topic": "HybridFilterExample" - }, - { - "alignment_status": "validated", - "assertion_count": 9, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 37, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 88, - "line_port_matlab_function_count": 37, - "line_port_matlab_lines": 88, - "line_port_python_function_count": 86, - "line_port_python_lines": 288, - "matlab_code_blocks": [ - { - "end_line": 34, - "line_count": 6, - "preview": "clear all;", - "start_line": 29 - }, - { - "end_line": 38, - "line_count": 2, - "preview": "mu{1}=-3;", - "start_line": 37 - }, - { - "end_line": 53, - "line_count": 2, - "preview": "H{1}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1');", - "start_line": 52 - }, - { - "end_line": 64, - "line_count": 1, - "preview": "S{1}=tf([1],1,Ts,'Variable','z^-1');", - "start_line": 64 - }, - { - "end_line": 66, - "line_count": 1, - "preview": "S{2}=tf([-1],1,Ts,'Variable','z^-1');", - "start_line": 66 - }, - { - "end_line": 81, - "line_count": 1, - "preview": "E{1}=tf([1],1,Ts,'Variable','z^-1');", - "start_line": 81 - }, - { - "end_line": 83, - "line_count": 1, - "preview": "E{2}=tf([-4],1,Ts,'Variable','z^-1');", - "start_line": 83 - }, - { - "end_line": 91, - "line_count": 3, - "preview": "f=1; %Stimulus frequency [Hz]", - "start_line": 89 - }, - { - "end_line": 103, - "line_count": 9, - "preview": "assignin('base','S1',S{1});", - "start_line": 95 - }, - { - "end_line": 117, - "line_count": 9, - "preview": "fitType = 'binomial';", - "start_line": 109 - }, - { - "end_line": 122, - "line_count": 4, - "preview": "for i=1:numNeurons", - "start_line": 119 - }, - { - "end_line": 127, - "line_count": 3, - "preview": "sC=nstColl(nst);", - "start_line": 125 - }, - { - "end_line": 133, - "line_count": 3, - "preview": "figure;", - "start_line": 131 - }, - { - "end_line": 140, - "line_count": 1, - "preview": "baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'});", - "start_line": 140 - }, - { - "end_line": 142, - "line_count": 1, - "preview": "spikeColl = sC; %Use the generated data as our collection of spikes", - "start_line": 142 - }, - { - "end_line": 145, - "line_count": 2, - "preview": "cc=CovColl({stim,baseline});", - "start_line": 144 - }, - { - "end_line": 149, - "line_count": 1, - "preview": "clear c;", - "start_line": 149 - }, - { - "end_line": 151, - "line_count": 1, - "preview": "selfHist = [0:1:3]*Ts;", - "start_line": 151 - }, - { - "end_line": 154, - "line_count": 1, - "preview": "ensHist = [0 1]*Ts;", - "start_line": 154 - }, - { - "end_line": 158, - "line_count": 1, - "preview": "sampleRate = 1/Ts;", - "start_line": 158 - }, - { - "end_line": 165, - "line_count": 2, - "preview": "c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);", - "start_line": 164 - }, - { - "end_line": 169, - "line_count": 2, - "preview": "c{2} = TrialConfig({{'Baseline','mu'}},sampleRate,[],ensHist);", - "start_line": 168 - }, - { - "end_line": 174, - "line_count": 3, - "preview": "c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,...", - "start_line": 172 - }, - { - "end_line": 179, - "line_count": 2, - "preview": "cfgColl= ConfigColl(c);", - "start_line": 178 - }, - { - "end_line": 184, - "line_count": 3, - "preview": "results{1}.plotResults;", - "start_line": 182 - }, - { - "end_line": 194, - "line_count": 7, - "preview": "actNetwork = zeros(numNeurons,numNeurons);", - "start_line": 188 - }, - { - "end_line": 200, - "line_count": 3, - "preview": "[coeffs,labels]=results{i}.getCoeffs;", - "start_line": 198 - }, - { - "end_line": 214, - "line_count": 13, - "preview": "maxVal=max(max(abs(actNetwork)));", - "start_line": 202 - } - ], - "matlab_code_lines": 88, - "matlab_file": "helpfiles/NetworkTutorial.m", - "matlab_reference_image_count": 8, - "matlab_reference_images": [ - "helpfiles/NetworkTutorial.png", - "helpfiles/NetworkTutorial_01.png", - "helpfiles/NetworkTutorial_02.png", - "helpfiles/NetworkTutorial_03.png", - "helpfiles/NetworkTutorial_04.png", - "helpfiles/NetworkTutorial_05.png", - "helpfiles/PPSimExample-BlockDiagram.png", - "helpfiles/SimulatedNetwork2.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 2, - "preview": "section_index = 5" - }, - { - "cell_index": 6, - "line_count": 2, - "preview": "section_index = 6" - }, - { - "cell_index": 7, - "line_count": 2, - "preview": "section_index = 7" - }, - { - "cell_index": 8, - "line_count": 2, - "preview": "section_index = 8" - }, - { - "cell_index": 9, - "line_count": 2, - "preview": "section_index = 9" - }, - { - "cell_index": 10, - "line_count": 2, - "preview": "section_index = 10" - }, - { - "cell_index": 11, - "line_count": 2, - "preview": "section_index = 11" - }, - { - "cell_index": 12, - "line_count": 2, - "preview": "section_index = 12" - }, - { - "cell_index": 13, - "line_count": 2, - "preview": "section_index = 13" - }, - { - "cell_index": 14, - "line_count": 2, - "preview": "section_index = 14" - }, - { - "cell_index": 15, - "line_count": 2, - "preview": "section_index = 15" - }, - { - "cell_index": 16, - "line_count": 2, - "preview": "section_index = 16" - }, - { - "cell_index": 17, - "line_count": 2, - "preview": "section_index = 17" - }, - { - "cell_index": 18, - "line_count": 2, - "preview": "section_index = 18" - }, - { - "cell_index": 19, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=19, matlab_line_number=131, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 20, - "line_count": 2, - "preview": "section_index = 20" - }, - { - "cell_index": 21, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=21, matlab_line_number=205, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 22, - "line_count": 189, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=22, matlab_line_number=216, matlab_snippet=\"" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 2, - "preview": "section_index = 5" - }, - { - "cell_index": 6, - "line_count": 2, - "preview": "section_index = 6" - }, - { - "cell_index": 7, - "line_count": 2, - "preview": "section_index = 7" - }, - { - "cell_index": 8, - "line_count": 2, - "preview": "section_index = 8" - }, - { - "cell_index": 9, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=66, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 10, - "line_count": 2, - "preview": "section_index = 10" - }, - { - "cell_index": 11, - "line_count": 2, - "preview": "section_index = 11" - }, - { - "cell_index": 12, - "line_count": 2, - "preview": "section_index = 12" - }, - { - "cell_index": 13, - "line_count": 2, - "preview": "section_index = 13" - }, - { - "cell_index": 14, - "line_count": 2, - "preview": "section_index = 14" - }, - { - "cell_index": 15, - "line_count": 2, - "preview": "section_index = 15" - }, - { - "cell_index": 16, - "line_count": 2, - "preview": "section_index = 16" - }, - { - "cell_index": 17, - "line_count": 139, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=17, matlab_line_number=118, matlab_snippet=\"=u2);", - "start_line": 31 - }, - { - "end_line": 42, - "line_count": 9, - "preview": "figure(1);", - "start_line": 34 - }, - { - "end_line": 49, - "line_count": 6, - "preview": "figure(2);", - "start_line": 44 - }, - { - "end_line": 61, - "line_count": 7, - "preview": "numRealizations = 20;", - "start_line": 55 - }, - { - "end_line": 65, - "line_count": 2, - "preview": "parity = struct();", - "start_line": 64 - } - ], - "matlab_code_lines": 40, - "matlab_file": "helpfiles/PPThinning.m", - "matlab_reference_image_count": 5, - "matlab_reference_images": [ - "helpfiles/PPThinning.png", - "helpfiles/PPThinning_01.png", - "helpfiles/PPThinning_02.png", - "helpfiles/PPThinning_03.png", - "helpfiles/PPThinning_04.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=34, matlab_snippet=\"figure(1);\")" - }, - { - "cell_index": 4, - "line_count": 106, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=57, matlab_snippet=\"figure(3);\")" - } - ], - "python_code_lines": 124, - "python_notebook": "notebooks/helpfiles/PPThinning.ipynb", - "python_to_matlab_line_ratio": 3.1, - "python_validation_image_count": 4, - "python_validation_images": [ - "baseline/validation/notebook_images/PPThinning/PPThinning_001.png", - "baseline/validation/notebook_images/PPThinning/PPThinning_002.png", - "baseline/validation/notebook_images/PPThinning/PPThinning_003.png", - "baseline/validation/notebook_images/PPThinning/PPThinning_004.png" - ], - "strict_line_status": "line_port_gap", - "topic": "PPThinning" - }, - { - "alignment_status": "validated", - "assertion_count": 3, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 14, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 28, - "line_port_matlab_function_count": 14, - "line_port_matlab_lines": 28, - "line_port_python_function_count": 63, - "line_port_python_lines": 155, - "matlab_code_blocks": [ - { - "end_line": 25, - "line_count": 11, - "preview": "close all;", - "start_line": 15 - }, - { - "end_line": 39, - "line_count": 10, - "preview": "figure;", - "start_line": 30 - }, - { - "end_line": 48, - "line_count": 7, - "preview": "psth_mean_hz = mean(psth.data);", - "start_line": 42 - } - ], - "matlab_code_lines": 28, - "matlab_file": "helpfiles/PSTHEstimation.m", - "matlab_reference_image_count": 3, - "matlab_reference_images": [ - "helpfiles/PSTHEstimation.png", - "helpfiles/PSTHEstimation_01.png", - "helpfiles/PSTHEstimation_02.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=24, matlab_snippet=\"spikeColl.plot; set(gca,'ytickLabel',[]);\")" - }, - { - "cell_index": 3, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=30, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 4, - "line_count": 92, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=57, matlab_snippet=\"" - }, - { - "cell_index": 2, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=16, matlab_snippet=\"subplot(2,1,1); s.plot;\")" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=44, matlab_snippet=\"figure\")" - }, - { - "cell_index": 5, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=48, matlab_snippet=\"figure\")" - }, - { - "cell_index": 6, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=54, matlab_snippet=\"figure\")" - }, - { - "cell_index": 7, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=74, matlab_snippet=\"figure\")" - }, - { - "cell_index": 8, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=8, matlab_line_number=80, matlab_snippet=\"figure\")" - }, - { - "cell_index": 9, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=85, matlab_snippet=\"figure\")" - }, - { - "cell_index": 10, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=10, matlab_line_number=92, matlab_snippet=\"figure\")" - }, - { - "cell_index": 11, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=97, matlab_snippet=\"figure\")" - }, - { - "cell_index": 12, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=12, matlab_line_number=108, matlab_snippet=\"figure\")" - }, - { - "cell_index": 13, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=13, matlab_line_number=123, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 14, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=14, matlab_line_number=139, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 15, - "line_count": 182, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=15, matlab_line_number=155, matlab_snippet=\"figure;\")" - } - ], - "python_code_lines": 313, - "python_notebook": "notebooks/helpfiles/SignalObjExamples.ipynb", - "python_to_matlab_line_ratio": 3.8641975308641974, - "python_validation_image_count": 6, - "python_validation_images": [ - "baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_001.png", - "baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_002.png", - "baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_003.png", - "baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_004.png", - "baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_005.png", - "baseline/validation/notebook_images/SignalObjExamples/SignalObjExamples_006.png" - ], - "strict_line_status": "line_port_gap", - "topic": "SignalObjExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 2, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 47, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 92, - "line_port_matlab_function_count": 47, - "line_port_matlab_lines": 92, - "line_port_python_function_count": 94, - "line_port_python_lines": 230, - "matlab_code_blocks": [ - { - "end_line": 14, - "line_count": 9, - "preview": "delta = 0.001;", - "start_line": 6 - }, - { - "end_line": 20, - "line_count": 5, - "preview": "velSig = SignalObj(time, [vx, vy],'vel');", - "start_line": 16 - }, - { - "end_line": 27, - "line_count": 4, - "preview": "figure;", - "start_line": 24 - }, - { - "end_line": 32, - "line_count": 2, - "preview": "clear lambdaCIF lambda tempSpikeColl n spikeColl", - "start_line": 31 - }, - { - "end_line": 40, - "line_count": 7, - "preview": "coeffs = -abs(1*randn(numRealizations,5));", - "start_line": 34 - }, - { - "end_line": 44, - "line_count": 3, - "preview": "tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);", - "start_line": 42 - }, - { - "end_line": 55, - "line_count": 10, - "preview": "try", - "start_line": 46 - }, - { - "end_line": 63, - "line_count": 5, - "preview": "figure;", - "start_line": 59 - }, - { - "end_line": 68, - "line_count": 3, - "preview": "clear placeField;", - "start_line": 66 - }, - { - "end_line": 72, - "line_count": 3, - "preview": "for i=1:numRealizations", - "start_line": 70 - }, - { - "end_line": 74, - "line_count": 1, - "preview": "end", - "start_line": 74 - }, - { - "end_line": 76, - "line_count": 1, - "preview": "fact=factor(numRealizations);", - "start_line": 76 - }, - { - "end_line": 88, - "line_count": 11, - "preview": "for i=1:numRealizations", - "start_line": 78 - }, - { - "end_line": 90, - "line_count": 1, - "preview": "end", - "start_line": 90 - }, - { - "end_line": 95, - "line_count": 3, - "preview": "spikeColl = nstColl(n);", - "start_line": 93 - }, - { - "end_line": 118, - "line_count": 21, - "preview": "vx=var(px(2:end)-px(1:end-1));", - "start_line": 98 - }, - { - "end_line": 123, - "line_count": 3, - "preview": "parity = struct();", - "start_line": 121 - } - ], - "matlab_code_lines": 92, - "matlab_file": "helpfiles/StimulusDecode2D.m", - "matlab_reference_image_count": 7, - "matlab_reference_images": [ - "helpfiles/StimulusDecode2D.png", - "helpfiles/StimulusDecode2D_01.png", - "helpfiles/StimulusDecode2D_02.png", - "helpfiles/StimulusDecode2D_03.png", - "helpfiles/StimulusDecode2D_04.png", - "helpfiles/StimulusDecode2D_05.png", - "helpfiles/StimulusDecode2D_06.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=59, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 160, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=116, matlab_snippet=\"figure;\")" - } - ], - "python_code_lines": 178, - "python_notebook": "notebooks/helpfiles/StimulusDecode2D.ipynb", - "python_to_matlab_line_ratio": 1.934782608695652, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/StimulusDecode2D/StimulusDecode2D_001.png" - ], - "strict_line_status": "line_port_partial", - "topic": "StimulusDecode2D" - }, - { - "alignment_status": "validated", - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 2, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 3, - "line_port_matlab_function_count": 2, - "line_port_matlab_lines": 3, - "line_port_python_function_count": 25, - "line_port_python_lines": 69, - "matlab_code_blocks": [ - { - "end_line": 5, - "line_count": 3, - "preview": "tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2);", - "start_line": 3 - } - ], - "matlab_code_lines": 3, - "matlab_file": "helpfiles/TrialConfigExamples.m", - "matlab_reference_image_count": 0, - "matlab_reference_images": [], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 79, - "preview": "import matplotlib" - } - ], - "python_code_lines": 79, - "python_notebook": "notebooks/helpfiles/TrialConfigExamples.ipynb", - "python_to_matlab_line_ratio": 26.333333333333332, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/TrialConfigExamples/TrialConfigExamples_001.png" - ], - "strict_line_status": "line_port_gap", - "topic": "TrialConfigExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 5, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 11, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 25, - "line_port_matlab_function_count": 11, - "line_port_matlab_lines": 25, - "line_port_python_function_count": 59, - "line_port_python_lines": 178, - "matlab_code_blocks": [ - { - "end_line": 7, - "line_count": 2, - "preview": "close all; clear all;", - "start_line": 6 - }, - { - "end_line": 13, - "line_count": 3, - "preview": "windowTimes = [0 .1 .2 .4];", - "start_line": 11 - }, - { - "end_line": 20, - "line_count": 4, - "preview": "load CovariateSample.mat; %load position and force covariates", - "start_line": 17 - }, - { - "end_line": 27, - "line_count": 4, - "preview": "eTimes = sort(rand(1,2)*lengthTrial);", - "start_line": 24 - }, - { - "end_line": 37, - "line_count": 7, - "preview": "clear nst;", - "start_line": 31 - }, - { - "end_line": 43, - "line_count": 2, - "preview": "trial1=Trial(spikeColl, cc, e, h);", - "start_line": 42 - }, - { - "end_line": 48, - "line_count": 2, - "preview": "trial1.setCovMask({{'Position','x'},{'Force','f_x'}})", - "start_line": 47 - }, - { - "end_line": 50, - "line_count": 1, - "preview": "trial1.getHistForNeurons([1:2]);", - "start_line": 50 - } - ], - "matlab_code_lines": 25, - "matlab_file": "helpfiles/TrialExamples.m", - "matlab_reference_image_count": 7, - "matlab_reference_images": [ - "helpfiles/TrialExamples.png", - "helpfiles/TrialExamples_01.png", - "helpfiles/TrialExamples_02.png", - "helpfiles/TrialExamples_03.png", - "helpfiles/TrialExamples_04.png", - "helpfiles/TrialExamples_05.png", - "helpfiles/TrialExamples_06.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=13, matlab_snippet=\"figure; h.plot;\")" - }, - { - "cell_index": 4, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=20, matlab_snippet=\"figure; cc.plot;\")" - }, - { - "cell_index": 5, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=27, matlab_snippet=\"figure; e.plot;\")" - }, - { - "cell_index": 6, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=37, matlab_snippet=\"figure; spikeColl.plot;\")" - }, - { - "cell_index": 7, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=7, matlab_line_number=43, matlab_snippet=\"figure; trial1.plot; % plot all the data;\")" - }, - { - "cell_index": 8, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=8, matlab_line_number=48, matlab_snippet=\"figure; trial1.plot;\")" - }, - { - "cell_index": 9, - "line_count": 77, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=51, matlab_snippet=\"" - } - ], - "python_code_lines": 133, - "python_notebook": "notebooks/helpfiles/TrialExamples.ipynb", - "python_to_matlab_line_ratio": 5.32, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/TrialExamples/TrialExamples_001.png" - ], - "strict_line_status": "line_port_gap", - "topic": "TrialExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 2, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 24, - "line_port_coverage": 0.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 0, - "line_port_matlab_function_count": 24, - "line_port_matlab_lines": 77, - "line_port_python_function_count": 68, - "line_port_python_lines": 266, - "matlab_code_blocks": [ - { - "end_line": 12, - "line_count": 2, - "preview": "clear all;", - "start_line": 11 - }, - { - "end_line": 18, - "line_count": 5, - "preview": "p=0.01; % bernoilli probability", - "start_line": 14 - }, - { - "end_line": 20, - "line_count": 1, - "preview": "mu = log(lambda*delta/(1-lambda*delta))", - "start_line": 20 - }, - { - "end_line": 30, - "line_count": 8, - "preview": "for i=1:2", - "start_line": 23 - }, - { - "end_line": 35, - "line_count": 1, - "preview": "nst{1}.plotISIHistogram;", - "start_line": 35 - }, - { - "end_line": 46, - "line_count": 4, - "preview": "spikeColl=nstColl(nst); %create a nstColl - a collection of spikeTrains", - "start_line": 43 - }, - { - "end_line": 50, - "line_count": 2, - "preview": "clear c;", - "start_line": 49 - }, - { - "end_line": 54, - "line_count": 3, - "preview": "c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]);", - "start_line": 52 - }, - { - "end_line": 65, - "line_count": 6, - "preview": "results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);", - "start_line": 60 - }, - { - "end_line": 80, - "line_count": 6, - "preview": "p1=0.001; % bernoilli probability of process 1", - "start_line": 75 - }, - { - "end_line": 86, - "line_count": 5, - "preview": "p2=0.01; % bernoilli probability of process 1", - "start_line": 82 - }, - { - "end_line": 90, - "line_count": 2, - "preview": "lambdaConst = (N1*p1 + N2*p2)/(T1+T2)", - "start_line": 89 - }, - { - "end_line": 102, - "line_count": 9, - "preview": "for i=1:2", - "start_line": 94 - }, - { - "end_line": 107, - "line_count": 4, - "preview": "nst{i}=nspikeTrain([spikeTimes1 spikeTimes2],'',delta);", - "start_line": 104 - }, - { - "end_line": 113, - "line_count": 3, - "preview": "spikeColl=nstColl(nst); %create a nstColl", - "start_line": 111 - }, - { - "end_line": 118, - "line_count": 3, - "preview": "sampleRate=1000;", - "start_line": 116 - }, - { - "end_line": 121, - "line_count": 2, - "preview": "c{1} = TrialConfig({{'Baseline','muConst'}},sampleRate,[],[]);", - "start_line": 120 - }, - { - "end_line": 125, - "line_count": 3, - "preview": "c{2} = TrialConfig({{'Baseline','mu1','mu2'}},sampleRate,[],[]);", - "start_line": 123 - }, - { - "end_line": 134, - "line_count": 6, - "preview": "results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);", - "start_line": 129 - }, - { - "end_line": 138, - "line_count": 2, - "preview": "Summary = FitResSummary(results);", - "start_line": 137 - } - ], - "matlab_code_lines": 77, - "matlab_file": "helpfiles/ValidationDataSet.m", - "matlab_reference_image_count": 13, - "matlab_reference_images": [ - "helpfiles/ValidationDataSet.png", - "helpfiles/ValidationDataSet_01.png", - "helpfiles/ValidationDataSet_02.png", - "helpfiles/ValidationDataSet_03.png", - "helpfiles/ValidationDataSet_04.png", - "helpfiles/ValidationDataSet_05.png", - "helpfiles/ValidationDataSet_06.png", - "helpfiles/ValidationDataSet_07.png", - "helpfiles/ValidationDataSet_08.png", - "helpfiles/ValidationDataSet_09.png", - "helpfiles/ValidationDataSet_10.png", - "helpfiles/ValidationDataSet_11.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 2, - "preview": "section_index = 5" - }, - { - "cell_index": 6, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=6, matlab_line_number=61, matlab_snippet=\"results{1}.plotResults; subplot(2,4,[5 6]); plot(mu," - }, - { - "cell_index": 7, - "line_count": 2, - "preview": "section_index = 7" - }, - { - "cell_index": 8, - "line_count": 2, - "preview": "section_index = 8" - }, - { - "cell_index": 9, - "line_count": 2, - "preview": "section_index = 9" - }, - { - "cell_index": 10, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=10, matlab_line_number=132, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 11, - "line_count": 182, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=135, matlab_snippet=\"" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 2, - "preview": "section_index = 3" - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=98, matlab_snippet=\"figure;\")" - }, - { - "cell_index": 6, - "line_count": 2, - "preview": "section_index = 6" - }, - { - "cell_index": 7, - "line_count": 2, - "preview": "section_index = 7" - }, - { - "cell_index": 8, - "line_count": 2, - "preview": "section_index = 8" - }, - { - "cell_index": 9, - "line_count": 156, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=146, matlab_snippet=\"=0", - "start_line": 480 - }, - { - "end_line": 489, - "line_count": 2, - "preview": "scrsz = get(0,'ScreenSize');", - "start_line": 488 - }, - { - "end_line": 498, - "line_count": 8, - "preview": "subplot(2,2,3);spikeCollSim.plot;", - "start_line": 491 - }, - { - "end_line": 506, - "line_count": 7, - "preview": "subplot(2,2,1);lambda.plot;", - "start_line": 500 - }, - { - "end_line": 515, - "line_count": 8, - "preview": "x = load(fullfile(psthDir,'Results.mat'));", - "start_line": 508 - }, - { - "end_line": 520, - "line_count": 4, - "preview": "spikeCollReal1=nstColl(nst);", - "start_line": 517 - }, - { - "end_line": 527, - "line_count": 6, - "preview": "xlabel('time [s]','Interpreter','none','FontName', 'Arial',...", - "start_line": 522 - }, - { - "end_line": 534, - "line_count": 6, - "preview": "cellNum=1; clear nst;", - "start_line": 529 - }, - { - "end_line": 539, - "line_count": 4, - "preview": "spikeCollReal2=nstColl(nst);", - "start_line": 536 - }, - { - "end_line": 546, - "line_count": 6, - "preview": "xlabel('time [s]','Interpreter','none','FontName', 'Arial',...", - "start_line": 541 - }, - { - "end_line": 551, - "line_count": 1, - "preview": "close all;", - "start_line": 551 - }, - { - "end_line": 554, - "line_count": 2, - "preview": "scrsz = get(0,'ScreenSize');", - "start_line": 553 - }, - { - "end_line": 560, - "line_count": 5, - "preview": "binsize = .05; %50ms window", - "start_line": 556 - }, - { - "end_line": 564, - "line_count": 3, - "preview": "h1=true.plot([],{{' ''b'',''Linewidth'',4'}});", - "start_line": 562 - }, - { - "end_line": 569, - "line_count": 4, - "preview": "xlabel('time [s]','Interpreter','none','FontName', 'Arial',...", - "start_line": 566 - }, - { - "end_line": 574, - "line_count": 4, - "preview": "legend off;", - "start_line": 571 - }, - { - "end_line": 583, - "line_count": 6, - "preview": "subplot(2,3,1);spikeCollSim.plot;", - "start_line": 578 - }, - { - "end_line": 588, - "line_count": 4, - "preview": "subplot(2,3,5);", - "start_line": 585 - }, - { - "end_line": 595, - "line_count": 6, - "preview": "h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}});", - "start_line": 590 - }, - { - "end_line": 614, - "line_count": 18, - "preview": "h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');", - "start_line": 597 - }, - { - "end_line": 625, - "line_count": 9, - "preview": "h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}');", - "start_line": 617 - }, - { - "end_line": 640, - "line_count": 4, - "preview": "close all;", - "start_line": 637 - }, - { - "end_line": 645, - "line_count": 4, - "preview": "delta = 0.001; Tmax = 1;", - "start_line": 642 - }, - { - "end_line": 647, - "line_count": 1, - "preview": "for i=1:numRealizations", - "start_line": 647 - }, - { - "end_line": 652, - "line_count": 3, - "preview": "f=2; b1(i)=3*((i)/numRealizations);b0=-3;", - "start_line": 650 - }, - { - "end_line": 655, - "line_count": 2, - "preview": "stim=Covariate(time',u,'Stimulus','time','s','Voltage',{'sin'});", - "start_line": 654 - }, - { - "end_line": 659, - "line_count": 3, - "preview": "mu=b0;", - "start_line": 657 - }, - { - "end_line": 663, - "line_count": 3, - "preview": "S=tf([b1(i)],1,Ts,'Variable','z^-1');", - "start_line": 661 - }, - { - "end_line": 669, - "line_count": 1, - "preview": "[sC, lambdaTemp]=CIF.simulateCIF(mu,H,S,E,stim,ens,1,simTypeSelect);", - "start_line": 669 - }, - { - "end_line": 675, - "line_count": 5, - "preview": "if(i==1)", - "start_line": 671 - }, - { - "end_line": 679, - "line_count": 3, - "preview": "nst{i} = sC.getNST(1); %get the neural spikeTrain from the collection", - "start_line": 677 - }, - { - "end_line": 681, - "line_count": 1, - "preview": "spikeColl = nstColl(nst); %Create a collection of the spike trains across trials", - "start_line": 681 - }, - { - "end_line": 686, - "line_count": 3, - "preview": "close all;", - "start_line": 684 - }, - { - "end_line": 697, - "line_count": 9, - "preview": "subplot(3,2,[3 4]); spikeColl.plot;", - "start_line": 689 - }, - { - "end_line": 707, - "line_count": 4, - "preview": "stimData = exp(b0 + u'*b1);", - "start_line": 704 - }, - { - "end_line": 710, - "line_count": 1, - "preview": "subplot(3,2,1); plot(time,u,'k','LineWidth',3);", - "start_line": 710 - }, - { - "end_line": 717, - "line_count": 6, - "preview": "xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',...", - "start_line": 712 - }, - { - "end_line": 725, - "line_count": 7, - "preview": "subplot(3,2,2); plot(1:length(b1),b1,'k','LineWidth',3);", - "start_line": 719 - }, - { - "end_line": 736, - "line_count": 10, - "preview": "subplot(3,2,[5 6]);", - "start_line": 727 - }, - { - "end_line": 739, - "line_count": 1, - "preview": "axis tight;", - "start_line": 739 - }, - { - "end_line": 746, - "line_count": 3, - "preview": "stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});", - "start_line": 744 - }, - { - "end_line": 749, - "line_count": 1, - "preview": "windowTimes=[0:.001:.003];", - "start_line": 749 - }, - { - "end_line": 753, - "line_count": 1, - "preview": "numBasis = 25;", - "start_line": 753 - }, - { - "end_line": 756, - "line_count": 2, - "preview": "spikeColl.resample(1/delta); % Enforce sampleRate", - "start_line": 755 - }, - { - "end_line": 759, - "line_count": 1, - "preview": "dN=spikeColl.dataToMatrix'; % Convert the spikeTrains into a matrix", - "start_line": 759 - }, - { - "end_line": 762, - "line_count": 1, - "preview": "dN(dN>1)=1; % One should sample finely enough so there is", - "start_line": 762 - }, - { - "end_line": 769, - "line_count": 1, - "preview": "basisWidth=(spikeColl.maxTime-spikeColl.minTime)/numBasis;", - "start_line": 769 - }, - { - "end_line": 777, - "line_count": 7, - "preview": "if(simTypeSelect==0)", - "start_line": 771 - }, - { - "end_line": 781, - "line_count": 2, - "preview": "else", - "start_line": 780 - }, - { - "end_line": 783, - "line_count": 1, - "preview": "end", - "start_line": 783 - }, - { - "end_line": 788, - "line_count": 3, - "preview": "[psthSig, ~, psthResult] =spikeColl.psthGLM(basisWidth,windowTimes,fitType);", - "start_line": 786 - }, - { - "end_line": 793, - "line_count": 1, - "preview": "x0=psthResult.getCoeffs; %The initial estimate for the SSGLM model", - "start_line": 793 - }, - { - "end_line": 800, - "line_count": 5, - "preview": "numVarEstIter=10;", - "start_line": 796 - }, - { - "end_line": 803, - "line_count": 1, - "preview": "CompilingHelpFile=1;", - "start_line": 803 - }, - { - "end_line": 810, - "line_count": 6, - "preview": "if(~CompilingHelpFile)", - "start_line": 805 - }, - { - "end_line": 814, - "line_count": 3, - "preview": "fR = fitResults.toStructure;", - "start_line": 812 - }, - { - "end_line": 829, - "line_count": 13, - "preview": "installPath = which('nSTAT_Install');", - "start_line": 817 - }, - { - "end_line": 832, - "line_count": 1, - "preview": "t=psthResult.mergeResults(fitResults);", - "start_line": 832 - }, - { - "end_line": 840, - "line_count": 7, - "preview": "t.lambda.setDataLabels({'\\lambda_{PSTH}','\\lambda_{SSGLM}'});", - "start_line": 834 - }, - { - "end_line": 845, - "line_count": 4, - "preview": "S=FitResSummary(t);", - "start_line": 842 - }, - { - "end_line": 849, - "line_count": 1, - "preview": "close all;", - "start_line": 849 - }, - { - "end_line": 857, - "line_count": 7, - "preview": "minTime=0; maxTime = Tmax;", - "start_line": 851 - }, - { - "end_line": 868, - "line_count": 7, - "preview": "if(~isempty(numBasis))", - "start_line": 862 - }, - { - "end_line": 875, - "line_count": 5, - "preview": "if(strcmp(fitType,'poisson'))", - "start_line": 871 - }, - { - "end_line": 879, - "line_count": 2, - "preview": "scrsz = get(0,'ScreenSize');", - "start_line": 878 - }, - { - "end_line": 889, - "line_count": 7, - "preview": "subplot(3,1,[1 2 3]);", - "start_line": 883 - }, - { - "end_line": 894, - "line_count": 4, - "preview": "surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),...", - "start_line": 891 - }, - { - "end_line": 898, - "line_count": 3, - "preview": "title('SSGLM Estimated vs. Actual Stimulus Effect','FontWeight','bold',...", - "start_line": 896 - }, - { - "end_line": 901, - "line_count": 2, - "preview": "close all;", - "start_line": 900 - }, - { - "end_line": 909, - "line_count": 6, - "preview": "subplot(3,1,1);", - "start_line": 904 - }, - { - "end_line": 917, - "line_count": 7, - "preview": "title('True Stimulus Effect','FontWeight','bold',...", - "start_line": 911 - }, - { - "end_line": 927, - "line_count": 6, - "preview": "subplot(3,1,2);", - "start_line": 922 - }, - { - "end_line": 931, - "line_count": 3, - "preview": "title('PSTH Estimated Stimulus Effect','FontWeight','bold',...", - "start_line": 929 - }, - { - "end_line": 936, - "line_count": 4, - "preview": "set(gca,'xtick',[],'xtickLabel',[]);", - "start_line": 933 - }, - { - "end_line": 945, - "line_count": 7, - "preview": "subplot(3,1,3);", - "start_line": 939 - }, - { - "end_line": 954, - "line_count": 7, - "preview": "title('SSGLM Estimated Stimulus Effect','FontWeight','bold',...", - "start_line": 948 - }, - { - "end_line": 961, - "line_count": 3, - "preview": "echo off;", - "start_line": 959 - }, - { - "end_line": 970, - "line_count": 7, - "preview": "if(~isempty(numBasis))", - "start_line": 964 - }, - { - "end_line": 977, - "line_count": 3, - "preview": "t0=0; tf=Tmax;", - "start_line": 975 - }, - { - "end_line": 983, - "line_count": 5, - "preview": "lt=find(sigMat(1,:)==1,1,'first');", - "start_line": 979 - }, - { - "end_line": 988, - "line_count": 4, - "preview": "subplot(2,3,1);", - "start_line": 985 - }, - { - "end_line": 998, - "line_count": 8, - "preview": "v=axis;", - "start_line": 991 - }, - { - "end_line": 1012, - "line_count": 11, - "preview": "h=subplot(2,3,[2 3 5 6]);", - "start_line": 1002 - }, - { - "end_line": 1017, - "line_count": 4, - "preview": "set(h,'XAxisLocation','top','YAxisLocation','right');", - "start_line": 1014 - }, - { - "end_line": 1033, - "line_count": 15, - "preview": "subplot(2,3,4)", - "start_line": 1019 - }, - { - "end_line": 1040, - "line_count": 5, - "preview": "h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}}); hold all;", - "start_line": 1036 - }, - { - "end_line": 1047, - "line_count": 6, - "preview": "title({'Learning Trial Vs. Baseline Trial';'with 95% CIs'},'FontWeight','bold',...", - "start_line": 1042 - }, - { - "end_line": 1070, - "line_count": 3, - "preview": "close all;", - "start_line": 1068 - }, - { - "end_line": 1074, - "line_count": 2, - "preview": "scrsz = get(0,'ScreenSize');", - "start_line": 1073 - }, - { - "end_line": 1081, - "line_count": 6, - "preview": "for i=1:length(exampleCell)", - "start_line": 1076 - }, - { - "end_line": 1093, - "line_count": 11, - "preview": "title(['Cell#' num2str(exampleCell(i))],'FontWeight','bold',...", - "start_line": 1083 - }, - { - "end_line": 1100, - "line_count": 4, - "preview": "numAnimals=2;", - "start_line": 1097 - }, - { - "end_line": 1103, - "line_count": 2, - "preview": "clear x y neuron time nst tc tcc z;", - "start_line": 1102 - }, - { - "end_line": 1108, - "line_count": 3, - "preview": "for i=1:length(neuron)", - "start_line": 1106 - }, - { - "end_line": 1112, - "line_count": 1, - "preview": "[theta,r] = cart2pol(x,y);", - "start_line": 1112 - }, - { - "end_line": 1124, - "line_count": 6, - "preview": "cnt=0;", - "start_line": 1119 - }, - { - "end_line": 1129, - "line_count": 3, - "preview": "end", - "start_line": 1127 - }, - { - "end_line": 1133, - "line_count": 2, - "preview": "delta=min(diff(time));", - "start_line": 1132 - }, - { - "end_line": 1141, - "line_count": 7, - "preview": "baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',...", - "start_line": 1135 - }, - { - "end_line": 1145, - "line_count": 2, - "preview": "spikeColl = nstColl(nst);", - "start_line": 1144 - }, - { - "end_line": 1155, - "line_count": 7, - "preview": "tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',...", - "start_line": 1149 - }, - { - "end_line": 1158, - "line_count": 1, - "preview": "results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);", - "start_line": 1158 - }, - { - "end_line": 1165, - "line_count": 5, - "preview": "resStruct =FitResult.CellArrayToStructure(results);", - "start_line": 1161 - }, - { - "end_line": 1171, - "line_count": 2, - "preview": "clear Summary;", - "start_line": 1170 - }, - { - "end_line": 1176, - "line_count": 4, - "preview": "for n=1:numAnimals", - "start_line": 1173 - }, - { - "end_line": 1178, - "line_count": 1, - "preview": "end", - "start_line": 1178 - }, - { - "end_line": 1187, - "line_count": 8, - "preview": "close all;", - "start_line": 1180 - }, - { - "end_line": 1191, - "line_count": 3, - "preview": "boxplot(dKS ,{'Animal 1', 'Animal 2'},'labelorientation','inline');", - "start_line": 1189 - }, - { - "end_line": 1197, - "line_count": 4, - "preview": "subplot(1,3,2);", - "start_line": 1194 - }, - { - "end_line": 1200, - "line_count": 2, - "preview": "boxplot(dAIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline');", - "start_line": 1199 - }, - { - "end_line": 1206, - "line_count": 4, - "preview": "subplot(1,3,3);", - "start_line": 1203 - }, - { - "end_line": 1209, - "line_count": 2, - "preview": "boxplot(dBIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline'); %ylabel('\\Delta BIC'); %xticklabel_rotate([],45,[],'Fontsize',6);", - "start_line": 1208 - }, - { - "end_line": 1215, - "line_count": 1, - "preview": "close all;", - "start_line": 1215 - }, - { - "end_line": 1219, - "line_count": 3, - "preview": "[x_new,y_new]=meshgrid(-1:.01:1); %define new x and y", - "start_line": 1217 - }, - { - "end_line": 1225, - "line_count": 4, - "preview": "newData{1} =ones(size(x_new));", - "start_line": 1222 - }, - { - "end_line": 1241, - "line_count": 13, - "preview": "idx = r_new<=1;", - "start_line": 1229 - }, - { - "end_line": 1245, - "line_count": 1, - "preview": "for n=1:numAnimals", - "start_line": 1245 - }, - { - "end_line": 1250, - "line_count": 4, - "preview": "clear lambdaGaussian lambdaZernike;", - "start_line": 1247 - }, - { - "end_line": 1252, - "line_count": 1, - "preview": "for i=1:length(neuron)", - "start_line": 1252 - }, - { - "end_line": 1256, - "line_count": 3, - "preview": "lambdaGaussian{i} = results{i}.evalLambda(1,newData);", - "start_line": 1254 - }, - { - "end_line": 1262, - "line_count": 1, - "preview": "for i=1:length(neuron)", - "start_line": 1262 - }, - { - "end_line": 1296, - "line_count": 30, - "preview": "if(n==1)", - "start_line": 1267 - }, - { - "end_line": 1307, - "line_count": 10, - "preview": "if(n==1)", - "start_line": 1298 - }, - { - "end_line": 1329, - "line_count": 21, - "preview": "end", - "start_line": 1309 - }, - { - "end_line": 1332, - "line_count": 1, - "preview": "end", - "start_line": 1332 - }, - { - "end_line": 1339, - "line_count": 4, - "preview": "clear lambdaGaussian lambdaZernike;", - "start_line": 1336 - }, - { - "end_line": 1341, - "line_count": 1, - "preview": "for i=1:length(neuron)", - "start_line": 1341 - }, - { - "end_line": 1345, - "line_count": 3, - "preview": "lambdaGaussian{i} = results{i}.evalLambda(1,newData);", - "start_line": 1343 - }, - { - "end_line": 1352, - "line_count": 1, - "preview": "exampleCell = 25;", - "start_line": 1352 - }, - { - "end_line": 1366, - "line_count": 9, - "preview": "close all;", - "start_line": 1358 - }, - { - "end_line": 1377, - "line_count": 7, - "preview": "plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');", - "start_line": 1371 - }, - { - "end_line": 1400, - "line_count": 12, - "preview": "close all; clear all;", - "start_line": 1389 - }, - { - "end_line": 1411, - "line_count": 10, - "preview": "if(i==1)", - "start_line": 1402 - }, - { - "end_line": 1419, - "line_count": 7, - "preview": "spikeColl = CIF.simulateCIFByThinningFromLambda(...", - "start_line": 1413 - }, - { - "end_line": 1435, - "line_count": 15, - "preview": "subplot(3,1,1); plot(time,x,'k');", - "start_line": 1421 - }, - { - "end_line": 1445, - "line_count": 9, - "preview": "subplot(3,1,3); spikeColl.plot;", - "start_line": 1437 - }, - { - "end_line": 1449, - "line_count": 3, - "preview": "stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'});", - "start_line": 1447 - }, - { - "end_line": 1453, - "line_count": 1, - "preview": "close all;", - "start_line": 1453 - }, - { - "end_line": 1457, - "line_count": 3, - "preview": "clear lambdaCIF;", - "start_line": 1455 - }, - { - "end_line": 1464, - "line_count": 5, - "preview": "Q=std(stim.data(2:end)-stim.data(1:end-1));", - "start_line": 1460 - }, - { - "end_line": 1468, - "line_count": 2, - "preview": "[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, ...", - "start_line": 1467 - }, - { - "end_line": 1475, - "line_count": 6, - "preview": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]);", - "start_line": 1470 - }, - { - "end_line": 1479, - "line_count": 3, - "preview": "estimatedStimulus = Covariate(time,x_u(1:end),'\\hat{x}(t)','time','s','');", - "start_line": 1477 - }, - { - "end_line": 1496, - "line_count": 12, - "preview": "hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}});", - "start_line": 1485 - }, - { - "end_line": 1509, - "line_count": 4, - "preview": "close all;", - "start_line": 1506 - }, - { - "end_line": 1512, - "line_count": 2, - "preview": "q=1e-4;", - "start_line": 1511 - }, - { - "end_line": 1519, - "line_count": 6, - "preview": "delta = .001; % Time increment", - "start_line": 1514 - }, - { - "end_line": 1523, - "line_count": 3, - "preview": "x0 = [0;0;0;0]; % Initial Position and velocities (states)", - "start_line": 1521 - }, - { - "end_line": 1528, - "line_count": 4, - "preview": "A=[1 0 delta 0 ; %State transition matrix", - "start_line": 1525 - }, - { - "end_line": 1530, - "line_count": 1, - "preview": "x=zeros(4,length(time));", - "start_line": 1530 - }, - { - "end_line": 1544, - "line_count": 9, - "preview": "R=chol(Q);", - "start_line": 1536 - }, - { - "end_line": 1546, - "line_count": 1, - "preview": "end", - "start_line": 1546 - }, - { - "end_line": 1550, - "line_count": 3, - "preview": "end", - "start_line": 1548 - }, - { - "end_line": 1553, - "line_count": 1, - "preview": "Q=diag(var(diff(x,[],2),[],2))*100;", - "start_line": 1553 - }, - { - "end_line": 1558, - "line_count": 3, - "preview": "scrsz = get(0,'ScreenSize');", - "start_line": 1556 - }, - { - "end_line": 1570, - "line_count": 11, - "preview": "subplot(4,2,[1 3]);", - "start_line": 1560 - }, - { - "end_line": 1580, - "line_count": 8, - "preview": "subplot(4,2,5); h1=plot(time,100*x(1,:),'k','Linewidth',2); hold on;", - "start_line": 1573 - }, - { - "end_line": 1592, - "line_count": 10, - "preview": "subplot(4,2,7);", - "start_line": 1583 - }, - { - "end_line": 1596, - "line_count": 2, - "preview": "gamma=0;", - "start_line": 1595 - }, - { - "end_line": 1607, - "line_count": 6, - "preview": "numCells = 20;", - "start_line": 1602 - }, - { - "end_line": 1614, - "line_count": 6, - "preview": "dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (", - "start_line": 1609 - }, - { - "end_line": 1624, - "line_count": 9, - "preview": "if(strcmp(fitType,'poisson'))", - "start_line": 1616 - }, - { - "end_line": 1629, - "line_count": 2, - "preview": "lambdaCIF{i} = CIF([MuCoeffs(i) 0 0 bCoeffs(i,:)],...", - "start_line": 1628 - }, - { - "end_line": 1635, - "line_count": 5, - "preview": "tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1); nst{i} = tempSpikeColl{i}.getNST(1); % grab the realizatio", - "start_line": 1631 - }, - { - "end_line": 1645, - "line_count": 7, - "preview": "end", - "start_line": 1639 - }, - { - "end_line": 1653, - "line_count": 7, - "preview": "subplot(4,2,[2,4]); spikeColl.plot;", - "start_line": 1647 - }, - { - "end_line": 1669, - "line_count": 11, - "preview": "close all;", - "start_line": 1659 - }, - { - "end_line": 1674, - "line_count": 4, - "preview": "dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X (", - "start_line": 1671 - }, - { - "end_line": 1681, - "line_count": 5, - "preview": "for i=1:numCells", - "start_line": 1677 - }, - { - "end_line": 1688, - "line_count": 6, - "preview": "lambdaData = tempData./(1+tempData);", - "start_line": 1683 - }, - { - "end_line": 1695, - "line_count": 3, - "preview": "tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1);", - "start_line": 1693 - }, - { - "end_line": 1697, - "line_count": 1, - "preview": "end", - "start_line": 1697 - }, - { - "end_line": 1700, - "line_count": 1, - "preview": "spikeColl = nstColl(nst); % Create a neural spike train collection", - "start_line": 1700 - }, - { - "end_line": 1705, - "line_count": 2, - "preview": "dN=spikeColl.dataToMatrix';", - "start_line": 1704 - }, - { - "end_line": 1709, - "line_count": 1, - "preview": "[C,N] = size(dN); % N time samples, C cells", - "start_line": 1709 - }, - { - "end_line": 1711, - "line_count": 1, - "preview": "beta=[zeros(2,numCells); bCoeffs'];", - "start_line": 1711 - }, - { - "end_line": 1718, - "line_count": 3, - "preview": "[x_p, W_p, x_u, W_u,x_uT,W_uT,x_pT,W_pT] = ...", - "start_line": 1716 - }, - { - "end_line": 1724, - "line_count": 3, - "preview": "[x_pf, W_pf, x_uf, W_uf] = ...", - "start_line": 1722 - }, - { - "end_line": 1741, - "line_count": 15, - "preview": "if(k==numExamples)", - "start_line": 1727 - }, - { - "end_line": 1751, - "line_count": 8, - "preview": "subplot(4,2,5);", - "start_line": 1744 - }, - { - "end_line": 1765, - "line_count": 13, - "preview": "subplot(4,2,6);", - "start_line": 1753 - }, - { - "end_line": 1773, - "line_count": 7, - "preview": "subplot(4,2,7);", - "start_line": 1767 - }, - { - "end_line": 1781, - "line_count": 7, - "preview": "subplot(4,2,8);", - "start_line": 1775 - }, - { - "end_line": 1784, - "line_count": 1, - "preview": "end", - "start_line": 1784 - }, - { - "end_line": 1833, - "line_count": 13, - "preview": "clear all;", - "start_line": 1821 - }, - { - "end_line": 1842, - "line_count": 8, - "preview": "A{1} = [1 0 0 0 0 0;", - "start_line": 1835 - }, - { - "end_line": 1845, - "line_count": 2, - "preview": "Px0{2} =1e-6*eye(6,6);", - "start_line": 1844 - }, - { - "end_line": 1848, - "line_count": 2, - "preview": "minCovVal = 1e-12;", - "start_line": 1847 - }, - { - "end_line": 1857, - "line_count": 6, - "preview": "Q{2}=[minCovVal 0 0 0 0 0;", - "start_line": 1852 - }, - { - "end_line": 1859, - "line_count": 1, - "preview": "Q{1}=minCovVal*eye(2,2);", - "start_line": 1859 - }, - { - "end_line": 1863, - "line_count": 3, - "preview": "mstate = zeros(1,length(time));", - "start_line": 1861 - }, - { - "end_line": 1868, - "line_count": 3, - "preview": "X=zeros(max([size(A{1},1),size(A{2},1)]),length(time));", - "start_line": 1866 - }, - { - "end_line": 1870, - "line_count": 1, - "preview": "for i = 1:length(time)", - "start_line": 1870 - }, - { - "end_line": 1889, - "line_count": 18, - "preview": "if(i==1)", - "start_line": 1872 - }, - { - "end_line": 1891, - "line_count": 1, - "preview": "end", - "start_line": 1891 - }, - { - "end_line": 1909, - "line_count": 16, - "preview": "load(fullfile(fileparts(which('nSTATPaperExamples')),'paperHybridFilterExample.mat'));", - "start_line": 1894 - }, - { - "end_line": 1920, - "line_count": 8, - "preview": "subplot(4,2,[6 8]);", - "start_line": 1913 - }, - { - "end_line": 1930, - "line_count": 9, - "preview": "subplot(4,2,5);", - "start_line": 1922 - }, - { - "end_line": 1941, - "line_count": 9, - "preview": "subplot(4,2,7);", - "start_line": 1933 - }, - { - "end_line": 1946, - "line_count": 4, - "preview": "meanMu = log(10*delta); % baseline firing rate", - "start_line": 1943 - }, - { - "end_line": 1948, - "line_count": 1, - "preview": "dataMat = [ones(size(X,2),1),X(:,1:end)'];", - "start_line": 1948 - }, - { - "end_line": 1951, - "line_count": 2, - "preview": "clear lambda tempSpikeColl lambdaCIF n;", - "start_line": 1950 - }, - { - "end_line": 1975, - "line_count": 23, - "preview": "for i=1:numCells", - "start_line": 1953 - }, - { - "end_line": 1997, - "line_count": 12, - "preview": "nonMovingInd = intersect(find(X(5,:)==0),find(X(6,:)==0));", - "start_line": 1986 - }, - { - "end_line": 2003, - "line_count": 5, - "preview": "for n=1:numExamples", - "start_line": 1999 - }, - { - "end_line": 2008, - "line_count": 1, - "preview": "dataMat = [ones(size(X,2),1),X(:,1:end)'];", - "start_line": 2008 - }, - { - "end_line": 2011, - "line_count": 2, - "preview": "clear lambda tempSpikeColl lambdaCIF nst;", - "start_line": 2010 - }, - { - "end_line": 2028, - "line_count": 16, - "preview": "for i=1:numCells", - "start_line": 2013 - }, - { - "end_line": 2036, - "line_count": 4, - "preview": "spikeColl = nstColl(nst);", - "start_line": 2033 - }, - { - "end_line": 2044, - "line_count": 6, - "preview": "Mu0=.5*ones(size(p_ij,1),1);", - "start_line": 2039 - }, - { - "end_line": 2048, - "line_count": 3, - "preview": "x0{2} = X(ind{2},1);", - "start_line": 2046 - }, - { - "end_line": 2057, - "line_count": 6, - "preview": "[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=...", - "start_line": 2052 - }, - { - "end_line": 2065, - "line_count": 6, - "preview": "X_estAll(:,:,n) = X_est;", - "start_line": 2060 - }, - { - "end_line": 2073, - "line_count": 5, - "preview": "subplot(4,3,[1 4]);", - "start_line": 2069 - }, - { - "end_line": 2079, - "line_count": 4, - "preview": "subplot(4,3,[7 10]);", - "start_line": 2076 - }, - { - "end_line": 2085, - "line_count": 4, - "preview": "subplot(4,3,[2 3 5 6]);", - "start_line": 2082 - }, - { - "end_line": 2091, - "line_count": 4, - "preview": "subplot(4,3,8);", - "start_line": 2088 - }, - { - "end_line": 2097, - "line_count": 4, - "preview": "subplot(4,3,9);", - "start_line": 2094 - }, - { - "end_line": 2103, - "line_count": 4, - "preview": "subplot(4,3,11);", - "start_line": 2100 - }, - { - "end_line": 2108, - "line_count": 4, - "preview": "subplot(4,3,12);", - "start_line": 2105 - }, - { - "end_line": 2113, - "line_count": 1, - "preview": "end", - "start_line": 2113 - }, - { - "end_line": 2133, - "line_count": 11, - "preview": "subplot(4,3,[1 4]);", - "start_line": 2123 - }, - { - "end_line": 2148, - "line_count": 10, - "preview": "subplot(4,3,[7 10]);", - "start_line": 2139 - }, - { - "end_line": 2158, - "line_count": 8, - "preview": "subplot(4,3,[2 3 5 6]);", - "start_line": 2151 - }, - { - "end_line": 2164, - "line_count": 5, - "preview": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on;", - "start_line": 2160 - }, - { - "end_line": 2175, - "line_count": 8, - "preview": "subplot(4,3,8);", - "start_line": 2168 - }, - { - "end_line": 2190, - "line_count": 13, - "preview": "subplot(4,3,9);", - "start_line": 2178 - }, - { - "end_line": 2199, - "line_count": 7, - "preview": "subplot(4,3,11);", - "start_line": 2193 - }, - { - "end_line": 2208, - "line_count": 7, - "preview": "subplot(4,3,12);", - "start_line": 2202 - }, - { - "end_line": 2217, - "line_count": 7, - "preview": "parity = struct();", - "start_line": 2211 - }, - { - "end_line": 2220, - "line_count": 2, - "preview": "function [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ...", - "start_line": 2219 - }, - { - "end_line": 2223, - "line_count": 1, - "preview": "candidateRoots = {};", - "start_line": 2223 - }, - { - "end_line": 2228, - "line_count": 4, - "preview": "scriptPath = mfilename('fullpath');", - "start_line": 2225 - }, - { - "end_line": 2233, - "line_count": 4, - "preview": "paperPath = which('nSTATPaperExamples');", - "start_line": 2230 - }, - { - "end_line": 2238, - "line_count": 4, - "preview": "installPath = which('nSTAT_Install');", - "start_line": 2235 - }, - { - "end_line": 2247, - "line_count": 8, - "preview": "try", - "start_line": 2240 - }, - { - "end_line": 2249, - "line_count": 1, - "preview": "candidateRoots = appendCandidateRoot(candidateRoots, pwd);", - "start_line": 2249 - }, - { - "end_line": 2258, - "line_count": 8, - "preview": "nSTATDir = '';", - "start_line": 2251 - }, - { - "end_line": 2265, - "line_count": 6, - "preview": "if isempty(nSTATDir)", - "start_line": 2260 - }, - { - "end_line": 2271, - "line_count": 5, - "preview": "dataDir = fullfile(nSTATDir,'data');", - "start_line": 2267 - }, - { - "end_line": 2277, - "line_count": 5, - "preview": "if exist(dataDir,'dir') ~= 7", - "start_line": 2273 - }, - { - "end_line": 2282, - "line_count": 4, - "preview": "function roots = appendCandidateRoot(roots, startDir)", - "start_line": 2279 - }, - { - "end_line": 2295, - "line_count": 12, - "preview": "thisDir = startDir;", - "start_line": 2284 - } - ], - "matlab_code_lines": 1576, - "matlab_file": "helpfiles/nSTATPaperExamples.m", - "matlab_reference_image_count": 26, - "matlab_reference_images": [ - "helpfiles/nSTATPaperExamples.png", - "helpfiles/nSTATPaperExamples_01.png", - "helpfiles/nSTATPaperExamples_02.png", - "helpfiles/nSTATPaperExamples_03.png", - "helpfiles/nSTATPaperExamples_04.png", - "helpfiles/nSTATPaperExamples_05.png", - "helpfiles/nSTATPaperExamples_06.png", - "helpfiles/nSTATPaperExamples_07.png", - "helpfiles/nSTATPaperExamples_08.png", - "helpfiles/nSTATPaperExamples_09.png", - "helpfiles/nSTATPaperExamples_10.png", - "helpfiles/nSTATPaperExamples_11.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=73, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 " - }, - { - "cell_index": 4, - "line_count": 2, - "preview": "section_index = 4" - }, - { - "cell_index": 5, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=125, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04" - }, - { - "cell_index": 6, - "line_count": 2, - "preview": "section_index = 6" - }, - { - "cell_index": 7, - "line_count": 2, - "preview": "section_index = 7" - }, - { - "cell_index": 8, - "line_count": 2, - "preview": "section_index = 8" - }, - { - "cell_index": 9, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=9, matlab_line_number=195, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04" - }, - { - "cell_index": 10, - "line_count": 2, - "preview": "section_index = 10" - }, - { - "cell_index": 11, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=11, matlab_line_number=265, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz" - }, - { - "cell_index": 12, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=12, matlab_line_number=323, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz" - }, - { - "cell_index": 13, - "line_count": 2, - "preview": "section_index = 13" - }, - { - "cell_index": 14, - "line_count": 2, - "preview": "section_index = 14" - }, - { - "cell_index": 15, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=15, matlab_line_number=489, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz" - }, - { - "cell_index": 16, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=16, matlab_line_number=554, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz" - }, - { - "cell_index": 17, - "line_count": 2, - "preview": "section_index = 17" - }, - { - "cell_index": 18, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=18, matlab_line_number=686, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz" - }, - { - "cell_index": 19, - "line_count": 2, - "preview": "section_index = 19" - }, - { - "cell_index": 20, - "line_count": 2, - "preview": "section_index = 20" - }, - { - "cell_index": 21, - "line_count": 2, - "preview": "section_index = 21" - }, - { - "cell_index": 22, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=22, matlab_line_number=836, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz" - }, - { - "cell_index": 23, - "line_count": 16, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=23, matlab_line_number=879, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 " - }, - { - "cell_index": 24, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=24, matlab_line_number=983, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 " - }, - { - "cell_index": 25, - "line_count": 2, - "preview": "section_index = 25" - }, - { - "cell_index": 26, - "line_count": 2, - "preview": "section_index = 26" - }, - { - "cell_index": 27, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=27, matlab_line_number=1074, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1" - }, - { - "cell_index": 28, - "line_count": 2, - "preview": "section_index = 28" - }, - { - "cell_index": 29, - "line_count": 2, - "preview": "section_index = 29" - }, - { - "cell_index": 30, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=30, matlab_line_number=1182, matlab_snippet=\"h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1" - }, - { - "cell_index": 31, - "line_count": 30, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=31, matlab_line_number=1268, matlab_snippet=\"h4=figure(4);\")" - }, - { - "cell_index": 32, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=32, matlab_line_number=1359, matlab_snippet=\"h9=figure(9);\")" - }, - { - "cell_index": 33, - "line_count": 2, - "preview": "section_index = 33" - }, - { - "cell_index": 34, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=34, matlab_line_number=1418, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...\"" - }, - { - "cell_index": 35, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=35, matlab_line_number=1470, matlab_snippet=\"h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrs" - }, - { - "cell_index": 36, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=36, matlab_line_number=1557, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)" - }, - { - "cell_index": 37, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=37, matlab_line_number=1662, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)" - }, - { - "cell_index": 38, - "line_count": 2, - "preview": "section_index = 38" - }, - { - "cell_index": 39, - "line_count": 2, - "preview": "section_index = 39" - }, - { - "cell_index": 40, - "line_count": 2, - "preview": "section_index = 40" - }, - { - "cell_index": 41, - "line_count": 2, - "preview": "section_index = 41" - }, - { - "cell_index": 42, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=42, matlab_line_number=1899, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)" - }, - { - "cell_index": 43, - "line_count": 1823, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=43, matlab_line_number=1996, matlab_snippet=\"fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)" - } - ], - "python_code_lines": 2073, - "python_notebook": "notebooks/helpfiles/nSTATPaperExamples.ipynb", - "python_to_matlab_line_ratio": 1.3153553299492386, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/nSTATPaperExamples/nSTATPaperExamples_001.png" - ], - "strict_line_status": "line_port_gap", - "topic": "nSTATPaperExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 6, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 10, - "line_port_matlab_function_count": 6, - "line_port_matlab_lines": 10, - "line_port_python_function_count": 42, - "line_port_python_lines": 131, - "matlab_code_blocks": [ - { - "end_line": 9, - "line_count": 4, - "preview": "spikeTimes = sort(rand(1,100))*1;", - "start_line": 6 - }, - { - "end_line": 18, - "line_count": 2, - "preview": "figure; nst.resample(1/.1);", - "start_line": 17 - }, - { - "end_line": 24, - "line_count": 2, - "preview": "figure; nst.resample(1/.01);", - "start_line": 23 - }, - { - "end_line": 30, - "line_count": 2, - "preview": "figure; nst.resample(1/nst.getMaxBinSizeBinary);", - "start_line": 29 - } - ], - "matlab_code_lines": 10, - "matlab_file": "helpfiles/nSpikeTrainExamples.m", - "matlab_reference_image_count": 6, - "matlab_reference_images": [ - "helpfiles/nSpikeTrainExamples.png", - "helpfiles/nSpikeTrainExamples_01.png", - "helpfiles/nSpikeTrainExamples_02.png", - "helpfiles/nSpikeTrainExamples_03.png", - "helpfiles/nSpikeTrainExamples_04.png", - "helpfiles/nSpikeTrainExamples_05.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=2, matlab_line_number=9, matlab_snippet=\"figure; nst.plot;\")" - }, - { - "cell_index": 3, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=17, matlab_snippet=\"figure; nst.resample(1/.1);\")" - }, - { - "cell_index": 4, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=23, matlab_snippet=\"figure; nst.resample(1/.01);\")" - }, - { - "cell_index": 5, - "line_count": 59, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=29, matlab_snippet=\"figure; nst.resample(1/nst.getMaxBinSizeBinary);\")" - } - ], - "python_code_lines": 86, - "python_notebook": "notebooks/helpfiles/nSpikeTrainExamples.ipynb", - "python_to_matlab_line_ratio": 8.6, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/nSpikeTrainExamples/nSpikeTrainExamples_001.png" - ], - "strict_line_status": "line_port_gap", - "topic": "nSpikeTrainExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 4, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 11, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 16, - "line_port_matlab_function_count": 11, - "line_port_matlab_lines": 16, - "line_port_python_function_count": 50, - "line_port_python_lines": 134, - "matlab_code_blocks": [ - { - "end_line": 10, - "line_count": 7, - "preview": "close all; clear all;", - "start_line": 4 - }, - { - "end_line": 14, - "line_count": 1, - "preview": "figure; spikeColl.plot;", - "start_line": 14 - }, - { - "end_line": 18, - "line_count": 2, - "preview": "spikeColl.setMask([1 4 7]);", - "start_line": 17 - }, - { - "end_line": 24, - "line_count": 4, - "preview": "figure;", - "start_line": 21 - }, - { - "end_line": 28, - "line_count": 2, - "preview": "s1=n1.getSigRep(.001,0,1);", - "start_line": 27 - } - ], - "matlab_code_lines": 16, - "matlab_file": "helpfiles/nstCollExamples.m", - "matlab_reference_image_count": 4, - "matlab_reference_images": [ - "helpfiles/nstCollExamples.png", - "helpfiles/nstCollExamples_01.png", - "helpfiles/nstCollExamples_02.png", - "helpfiles/nstCollExamples_03.png" - ], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 0, - "preview": "" - }, - { - "cell_index": 2, - "line_count": 2, - "preview": "section_index = 2" - }, - { - "cell_index": 3, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=3, matlab_line_number=14, matlab_snippet=\"figure; spikeColl.plot;\")" - }, - { - "cell_index": 4, - "line_count": 9, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=4, matlab_line_number=18, matlab_snippet=\"figure; spikeColl.plot;\")" - }, - { - "cell_index": 5, - "line_count": 69, - "preview": "fig = FIGURE_TRACKER.new_figure(section_index=5, matlab_line_number=21, matlab_snippet=\"figure;\")" - } - ], - "python_code_lines": 89, - "python_notebook": "notebooks/helpfiles/nstCollExamples.ipynb", - "python_to_matlab_line_ratio": 5.5625, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/nstCollExamples/nstCollExamples_001.png" - ], - "strict_line_status": "line_port_gap", - "topic": "nstCollExamples" - }, - { - "alignment_status": "validated", - "assertion_count": 14, - "has_plot_call": true, - "has_topic_checkpoint": true, - "line_port_common_function_count": 47, - "line_port_coverage": 1.0, - "line_port_function_recall": 1.0, - "line_port_matched_lines": 126, - "line_port_matlab_function_count": 47, - "line_port_matlab_lines": 126, - "line_port_python_function_count": 91, - "line_port_python_lines": 281, - "matlab_code_blocks": [ - { - "end_line": 1, - "line_count": 1, - "preview": "function publish_all_helpfiles(varargin)", - "start_line": 1 - }, - { - "end_line": 8, - "line_count": 1, - "preview": "opts = parseOptions(varargin{:});", - "start_line": 8 - }, - { - "end_line": 18, - "line_count": 9, - "preview": "helpDir = fileparts(mfilename('fullpath'));", - "start_line": 10 - }, - { - "end_line": 21, - "line_count": 2, - "preview": "copyfile(fullfile(helpDir, '*'), stagingDir);", - "start_line": 20 - }, - { - "end_line": 27, - "line_count": 5, - "preview": "restoredefaultpath;", - "start_line": 23 - }, - { - "end_line": 31, - "line_count": 3, - "preview": "publishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', opts.EvalCode);", - "start_line": 29 - }, - { - "end_line": 45, - "line_count": 13, - "preview": "stageFiles = dir(fullfile(stagingDir, '*.m'));", - "start_line": 33 - }, - { - "end_line": 56, - "line_count": 10, - "preview": "rootReferenceFiles = {'Analysis.m', 'SignalObj.m', 'FitResult.m'};", - "start_line": 47 - }, - { - "end_line": 64, - "line_count": 7, - "preview": "if ~isempty(failures)", - "start_line": 58 - }, - { - "end_line": 66, - "line_count": 1, - "preview": "copyfile(fullfile(outputDir, '*'), helpDir, 'f');", - "start_line": 66 - }, - { - "end_line": 69, - "line_count": 2, - "preview": "builddocsearchdb(helpDir);", - "start_line": 68 - }, - { - "end_line": 72, - "line_count": 2, - "preview": "validateHelpTargets(helpDir);", - "start_line": 71 - }, - { - "end_line": 76, - "line_count": 3, - "preview": "fprintf('nSTAT help publication completed successfully.\\n');", - "start_line": 74 - }, - { - "end_line": 83, - "line_count": 6, - "preview": "function opts = parseOptions(varargin)", - "start_line": 78 - }, - { - "end_line": 87, - "line_count": 3, - "preview": "opts.EvalCode = logical(parser.Results.EvalCode);", - "start_line": 85 - }, - { - "end_line": 95, - "line_count": 7, - "preview": "function removeStagedArtifacts(stagingDir)", - "start_line": 89 - }, - { - "end_line": 102, - "line_count": 6, - "preview": "function removePattern(stagingDir, pattern)", - "start_line": 97 - }, - { - "end_line": 108, - "line_count": 5, - "preview": "function validateHelpTargets(helpDir)", - "start_line": 104 - }, - { - "end_line": 123, - "line_count": 14, - "preview": "raw = fileread(helptocPath);", - "start_line": 110 - }, - { - "end_line": 136, - "line_count": 12, - "preview": "function validateHtmlGeneratorMetadata(helpDir, expectedGenerator)", - "start_line": 125 - }, - { - "end_line": 151, - "line_count": 14, - "preview": "function cleanupTempDirs(stagingDir, outputDir)", - "start_line": 138 - } - ], - "matlab_code_lines": 126, - "matlab_file": "helpfiles/publish_all_helpfiles.m", - "matlab_reference_image_count": 0, - "matlab_reference_images": [], - "python_code_cells": [ - { - "cell_index": 1, - "line_count": 292, - "preview": "import matplotlib" - } - ], - "python_code_lines": 292, - "python_notebook": "notebooks/helpfiles/publish_all_helpfiles.ipynb", - "python_to_matlab_line_ratio": 2.3174603174603177, - "python_validation_image_count": 1, - "python_validation_images": [ - "baseline/validation/notebook_images/publish_all_helpfiles/publish_all_helpfiles_001.png" - ], - "strict_line_status": "line_port_partial", - "topic": "publish_all_helpfiles" - } - ] - }, - "generated_at_utc": "deterministic", - "matlab_root": "", - "method_functional_audit": { - "class_summary": [ - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 98, - "eligible_method_count": 98, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "SignalObj", - "matlab_method_count": 98, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 14, - "eligible_method_count": 14, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "Covariate", - "matlab_method_count": 14, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 5, - "eligible_method_count": 5, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "ConfidenceInterval", - "matlab_method_count": 5, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 5, - "eligible_method_count": 5, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "Events", - "matlab_method_count": 5, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 8, - "eligible_method_count": 8, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "History", - "matlab_method_count": 8, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 29, - "eligible_method_count": 29, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "nspikeTrain", - "matlab_method_count": 29, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 53, - "eligible_method_count": 53, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "nstColl", - "matlab_method_count": 53, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 55, - "eligible_method_count": 55, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "CovColl", - "matlab_method_count": 55, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 6, - "eligible_method_count": 6, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "TrialConfig", - "matlab_method_count": 6, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 9, - "eligible_method_count": 9, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "ConfigColl", - "matlab_method_count": 9, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 68, - "eligible_method_count": 68, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "Trial", - "matlab_method_count": 68, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 21, - "eligible_method_count": 21, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "CIF", - "matlab_method_count": 21, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 22, - "eligible_method_count": 22, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "Analysis", - "matlab_method_count": 22, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 33, - "eligible_method_count": 33, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "FitResult", - "matlab_method_count": 33, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 1.0, - "contract_verified_count": 30, - "eligible_method_count": 30, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 0, - "matlab_class": "FitResSummary", - "matlab_method_count": 30, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - }, - { - "contract_coverage_ratio": 0.5333333333333333, - "contract_verified_count": 24, - "eligible_method_count": 24, - "eligible_verified_ratio": 1.0, - "excluded_method_count": 21, - "matlab_class": "DecodingAlgorithms", - "matlab_method_count": 45, - "missing_symbol_count": 0, - "probe_verified_count": 0, - "unverified_behavior_count": 0 - } - ], - "method_rows": [ - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "copy", - "mapped_via_alias": true, - "matlab_class": "SignalObj", - "matlab_method": "SignalObj", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setName", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setXlabel", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setXlabel", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setYLabel", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setYLabel", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setUnits", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setUnits", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setXUnits", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setXUnits", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setYUnits", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setYUnits", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setSampleRate", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setSampleRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setDataLabels", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setDataLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMinTime", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setMinTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMaxTime", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setMaxTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setPlotProps", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setPlotProps", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMask", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "time", - "mapped_via_alias": true, - "matlab_class": "SignalObj", - "matlab_method": "getTime", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "data", - "mapped_via_alias": true, - "matlab_class": "SignalObj", - "matlab_method": "getData", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getOriginalData", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getOriginalData", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getOrigDataSig", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getOrigDataSig", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getValueAt", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getValueAt", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getPlotProps", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getPlotProps", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getIndicesFromLabels", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getIndicesFromLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "plus", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "plus", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "minus", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "minus", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "uplus", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "uplus", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "uminus", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "uminus", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "power", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "power", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "sqrt", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "sqrt", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "times", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "times", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "mtimes", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "mtimes", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "rdivide", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "rdivide", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "ldivide", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "ldivide", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "ctranspose", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "ctranspose", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "transpose", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "transpose", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "derivative", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "derivative", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "derivativeAt", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "derivativeAt", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "integral", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "integral", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "filter", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "filter", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "filtfilt", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "filtfilt", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "makeCompatible", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "makeCompatible", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "abs", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "abs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "log", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "log", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "median", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "median", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "mode", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "mode", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "mean", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "mean", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "std", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "std", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "max", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "max", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "min", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "min", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "autocorrelation", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "autocorrelation", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "crosscorrelation", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "crosscorrelation", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "periodogram", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "periodogram", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "MTMspectrum", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "MTMspectrum", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "spectrogram", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "spectrogram", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "xcorr", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "xcorr", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "xcov", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "xcov", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "merge", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "merge", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "copySignal", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "copySignal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resample", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "resample", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resampleMe", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "resampleMe", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "restoreToOriginal", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "restoreToOriginal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resetMask", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "resetMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "findIndFromDataMask", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "findIndFromDataMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "findNearestTimeIndices", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "findNearestTimeIndices", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "findNearestTimeIndex", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "findNearestTimeIndex", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "shift", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "shift", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "shiftMe", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "shiftMe", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "alignTime", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "alignTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotPropsSet", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "plotPropsSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "areDataLabelsEmpty", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "areDataLabelsEmpty", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isLabelPresent", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "isLabelPresent", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isMaskSet", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "isMaskSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "convertNamesToIndices", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "convertNamesToIndices", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "alignToMax", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "alignToMax", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "findGlobalPeak", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "findGlobalPeak", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "findPeaks", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "findPeaks", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "findMaxima", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "findMaxima", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "findMinima", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "findMinima", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "clearPlotProps", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "clearPlotProps", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "dataToStructure", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "dataToStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "dataToMatrix", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "dataToMatrix", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getSubSignal", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getSubSignal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "normWindowedSignal", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "normWindowedSignal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "windowedSignal", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "windowedSignal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getSigInTimeWindow", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getSigInTimeWindow", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getSubSignalsWithinNStd", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getSubSignalsWithinNStd", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "plot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setupPlots", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setupPlots", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotVariability", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "plotVariability", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotAllVariability", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "plotAllVariability", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getIndexFromLabel", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getIndexFromLabel", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setDataMask", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setDataMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setMaskByInd", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setMaskByInd", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setMaskByLabels", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "setMaskByLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getSubSignalFromInd", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getSubSignalFromInd", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getSubSignalFromNames", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getSubSignalFromNames", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "signalFromStruct", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "signalFromStruct", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "convertSigStructureToStructure", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "convertSigStructureToStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "convertSimpleStructureToSigStructure", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "convertSimpleStructureToSigStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "cell2str", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "cell2str", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getAvailableColor", - "mapped_via_alias": false, - "matlab_class": "SignalObj", - "matlab_method": "getAvailableColor", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "Covariate", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "Covariate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeMeanPlusCI", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "computeMeanPlusCI", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "plot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getSubSignal", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "getSubSignal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getSigRep", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "getSigRep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "filtfilt", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "filtfilt", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isConfIntervalSet", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "isConfIntervalSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setConfInterval", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "setConfInterval", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "copySignal", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "copySignal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "plus", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "plus", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "minus", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "minus", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "dataToStructure", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "dataToStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "Covariate", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "ConfidenceInterval", - "mapped_via_alias": false, - "matlab_class": "ConfidenceInterval", - "matlab_method": "ConfidenceInterval", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setColor", - "mapped_via_alias": false, - "matlab_class": "ConfidenceInterval", - "matlab_method": "setColor", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setValue", - "mapped_via_alias": false, - "matlab_class": "ConfidenceInterval", - "matlab_method": "setValue", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot", - "mapped_via_alias": false, - "matlab_class": "ConfidenceInterval", - "matlab_method": "plot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "ConfidenceInterval", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "Events", - "mapped_via_alias": false, - "matlab_class": "Events", - "matlab_method": "Events", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot", - "mapped_via_alias": false, - "matlab_class": "Events", - "matlab_method": "plot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "Events", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "Events", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "dsxy2figxy", - "mapped_via_alias": false, - "matlab_class": "Events", - "matlab_method": "dsxy2figxy", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "History", - "mapped_via_alias": false, - "matlab_class": "History", - "matlab_method": "History", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "computeHistory", - "mapped_via_alias": false, - "matlab_class": "History", - "matlab_method": "computeHistory", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setWindow", - "mapped_via_alias": false, - "matlab_class": "History", - "matlab_method": "setWindow", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot", - "mapped_via_alias": false, - "matlab_class": "History", - "matlab_method": "plot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toFilter", - "mapped_via_alias": false, - "matlab_class": "History", - "matlab_method": "toFilter", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "History", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "History", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "computeNSTHistoryWindow", - "mapped_via_alias": false, - "matlab_class": "History", - "matlab_method": "computeNSTHistoryWindow", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "nspikeTrain", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "nspikeTrain", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getLStatistic", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "getLStatistic", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMER", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "setMER", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setName", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "setName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeStatistics", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "computeStatistics", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setSigRep", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "setSigRep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMinTime", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "setMinTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMaxTime", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "setMaxTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "clearSigRep", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "clearSigRep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resample", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "resample", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getSigRep", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "getSigRep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getMaxBinSizeBinary", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "getMaxBinSizeBinary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotISISpectrumFunction", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "plotISISpectrumFunction", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "spike_times", - "mapped_via_alias": true, - "matlab_class": "nspikeTrain", - "matlab_method": "getSpikeTimes", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotJointISIHistogram", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "plotJointISIHistogram", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getFieldVal", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "getFieldVal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotISIHistogram", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "plotISIHistogram", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotExponentialFit", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "plotExponentialFit", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotProbPlot", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "plotProbPlot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getISIs", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "getISIs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getMinISI", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "getMinISI", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "partitionNST", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "partitionNST", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isSigRepBinary", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "isSigRepBinary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeRate", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "computeRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "restoreToOriginal", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "restoreToOriginal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "nstCopy", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "nstCopy", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "plot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "nspikeTrain", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "copy", - "mapped_via_alias": true, - "matlab_class": "nstColl", - "matlab_method": "nstColl", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "merge", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "merge", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getFirstSpikeTime", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getFirstSpikeTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getLastSpikeTime", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getLastSpikeTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getMaxBinSizeBinary", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getMaxBinSizeBinary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNeighbors", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getNeighbors", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getFieldVal", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getFieldVal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "shiftTime", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "shiftTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMinTime", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "setMinTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMaxTime", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "setMaxTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setMask", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "setMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setNeuronMaskFromInd", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "setNeuronMaskFromInd", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setNeuronMask", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "setNeuronMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setNeighbors", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "setNeighbors", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getIndFromMask", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getIndFromMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getIndFromMaskMinusOne", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getIndFromMaskMinusOne", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isNeuronMaskSet", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "isNeuronMaskSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "areNeighborsSet", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "areNeighborsSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "restoreToOriginal", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "restoreToOriginal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "findMaxSampleRate", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "findMaxSampleRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resetMask", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "resetMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "addToColl", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "addToColl", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getUniqueNSTnames", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getUniqueNSTnames", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNSTnames", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getNSTnames", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNSTIndicesFromName", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getNSTIndicesFromName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNSTnameFromInd", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getNSTnameFromInd", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNSTFromName", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getNSTFromName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNST", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getNST", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resample", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "resample", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isSigRepBinary", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "isSigRepBinary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "BinarySigRep", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "BinarySigRep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getEnsembleNeuronCovariates", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getEnsembleNeuronCovariates", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "addNeuronNamesToEnsCovColl", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "addNeuronNamesToEnsCovColl", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "dataToMatrix", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "dataToMatrix", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toSpikeTrain", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "toSpikeTrain", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "psth", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "psth", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "psthBars", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "psthBars", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "ssglm", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "ssglm", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "psthGLM", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "psthGLM", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "plot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getMinISIs", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getMinISIs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getISIs", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getISIs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotISIHistogram", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "plotISIHistogram", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotExponentialFit", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "plotExponentialFit", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "estimateVarianceAcrossTrials", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "estimateVarianceAcrossTrials", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getSpikeTimes", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "getSpikeTimes", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "generateUnitImpulseBasis", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "generateUnitImpulseBasis", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "addSingleSpikeToColl", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "addSingleSpikeToColl", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "ensureConsistancy", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "ensureConsistancy", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "enforceSampleRate", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "enforceSampleRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "updateTimes", - "mapped_via_alias": false, - "matlab_class": "nstColl", - "matlab_method": "updateTimes", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "copy", - "mapped_via_alias": true, - "matlab_class": "CovColl", - "matlab_method": "CovColl", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMinTime", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "setMinTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMaxTime", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "setMaxTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setSampleRate", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "setSampleRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setMask", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "setMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCovDataMask", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "getCovDataMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isCovMaskSet", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "isCovMaskSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "nActCovar", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "nActCovar", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "maskAwayCov", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "maskAwayCov", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "copy", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "copy", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "maskAwayOnlyCov", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "maskAwayOnlyCov", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "maskAwayAllExcept", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "maskAwayAllExcept", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCov", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "getCov", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCovIndicesFromNames", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "getCovIndicesFromNames", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCovDimension", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "getCovDimension", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getAllCovLabels", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "getAllCovLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCovLabelsFromMask", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "getCovLabelsFromMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "findMinTime", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "findMinTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "findMaxTime", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "findMaxTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "addToColl", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "addToColl", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "addCovCollection", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "addCovCollection", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isCovPresent", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "isCovPresent", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resample", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "resample", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "restoreToOriginal", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "restoreToOriginal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "restrictToTimeWindow", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "restrictToTimeWindow", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "removeCovariate", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "removeCovariate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resetMask", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "resetMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "enforceSampleRate", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "enforceSampleRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setCovShift", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "setCovShift", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resetCovShift", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "resetCovShift", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "flattenCovMask", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "flattenCovMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "dataToMatrix", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "dataToMatrix", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "dataToMatrixFromNames", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "dataToMatrixFromNames", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "dataToMatrixFromSel", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "dataToMatrixFromSel", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "dataToStructure", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "dataToStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "plot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setMasksFromSelector", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "setMasksFromSelector", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCovMaskFromSelector", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "getCovMaskFromSelector", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getSelectorFromMasks", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "getSelectorFromMasks", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isaSelectorCell", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "isaSelectorCell", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "generateSelectorCell", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "generateSelectorCell", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "addCovCellToColl", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "addCovCellToColl", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "addSingleCovToColl", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "addSingleCovToColl", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "updateTimes", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "updateTimes", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getCovIndFromName", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "getCovIndFromName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "removeFromColl", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "removeFromColl", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "removeFromCollByIndices", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "removeFromCollByIndices", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "generateRemainingIndex", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "generateRemainingIndex", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "covIndFromSelector", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "covIndFromSelector", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "numActCov", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "numActCov", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "sumDimensions", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "sumDimensions", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "parseDataSelectorArray", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "parseDataSelectorArray", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "containsChars", - "mapped_via_alias": false, - "matlab_class": "CovColl", - "matlab_method": "containsChars", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getName", - "mapped_via_alias": true, - "matlab_class": "TrialConfig", - "matlab_method": "TrialConfig", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setConfig", - "mapped_via_alias": false, - "matlab_class": "TrialConfig", - "matlab_method": "setConfig", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getName", - "mapped_via_alias": false, - "matlab_class": "TrialConfig", - "matlab_method": "getName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setName", - "mapped_via_alias": false, - "matlab_class": "TrialConfig", - "matlab_method": "setName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "TrialConfig", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "TrialConfig", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "ConfigColl", - "mapped_via_alias": false, - "matlab_class": "ConfigColl", - "matlab_method": "ConfigColl", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "addConfig", - "mapped_via_alias": false, - "matlab_class": "ConfigColl", - "matlab_method": "addConfig", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getConfig", - "mapped_via_alias": false, - "matlab_class": "ConfigColl", - "matlab_method": "getConfig", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setConfig", - "mapped_via_alias": false, - "matlab_class": "ConfigColl", - "matlab_method": "setConfig", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getConfigNames", - "mapped_via_alias": false, - "matlab_class": "ConfigColl", - "matlab_method": "getConfigNames", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setConfigNames", - "mapped_via_alias": false, - "matlab_class": "ConfigColl", - "matlab_method": "setConfigNames", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getSubsetConfigs", - "mapped_via_alias": false, - "matlab_class": "ConfigColl", - "matlab_method": "getSubsetConfigs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "ConfigColl", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "ConfigColl", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getDesignMatrix", - "mapped_via_alias": true, - "matlab_class": "Trial", - "matlab_method": "Trial", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setTrialEvents", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setTrialEvents", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setTrialPartition", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setTrialPartition", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getTrialPartition", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getTrialPartition", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setTrialTimesFor", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setTrialTimesFor", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMinTime", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setMinTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setMaxTime", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setMaxTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "updateTimePartitions", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "updateTimePartitions", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setSampleRate", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setSampleRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setEnsCovMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setEnsCovMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setCovMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setCovMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setNeuronMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setNeuronMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setNeighbors", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setNeighbors", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setHistory", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setHistory", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setEnsCovHist", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "setEnsCovHist", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isNeuronMaskSet", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "isNeuronMaskSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isCovMaskSet", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "isCovMaskSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isMaskSet", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "isMaskSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isHistSet", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "isHistSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isEnsCovHistSet", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "isEnsCovHistSet", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "addCov", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "addCov", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "removeCov", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "removeCov", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getSpikeVector", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getSpikeVector", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getDesignMatrix", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getDesignMatrix", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getEnsCovMatrix", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getEnsCovMatrix", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getHistForNeurons", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getHistForNeurons", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getHistMatrices", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getHistMatrices", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getEnsembleNeuronCovariates", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getEnsembleNeuronCovariates", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNeuronIndFromMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getNeuronIndFromMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNumUniqueNeurons", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getNumUniqueNeurons", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNeuronNames", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getNeuronNames", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getUniqueNeuronNames", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getUniqueNeuronNames", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNeuronIndFromName", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getNeuronIndFromName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNeuronNeighbors", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getNeuronNeighbors", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCovSelectorFromMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getCovSelectorFromMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getCov", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getCov", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNeuron", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getNeuron", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getEvents", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getEvents", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getAllLabels", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getAllLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getNumHist", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getNumHist", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getAllCovLabels", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getAllCovLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCovLabelsFromMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getCovLabelsFromMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getHistLabels", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getHistLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getEnsCovLabels", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getEnsCovLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getEnsCovLabelsFromMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getEnsCovLabelsFromMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getLabelsFromMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "getLabelsFromMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "flattenCovMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "flattenCovMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "flattenMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "flattenMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "shiftCovariates", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "shiftCovariates", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resetEnsCovMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "resetEnsCovMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resetCovMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "resetCovMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resetNeuronMask", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "resetNeuronMask", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resetHistory", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "resetHistory", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resample", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "resample", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resampleEnsColl", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "resampleEnsColl", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "restoreToOriginal", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "restoreToOriginal", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "makeConsistentSampleRate", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "makeConsistentSampleRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "makeConsistentTime", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "makeConsistentTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotRaster", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "plotRaster", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "plotCovariates", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "plotCovariates", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "plot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "isSampleRateConsistent", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "isSampleRateConsistent", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "findMinTime", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "findMinTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "findMaxTime", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "findMaxTime", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "findMinSampleRate", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "findMinSampleRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "findMaxSampleRate", - "mapped_via_alias": false, - "matlab_class": "Trial", - "matlab_method": "findMaxSampleRate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "CIF", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "CIF", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "CIFCopy", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "CIFCopy", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setSpikeTrain", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "setSpikeTrain", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setHistory", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "setHistory", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalLambdaDelta", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalLambdaDelta", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalGradient", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalGradient", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalGradientLog", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalGradientLog", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalJacobian", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalJacobian", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalJacobianLog", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalJacobianLog", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalLDGamma", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalLDGamma", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalLogLDGamma", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalLogLDGamma", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalGradientLDGamma", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalGradientLDGamma", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalGradientLogLDGamma", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalGradientLogLDGamma", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalJacobianLogLDGamma", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalJacobianLogLDGamma", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalJacobianLDGamma", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalJacobianLDGamma", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isSymBeta", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "isSymBeta", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "simulateCIFByThinningFromLambda", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "simulateCIFByThinningFromLambda", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "simulateCIFByThinning", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "simulateCIFByThinning", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "simulateCIF", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "simulateCIF", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "evalFunctionWithVectorArgs", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "evalFunctionWithVectorArgs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "resolveSimulinkModelName", - "mapped_via_alias": false, - "matlab_class": "CIF", - "matlab_method": "resolveSimulinkModelName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "RunAnalysisForNeuron", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "RunAnalysisForNeuron", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "RunAnalysisForAllNeurons", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "RunAnalysisForAllNeurons", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "GLMFit", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "GLMFit", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotInvGausTrans", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "plotInvGausTrans", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotFitResidual", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "plotFitResidual", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "KSPlot", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "KSPlot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "plotSeqCorr", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "plotSeqCorr", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotCoeffs", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "plotCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeInvGausTrans", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "computeInvGausTrans", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "computeKSStats", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "computeKSStats", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeFitResidual", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "computeFitResidual", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "compHistEnsCoeffForAll", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "compHistEnsCoeffForAll", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "compHistEnsCoeff", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "compHistEnsCoeff", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "computeGrangerCausalityMatrix", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "computeGrangerCausalityMatrix", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeHistLag", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "computeHistLag", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeHistLagForAll", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "computeHistLagForAll", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeNeighbors", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "computeNeighbors", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "spikeTrigAvg", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "spikeTrigAvg", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "flatMaskCellToMat", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "flatMaskCellToMat", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "bnlrCG", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "bnlrCG", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "ksdiscrete", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "ksdiscrete", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fdr_bh", - "mapped_via_alias": false, - "matlab_class": "Analysis", - "matlab_method": "fdr_bh", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "FitResult", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "FitResult", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "setNeuronName", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "setNeuronName", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "mergeResults", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "mergeResults", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getSubsetFitResult", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "getSubsetFitResult", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "addParamsToFit", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "addParamsToFit", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeValLambda", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "computeValLambda", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "mapCovLabelsToUniqueLabels", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "mapCovLabelsToUniqueLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getPlotParams", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "getPlotParams", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotValidation", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "plotValidation", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "isValDataPresent", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "isValDataPresent", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "predict", - "mapped_via_alias": true, - "matlab_class": "FitResult", - "matlab_method": "evalLambda", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computePlotParams", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "computePlotParams", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getCoeffIndex", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "getCoeffIndex", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotCoeffsWithoutHistory", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "plotCoeffsWithoutHistory", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getHistIndex", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "getHistIndex", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "getCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getHistCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "getHistCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotHistCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "plotHistCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "plotCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotResults", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "plotResults", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "KSPlot", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "KSPlot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotSeqCorr", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "plotSeqCorr", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotInvGausTrans", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "plotInvGausTrans", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotResidual", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "plotResidual", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setKSStats", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "setKSStats", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setInvGausStats", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "setInvGausStats", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setFitResidual", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "setFitResidual", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "getParam", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "getParam", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "CellArrayToStructure", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "CellArrayToStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "xticklabel_rotate", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "xticklabel_rotate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getUniqueLabels", - "mapped_via_alias": false, - "matlab_class": "FitResult", - "matlab_method": "getUniqueLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "FitResSummary", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "FitResSummary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "mapCovLabelsToUniqueLabels", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "mapCovLabelsToUniqueLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getDiffAIC", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "getDiffAIC", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getDiffBIC", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "getDiffBIC", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getDifflogLL", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "getDifflogLL", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "binCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "binCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "setCoeffRange", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "setCoeffRange", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getSigCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "getSigCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotIC", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotIC", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotAllCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotAllCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot3dCoeffSummary", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plot3dCoeffSummary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plot2dCoeffSummary", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plot2dCoeffSummary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotKSSummary", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotKSSummary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotAIC", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotAIC", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotBIC", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotBIC", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotlogLL", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotlogLL", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotResidualSummary", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotResidualSummary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotSummary", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotSummary", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "boxPlot", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "boxPlot", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "toStructure", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "toStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCoeffIndex", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "getCoeffIndex", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotCoeffsWithoutHistory", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotCoeffsWithoutHistory", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getHistIndex", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "getHistIndex", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "getCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getHistCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "getHistCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "plotHistCoeffs", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "plotHistCoeffs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "fromStructure", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "fromStructure", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeDiffMat", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "computeDiffMat", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "getUniqueLabels", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "getUniqueLabels", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "xticklabel_rotate", - "mapped_via_alias": false, - "matlab_class": "FitResSummary", - "matlab_method": "xticklabel_rotate", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "PPDecodeFilter", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPDecodeFilter", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "PPDecodeFilterLinear", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPDecodeFilterLinear", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "PP_fixedIntervalSmoother", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PP_fixedIntervalSmoother", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "PPDecode_predict", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPDecode_predict", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "PPDecode_update", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPDecode_update", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "PPDecode_updateLinear", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPDecode_updateLinear", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "PPHybridFilterLinear", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPHybridFilterLinear", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "PPHybridFilter", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPHybridFilter", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "ukf", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "ukf", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "ukf_ut", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "ukf_ut", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "ukf_sigmas", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "ukf_sigmas", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "kalman_filter", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "kalman_filter", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "kalman_update", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "kalman_update", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "kalman_predict", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "kalman_predict", - "present_in_compat_surface": true, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "kalman_fixedIntervalSmoother", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "kalman_fixedIntervalSmoother", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "kalman_smootherFromFiltered", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "kalman_smootherFromFiltered", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "kalman_smoother", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "kalman_smoother", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "PPSS_EMFB", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPSS_EMFB", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "PPSS_EM", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPSS_EM", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "PPSS_EStep", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPSS_EStep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "PPSS_MStep", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PPSS_MStep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "prepareEMResults", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "prepareEMResults", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "ComputeStimulusCIs", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "ComputeStimulusCIs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "estimateInfoMat", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "estimateInfoMat", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "compute_spike_rate_cis", - "mapped_via_alias": true, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "computeSpikeRateCIs", - "present_in_compat_surface": false, - "present_in_python_surface": true - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "computeSpikeRateDiffCIs", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "computeSpikeRateDiffCIs", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "KF_EMCreateConstraints", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "KF_EMCreateConstraints", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "KF_EM", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "KF_EM", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "KF_ComputeParamStandardErrors", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "KF_ComputeParamStandardErrors", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "KF_EStep", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "KF_EStep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "KF_MStep", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "KF_MStep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "mPPCO_fixedIntervalSmoother", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "mPPCO_fixedIntervalSmoother", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": true, - "mapped_python_member": "mPPCODecodeLinear", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "mPPCODecodeLinear", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "mPPCODecode_predict", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "mPPCODecode_predict", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": false, - "functional_status": "contract_verified", - "has_behavior_contract": true, - "has_probe_verification": false, - "mapped_python_member": "mPPCODecode_update", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "mPPCODecode_update", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "mPPCO_EMCreateConstraints", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "mPPCO_EMCreateConstraints", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "mPPCO_ComputeParamStandardErrors", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "mPPCO_ComputeParamStandardErrors", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "mPPCO_EM", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "mPPCO_EM", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "mPPCO_EStep", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "mPPCO_EStep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "mPPCO_MStep", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "mPPCO_MStep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "PP_EMCreateConstraints", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PP_EMCreateConstraints", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "PP_ComputeParamStandardErrors", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PP_ComputeParamStandardErrors", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "PP_EM", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PP_EM", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "PP_EStep", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PP_EStep", - "present_in_compat_surface": true, - "present_in_python_surface": false - }, - { - "excluded_method": true, - "functional_status": "excluded_matlab_stub", - "has_behavior_contract": false, - "has_probe_verification": false, - "mapped_python_member": "PP_MStep", - "mapped_via_alias": false, - "matlab_class": "DecodingAlgorithms", - "matlab_method": "PP_MStep", - "present_in_compat_surface": true, - "present_in_python_surface": false - } - ], - "summary": { - "contract_explicit_verified_methods": 480, - "contract_verified_methods": 480, - "contract_verified_ratio": 0.9580838323353293, - "eligible_methods": 480, - "eligible_verified_ratio": 1.0, - "excluded_methods": 21, - "missing_symbol_methods": 0, - "probe_verified_methods": 0, - "total_methods": 501, - "unverified_behavior_methods": 0 - } - }, - "repo_root": "." -} diff --git a/parity/functional_gate_policy.yml b/parity/functional_gate_policy.yml deleted file mode 100644 index 39c28360..00000000 --- a/parity/functional_gate_policy.yml +++ /dev/null @@ -1,67 +0,0 @@ -version: 1 -policy_name: functional_equivalence_gate - -method_thresholds: - min_verified_ratio_overall: 0.958 - min_eligible_verified_ratio_overall: 1.0 - min_contract_explicit_verified_methods: 480 - max_probe_verified_methods: 0 - max_unverified_behavior_methods: 0 - max_missing_symbol_methods: 0 - class_min_verified_methods: - SignalObj: 98 - Covariate: 14 - ConfidenceInterval: 5 - Events: 5 - History: 8 - nspikeTrain: 29 - nstColl: 53 - CovColl: 55 - TrialConfig: 6 - ConfigColl: 9 - Trial: 68 - CIF: 21 - Analysis: 22 - FitResult: 33 - FitResSummary: 30 - DecodingAlgorithms: 24 - class_min_eligible_verified_ratio: - SignalObj: 1.0 - Covariate: 1.0 - ConfidenceInterval: 1.0 - Events: 1.0 - History: 1.0 - nspikeTrain: 1.0 - nstColl: 1.0 - CovColl: 1.0 - TrialConfig: 1.0 - ConfigColl: 1.0 - Trial: 1.0 - CIF: 1.0 - Analysis: 1.0 - FitResult: 1.0 - FitResSummary: 1.0 - DecodingAlgorithms: 1.0 - class_max_probe_verified_methods: - SignalObj: 0 - Covariate: 0 - ConfidenceInterval: 0 - Events: 0 - History: 0 - nspikeTrain: 0 - nstColl: 0 - CovColl: 0 - TrialConfig: 0 - ConfigColl: 0 - Trial: 0 - CIF: 0 - Analysis: 0 - FitResult: 0 - FitResSummary: 0 - DecodingAlgorithms: 0 - -example_thresholds: - max_missing_artifact_topics: 0 - max_missing_executable_topics: 0 - max_pending_manual_review_topics: 0 - max_matlab_doc_only_topics: 4 diff --git a/parity/help_source_manifest.yml b/parity/help_source_manifest.yml new file mode 100644 index 00000000..b7e358ad --- /dev/null +++ b/parity/help_source_manifest.yml @@ -0,0 +1,272 @@ +version: 1 +topics: +- topic: AnalysisExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/AnalysisExamples.mlx + expected_section_count: 2 + expected_figure_count: 4 + detected_figure_count: 4 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/AnalysisExamples.ipynb + python_cell_count: 2 + no_figure_utility: false +- topic: ConfigCollExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/ConfigCollExamples.mlx + expected_section_count: 1 + expected_figure_count: 0 + detected_figure_count: 0 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/ConfigCollExamples.ipynb + python_cell_count: 1 + no_figure_utility: false +- topic: CovCollExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/CovCollExamples.mlx + expected_section_count: 1 + expected_figure_count: 2 + detected_figure_count: 2 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/CovCollExamples.ipynb + python_cell_count: 1 + no_figure_utility: false +- topic: CovariateExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/CovariateExamples.mlx + expected_section_count: 2 + expected_figure_count: 2 + detected_figure_count: 2 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/CovariateExamples.ipynb + python_cell_count: 2 + no_figure_utility: false +- topic: DecodingExample + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/DecodingExample.mlx + expected_section_count: 3 + expected_figure_count: 5 + detected_figure_count: 4 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/DecodingExample.ipynb + python_cell_count: 3 + no_figure_utility: false +- topic: DecodingExampleWithHist + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/DecodingExampleWithHist.mlx + expected_section_count: 1 + expected_figure_count: 2 + detected_figure_count: 2 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/DecodingExampleWithHist.ipynb + python_cell_count: 1 + no_figure_utility: false +- topic: EventsExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/EventsExamples.mlx + expected_section_count: 1 + expected_figure_count: 3 + detected_figure_count: 3 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/EventsExamples.ipynb + python_cell_count: 1 + no_figure_utility: false +- topic: ExplicitStimulusWhiskerData + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/ExplicitStimulusWhiskerData.mlx + expected_section_count: 6 + expected_figure_count: 8 + detected_figure_count: 5 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/ExplicitStimulusWhiskerData.ipynb + python_cell_count: 6 + no_figure_utility: false +- topic: FitResSummaryExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/FitResSummaryExamples.mlx + expected_section_count: 1 + expected_figure_count: 0 + detected_figure_count: 0 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/FitResSummaryExamples.ipynb + python_cell_count: 1 + no_figure_utility: false +- topic: FitResultExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/FitResultExamples.mlx + expected_section_count: 1 + expected_figure_count: 0 + detected_figure_count: 0 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/FitResultExamples.ipynb + python_cell_count: 1 + no_figure_utility: false +- topic: HippocampalPlaceCellExample + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/HippocampalPlaceCellExample.mlx + expected_section_count: 5 + expected_figure_count: 9 + detected_figure_count: 7 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/HippocampalPlaceCellExample.ipynb + python_cell_count: 5 + no_figure_utility: false +- topic: HistoryExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/HistoryExamples.mlx + expected_section_count: 3 + expected_figure_count: 3 + detected_figure_count: 3 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/HistoryExamples.ipynb + python_cell_count: 3 + no_figure_utility: false +- topic: NetworkTutorial + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/NetworkTutorial.mlx + expected_section_count: 11 + expected_figure_count: 4 + detected_figure_count: 2 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/NetworkTutorial.ipynb + python_cell_count: 11 + no_figure_utility: false +- topic: PPSimExample + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/PPSimExample.mlx + expected_section_count: 9 + expected_figure_count: 3 + detected_figure_count: 1 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/PPSimExample.ipynb + python_cell_count: 9 + no_figure_utility: false +- topic: PPThinning + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/PPThinning.mlx + expected_section_count: 4 + expected_figure_count: 3 + detected_figure_count: 3 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/PPThinning.ipynb + python_cell_count: 4 + no_figure_utility: false +- topic: PSTHEstimation + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/PSTHEstimation.mlx + expected_section_count: 3 + expected_figure_count: 2 + detected_figure_count: 2 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/PSTHEstimation.ipynb + python_cell_count: 3 + no_figure_utility: false +- topic: SignalObjExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/SignalObjExamples.mlx + expected_section_count: 7 + expected_figure_count: 16 + detected_figure_count: 16 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/SignalObjExamples.ipynb + python_cell_count: 7 + no_figure_utility: false +- topic: StimulusDecode2D + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/StimulusDecode2D.mlx + expected_section_count: 3 + expected_figure_count: 4 + detected_figure_count: 4 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/StimulusDecode2D.ipynb + python_cell_count: 3 + no_figure_utility: false +- topic: TrialConfigExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/TrialConfigExamples.mlx + expected_section_count: 1 + expected_figure_count: 0 + detected_figure_count: 0 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/TrialConfigExamples.ipynb + python_cell_count: 1 + no_figure_utility: false +- topic: TrialExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/TrialExamples.mlx + expected_section_count: 3 + expected_figure_count: 6 + detected_figure_count: 6 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/TrialExamples.ipynb + python_cell_count: 3 + no_figure_utility: false +- topic: ValidationDataSet + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/ValidationDataSet.mlx + expected_section_count: 3 + expected_figure_count: 8 + detected_figure_count: 3 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/ValidationDataSet.ipynb + python_cell_count: 3 + no_figure_utility: false +- topic: mEPSCAnalysis + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/mEPSCAnalysis.mlx + expected_section_count: 9 + expected_figure_count: 4 + detected_figure_count: 2 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/mEPSCAnalysis.ipynb + python_cell_count: 9 + no_figure_utility: false +- topic: nSTATPaperExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/nSTATPaperExamples.mlx + expected_section_count: 31 + expected_figure_count: 1 + detected_figure_count: 25 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/nSTATPaperExamples.ipynb + python_cell_count: 31 + no_figure_utility: false +- topic: nSpikeTrainExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/nSpikeTrainExamples.mlx + expected_section_count: 2 + expected_figure_count: 4 + detected_figure_count: 4 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/nSpikeTrainExamples.ipynb + python_cell_count: 2 + no_figure_utility: false +- topic: nstCollExamples + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/nstCollExamples.mlx + expected_section_count: 2 + expected_figure_count: 3 + detected_figure_count: 3 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/nstCollExamples.ipynb + python_cell_count: 2 + no_figure_utility: false +- topic: AnalysisExamples2 + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/AnalysisExamples2.mlx + expected_section_count: 3 + expected_figure_count: 4 + detected_figure_count: 2 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/AnalysisExamples2.ipynb + python_cell_count: 3 + no_figure_utility: false +- topic: DocumentationSetup2025b + source_type: m + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/DocumentationSetup2025b.m + expected_section_count: 6 + expected_figure_count: 0 + detected_figure_count: 0 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/DocumentationSetup2025b.ipynb + python_cell_count: 6 + no_figure_utility: false +- topic: FitResultReference + source_type: m + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/FitResultReference.m + expected_section_count: 2 + expected_figure_count: 0 + detected_figure_count: 0 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/FitResultReference.ipynb + python_cell_count: 2 + no_figure_utility: false +- topic: HybridFilterExample + source_type: mlx + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/HybridFilterExample.mlx + expected_section_count: 4 + expected_figure_count: 1 + detected_figure_count: 2 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/HybridFilterExample.ipynb + python_cell_count: 4 + no_figure_utility: false +- topic: publish_all_helpfiles + source_type: m + source_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/publish_all_helpfiles.m + expected_section_count: 1 + expected_figure_count: 0 + detected_figure_count: 0 + notebook_output_path: /Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT-python/notebooks/publish_all_helpfiles.ipynb + python_cell_count: 1 + no_figure_utility: true diff --git a/parity/help_source_parsing_report.json b/parity/help_source_parsing_report.json new file mode 100644 index 00000000..d0335624 --- /dev/null +++ b/parity/help_source_parsing_report.json @@ -0,0 +1,5072 @@ +{ + "matlab_help_root": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles", + "topics": [ + { + "topic": "AnalysisExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/AnalysisExamples.mlx", + "section_count": 2, + "figure_count": 4, + "detected_figure_count": 4, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 12, + "source_line_no": 700, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 13, + "source_line_no": 701, + "source_snippet": "plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 18, + "source_line_no": 1001, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 24, + "source_line_no": 1300, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 38, + "source_line_no": 1314, + "source_snippet": "plot3(cos(-pi:1e-2:pi),sin(-pi:1e-2:pi),zeros(size(-pi:1e-2:pi)))", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 39, + "source_line_no": 1315, + "source_snippet": "plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 74, + "source_line_no": 1925, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 1, + "section_line_index": 75, + "source_line_no": 1926, + "source_snippet": "plot( ([1:N]-.5)/N, KSSorted, 0:.01:1,0:.01:1, 'g',0:.01:1, [0:.01:1]+1.36/sqrt(N), 'r', 0:.01:1,[0:.01:1]-1.36/sqrt(N), 'r' )", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 1, + "section_line_index": 79, + "source_line_no": 1930, + "source_snippet": "title('KS Plot with 95% Confidence Intervals')", + "event_type": "add_to_current", + "figure_ordinal": 4 + } + ] + }, + { + "topic": "ConfigCollExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/ConfigCollExamples.mlx", + "section_count": 1, + "figure_count": 0, + "detected_figure_count": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "CovCollExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/CovCollExamples.mlx", + "section_count": 1, + "figure_count": 2, + "detected_figure_count": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 0, + "section_line_index": 4, + "source_line_no": 203, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 4, + "source_line_no": 203, + "source_snippet": "cc.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 13, + "source_line_no": 212, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 13, + "source_line_no": 212, + "source_snippet": "cc.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + } + ] + }, + { + "topic": "CovariateExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/CovariateExamples.mlx", + "section_count": 2, + "figure_count": 2, + "detected_figure_count": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 20, + "source_line_no": 1100, + "source_snippet": "position.getSigRep.plot('all',plotProps)", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 22, + "source_line_no": 1102, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 23, + "source_line_no": 1103, + "source_snippet": "subplot(1,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 23, + "source_line_no": 1103, + "source_snippet": "force.getSigRep.plot('all',plotPropsForce)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 28, + "source_line_no": 1108, + "source_snippet": "subplot(1,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 28, + "source_line_no": 1108, + "source_snippet": "force.getSigRep('zero-mean').plot('all',plotPropsForce)", + "event_type": "add_to_current", + "figure_ordinal": 2 + } + ] + }, + { + "topic": "DecodingExample", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/DecodingExample.mlx", + "section_count": 3, + "figure_count": 5, + "detected_figure_count": 4, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 12, + "source_line_no": 412, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 13, + "source_line_no": 413, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 13, + "source_line_no": 413, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 14, + "source_line_no": 414, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 14, + "source_line_no": 414, + "source_snippet": "lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 3, + "source_line_no": 703, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 6, + "source_line_no": 706, + "source_snippet": "trial.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 18, + "source_line_no": 718, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 41, + "source_line_no": 1115, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 2, + "section_line_index": 45, + "source_line_no": 1119, + "source_snippet": "hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'g')", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 2, + "section_line_index": 48, + "source_line_no": 1122, + "source_snippet": "hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 4 + } + ] + }, + { + "topic": "DecodingExampleWithHist", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/DecodingExampleWithHist.mlx", + "section_count": 1, + "figure_count": 2, + "detected_figure_count": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 0, + "section_line_index": 24, + "source_line_no": 322, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 25, + "source_line_no": 323, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 25, + "source_line_no": 323, + "source_snippet": "sC.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 26, + "source_line_no": 324, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 26, + "source_line_no": 324, + "source_snippet": "stim.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 53, + "source_line_no": 351, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 54, + "source_line_no": 352, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 58, + "source_line_no": 356, + "source_snippet": "hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'r')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 61, + "source_line_no": 359, + "source_snippet": "hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 67, + "source_line_no": 365, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 71, + "source_line_no": 369, + "source_snippet": "hEst=plot(time,x_uNoHist(1:end),'b',time,ciLower,'g',time,ciUpper,'r')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 74, + "source_line_no": 372, + "source_snippet": "hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 78, + "source_line_no": 376, + "source_snippet": "title(['Decoded Stimulus No Hist +/- 99% confidence intervals using ' num2str(numRealizations) ' cells'])", + "event_type": "add_to_current", + "figure_ordinal": 2 + } + ] + }, + { + "topic": "EventsExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/EventsExamples.mlx", + "section_count": 1, + "figure_count": 3, + "detected_figure_count": 3, + "no_figure_utility": false, + "events": [ + { + "section_index": 0, + "section_line_index": 7, + "source_line_no": 305, + "source_snippet": "e.plot", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 9, + "source_line_no": 600, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 9, + "source_line_no": 600, + "source_snippet": "e.plot([],'r')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 10, + "source_line_no": 601, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 0, + "section_line_index": 10, + "source_line_no": 601, + "source_snippet": "e.plot([],'g')", + "event_type": "add_to_current", + "figure_ordinal": 3 + } + ] + }, + { + "topic": "ExplicitStimulusWhiskerData", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/ExplicitStimulusWhiskerData.mlx", + "section_count": 6, + "figure_count": 8, + "detected_figure_count": 5, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 21, + "source_line_no": 421, + "source_snippet": "trial.plot", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 23, + "source_line_no": 423, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 24, + "source_line_no": 424, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 26, + "source_line_no": 426, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 27, + "source_line_no": 427, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 28, + "source_line_no": 428, + "source_snippet": "stim.getSigInTimeWindow(0,21).plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 10, + "source_line_no": 809, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 11, + "source_line_no": 810, + "source_snippet": "results.Residual.xcov(stim).windowedSignal([0,1]).plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 3, + "section_line_index": 11, + "source_line_no": 1210, + "source_snippet": "results.plotResults", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 4, + "section_line_index": 22, + "source_line_no": 1621, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 4, + "section_line_index": 32, + "source_line_no": 1800, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 34, + "source_line_no": 1802, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 34, + "source_line_no": 1802, + "source_snippet": "plot(x,results{1}.KSStats.ks_stat,'.')", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 35, + "source_line_no": 1803, + "source_snippet": "plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 40, + "source_line_no": 1808, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 40, + "source_line_no": 1808, + "source_snippet": "plot(x,dAIC,'.')", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 43, + "source_line_no": 1811, + "source_snippet": "plot(x(windowIndex),dAIC(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 45, + "source_line_no": 1813, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 45, + "source_line_no": 1813, + "source_snippet": "plot(x,dBIC,'.')", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 47, + "source_line_no": 1815, + "source_snippet": "plot(x(windowIndex),dBIC(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 53, + "source_line_no": 1821, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 5 + }, + { + "section_index": 4, + "section_line_index": 54, + "source_line_no": 1822, + "source_snippet": "plot(x,dBIC,'.')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 5, + "section_line_index": 8, + "source_line_no": 2207, + "source_snippet": "c{3}.setName('Baseline+Stimulus+Hist')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 5, + "section_line_index": 11, + "source_line_no": 2210, + "source_snippet": "results.plotResults", + "event_type": "add_to_current", + "figure_ordinal": 5 + } + ] + }, + { + "topic": "FitResSummaryExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/FitResSummaryExamples.mlx", + "section_count": 1, + "figure_count": 0, + "detected_figure_count": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "FitResultExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/FitResultExamples.mlx", + "section_count": 1, + "figure_count": 0, + "detected_figure_count": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "HippocampalPlaceCellExample", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/HippocampalPlaceCellExample.mlx", + "section_count": 5, + "figure_count": 9, + "detected_figure_count": 7, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 3, + "source_line_no": 902, + "source_snippet": "figure(1)", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 4, + "source_line_no": 903, + "source_snippet": "plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 3, + "section_line_index": 5, + "source_line_no": 1604, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 4, + "section_line_index": 52, + "source_line_no": 1952, + "source_snippet": "h4=figure(4)", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "section_line_index": 60, + "source_line_no": 1960, + "source_snippet": "subplot(7,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "section_line_index": 62, + "source_line_no": 1962, + "source_snippet": "h6=figure(6)", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 4, + "section_line_index": 70, + "source_line_no": 1970, + "source_snippet": "subplot(6,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 4, + "section_line_index": 72, + "source_line_no": 1972, + "source_snippet": "pcolor(x_new,y_new,lambdaGaussian{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 4, + "section_line_index": 77, + "source_line_no": 1977, + "source_snippet": "h5=figure(5)", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 86, + "source_line_no": 1986, + "source_snippet": "subplot(7,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 4, + "section_line_index": 88, + "source_line_no": 1988, + "source_snippet": "h7=figure(7)", + "event_type": "new_figure", + "figure_ordinal": 5 + }, + { + "section_index": 4, + "section_line_index": 96, + "source_line_no": 1996, + "source_snippet": "subplot(6,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 4, + "section_line_index": 98, + "source_line_no": 1998, + "source_snippet": "pcolor(x_new,y_new,lambdaZernike{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 4, + "section_line_index": 124, + "source_line_no": 2024, + "source_snippet": "figure(8)", + "event_type": "new_figure", + "figure_ordinal": 6 + }, + { + "section_index": 4, + "section_line_index": 125, + "source_line_no": 2025, + "source_snippet": "plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 4, + "section_line_index": 129, + "source_line_no": 2029, + "source_snippet": "figure(9)", + "event_type": "new_figure", + "figure_ordinal": 7 + }, + { + "section_index": 4, + "section_line_index": 139, + "source_line_no": 2039, + "source_snippet": "plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 7 + } + ] + }, + { + "topic": "HistoryExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/HistoryExamples.mlx", + "section_count": 3, + "figure_count": 3, + "detected_figure_count": 3, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 2, + "source_line_no": 701, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 2, + "source_line_no": 701, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 2, + "source_line_no": 701, + "source_snippet": "h.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 3, + "source_line_no": 702, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 3, + "source_line_no": 702, + "source_snippet": "histn1.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 4, + "source_line_no": 703, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 4, + "source_line_no": 703, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 14, + "source_line_no": 1501, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 14, + "source_line_no": 1501, + "source_snippet": "histColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + } + ] + }, + { + "topic": "NetworkTutorial", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/NetworkTutorial.mlx", + "section_count": 11, + "figure_count": 4, + "detected_figure_count": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 8, + "section_line_index": 23, + "source_line_no": 4122, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 8, + "section_line_index": 24, + "source_line_no": 4123, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 8, + "section_line_index": 24, + "source_line_no": 4123, + "source_snippet": "sC.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 8, + "section_line_index": 25, + "source_line_no": 4124, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 8, + "section_line_index": 25, + "source_line_no": 4124, + "source_snippet": "stim.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 10, + "section_line_index": 25, + "source_line_no": 4825, + "source_snippet": "c{3}.setName('Stim+Hist+EnsHist')", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 10, + "section_line_index": 56, + "source_line_no": 4856, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 10, + "section_line_index": 58, + "source_line_no": 4858, + "source_snippet": "subplot(1,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 10, + "section_line_index": 59, + "source_line_no": 4859, + "source_snippet": "imagesc(actNetwork,CLIM)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 10, + "section_line_index": 62, + "source_line_no": 4862, + "source_snippet": "subplot(1,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 10, + "section_line_index": 63, + "source_line_no": 4863, + "source_snippet": "imagesc(network1ms,CLIM)", + "event_type": "add_to_current", + "figure_ordinal": 2 + } + ] + }, + { + "topic": "PPSimExample", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/PPSimExample.mlx", + "section_count": 9, + "figure_count": 3, + "detected_figure_count": 1, + "no_figure_utility": false, + "events": [ + { + "section_index": 4, + "section_line_index": 11, + "source_line_no": 2209, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 4, + "section_line_index": 12, + "source_line_no": 2210, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 4, + "section_line_index": 12, + "source_line_no": 2210, + "source_snippet": "sC.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 4, + "section_line_index": 13, + "source_line_no": 2211, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 4, + "section_line_index": 13, + "source_line_no": 2211, + "source_snippet": "stim.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 6, + "section_line_index": 10, + "source_line_no": 3801, + "source_snippet": "c{3}.setName('Stim+Hist')", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 8, + "section_line_index": 1, + "source_line_no": 4701, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 1 + } + ] + }, + { + "topic": "PPThinning", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/PPThinning.mlx", + "section_count": 4, + "figure_count": 3, + "detected_figure_count": 3, + "no_figure_utility": false, + "events": [ + { + "section_index": 2, + "section_line_index": 0, + "source_line_no": 700, + "source_snippet": "figure(1)", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 3, + "source_line_no": 703, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 3, + "source_line_no": 703, + "source_snippet": "n1.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 3, + "source_line_no": 703, + "source_snippet": "plot(tSpikes,ones(size(tSpikes)),'.')", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 5, + "source_line_no": 705, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 6, + "source_line_no": 706, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 6, + "source_line_no": 706, + "source_snippet": "n2.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 6, + "source_line_no": 706, + "source_snippet": "plot(tSpikes,ones(size(tSpikes)),'.')", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 8, + "source_line_no": 708, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 10, + "source_line_no": 710, + "source_snippet": "figure(2)", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 11, + "source_line_no": 711, + "source_snippet": "n2.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 13, + "source_line_no": 713, + "source_snippet": "scaledProb.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 3, + "source_line_no": 1102, + "source_snippet": "figure(3)", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 3, + "section_line_index": 4, + "source_line_no": 1103, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 3, + "section_line_index": 5, + "source_line_no": 1104, + "source_snippet": "lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + } + ] + }, + { + "topic": "PSTHEstimation", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/PSTHEstimation.mlx", + "section_count": 3, + "figure_count": 2, + "detected_figure_count": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 10, + "source_line_no": 509, + "source_snippet": "spikeColl.plot", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 11, + "source_line_no": 510, + "source_snippet": "lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 0, + "source_line_no": 800, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 5, + "source_line_no": 805, + "source_snippet": "h1=trueRate.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 6, + "source_line_no": 806, + "source_snippet": "h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 7, + "source_line_no": 807, + "source_snippet": "h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 2 + } + ] + }, + { + "topic": "SignalObjExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/SignalObjExamples.mlx", + "section_count": 7, + "figure_count": 16, + "detected_figure_count": 16, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 6, + "source_line_no": 505, + "source_snippet": "subplot(2,1,1)", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 6, + "source_line_no": 505, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 7, + "source_line_no": 506, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 7, + "source_line_no": 506, + "source_snippet": "s1.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 10, + "source_line_no": 900, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 10, + "source_line_no": 900, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 11, + "source_line_no": 901, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 11, + "source_line_no": 901, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 16, + "source_line_no": 1202, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 17, + "source_line_no": 1203, + "source_snippet": "s.getSubSignal({'v1'}).plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 0, + "source_line_no": 1500, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 2, + "source_line_no": 1502, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 2, + "source_line_no": 1502, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 3, + "source_line_no": 1503, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 3, + "source_line_no": 1503, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 4, + "source_line_no": 1700, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 2, + "section_line_index": 5, + "source_line_no": 1701, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 2, + "section_line_index": 5, + "source_line_no": 1701, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 2, + "section_line_index": 6, + "source_line_no": 1702, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 2, + "section_line_index": 6, + "source_line_no": 1702, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 2, + "section_line_index": 17, + "source_line_no": 2100, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 5 + }, + { + "section_index": 2, + "section_line_index": 19, + "source_line_no": 2102, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 2, + "section_line_index": 19, + "source_line_no": 2102, + "source_snippet": "s.plot('v1',{{' ''k'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 2, + "section_line_index": 20, + "source_line_no": 2103, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 2, + "section_line_index": 20, + "source_line_no": 2103, + "source_snippet": "s.plot('all',{{' ''k'' '},{' ''-.g'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 2, + "section_line_index": 21, + "source_line_no": 2300, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 6 + }, + { + "section_index": 2, + "section_line_index": 22, + "source_line_no": 2301, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 2, + "section_line_index": 22, + "source_line_no": 2301, + "source_snippet": "s.plot({'v1','v2'})", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 2, + "section_line_index": 23, + "source_line_no": 2302, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 2, + "section_line_index": 23, + "source_line_no": 2302, + "source_snippet": "s.plot({'v1','v2'},{{' ''k'' '},{' ''-.g'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 3, + "section_line_index": 0, + "source_line_no": 2600, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 7 + }, + { + "section_index": 3, + "section_line_index": 3, + "source_line_no": 2603, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 3, + "section_line_index": 3, + "source_line_no": 2603, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 3, + "section_line_index": 4, + "source_line_no": 2604, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 3, + "section_line_index": 4, + "source_line_no": 2604, + "source_snippet": "s1.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 3, + "section_line_index": 5, + "source_line_no": 2800, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 8 + }, + { + "section_index": 3, + "section_line_index": 6, + "source_line_no": 2801, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 3, + "section_line_index": 6, + "source_line_no": 2801, + "source_snippet": "s.getSigInTimeWindow(-2,3).plot", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 3, + "section_line_index": 7, + "source_line_no": 2802, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 3, + "section_line_index": 7, + "source_line_no": 2802, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 4, + "section_line_index": 1, + "source_line_no": 3101, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 9 + }, + { + "section_index": 4, + "section_line_index": 4, + "source_line_no": 3104, + "source_snippet": "s5.plot", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 4, + "section_line_index": 6, + "source_line_no": 3106, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 10 + }, + { + "section_index": 4, + "section_line_index": 8, + "source_line_no": 3108, + "source_snippet": "s2.plot", + "event_type": "add_to_current", + "figure_ordinal": 10 + }, + { + "section_index": 4, + "section_line_index": 10, + "source_line_no": 3400, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 11 + }, + { + "section_index": 4, + "section_line_index": 12, + "source_line_no": 3402, + "source_snippet": "s4.plot", + "event_type": "add_to_current", + "figure_ordinal": 11 + }, + { + "section_index": 4, + "section_line_index": 14, + "source_line_no": 3404, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "section_line_index": 15, + "source_line_no": 3405, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "section_line_index": 16, + "source_line_no": 3406, + "source_snippet": "s.integral.plot", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "section_line_index": 17, + "source_line_no": 3407, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "section_line_index": 18, + "source_line_no": 3408, + "source_snippet": "s.derivative.plot", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "section_line_index": 19, + "source_line_no": 3409, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "section_line_index": 21, + "source_line_no": 3411, + "source_snippet": "s6.plot", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 5, + "section_line_index": 1, + "source_line_no": 3701, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 13 + }, + { + "section_index": 5, + "section_line_index": 4, + "source_line_no": 3704, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 14 + }, + { + "section_index": 6, + "section_line_index": 6, + "source_line_no": 4105, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 15 + }, + { + "section_index": 6, + "section_line_index": 7, + "source_line_no": 4106, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 15 + }, + { + "section_index": 6, + "section_line_index": 7, + "source_line_no": 4106, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 15 + }, + { + "section_index": 6, + "section_line_index": 8, + "source_line_no": 4107, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 15 + }, + { + "section_index": 6, + "section_line_index": 11, + "source_line_no": 4400, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 16 + }, + { + "section_index": 6, + "section_line_index": 13, + "source_line_no": 4402, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 16 + }, + { + "section_index": 6, + "section_line_index": 15, + "source_line_no": 4404, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 16 + }, + { + "section_index": 6, + "section_line_index": 17, + "source_line_no": 4406, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 16 + } + ] + }, + { + "topic": "StimulusDecode2D", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/StimulusDecode2D.mlx", + "section_count": 3, + "figure_count": 4, + "detected_figure_count": 4, + "no_figure_utility": false, + "events": [ + { + "section_index": 0, + "section_line_index": 20, + "source_line_no": 318, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 21, + "source_line_no": 319, + "source_snippet": "plot(px,py)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 28, + "source_line_no": 628, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 30, + "source_line_no": 630, + "source_snippet": "lambda{i}.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 37, + "source_line_no": 637, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 49, + "source_line_no": 649, + "source_snippet": "subplot(1,numRealizations,i)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 51, + "source_line_no": 651, + "source_snippet": "subplot(fact(1),fact(2),i)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 53, + "source_line_no": 653, + "source_snippet": "subplot(fact(1)*fact(2),fact(3),i)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 55, + "source_line_no": 655, + "source_snippet": "pcolor(X,Y,placeField{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 21, + "source_line_no": 1118, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 2, + "section_line_index": 22, + "source_line_no": 1119, + "source_snippet": "plot(x_u(1,:),x_u(2,:),'b',px,py,'k')", + "event_type": "add_to_current", + "figure_ordinal": 4 + } + ] + }, + { + "topic": "TrialConfigExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/TrialConfigExamples.mlx", + "section_count": 1, + "figure_count": 0, + "detected_figure_count": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "TrialExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/TrialExamples.mlx", + "section_count": 3, + "figure_count": 6, + "detected_figure_count": 6, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 5, + "source_line_no": 602, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 5, + "source_line_no": 602, + "source_snippet": "h.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 10, + "source_line_no": 903, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 10, + "source_line_no": 903, + "source_snippet": "cc.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 15, + "source_line_no": 1203, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 15, + "source_line_no": 1203, + "source_snippet": "e.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 23, + "source_line_no": 1506, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 1, + "section_line_index": 23, + "source_line_no": 1506, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 1, + "section_line_index": 26, + "source_line_no": 1801, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 5 + }, + { + "section_index": 1, + "section_line_index": 26, + "source_line_no": 1801, + "source_snippet": "trial1.plot", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 1, + "section_line_index": 29, + "source_line_no": 2101, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 6 + }, + { + "section_index": 1, + "section_line_index": 29, + "source_line_no": 2101, + "source_snippet": "trial1.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + } + ] + }, + { + "topic": "ValidationDataSet", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/ValidationDataSet.mlx", + "section_count": 3, + "figure_count": 8, + "detected_figure_count": 3, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 37, + "source_line_no": 1701, + "source_snippet": "subplot(2,4,[5 6])", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 37, + "source_line_no": 1701, + "source_snippet": "plot(mu,'ro', 'MarkerSize',10)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 38, + "source_line_no": 1702, + "source_snippet": "subplot(2,4,[5 6])", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 38, + "source_line_no": 1702, + "source_snippet": "plot(mu,'ro', 'MarkerSize',10)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 39, + "source_line_no": 1703, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 40, + "source_line_no": 1704, + "source_snippet": "subplot(1,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 40, + "source_line_no": 1704, + "source_snippet": "results{1}.lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 40, + "source_line_no": 1704, + "source_snippet": "plot(results{1}.lambda.time,lambda*ones(length(results{1}.lambda.time),1),'r-.','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 41, + "source_line_no": 1705, + "source_snippet": "subplot(1,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 41, + "source_line_no": 1705, + "source_snippet": "results{2}.lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 41, + "source_line_no": 1705, + "source_snippet": "plot(results{2}.lambda.time,lambda*ones(length(results{2}.lambda.time),1),'r-.','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "section_line_index": 53, + "source_line_no": 3003, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 54, + "source_line_no": 3004, + "source_snippet": "subplot(1,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 54, + "source_line_no": 3004, + "source_snippet": "results{1}.lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 55, + "source_line_no": 3005, + "source_snippet": "subplot(1,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 55, + "source_line_no": 3005, + "source_snippet": "results{2}.lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "section_line_index": 58, + "source_line_no": 3301, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 3 + } + ] + }, + { + "topic": "mEPSCAnalysis", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/mEPSCAnalysis.mlx", + "section_count": 9, + "figure_count": 4, + "detected_figure_count": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 2, + "section_line_index": 24, + "source_line_no": 1823, + "source_snippet": "results.plotResults", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 4, + "section_line_index": 1, + "source_line_no": 2600, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "section_line_index": 2, + "source_line_no": 2601, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 7, + "section_line_index": 2, + "source_line_no": 3601, + "source_snippet": "results.plotResults", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 7, + "section_line_index": 4, + "source_line_no": 3603, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 2 + } + ] + }, + { + "topic": "nSTATPaperExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/nSTATPaperExamples.mlx", + "section_count": 31, + "figure_count": 1, + "detected_figure_count": 25, + "no_figure_utility": false, + "events": [ + { + "section_index": 2, + "section_line_index": 37, + "source_line_no": 1036, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 40, + "source_line_no": 1039, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 40, + "source_line_no": 1039, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 49, + "source_line_no": 1048, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 49, + "source_line_no": 1048, + "source_snippet": "results.KSPlot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 50, + "source_line_no": 1049, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 51, + "source_line_no": 1050, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 51, + "source_line_no": 1050, + "source_snippet": "results.lambda.plot([],{{' ''b'' ,''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 4, + "section_line_index": 2, + "source_line_no": 1801, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "section_line_index": 5, + "source_line_no": 1804, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "section_line_index": 6, + "source_line_no": 1805, + "source_snippet": "nstConst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "section_line_index": 14, + "source_line_no": 1813, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "section_line_index": 15, + "source_line_no": 1814, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 7, + "section_line_index": 9, + "source_line_no": 3004, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 12, + "source_line_no": 3007, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 12, + "source_line_no": 3007, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 24, + "source_line_no": 3019, + "source_snippet": "plot([495", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 25, + "source_line_no": 3020, + "source_snippet": "plot([765", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 27, + "source_line_no": 3022, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 27, + "source_line_no": 3022, + "source_snippet": "results.KSPlot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 28, + "source_line_no": 3023, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 29, + "source_line_no": 3024, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 30, + "source_line_no": 3025, + "source_snippet": "results.lambda.getSubSignal(1).plot([],{{' ''b'' ,''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "section_line_index": 31, + "source_line_no": 3026, + "source_snippet": "results.lambda.getSubSignal(2).plot([],{{' ''g'' ,''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 9, + "section_line_index": 29, + "source_line_no": 3628, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "section_line_index": 30, + "source_line_no": 3629, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "section_line_index": 32, + "source_line_no": 3631, + "source_snippet": "nst2.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "section_line_index": 42, + "source_line_no": 3641, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "section_line_index": 43, + "source_line_no": 3642, + "source_snippet": "stim.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "section_line_index": 56, + "source_line_no": 3655, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "section_line_index": 57, + "source_line_no": 3656, + "source_snippet": "stim.derivative.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "section_line_index": 81, + "source_line_no": 3910, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 5 + }, + { + "section_index": 9, + "section_line_index": 83, + "source_line_no": 3912, + "source_snippet": "subplot(7,2,[1 3 5])", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 9, + "section_line_index": 84, + "source_line_no": 3913, + "source_snippet": "results.Residual.xcov(stim).windowedSignal([0,1]).plot", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 9, + "section_line_index": 92, + "source_line_no": 3921, + "source_snippet": "h=plot(ShiftTime,m,'ro','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 34, + "source_line_no": 4733, + "source_snippet": "subplot(7,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 36, + "source_line_no": 4735, + "source_snippet": "plot(x,results{1}.KSStats.ks_stat,'.-')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 37, + "source_line_no": 4736, + "source_snippet": "plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 51, + "source_line_no": 4750, + "source_snippet": "subplot(7,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 51, + "source_line_no": 4750, + "source_snippet": "plot(x,dAIC,'.-')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 57, + "source_line_no": 4756, + "source_snippet": "plot(x(windowIndex),dAIC(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 60, + "source_line_no": 4759, + "source_snippet": "subplot(7,2,6)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 60, + "source_line_no": 4759, + "source_snippet": "plot(x,dBIC,'.-')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 63, + "source_line_no": 4762, + "source_snippet": "plot(x(windowIndex),dBIC(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 85, + "source_line_no": 4784, + "source_snippet": "c{3}.setName('Baseline+Stimulus+Hist')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 91, + "source_line_no": 4790, + "source_snippet": "'\\lambda_{const+stim+hist}'})", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 92, + "source_line_no": 4791, + "source_snippet": "subplot(7,2,[9 11 13])", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 92, + "source_line_no": 4791, + "source_snippet": "results.KSPlot", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "section_line_index": 93, + "source_line_no": 4792, + "source_snippet": "subplot(7,2,[10 12 14])", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 12, + "section_line_index": 23, + "source_line_no": 5023, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "section_line_index": 25, + "source_line_no": 5025, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "section_line_index": 25, + "source_line_no": 5025, + "source_snippet": "spikeCollSim.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "section_line_index": 34, + "source_line_no": 5034, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "section_line_index": 34, + "source_line_no": 5034, + "source_snippet": "lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "section_line_index": 53, + "source_line_no": 5053, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "section_line_index": 53, + "source_line_no": 5053, + "source_snippet": "spikeCollReal1.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "section_line_index": 72, + "source_line_no": 5072, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "section_line_index": 72, + "source_line_no": 5072, + "source_snippet": "spikeCollReal2.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 13, + "section_line_index": 3, + "source_line_no": 5303, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 9, + "source_line_no": 5309, + "source_snippet": "subplot(2,3,4)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 11, + "source_line_no": 5311, + "source_snippet": "h1=true.plot([],{{' ''b'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 12, + "source_line_no": 5312, + "source_snippet": "h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 13, + "source_line_no": 5313, + "source_snippet": "h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 27, + "source_line_no": 5327, + "source_snippet": "subplot(2,3,1)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 27, + "source_line_no": 5327, + "source_snippet": "spikeCollSim.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 34, + "source_line_no": 5334, + "source_snippet": "subplot(2,3,5)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 39, + "source_line_no": 5339, + "source_snippet": "h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 40, + "source_line_no": 5340, + "source_snippet": "h2=psthReal1.plot([],{{' ''rx'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 49, + "source_line_no": 5349, + "source_snippet": "subplot(2,3,2)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 49, + "source_line_no": 5349, + "source_snippet": "spikeCollReal1.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 55, + "source_line_no": 5355, + "source_snippet": "subplot(2,3,6)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 58, + "source_line_no": 5358, + "source_snippet": "h3=psthGLMReal2.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 59, + "source_line_no": 5359, + "source_snippet": "h2=psthReal2.plot([],{{' ''rx'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 69, + "source_line_no": 5369, + "source_snippet": "subplot(2,3,3)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "section_line_index": 69, + "source_line_no": 5369, + "source_snippet": "spikeCollReal2.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 15, + "section_line_index": 2, + "source_line_no": 6002, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "section_line_index": 5, + "source_line_no": 6005, + "source_snippet": "subplot(3,2,[3 4])", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "section_line_index": 5, + "source_line_no": 6005, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "section_line_index": 26, + "source_line_no": 6026, + "source_snippet": "subplot(3,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "section_line_index": 26, + "source_line_no": 6026, + "source_snippet": "plot(time,u,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "section_line_index": 35, + "source_line_no": 6035, + "source_snippet": "subplot(3,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "section_line_index": 35, + "source_line_no": 6035, + "source_snippet": "plot(1:length(b1),b1,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "section_line_index": 43, + "source_line_no": 6043, + "source_snippet": "subplot(3,2,[5 6])", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "section_line_index": 44, + "source_line_no": 6044, + "source_snippet": "imagesc(stimData'./delta); set(gca, 'YDir','normal');", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 17, + "section_line_index": 30, + "source_line_no": 7004, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "section_line_index": 31, + "source_line_no": 7005, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "section_line_index": 31, + "source_line_no": 7005, + "source_snippet": "t.KSPlot", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "section_line_index": 32, + "source_line_no": 7006, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "section_line_index": 32, + "source_line_no": 7006, + "source_snippet": "t.plotResidual", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "section_line_index": 33, + "source_line_no": 7007, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "section_line_index": 34, + "source_line_no": 7008, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "section_line_index": 70, + "source_line_no": 7230, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 10 + }, + { + "section_index": 17, + "section_line_index": 74, + "source_line_no": 7234, + "source_snippet": "subplot(3,1,[1 2 3])", + "event_type": "add_to_current", + "figure_ordinal": 10 + }, + { + "section_index": 17, + "section_line_index": 76, + "source_line_no": 7236, + "source_snippet": "surf((1:length(b1))',stim.time,actStimEffect,'FaceAlpha',0.1,...", + "event_type": "add_to_current", + "figure_ordinal": 10 + }, + { + "section_index": 17, + "section_line_index": 82, + "source_line_no": 7242, + "source_snippet": "surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),...", + "event_type": "add_to_current", + "figure_ordinal": 10 + }, + { + "section_index": 17, + "section_line_index": 92, + "source_line_no": 7252, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 11 + }, + { + "section_index": 17, + "section_line_index": 95, + "source_line_no": 7255, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 11 + }, + { + "section_index": 17, + "section_line_index": 113, + "source_line_no": 7273, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 11 + }, + { + "section_index": 17, + "section_line_index": 130, + "source_line_no": 7290, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 11 + }, + { + "section_index": 18, + "section_line_index": 23, + "source_line_no": 7523, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "section_line_index": 25, + "source_line_no": 7525, + "source_snippet": "subplot(2,3,1)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "section_line_index": 28, + "source_line_no": 7528, + "source_snippet": "spikeRateBinom.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "section_line_index": 32, + "source_line_no": 7532, + "source_snippet": "plot(lt*[1", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "section_line_index": 42, + "source_line_no": 7542, + "source_snippet": "h=subplot(2,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "section_line_index": 45, + "source_line_no": 7545, + "source_snippet": "imagesc(ProbMat)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "section_line_index": 49, + "source_line_no": 7549, + "source_snippet": "plot3(m,k,1,'r*')", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "section_line_index": 59, + "source_line_no": 7559, + "source_snippet": "subplot(2,3,4)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "section_line_index": 76, + "source_line_no": 7576, + "source_snippet": "h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "section_line_index": 77, + "source_line_no": 7577, + "source_snippet": "h2=stimlt.plot([],{{' ''r'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 20, + "section_line_index": 7, + "source_line_no": 8406, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9])", + "event_type": "new_figure", + "figure_ordinal": 13 + }, + { + "section_index": 20, + "section_line_index": 10, + "source_line_no": 8409, + "source_snippet": "subplot(2,2,i)", + "event_type": "add_to_current", + "figure_ordinal": 13 + }, + { + "section_index": 20, + "section_line_index": 11, + "source_line_no": 8410, + "source_snippet": "h1=plot(x,y,'b','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 13 + }, + { + "section_index": 20, + "section_line_index": 12, + "source_line_no": 8411, + "source_snippet": "h2=plot(neuron{exampleCell(i)}.xN,neuron{exampleCell(i)}.yN,'r.',...", + "event_type": "add_to_current", + "figure_ordinal": 13 + }, + { + "section_index": 22, + "section_line_index": 12, + "source_line_no": 9302, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5])", + "event_type": "new_figure", + "figure_ordinal": 14 + }, + { + "section_index": 22, + "section_line_index": 13, + "source_line_no": 9303, + "source_snippet": "subplot(1,3,1)", + "event_type": "add_to_current", + "figure_ordinal": 14 + }, + { + "section_index": 22, + "section_line_index": 24, + "source_line_no": 9314, + "source_snippet": "subplot(1,3,2)", + "event_type": "add_to_current", + "figure_ordinal": 14 + }, + { + "section_index": 22, + "section_line_index": 33, + "source_line_no": 9323, + "source_snippet": "subplot(1,3,3)", + "event_type": "add_to_current", + "figure_ordinal": 14 + }, + { + "section_index": 23, + "section_line_index": 53, + "source_line_no": 9653, + "source_snippet": "h4=figure(4)", + "event_type": "new_figure", + "figure_ordinal": 15 + }, + { + "section_index": 23, + "section_line_index": 64, + "source_line_no": 9664, + "source_snippet": "subplot(7,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 15 + }, + { + "section_index": 23, + "section_line_index": 66, + "source_line_no": 9666, + "source_snippet": "h6=figure(6)", + "event_type": "new_figure", + "figure_ordinal": 16 + }, + { + "section_index": 23, + "section_line_index": 77, + "source_line_no": 9677, + "source_snippet": "subplot(6,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 16 + }, + { + "section_index": 23, + "section_line_index": 79, + "source_line_no": 9679, + "source_snippet": "pcolor(x_new,y_new,lambdaGaussian{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 16 + }, + { + "section_index": 23, + "section_line_index": 84, + "source_line_no": 9684, + "source_snippet": "h5=figure(5)", + "event_type": "new_figure", + "figure_ordinal": 17 + }, + { + "section_index": 23, + "section_line_index": 95, + "source_line_no": 9695, + "source_snippet": "subplot(7,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 17 + }, + { + "section_index": 23, + "section_line_index": 97, + "source_line_no": 9697, + "source_snippet": "h7=figure(7)", + "event_type": "new_figure", + "figure_ordinal": 18 + }, + { + "section_index": 23, + "section_line_index": 108, + "source_line_no": 9708, + "source_snippet": "subplot(6,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 18 + }, + { + "section_index": 23, + "section_line_index": 110, + "source_line_no": 9710, + "source_snippet": "pcolor(x_new,y_new,lambdaZernike{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 18 + }, + { + "section_index": 23, + "section_line_index": 141, + "source_line_no": 9823, + "source_snippet": "h9=figure(9)", + "event_type": "new_figure", + "figure_ordinal": 19 + }, + { + "section_index": 23, + "section_line_index": 153, + "source_line_no": 9835, + "source_snippet": "plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 19 + }, + { + "section_index": 25, + "section_line_index": 29, + "source_line_no": 10329, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "section_line_index": 32, + "source_line_no": 10332, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "section_line_index": 32, + "source_line_no": 10332, + "source_snippet": "plot(time,x,'k')", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "section_line_index": 38, + "source_line_no": 10338, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "section_line_index": 38, + "source_line_no": 10338, + "source_snippet": "lambda.plot([],{{' ''k'',''Linewidth'',1'}})", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "section_line_index": 48, + "source_line_no": 10348, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "section_line_index": 48, + "source_line_no": 10348, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "section_line_index": 80, + "source_line_no": 10517, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6])", + "event_type": "new_figure", + "figure_ordinal": 21 + }, + { + "section_index": 25, + "section_line_index": 95, + "source_line_no": 10532, + "source_snippet": "hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 21 + }, + { + "section_index": 25, + "section_line_index": 96, + "source_line_no": 10533, + "source_snippet": "hStim=stim.plot([],{{' ''b'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 21 + }, + { + "section_index": 26, + "section_line_index": 52, + "source_line_no": 10951, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 55, + "source_line_no": 10954, + "source_snippet": "subplot(4,2,[1 3])", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 56, + "source_line_no": 10955, + "source_snippet": "plot(100*x(1,:),100*x(2,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 63, + "source_line_no": 10962, + "source_snippet": "h1=plot(100*x(1,1),100*x(2,1),'bo','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 64, + "source_line_no": 10963, + "source_snippet": "h2=plot(100*x(1,end),100*x(2,end),'ro','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 68, + "source_line_no": 10967, + "source_snippet": "subplot(4,2,5)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 68, + "source_line_no": 10967, + "source_snippet": "h1=plot(time,100*x(1,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 69, + "source_line_no": 10968, + "source_snippet": "h2=plot(time,100*x(2,:),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 78, + "source_line_no": 10977, + "source_snippet": "subplot(4,2,7)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 79, + "source_line_no": 10978, + "source_snippet": "h1=plot(time,100*x(3,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 80, + "source_line_no": 10979, + "source_snippet": "h2=plot(time,100*x(4,:),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 128, + "source_line_no": 11027, + "source_snippet": "subplot(4,2,[6 8])", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 129, + "source_line_no": 11028, + "source_snippet": "h2=lambda{i}.plot([],{{' ''k'', ''LineWidth'' ,.5'}})", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 142, + "source_line_no": 11041, + "source_snippet": "subplot(4,2,[2,4])", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 142, + "source_line_no": 11041, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "section_line_index": 154, + "source_line_no": 11103, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 220, + "source_line_no": 11169, + "source_snippet": "subplot(4,2,1:4)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 220, + "source_line_no": 11169, + "source_snippet": "h1=plot(100*x(1,:),100*x(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 227, + "source_line_no": 11176, + "source_snippet": "subplot(4,2,1:4)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 227, + "source_line_no": 11176, + "source_snippet": "h2=plot(100*x_u(1,:)',100*x_u(2,:)','b')", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 228, + "source_line_no": 11177, + "source_snippet": "subplot(4,2,1:4)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 228, + "source_line_no": 11177, + "source_snippet": "h3=plot(100*x_uf(1,:)',100*x_uf(2,:)','g')", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 231, + "source_line_no": 11180, + "source_snippet": "h1=plot(100*x0(1),100*x0(2),'bo','MarkerSize',10)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 232, + "source_line_no": 11181, + "source_snippet": "h2=plot(100*xT(1),100*xT(2),'ro','MarkerSize',10)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 236, + "source_line_no": 11185, + "source_snippet": "subplot(4,2,5)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 237, + "source_line_no": 11186, + "source_snippet": "h1=plot(time,100*x(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 238, + "source_line_no": 11187, + "source_snippet": "h2=plot(time,100*x_u(1,:)','b');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 239, + "source_line_no": 11188, + "source_snippet": "h3=plot(time,100*x_uf(1,:)','g');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 245, + "source_line_no": 11194, + "source_snippet": "subplot(4,2,6)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 246, + "source_line_no": 11195, + "source_snippet": "h1=plot(time,100*x(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 247, + "source_line_no": 11196, + "source_snippet": "h2=plot(time,100*x_u(2,:)','b');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 248, + "source_line_no": 11197, + "source_snippet": "h3=plot(time,100*x_uf(2,:)','g');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 259, + "source_line_no": 11208, + "source_snippet": "subplot(4,2,7)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 260, + "source_line_no": 11209, + "source_snippet": "h1=plot(time,100*x(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 261, + "source_line_no": 11210, + "source_snippet": "h2=plot(time,100*x_u(3,:)','b');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 262, + "source_line_no": 11211, + "source_snippet": "h3=plot(time,100*x_uf(3,:)','g');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 267, + "source_line_no": 11216, + "source_snippet": "subplot(4,2,8)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 268, + "source_line_no": 11217, + "source_snippet": "h1=plot(time,100*x(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 269, + "source_line_no": 11218, + "source_snippet": "h2=plot(time,100*x_u(4,:)','b');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "section_line_index": 270, + "source_line_no": 11219, + "source_snippet": "h3=plot(time,100*x_uf(4,:)','g');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 29, + "section_line_index": 77, + "source_line_no": 12306, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 79, + "source_line_no": 12308, + "source_snippet": "subplot(4,2,[1 3])", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 80, + "source_line_no": 12309, + "source_snippet": "plot(100*X(1,:),100*X(2,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 85, + "source_line_no": 12314, + "source_snippet": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',16)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 86, + "source_line_no": 12315, + "source_snippet": "h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',16)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 91, + "source_line_no": 12320, + "source_snippet": "subplot(4,2,[6 8])", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 92, + "source_line_no": 12321, + "source_snippet": "plot(time,mstate,'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 100, + "source_line_no": 12329, + "source_snippet": "subplot(4,2,5)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 101, + "source_line_no": 12330, + "source_snippet": "h1=plot(time,100*X(1,1:end),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 102, + "source_line_no": 12331, + "source_snippet": "h2=plot(time,100*X(2,1:end),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 111, + "source_line_no": 12340, + "source_snippet": "subplot(4,2,7)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 112, + "source_line_no": 12341, + "source_snippet": "h1=plot(time,100*X(3,1:end),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 113, + "source_line_no": 12342, + "source_snippet": "h2=plot(time,100*X(4,1:end),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 147, + "source_line_no": 12376, + "source_snippet": "subplot(4,2,[2 4])", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "section_line_index": 148, + "source_line_no": 12377, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 30, + "section_line_index": 14, + "source_line_no": 12713, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 87, + "source_line_no": 12786, + "source_snippet": "subplot(4,3,[1 4])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 88, + "source_line_no": 12787, + "source_snippet": "plot(time,mstate,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 89, + "source_line_no": 12788, + "source_snippet": "plot(time,S_est,'b-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 90, + "source_line_no": 12789, + "source_snippet": "plot(time,S_estNT,'g-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 94, + "source_line_no": 12793, + "source_snippet": "subplot(4,3,[7 10])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 95, + "source_line_no": 12794, + "source_snippet": "plot(time,MU_est(2,:),'b-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 96, + "source_line_no": 12795, + "source_snippet": "plot(time,MU_estNT(2,:),'g-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 100, + "source_line_no": 12799, + "source_snippet": "subplot(4,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 101, + "source_line_no": 12800, + "source_snippet": "h1=plot(100*X(1,:)',100*X(2,:)','k')", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 102, + "source_line_no": 12801, + "source_snippet": "h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.')", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 103, + "source_line_no": 12802, + "source_snippet": "h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.')", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 106, + "source_line_no": 12805, + "source_snippet": "subplot(4,3,8)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 107, + "source_line_no": 12806, + "source_snippet": "h1=plot(time,100*X(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 108, + "source_line_no": 12807, + "source_snippet": "h2=plot(time,100*X_est(1,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 109, + "source_line_no": 12808, + "source_snippet": "h3=plot(time,100*X_estNT(1,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 112, + "source_line_no": 12811, + "source_snippet": "subplot(4,3,9)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 113, + "source_line_no": 12812, + "source_snippet": "h1=plot(time,100*X(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 114, + "source_line_no": 12813, + "source_snippet": "h2=plot(time,100*X_est(2,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 115, + "source_line_no": 12814, + "source_snippet": "h3=plot(time,100*X_estNT(2,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 118, + "source_line_no": 12817, + "source_snippet": "subplot(4,3,11)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 119, + "source_line_no": 12818, + "source_snippet": "h1=plot(time,100*X(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 120, + "source_line_no": 12819, + "source_snippet": "h2=plot(time,100*X_est(3,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 121, + "source_line_no": 12820, + "source_snippet": "h3=plot(time,100*X_estNT(3,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 123, + "source_line_no": 12822, + "source_snippet": "subplot(4,3,12)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 124, + "source_line_no": 12823, + "source_snippet": "h1=plot(time,100*X(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 125, + "source_line_no": 12824, + "source_snippet": "h2=plot(time,100*X_est(4,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 126, + "source_line_no": 12825, + "source_snippet": "h3=plot(time,100*X_estNT(4,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 141, + "source_line_no": 12840, + "source_snippet": "subplot(4,3,[1 4])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 143, + "source_line_no": 12842, + "source_snippet": "plot(time,mstate,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 144, + "source_line_no": 12843, + "source_snippet": "plot(time,mean(S_estAll),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 145, + "source_line_no": 12844, + "source_snippet": "plot(time,mean(S_estNTAll),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 157, + "source_line_no": 12856, + "source_snippet": "subplot(4,3,[7 10])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 158, + "source_line_no": 12857, + "source_snippet": "plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 160, + "source_line_no": 12859, + "source_snippet": "plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 169, + "source_line_no": 12868, + "source_snippet": "subplot(4,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 170, + "source_line_no": 12869, + "source_snippet": "h1=plot(100*X(1,:)',100*X(2,:)','k')", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 173, + "source_line_no": 12872, + "source_snippet": "plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 174, + "source_line_no": 12873, + "source_snippet": "plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 178, + "source_line_no": 12877, + "source_snippet": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 179, + "source_line_no": 12878, + "source_snippet": "h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 186, + "source_line_no": 12885, + "source_snippet": "subplot(4,3,8)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 187, + "source_line_no": 12886, + "source_snippet": "h1=plot(time,100*X(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 188, + "source_line_no": 12887, + "source_snippet": "h2=plot(time,mXestAll(1,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 189, + "source_line_no": 12888, + "source_snippet": "h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 196, + "source_line_no": 12895, + "source_snippet": "subplot(4,3,9)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 197, + "source_line_no": 12896, + "source_snippet": "h1=plot(time,100*X(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 198, + "source_line_no": 12897, + "source_snippet": "h2=plot(time,mXestAll(2,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 199, + "source_line_no": 12898, + "source_snippet": "h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 211, + "source_line_no": 12910, + "source_snippet": "subplot(4,3,11)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 212, + "source_line_no": 12911, + "source_snippet": "h1=plot(time,100*X(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 213, + "source_line_no": 12912, + "source_snippet": "h2=plot(time,mXestAll(3,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 214, + "source_line_no": 12913, + "source_snippet": "h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 220, + "source_line_no": 12919, + "source_snippet": "subplot(4,3,12)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 221, + "source_line_no": 12920, + "source_snippet": "h1=plot(time,100*X(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 222, + "source_line_no": 12921, + "source_snippet": "h2=plot(time,mXestAll(4,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "section_line_index": 223, + "source_line_no": 12922, + "source_snippet": "h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + } + ] + }, + { + "topic": "nSpikeTrainExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/nSpikeTrainExamples.mlx", + "section_count": 2, + "figure_count": 4, + "detected_figure_count": 4, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 4, + "source_line_no": 403, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 4, + "source_line_no": 403, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 7, + "source_line_no": 800, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 8, + "source_line_no": 801, + "source_snippet": "nst.getSigRep.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 10, + "source_line_no": 1100, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 11, + "source_line_no": 1101, + "source_snippet": "nst.getSigRep.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 13, + "source_line_no": 1400, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 1, + "section_line_index": 14, + "source_line_no": 1401, + "source_snippet": "nst.getSigRep.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 + } + ] + }, + { + "topic": "nstCollExamples", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/nstCollExamples.mlx", + "section_count": 2, + "figure_count": 3, + "detected_figure_count": 3, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "section_line_index": 9, + "source_line_no": 600, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 9, + "source_line_no": 600, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "section_line_index": 12, + "source_line_no": 901, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 12, + "source_line_no": 901, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "section_line_index": 14, + "source_line_no": 1200, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 16, + "source_line_no": 1202, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 16, + "source_line_no": 1202, + "source_snippet": "n1.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 17, + "source_line_no": 1203, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 17, + "source_line_no": 1203, + "source_snippet": "n1.getSigRep.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 21, + "source_line_no": 1207, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "section_line_index": 21, + "source_line_no": 1207, + "source_snippet": "s1.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + } + ] + }, + { + "topic": "AnalysisExamples2", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/AnalysisExamples2.mlx", + "section_count": 3, + "figure_count": 4, + "detected_figure_count": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 0, + "section_line_index": 20, + "source_line_no": 1200, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 21, + "source_line_no": 1201, + "source_snippet": "plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 34, + "source_line_no": 1508, + "source_snippet": "tc{3}.setName('Quadratic+Hist')", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 38, + "source_line_no": 1802, + "source_snippet": "fitResults.plotResults", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "section_line_index": 40, + "source_line_no": 2100, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "section_line_index": 63, + "source_line_no": 2123, + "source_snippet": "plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...", + "event_type": "add_to_current", + "figure_ordinal": 2 + } + ] + }, + { + "topic": "DocumentationSetup2025b", + "source_type": "m", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/DocumentationSetup2025b.m", + "section_count": 6, + "figure_count": 0, + "detected_figure_count": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "FitResultReference", + "source_type": "m", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/FitResultReference.m", + "section_count": 2, + "figure_count": 0, + "detected_figure_count": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "HybridFilterExample", + "source_type": "mlx", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/HybridFilterExample.mlx", + "section_count": 4, + "figure_count": 1, + "detected_figure_count": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 2, + "section_line_index": 75, + "source_line_no": 1106, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 77, + "source_line_no": 1108, + "source_snippet": "subplot(4,2,[1 3])", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 78, + "source_line_no": 1109, + "source_snippet": "plot(100*X(1,:),100*X(2,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 83, + "source_line_no": 1114, + "source_snippet": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',16)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 84, + "source_line_no": 1115, + "source_snippet": "h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',16)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 89, + "source_line_no": 1120, + "source_snippet": "subplot(4,2,[6 8])", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 90, + "source_line_no": 1121, + "source_snippet": "plot(time,mstate,'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 98, + "source_line_no": 1129, + "source_snippet": "subplot(4,2,5)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 99, + "source_line_no": 1130, + "source_snippet": "h1=plot(time,100*X(1,1:end),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 100, + "source_line_no": 1131, + "source_snippet": "h2=plot(time,100*X(2,1:end),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 109, + "source_line_no": 1140, + "source_snippet": "subplot(4,2,7)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 110, + "source_line_no": 1141, + "source_snippet": "h1=plot(time,100*X(3,1:end),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 111, + "source_line_no": 1142, + "source_snippet": "h2=plot(time,100*X(4,1:end),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 145, + "source_line_no": 1176, + "source_snippet": "subplot(4,2,[2 4])", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "section_line_index": 146, + "source_line_no": 1177, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 3, + "section_line_index": 14, + "source_line_no": 1513, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 87, + "source_line_no": 1586, + "source_snippet": "subplot(4,3,[1 4])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 88, + "source_line_no": 1587, + "source_snippet": "plot(time,mstate,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 89, + "source_line_no": 1588, + "source_snippet": "plot(time,S_est,'b-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 90, + "source_line_no": 1589, + "source_snippet": "plot(time,S_estNT,'g-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 94, + "source_line_no": 1593, + "source_snippet": "subplot(4,3,[7 10])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 95, + "source_line_no": 1594, + "source_snippet": "plot(time,MU_est(2,:),'b-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 96, + "source_line_no": 1595, + "source_snippet": "plot(time,MU_estNT(2,:),'g-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 100, + "source_line_no": 1599, + "source_snippet": "subplot(4,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 101, + "source_line_no": 1600, + "source_snippet": "h1=plot(100*X(1,:)',100*X(2,:)','k')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 102, + "source_line_no": 1601, + "source_snippet": "h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 103, + "source_line_no": 1602, + "source_snippet": "h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 106, + "source_line_no": 1605, + "source_snippet": "subplot(4,3,8)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 107, + "source_line_no": 1606, + "source_snippet": "h1=plot(time,100*X(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 108, + "source_line_no": 1607, + "source_snippet": "h2=plot(time,100*X_est(1,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 109, + "source_line_no": 1608, + "source_snippet": "h3=plot(time,100*X_estNT(1,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 112, + "source_line_no": 1611, + "source_snippet": "subplot(4,3,9)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 113, + "source_line_no": 1612, + "source_snippet": "h1=plot(time,100*X(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 114, + "source_line_no": 1613, + "source_snippet": "h2=plot(time,100*X_est(2,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 115, + "source_line_no": 1614, + "source_snippet": "h3=plot(time,100*X_estNT(2,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 118, + "source_line_no": 1617, + "source_snippet": "subplot(4,3,11)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 119, + "source_line_no": 1618, + "source_snippet": "h1=plot(time,100*X(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 120, + "source_line_no": 1619, + "source_snippet": "h2=plot(time,100*X_est(3,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 121, + "source_line_no": 1620, + "source_snippet": "h3=plot(time,100*X_estNT(3,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 123, + "source_line_no": 1622, + "source_snippet": "subplot(4,3,12)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 124, + "source_line_no": 1623, + "source_snippet": "h1=plot(time,100*X(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 125, + "source_line_no": 1624, + "source_snippet": "h2=plot(time,100*X_est(4,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 126, + "source_line_no": 1625, + "source_snippet": "h3=plot(time,100*X_estNT(4,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 141, + "source_line_no": 1640, + "source_snippet": "subplot(4,3,[1 4])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 143, + "source_line_no": 1642, + "source_snippet": "plot(time,mstate,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 144, + "source_line_no": 1643, + "source_snippet": "plot(time,mean(S_estAll),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 145, + "source_line_no": 1644, + "source_snippet": "plot(time,mean(S_estNTAll),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 157, + "source_line_no": 1656, + "source_snippet": "subplot(4,3,[7 10])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 158, + "source_line_no": 1657, + "source_snippet": "plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 160, + "source_line_no": 1659, + "source_snippet": "plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 169, + "source_line_no": 1668, + "source_snippet": "subplot(4,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 170, + "source_line_no": 1669, + "source_snippet": "h1=plot(100*X(1,:)',100*X(2,:)','k')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 173, + "source_line_no": 1672, + "source_snippet": "plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 174, + "source_line_no": 1673, + "source_snippet": "plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 178, + "source_line_no": 1677, + "source_snippet": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 179, + "source_line_no": 1678, + "source_snippet": "h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 186, + "source_line_no": 1685, + "source_snippet": "subplot(4,3,8)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 187, + "source_line_no": 1686, + "source_snippet": "h1=plot(time,100*X(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 188, + "source_line_no": 1687, + "source_snippet": "h2=plot(time,mXestAll(1,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 189, + "source_line_no": 1688, + "source_snippet": "h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 196, + "source_line_no": 1695, + "source_snippet": "subplot(4,3,9)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 197, + "source_line_no": 1696, + "source_snippet": "h1=plot(time,100*X(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 198, + "source_line_no": 1697, + "source_snippet": "h2=plot(time,mXestAll(2,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 199, + "source_line_no": 1698, + "source_snippet": "h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 211, + "source_line_no": 1710, + "source_snippet": "subplot(4,3,11)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 212, + "source_line_no": 1711, + "source_snippet": "h1=plot(time,100*X(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 213, + "source_line_no": 1712, + "source_snippet": "h2=plot(time,mXestAll(3,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 214, + "source_line_no": 1713, + "source_snippet": "h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 220, + "source_line_no": 1719, + "source_snippet": "subplot(4,3,12)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 221, + "source_line_no": 1720, + "source_snippet": "h1=plot(time,100*X(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 222, + "source_line_no": 1721, + "source_snippet": "h2=plot(time,mXestAll(4,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "section_line_index": 223, + "source_line_no": 1722, + "source_snippet": "h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + } + ] + }, + { + "topic": "publish_all_helpfiles", + "source_type": "m", + "source_path": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local/helpfiles/publish_all_helpfiles.m", + "section_count": 1, + "figure_count": 0, + "detected_figure_count": 0, + "no_figure_utility": true, + "events": [] + } + ] +} \ No newline at end of file diff --git a/parity/helpfile_figure_manifest.json b/parity/helpfile_figure_manifest.json index f7cf333f..66df6e7a 100644 --- a/parity/helpfile_figure_manifest.json +++ b/parity/helpfile_figure_manifest.json @@ -1,1804 +1,4388 @@ { - "schema_version": 1, - "topics": { - "AnalysisExamples": { - "matlab_helpfile_path": "AnalysisExamples.m", - "matlab_reference_image_count": 5, - "detected_new_figure_events": 4, - "total_figures_expected": 5, + "topics": [ + { + "topic": "AnalysisExamples", + "total_figures_expected": 4, + "total_figures_detected": 4, + "no_figure_utility": false, "events": [ { - "section_index": 3, - "matlab_line_number": 30, - "matlab_snippet": "figure;", + "section_index": 1, + "source_line_no": 700, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "AnalysisExamples.png" + "figure_ordinal": 1 }, { - "section_index": 4, - "matlab_line_number": 38, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "AnalysisExamples_01.png" + "section_index": 1, + "source_line_no": 701, + "source_snippet": "plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 5, - "matlab_line_number": 47, - "matlab_snippet": "figure;", + "section_index": 1, + "source_line_no": 1001, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "AnalysisExamples_02.png" + "figure_ordinal": 2 }, { - "section_index": 7, - "matlab_line_number": 103, - "matlab_snippet": "figure;", + "section_index": 1, + "source_line_no": 1300, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "figure", - "reference_image_path": "AnalysisExamples_03.png" + "figure_ordinal": 3 }, { - "section_index": 7, - "matlab_line_number": 75, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "AnalysisExamples_04.png" - } - ] - }, - "ConfigCollExamples": { - "matlab_helpfile_path": "ConfigCollExamples.m", - "matlab_reference_image_count": 0, - "detected_new_figure_events": 0, - "total_figures_expected": 0, - "events": [] - }, - "CovCollExamples": { - "matlab_helpfile_path": "CovCollExamples.m", - "matlab_reference_image_count": 3, - "detected_new_figure_events": 2, - "total_figures_expected": 3, - "events": [ + "section_index": 1, + "source_line_no": 1314, + "source_snippet": "plot3(cos(-pi:1e-2:pi),sin(-pi:1e-2:pi),zeros(size(-pi:1e-2:pi)))", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, { "section_index": 1, - "matlab_line_number": 5, - "matlab_snippet": "figure; cc.plot; %plots all covariates and their components", - "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "CovCollExamples.png" + "source_line_no": 1315, + "source_snippet": "plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 3 }, { "section_index": 1, - "matlab_line_number": 14, - "matlab_snippet": "figure; cc.plot; %plot only x and f_y;", + "source_line_no": 1925, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "CovCollExamples_01.png" + "figure_ordinal": 4 }, { "section_index": 1, - "matlab_line_number": 1, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "CovCollExamples_02.png" + "source_line_no": 1926, + "source_snippet": "plot( ([1:N]-.5)/N, KSSorted, 0:.01:1,0:.01:1, 'g',0:.01:1, [0:.01:1]+1.36/sqrt(N), 'r', 0:.01:1,[0:.01:1]-1.36/sqrt(N), 'r' )", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 1, + "source_line_no": 1930, + "source_snippet": "title('KS Plot with 95% Confidence Intervals')", + "event_type": "add_to_current", + "figure_ordinal": 4 } ] }, - "CovariateExamples": { - "matlab_helpfile_path": "CovariateExamples.m", - "matlab_reference_image_count": 3, - "detected_new_figure_events": 2, - "total_figures_expected": 3, + { + "topic": "ConfigCollExamples", + "total_figures_expected": 0, + "total_figures_detected": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "CovCollExamples", + "total_figures_expected": 2, + "total_figures_detected": 2, + "no_figure_utility": false, "events": [ { - "section_index": 4, - "matlab_line_number": 31, - "matlab_snippet": "position.getSigRep.plot('all',plotProps); %same as position.plot", + "section_index": 0, + "source_line_no": 203, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "plot", - "reference_image_path": "CovariateExamples.png" + "figure_ordinal": 1 }, { - "section_index": 4, - "matlab_line_number": 33, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "CovariateExamples_01.png" + "section_index": 0, + "source_line_no": 203, + "source_snippet": "cc.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 4, - "matlab_line_number": 29, - "matlab_snippet": "", + "section_index": 0, + "source_line_no": 212, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "CovariateExamples_02.png" + "figure_ordinal": 2 + }, + { + "section_index": 0, + "source_line_no": 212, + "source_snippet": "cc.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 } ] }, - "DecodingExample": { - "matlab_helpfile_path": "DecodingExample.m", - "matlab_reference_image_count": 7, - "detected_new_figure_events": 4, - "total_figures_expected": 7, + { + "topic": "CovariateExamples", + "total_figures_expected": 2, + "total_figures_detected": 2, + "no_figure_utility": false, "events": [ { - "section_index": 2, - "matlab_line_number": 21, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "DecodingExample.png" - }, - { - "section_index": 3, - "matlab_line_number": 30, - "matlab_snippet": "figure;", + "section_index": 1, + "source_line_no": 1100, + "source_snippet": "position.getSigRep.plot('all',plotProps)", "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "DecodingExample_01.png" + "figure_ordinal": 1 }, { - "section_index": 3, - "matlab_line_number": 45, - "matlab_snippet": "figure;", + "section_index": 1, + "source_line_no": 1102, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "DecodingExample_02.png" + "figure_ordinal": 2 }, { - "section_index": 4, - "matlab_line_number": 80, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "figure", - "reference_image_path": "DecodingExample_03.png" + "section_index": 1, + "source_line_no": 1103, + "source_snippet": "subplot(1,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 4, - "matlab_line_number": 52, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "DecodingExample_04.png" + "section_index": 1, + "source_line_no": 1103, + "source_snippet": "force.getSigRep.plot('all',plotPropsForce)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 4, - "matlab_line_number": 52, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "synthetic", - "reference_image_path": "DecodingExample_05.png" + "section_index": 1, + "source_line_no": 1108, + "source_snippet": "subplot(1,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 4, - "matlab_line_number": 52, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 7, - "trigger": "synthetic", - "reference_image_path": "DecodingExample_06.png" + "section_index": 1, + "source_line_no": 1108, + "source_snippet": "force.getSigRep('zero-mean').plot('all',plotPropsForce)", + "event_type": "add_to_current", + "figure_ordinal": 2 } ] }, - "DecodingExampleWithHist": { - "matlab_helpfile_path": "DecodingExampleWithHist.m", - "matlab_reference_image_count": 3, - "detected_new_figure_events": 2, - "total_figures_expected": 3, + { + "topic": "DecodingExample", + "total_figures_expected": 5, + "total_figures_detected": 4, + "no_figure_utility": false, "events": [ { "section_index": 1, - "matlab_line_number": 34, - "matlab_snippet": "figure;", + "source_line_no": 412, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "DecodingExampleWithHist.png" + "figure_ordinal": 1 }, { "section_index": 1, - "matlab_line_number": 63, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "DecodingExampleWithHist_01.png" + "source_line_no": 413, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 413, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 414, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 414, + "source_snippet": "lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { "section_index": 2, - "matlab_line_number": 90, - "matlab_snippet": "", + "source_line_no": 703, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "DecodingExampleWithHist_02.png" - } - ] - }, - "EventsExamples": { - "matlab_helpfile_path": "EventsExamples.m", - "matlab_reference_image_count": 5, - "detected_new_figure_events": 2, - "total_figures_expected": 5, - "events": [ + "figure_ordinal": 2 + }, { "section_index": 2, - "matlab_line_number": 13, - "matlab_snippet": "figure; e.plot([],'r'); %dont specify handle, use red; handel = gca;", - "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "EventsExamples.png" + "source_line_no": 706, + "source_snippet": "trial.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { "section_index": 2, - "matlab_line_number": 14, - "matlab_snippet": "figure; e.plot([],'g'); %dont specify handle, use green;", + "source_line_no": 718, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "EventsExamples_01.png" + "figure_ordinal": 3 }, { "section_index": 2, - "matlab_line_number": 11, - "matlab_snippet": "", + "source_line_no": 1115, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "EventsExamples_02.png" + "figure_ordinal": 4 }, { "section_index": 2, - "matlab_line_number": 11, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "synthetic", - "reference_image_path": "EventsExamples_03.png" + "source_line_no": 1119, + "source_snippet": "hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'g')", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { "section_index": 2, - "matlab_line_number": 11, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "EventsExamples_04.png" + "source_line_no": 1122, + "source_snippet": "hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 4 } ] }, - "ExplicitStimulusWhiskerData": { - "matlab_helpfile_path": "ExplicitStimulusWhiskerData.m", - "matlab_reference_image_count": 10, - "detected_new_figure_events": 4, - "total_figures_expected": 10, + { + "topic": "DecodingExampleWithHist", + "total_figures_expected": 2, + "total_figures_detected": 2, + "no_figure_utility": false, "events": [ { - "section_index": 2, - "matlab_line_number": 30, - "matlab_snippet": "figure;", + "section_index": 0, + "source_line_no": 322, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "ExplicitStimulusWhiskerData.png" + "figure_ordinal": 1 }, { - "section_index": 3, - "matlab_line_number": 49, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "ExplicitStimulusWhiskerData_01.png" + "section_index": 0, + "source_line_no": 323, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 6, - "matlab_line_number": 113, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "ExplicitStimulusWhiskerData_02.png" + "section_index": 0, + "source_line_no": 323, + "source_snippet": "sC.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 6, - "matlab_line_number": 134, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "figure", - "reference_image_path": "ExplicitStimulusWhiskerData_03.png" + "section_index": 0, + "source_line_no": 324, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 7, - "matlab_line_number": 143, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "ExplicitStimulusWhiskerData_04.png" + "section_index": 0, + "source_line_no": 324, + "source_snippet": "stim.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 7, - "matlab_line_number": 143, - "matlab_snippet": "", + "section_index": 0, + "source_line_no": 351, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "synthetic", - "reference_image_path": "ExplicitStimulusWhiskerData_05.png" + "figure_ordinal": 2 }, { - "section_index": 7, - "matlab_line_number": 143, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 7, - "trigger": "synthetic", - "reference_image_path": "ExplicitStimulusWhiskerData_06.png" + "section_index": 0, + "source_line_no": 352, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 7, - "matlab_line_number": 143, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 8, - "trigger": "synthetic", - "reference_image_path": "ExplicitStimulusWhiskerData_07.png" + "section_index": 0, + "source_line_no": 356, + "source_snippet": "hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'r')", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 7, - "matlab_line_number": 143, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 9, - "trigger": "synthetic", - "reference_image_path": "ExplicitStimulusWhiskerData_08.png" + "section_index": 0, + "source_line_no": 359, + "source_snippet": "hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 7, - "matlab_line_number": 143, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 10, - "trigger": "synthetic", - "reference_image_path": "ExplicitStimulusWhiskerData_09.png" + "section_index": 0, + "source_line_no": 365, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "source_line_no": 369, + "source_snippet": "hEst=plot(time,x_uNoHist(1:end),'b',time,ciLower,'g',time,ciUpper,'r')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "source_line_no": 372, + "source_snippet": "hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 0, + "source_line_no": 376, + "source_snippet": "title(['Decoded Stimulus No Hist +/- 99% confidence intervals using ' num2str(numRealizations) ' cells'])", + "event_type": "add_to_current", + "figure_ordinal": 2 } ] }, - "FitResSummaryExamples": { - "matlab_helpfile_path": "FitResSummaryExamples.m", - "matlab_reference_image_count": 0, - "detected_new_figure_events": 0, - "total_figures_expected": 0, - "events": [] - }, - "FitResultExamples": { - "matlab_helpfile_path": "FitResultExamples.m", - "matlab_reference_image_count": 0, - "detected_new_figure_events": 0, - "total_figures_expected": 0, - "events": [] - }, - "HippocampalPlaceCellExample": { - "matlab_helpfile_path": "HippocampalPlaceCellExample.m", - "matlab_reference_image_count": 12, - "detected_new_figure_events": 7, - "total_figures_expected": 12, + { + "topic": "EventsExamples", + "total_figures_expected": 3, + "total_figures_detected": 3, + "no_figure_utility": false, "events": [ { - "section_index": 3, - "matlab_line_number": 23, - "matlab_snippet": "figure(1);", + "section_index": 0, + "source_line_no": 305, + "source_snippet": "e.plot", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "HippocampalPlaceCellExample.png" + "figure_ordinal": 1 }, { - "section_index": 6, - "matlab_line_number": 162, - "matlab_snippet": "h4=figure(4);", + "section_index": 0, + "source_line_no": 600, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "HippocampalPlaceCellExample_01.png" + "figure_ordinal": 2 }, { - "section_index": 6, - "matlab_line_number": 172, - "matlab_snippet": "h6=figure(6);", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "HippocampalPlaceCellExample_02.png" + "section_index": 0, + "source_line_no": 600, + "source_snippet": "e.plot([],'r')", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 6, - "matlab_line_number": 187, - "matlab_snippet": "h5=figure(5);", + "section_index": 0, + "source_line_no": 601, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "figure", - "reference_image_path": "HippocampalPlaceCellExample_03.png" + "figure_ordinal": 3 }, { - "section_index": 6, - "matlab_line_number": 198, - "matlab_snippet": "h7=figure(7);", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "figure", - "reference_image_path": "HippocampalPlaceCellExample_04.png" - }, + "section_index": 0, + "source_line_no": 601, + "source_snippet": "e.plot([],'g')", + "event_type": "add_to_current", + "figure_ordinal": 3 + } + ] + }, + { + "topic": "ExplicitStimulusWhiskerData", + "total_figures_expected": 8, + "total_figures_detected": 5, + "no_figure_utility": false, + "events": [ { - "section_index": 6, - "matlab_line_number": 234, - "matlab_snippet": "figure(8);", + "section_index": 1, + "source_line_no": 421, + "source_snippet": "trial.plot", "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "figure", - "reference_image_path": "HippocampalPlaceCellExample_05.png" + "figure_ordinal": 1 }, { - "section_index": 6, - "matlab_line_number": 239, - "matlab_snippet": "figure(9);", + "section_index": 1, + "source_line_no": 423, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 7, - "trigger": "figure", - "reference_image_path": "HippocampalPlaceCellExample_06.png" + "figure_ordinal": 2 }, { - "section_index": 6, - "matlab_line_number": 108, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 8, - "trigger": "synthetic", - "reference_image_path": "HippocampalPlaceCellExample_07.png" + "section_index": 1, + "source_line_no": 424, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 6, - "matlab_line_number": 108, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 9, - "trigger": "synthetic", - "reference_image_path": "HippocampalPlaceCellExample_08.png" + "section_index": 1, + "source_line_no": 426, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 6, - "matlab_line_number": 108, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 10, - "trigger": "synthetic", - "reference_image_path": "HippocampalPlaceCellExample_09.png" + "section_index": 1, + "source_line_no": 427, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 6, - "matlab_line_number": 108, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 11, - "trigger": "synthetic", - "reference_image_path": "HippocampalPlaceCellExample_10.png" + "section_index": 1, + "source_line_no": 428, + "source_snippet": "stim.getSigInTimeWindow(0,21).plot", + "event_type": "add_to_current", + "figure_ordinal": 2 }, - { - "section_index": 6, - "matlab_line_number": 108, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 12, - "trigger": "synthetic", - "reference_image_path": "HippocampalPlaceCellExample_11.png" - } - ] - }, - "HistoryExamples": { - "matlab_helpfile_path": "HistoryExamples.m", - "matlab_reference_image_count": 5, - "detected_new_figure_events": 3, - "total_figures_expected": 5, - "events": [ { "section_index": 2, - "matlab_line_number": 18, - "matlab_snippet": "figure; subplot(3,1,1); h.plot; ylabel('History Windows');", + "source_line_no": 809, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "HistoryExamples.png" + "figure_ordinal": 3 }, { "section_index": 2, - "matlab_line_number": 20, - "matlab_snippet": "figure; nst.plot; ylabel('Neural Spike Train');", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "HistoryExamples_01.png" + "source_line_no": 810, + "source_snippet": "results.Residual.xcov(stim).windowedSignal([0,1]).plot", + "event_type": "add_to_current", + "figure_ordinal": 3 }, { - "section_index": 5, - "matlab_line_number": 44, - "matlab_snippet": "figure; histColl.plot;", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "HistoryExamples_02.png" + "section_index": 3, + "source_line_no": 1210, + "source_snippet": "results.plotResults", + "event_type": "add_to_current", + "figure_ordinal": 3 }, { - "section_index": 5, - "matlab_line_number": 39, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "synthetic", - "reference_image_path": "HistoryExamples_03.png" + "section_index": 4, + "source_line_no": 1621, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 3 }, { - "section_index": 5, - "matlab_line_number": 39, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "HistoryExamples_04.png" - } - ] - }, - "NetworkTutorial": { - "matlab_helpfile_path": "NetworkTutorial.m", - "matlab_reference_image_count": 8, - "detected_new_figure_events": 2, - "total_figures_expected": 8, - "events": [ - { - "section_index": 19, - "matlab_line_number": 131, - "matlab_snippet": "figure;", + "section_index": 4, + "source_line_no": 1800, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "NetworkTutorial.png" + "figure_ordinal": 4 }, { - "section_index": 21, - "matlab_line_number": 205, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "NetworkTutorial_01.png" + "section_index": 4, + "source_line_no": 1802, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 22, - "matlab_line_number": 216, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "NetworkTutorial_02.png" + "section_index": 4, + "source_line_no": 1802, + "source_snippet": "plot(x,results{1}.KSStats.ks_stat,'.')", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 22, - "matlab_line_number": 216, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "synthetic", - "reference_image_path": "NetworkTutorial_03.png" + "section_index": 4, + "source_line_no": 1803, + "source_snippet": "plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 22, - "matlab_line_number": 216, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "NetworkTutorial_04.png" + "section_index": 4, + "source_line_no": 1808, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 22, - "matlab_line_number": 216, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "synthetic", - "reference_image_path": "NetworkTutorial_05.png" + "section_index": 4, + "source_line_no": 1808, + "source_snippet": "plot(x,dAIC,'.')", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 22, - "matlab_line_number": 216, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 7, - "trigger": "synthetic", - "reference_image_path": "PPSimExample-BlockDiagram.png" + "section_index": 4, + "source_line_no": 1811, + "source_snippet": "plot(x(windowIndex),dAIC(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 22, - "matlab_line_number": 216, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 8, - "trigger": "synthetic", - "reference_image_path": "SimulatedNetwork2.png" - } - ] - }, - "PPSimExample": { - "matlab_helpfile_path": "PPSimExample.m", - "matlab_reference_image_count": 6, - "detected_new_figure_events": 1, - "total_figures_expected": 6, - "events": [ + "section_index": 4, + "source_line_no": 1813, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, { - "section_index": 9, - "matlab_line_number": 66, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "PPSimExample-BlockDiagram.png" + "section_index": 4, + "source_line_no": 1813, + "source_snippet": "plot(x,dBIC,'.')", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 17, - "matlab_line_number": 118, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "synthetic", - "reference_image_path": "PPSimExample.png" + "section_index": 4, + "source_line_no": 1815, + "source_snippet": "plot(x(windowIndex),dBIC(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 17, - "matlab_line_number": 118, - "matlab_snippet": "", + "section_index": 4, + "source_line_no": 1821, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "PPSimExample_01.png" + "figure_ordinal": 5 }, { - "section_index": 17, - "matlab_line_number": 118, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "synthetic", - "reference_image_path": "PPSimExample_02.png" + "section_index": 4, + "source_line_no": 1822, + "source_snippet": "plot(x,dBIC,'.')", + "event_type": "add_to_current", + "figure_ordinal": 5 }, { - "section_index": 17, - "matlab_line_number": 118, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "PPSimExample_03.png" + "section_index": 5, + "source_line_no": 2207, + "source_snippet": "c{3}.setName('Baseline+Stimulus+Hist')", + "event_type": "add_to_current", + "figure_ordinal": 5 }, { - "section_index": 17, - "matlab_line_number": 118, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "synthetic", - "reference_image_path": "PPSimExample_04.png" + "section_index": 5, + "source_line_no": 2210, + "source_snippet": "results.plotResults", + "event_type": "add_to_current", + "figure_ordinal": 5 } ] }, - "PPThinning": { - "matlab_helpfile_path": "PPThinning.m", - "matlab_reference_image_count": 5, - "detected_new_figure_events": 3, - "total_figures_expected": 5, + { + "topic": "FitResSummaryExamples", + "total_figures_expected": 0, + "total_figures_detected": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "FitResultExamples", + "total_figures_expected": 0, + "total_figures_detected": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "HippocampalPlaceCellExample", + "total_figures_expected": 9, + "total_figures_detected": 7, + "no_figure_utility": false, "events": [ { - "section_index": 3, - "matlab_line_number": 34, - "matlab_snippet": "figure(1);", + "section_index": 1, + "source_line_no": 902, + "source_snippet": "figure(1)", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "PPThinning.png" + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 903, + "source_snippet": "plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { "section_index": 3, - "matlab_line_number": 44, - "matlab_snippet": "figure(2);", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "PPThinning_01.png" + "source_line_no": 1604, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { "section_index": 4, - "matlab_line_number": 57, - "matlab_snippet": "figure(3);", + "source_line_no": 1952, + "source_snippet": "h4=figure(4)", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "PPThinning_02.png" + "figure_ordinal": 2 }, { "section_index": 4, - "matlab_line_number": 51, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "synthetic", - "reference_image_path": "PPThinning_03.png" + "source_line_no": 1960, + "source_snippet": "subplot(7,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { "section_index": 4, - "matlab_line_number": 51, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "PPThinning_04.png" - } - ] - }, - "PSTHEstimation": { - "matlab_helpfile_path": "PSTHEstimation.m", - "matlab_reference_image_count": 3, - "detected_new_figure_events": 2, - "total_figures_expected": 3, - "events": [ - { - "section_index": 2, - "matlab_line_number": 24, - "matlab_snippet": "spikeColl.plot; set(gca,'ytickLabel',[]);", + "source_line_no": 1962, + "source_snippet": "h6=figure(6)", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "gcf", - "reference_image_path": "PSTHEstimation.png" + "figure_ordinal": 3 }, { - "section_index": 3, - "matlab_line_number": 30, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "PSTHEstimation_01.png" + "section_index": 4, + "source_line_no": 1970, + "source_snippet": "subplot(6,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 3 }, { "section_index": 4, - "matlab_line_number": 57, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "PSTHEstimation_02.png" - } - ] - }, - "SignalObjExamples": { - "matlab_helpfile_path": "SignalObjExamples.m", - "matlab_reference_image_count": 21, - "detected_new_figure_events": 16, - "total_figures_expected": 21, - "events": [ + "source_line_no": 1972, + "source_snippet": "pcolor(x_new,y_new,lambdaGaussian{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, { - "section_index": 2, - "matlab_line_number": 16, - "matlab_snippet": "subplot(2,1,1); s.plot;", + "section_index": 4, + "source_line_no": 1977, + "source_snippet": "h5=figure(5)", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "subplot", - "reference_image_path": "SignalObjExamples.png" + "figure_ordinal": 4 }, { "section_index": 4, - "matlab_line_number": 44, - "matlab_snippet": "figure", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_01.png" + "source_line_no": 1986, + "source_snippet": "subplot(7,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 5, - "matlab_line_number": 48, - "matlab_snippet": "figure", + "section_index": 4, + "source_line_no": 1988, + "source_snippet": "h7=figure(7)", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_02.png" + "figure_ordinal": 5 }, { - "section_index": 6, - "matlab_line_number": 54, - "matlab_snippet": "figure", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_03.png" + "section_index": 4, + "source_line_no": 1996, + "source_snippet": "subplot(6,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 5 }, { - "section_index": 7, - "matlab_line_number": 74, - "matlab_snippet": "figure", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_04.png" + "section_index": 4, + "source_line_no": 1998, + "source_snippet": "pcolor(x_new,y_new,lambdaZernike{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 5 }, { - "section_index": 8, - "matlab_line_number": 80, - "matlab_snippet": "figure", + "section_index": 4, + "source_line_no": 2024, + "source_snippet": "figure(8)", "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_05.png" + "figure_ordinal": 6 }, { - "section_index": 9, - "matlab_line_number": 85, - "matlab_snippet": "figure", - "event_type": "new_figure", - "figure_ordinal": 7, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_06.png" + "section_index": 4, + "source_line_no": 2025, + "source_snippet": "plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 6 }, { - "section_index": 10, - "matlab_line_number": 92, - "matlab_snippet": "figure", + "section_index": 4, + "source_line_no": 2029, + "source_snippet": "figure(9)", "event_type": "new_figure", - "figure_ordinal": 8, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_07.png" + "figure_ordinal": 7 }, { - "section_index": 11, - "matlab_line_number": 97, - "matlab_snippet": "figure", - "event_type": "new_figure", - "figure_ordinal": 9, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_08.png" - }, + "section_index": 4, + "source_line_no": 2039, + "source_snippet": "plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 7 + } + ] + }, + { + "topic": "HistoryExamples", + "total_figures_expected": 3, + "total_figures_detected": 3, + "no_figure_utility": false, + "events": [ { - "section_index": 11, - "matlab_line_number": 102, - "matlab_snippet": "figure", + "section_index": 1, + "source_line_no": 701, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 10, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_09.png" + "figure_ordinal": 1 }, { - "section_index": 12, - "matlab_line_number": 108, - "matlab_snippet": "figure", - "event_type": "new_figure", - "figure_ordinal": 11, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_10.png" + "section_index": 1, + "source_line_no": 701, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 12, - "matlab_line_number": 112, - "matlab_snippet": "figure", - "event_type": "new_figure", - "figure_ordinal": 12, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_11.png" + "section_index": 1, + "source_line_no": 701, + "source_snippet": "h.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 13, - "matlab_line_number": 123, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 13, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_12.png" + "section_index": 1, + "source_line_no": 702, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 13, - "matlab_line_number": 126, - "matlab_snippet": "figure", - "event_type": "new_figure", - "figure_ordinal": 14, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_13.png" + "section_index": 1, + "source_line_no": 702, + "source_snippet": "histn1.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 14, - "matlab_line_number": 139, - "matlab_snippet": "figure;", + "section_index": 1, + "source_line_no": 703, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 15, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_14.png" + "figure_ordinal": 2 }, { - "section_index": 15, - "matlab_line_number": 155, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 16, - "trigger": "figure", - "reference_image_path": "SignalObjExamples_15.png" + "section_index": 1, + "source_line_no": 703, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 15, - "matlab_line_number": 144, - "matlab_snippet": "", + "section_index": 2, + "source_line_no": 1501, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 17, - "trigger": "synthetic", - "reference_image_path": "SignalObjExamples_16.png" + "figure_ordinal": 3 }, { - "section_index": 15, - "matlab_line_number": 144, - "matlab_snippet": "", + "section_index": 2, + "source_line_no": 1501, + "source_snippet": "histColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + } + ] + }, + { + "topic": "NetworkTutorial", + "total_figures_expected": 4, + "total_figures_detected": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 8, + "source_line_no": 4122, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 18, - "trigger": "synthetic", - "reference_image_path": "SignalObjExamples_17.png" + "figure_ordinal": 1 }, { - "section_index": 15, - "matlab_line_number": 144, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 19, - "trigger": "synthetic", - "reference_image_path": "SignalObjExamples_18.png" + "section_index": 8, + "source_line_no": 4123, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 15, - "matlab_line_number": 144, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 20, - "trigger": "synthetic", - "reference_image_path": "SignalObjExamples_19.png" + "section_index": 8, + "source_line_no": 4123, + "source_snippet": "sC.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 15, - "matlab_line_number": 144, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 21, - "trigger": "synthetic", - "reference_image_path": "SignalObjExamples_20.png" - } - ] - }, - "StimulusDecode2D": { - "matlab_helpfile_path": "StimulusDecode2D.m", - "matlab_reference_image_count": 7, - "detected_new_figure_events": 4, - "total_figures_expected": 7, - "events": [ + "section_index": 8, + "source_line_no": 4124, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, { - "section_index": 1, - "matlab_line_number": 24, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "StimulusDecode2D.png" + "section_index": 8, + "source_line_no": 4124, + "source_snippet": "stim.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 2, - "matlab_line_number": 59, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "StimulusDecode2D_01.png" + "section_index": 10, + "source_line_no": 4825, + "source_snippet": "c{3}.setName('Stim+Hist+EnsHist')", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 2, - "matlab_line_number": 68, - "matlab_snippet": "figure;", + "section_index": 10, + "source_line_no": 4856, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "StimulusDecode2D_02.png" + "figure_ordinal": 2 }, { - "section_index": 4, - "matlab_line_number": 116, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "figure", - "reference_image_path": "StimulusDecode2D_03.png" + "section_index": 10, + "source_line_no": 4858, + "source_snippet": "subplot(1,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 4, - "matlab_line_number": 97, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "StimulusDecode2D_04.png" + "section_index": 10, + "source_line_no": 4859, + "source_snippet": "imagesc(actNetwork,CLIM)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 4, - "matlab_line_number": 97, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "synthetic", - "reference_image_path": "StimulusDecode2D_05.png" + "section_index": 10, + "source_line_no": 4862, + "source_snippet": "subplot(1,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 4, - "matlab_line_number": 97, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 7, - "trigger": "synthetic", - "reference_image_path": "StimulusDecode2D_06.png" + "section_index": 10, + "source_line_no": 4863, + "source_snippet": "imagesc(network1ms,CLIM)", + "event_type": "add_to_current", + "figure_ordinal": 2 } ] }, - "TrialConfigExamples": { - "matlab_helpfile_path": "TrialConfigExamples.m", - "matlab_reference_image_count": 0, - "detected_new_figure_events": 0, - "total_figures_expected": 0, - "events": [] - }, - "TrialExamples": { - "matlab_helpfile_path": "TrialExamples.m", - "matlab_reference_image_count": 7, - "detected_new_figure_events": 6, - "total_figures_expected": 7, + { + "topic": "PPSimExample", + "total_figures_expected": 3, + "total_figures_detected": 1, + "no_figure_utility": false, "events": [ { - "section_index": 3, - "matlab_line_number": 13, - "matlab_snippet": "figure; h.plot;", + "section_index": 4, + "source_line_no": 2209, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "TrialExamples.png" + "figure_ordinal": 1 }, { "section_index": 4, - "matlab_line_number": 20, - "matlab_snippet": "figure; cc.plot;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "TrialExamples_01.png" + "source_line_no": 2210, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 5, - "matlab_line_number": 27, - "matlab_snippet": "figure; e.plot;", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "TrialExamples_02.png" + "section_index": 4, + "source_line_no": 2210, + "source_snippet": "sC.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 6, - "matlab_line_number": 37, - "matlab_snippet": "figure; spikeColl.plot;", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "figure", - "reference_image_path": "TrialExamples_03.png" + "section_index": 4, + "source_line_no": 2211, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 7, - "matlab_line_number": 43, - "matlab_snippet": "figure; trial1.plot; % plot all the data;", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "figure", - "reference_image_path": "TrialExamples_04.png" + "section_index": 4, + "source_line_no": 2211, + "source_snippet": "stim.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 8, - "matlab_line_number": 48, - "matlab_snippet": "figure; trial1.plot;", - "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "figure", - "reference_image_path": "TrialExamples_05.png" + "section_index": 6, + "source_line_no": 3801, + "source_snippet": "c{3}.setName('Stim+Hist')", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 9, - "matlab_line_number": 51, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 7, - "trigger": "synthetic", - "reference_image_path": "TrialExamples_06.png" + "section_index": 8, + "source_line_no": 4701, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 1 } ] }, - "ValidationDataSet": { - "matlab_helpfile_path": "ValidationDataSet.m", - "matlab_reference_image_count": 13, - "detected_new_figure_events": 3, - "total_figures_expected": 13, + { + "topic": "PPThinning", + "total_figures_expected": 3, + "total_figures_detected": 3, + "no_figure_utility": false, "events": [ { - "section_index": 6, - "matlab_line_number": 61, - "matlab_snippet": "results{1}.plotResults; subplot(2,4,[5 6]); plot(mu,'ro', 'MarkerSize',10);", + "section_index": 2, + "source_line_no": 700, + "source_snippet": "figure(1)", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "subplot", - "reference_image_path": "ValidationDataSet.png" + "figure_ordinal": 1 }, { - "section_index": 6, - "matlab_line_number": 63, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "ValidationDataSet_01.png" + "section_index": 2, + "source_line_no": 703, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 10, - "matlab_line_number": 132, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "ValidationDataSet_02.png" + "section_index": 2, + "source_line_no": 703, + "source_snippet": "n1.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_03.png" + "section_index": 2, + "source_line_no": 703, + "source_snippet": "plot(tSpikes,ones(size(tSpikes)),'.')", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_04.png" + "section_index": 2, + "source_line_no": 705, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_05.png" + "section_index": 2, + "source_line_no": 706, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 7, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_06.png" + "section_index": 2, + "source_line_no": 706, + "source_snippet": "n2.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 8, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_07.png" + "section_index": 2, + "source_line_no": 706, + "source_snippet": "plot(tSpikes,ones(size(tSpikes)),'.')", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 9, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_08.png" + "section_index": 2, + "source_line_no": 708, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", + "section_index": 2, + "source_line_no": 710, + "source_snippet": "figure(2)", "event_type": "new_figure", - "figure_ordinal": 10, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_09.png" + "figure_ordinal": 2 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 11, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_10.png" + "section_index": 2, + "source_line_no": 711, + "source_snippet": "n2.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 12, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_11.png" + "section_index": 2, + "source_line_no": 713, + "source_snippet": "scaledProb.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 11, - "matlab_line_number": 135, - "matlab_snippet": "", + "section_index": 3, + "source_line_no": 1102, + "source_snippet": "figure(3)", "event_type": "new_figure", - "figure_ordinal": 13, - "trigger": "synthetic", - "reference_image_path": "ValidationDataSet_12.png" + "figure_ordinal": 3 + }, + { + "section_index": 3, + "source_line_no": 1103, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 3, + "source_line_no": 1104, + "source_snippet": "lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 } ] }, - "mEPSCAnalysis": { - "matlab_helpfile_path": "mEPSCAnalysis.m", - "matlab_reference_image_count": 6, - "detected_new_figure_events": 1, - "total_figures_expected": 6, + { + "topic": "PSTHEstimation", + "total_figures_expected": 2, + "total_figures_detected": 2, + "no_figure_utility": false, "events": [ { - "section_index": 5, - "matlab_line_number": 98, - "matlab_snippet": "figure;", + "section_index": 1, + "source_line_no": 509, + "source_snippet": "spikeColl.plot", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "mEPSCAnalysis.png" + "figure_ordinal": 1 }, { - "section_index": 9, - "matlab_line_number": 146, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "synthetic", - "reference_image_path": "mEPSCAnalysis_01.png" + "section_index": 1, + "source_line_no": 510, + "source_snippet": "lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 9, - "matlab_line_number": 146, - "matlab_snippet": "", + "section_index": 2, + "source_line_no": 800, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "mEPSCAnalysis_02.png" + "figure_ordinal": 2 }, { - "section_index": 9, - "matlab_line_number": 146, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "synthetic", - "reference_image_path": "mEPSCAnalysis_03.png" + "section_index": 2, + "source_line_no": 805, + "source_snippet": "h1=trueRate.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 9, - "matlab_line_number": 146, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "mEPSCAnalysis_04.png" + "section_index": 2, + "source_line_no": 806, + "source_snippet": "h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 9, - "matlab_line_number": 146, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "synthetic", - "reference_image_path": "mEPSCAnalysis_05.png" + "section_index": 2, + "source_line_no": 807, + "source_snippet": "h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 2 } ] }, - "nSTATPaperExamples": { - "matlab_helpfile_path": "nSTATPaperExamples.m", - "matlab_reference_image_count": 26, - "detected_new_figure_events": 25, - "total_figures_expected": 26, + { + "topic": "SignalObjExamples", + "total_figures_expected": 16, + "total_figures_detected": 16, + "no_figure_utility": false, "events": [ { - "section_index": 3, - "matlab_line_number": 73, - "matlab_snippet": "h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...", + "section_index": 1, + "source_line_no": 505, + "source_snippet": "subplot(2,1,1)", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples.png" + "figure_ordinal": 1 }, { - "section_index": 5, - "matlab_line_number": 125, - "matlab_snippet": "h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_01.png" + "section_index": 1, + "source_line_no": 505, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 9, - "matlab_line_number": 195, - "matlab_snippet": "h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_02.png" + "section_index": 1, + "source_line_no": 506, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 11, - "matlab_line_number": 265, - "matlab_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_03.png" + "section_index": 1, + "source_line_no": 506, + "source_snippet": "s1.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 12, - "matlab_line_number": 323, - "matlab_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_04.png" + "section_index": 1, + "source_line_no": 900, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 15, - "matlab_line_number": 489, - "matlab_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);", - "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_05.png" + "section_index": 1, + "source_line_no": 900, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 16, - "matlab_line_number": 554, - "matlab_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);", - "event_type": "new_figure", - "figure_ordinal": 7, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_06.png" + "section_index": 1, + "source_line_no": 901, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 18, - "matlab_line_number": 686, - "matlab_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);", - "event_type": "new_figure", - "figure_ordinal": 8, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_07.png" + "section_index": 1, + "source_line_no": 901, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 22, - "matlab_line_number": 836, - "matlab_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);", + "section_index": 1, + "source_line_no": 1202, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 9, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_08.png" + "figure_ordinal": 2 }, { - "section_index": 23, - "matlab_line_number": 879, - "matlab_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);", - "event_type": "new_figure", - "figure_ordinal": 10, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_09.png" + "section_index": 1, + "source_line_no": 1203, + "source_snippet": "s.getSubSignal({'v1'}).plot", + "event_type": "add_to_current", + "figure_ordinal": 2 }, { - "section_index": 23, - "matlab_line_number": 901, - "matlab_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]);", + "section_index": 2, + "source_line_no": 1500, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 11, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_10.png" + "figure_ordinal": 3 }, { - "section_index": 24, - "matlab_line_number": 983, - "matlab_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]);", - "event_type": "new_figure", - "figure_ordinal": 12, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_11.png" + "section_index": 2, + "source_line_no": 1502, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 3 }, { - "section_index": 27, - "matlab_line_number": 1074, - "matlab_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9]);", - "event_type": "new_figure", - "figure_ordinal": 13, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_12.png" + "section_index": 2, + "source_line_no": 1502, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 }, { - "section_index": 30, - "matlab_line_number": 1182, - "matlab_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5]);", - "event_type": "new_figure", - "figure_ordinal": 14, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_13.png" + "section_index": 2, + "source_line_no": 1503, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 3 }, { - "section_index": 31, - "matlab_line_number": 1268, - "matlab_snippet": "h4=figure(4);", - "event_type": "new_figure", - "figure_ordinal": 15, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_14.png" + "section_index": 2, + "source_line_no": 1503, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 }, { - "section_index": 31, - "matlab_line_number": 1281, - "matlab_snippet": "h6=figure(6);", + "section_index": 2, + "source_line_no": 1700, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 16, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_15.png" + "figure_ordinal": 4 }, { - "section_index": 31, - "matlab_line_number": 1299, - "matlab_snippet": "h5=figure(5);", - "event_type": "new_figure", - "figure_ordinal": 17, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_16.png" + "section_index": 2, + "source_line_no": 1701, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 31, - "matlab_line_number": 1312, - "matlab_snippet": "h7=figure(7);", - "event_type": "new_figure", - "figure_ordinal": 18, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_17.png" + "section_index": 2, + "source_line_no": 1701, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 32, - "matlab_line_number": 1359, - "matlab_snippet": "h9=figure(9);", - "event_type": "new_figure", - "figure_ordinal": 19, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_18.png" + "section_index": 2, + "source_line_no": 1702, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 34, - "matlab_line_number": 1418, - "matlab_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...", - "event_type": "new_figure", - "figure_ordinal": 20, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_19.png" + "section_index": 2, + "source_line_no": 1702, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { - "section_index": 35, - "matlab_line_number": 1470, - "matlab_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]);", + "section_index": 2, + "source_line_no": 2100, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 21, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_20.png" + "figure_ordinal": 5 }, { - "section_index": 36, - "matlab_line_number": 1557, - "matlab_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", - "event_type": "new_figure", - "figure_ordinal": 22, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_21.png" + "section_index": 2, + "source_line_no": 2102, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 5 }, { - "section_index": 37, - "matlab_line_number": 1662, - "matlab_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", - "event_type": "new_figure", - "figure_ordinal": 23, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_22.png" + "section_index": 2, + "source_line_no": 2102, + "source_snippet": "s.plot('v1',{{' ''k'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 5 }, { - "section_index": 42, - "matlab_line_number": 1899, - "matlab_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", - "event_type": "new_figure", - "figure_ordinal": 24, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_23.png" + "section_index": 2, + "source_line_no": 2103, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 5 }, { - "section_index": 43, - "matlab_line_number": 1996, - "matlab_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", - "event_type": "new_figure", - "figure_ordinal": 25, - "trigger": "figure", - "reference_image_path": "nSTATPaperExamples_24.png" + "section_index": 2, + "source_line_no": 2103, + "source_snippet": "s.plot('all',{{' ''k'' '},{' ''-.g'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 5 }, - { - "section_index": 43, - "matlab_line_number": 1979, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 26, - "trigger": "synthetic", - "reference_image_path": "nSTATPaperExamples_25.png" - } - ] - }, - "nSpikeTrainExamples": { - "matlab_helpfile_path": "nSpikeTrainExamples.m", - "matlab_reference_image_count": 6, - "detected_new_figure_events": 4, - "total_figures_expected": 6, - "events": [ { "section_index": 2, - "matlab_line_number": 9, - "matlab_snippet": "figure; nst.plot;", + "source_line_no": 2300, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "nSpikeTrainExamples.png" + "figure_ordinal": 6 }, { - "section_index": 3, - "matlab_line_number": 17, - "matlab_snippet": "figure; nst.resample(1/.1);", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "nSpikeTrainExamples_01.png" + "section_index": 2, + "source_line_no": 2301, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 6 }, { - "section_index": 4, - "matlab_line_number": 23, - "matlab_snippet": "figure; nst.resample(1/.01);", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "nSpikeTrainExamples_02.png" + "section_index": 2, + "source_line_no": 2301, + "source_snippet": "s.plot({'v1','v2'})", + "event_type": "add_to_current", + "figure_ordinal": 6 }, { - "section_index": 5, - "matlab_line_number": 29, - "matlab_snippet": "figure; nst.resample(1/nst.getMaxBinSizeBinary);", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "figure", - "reference_image_path": "nSpikeTrainExamples_03.png" + "section_index": 2, + "source_line_no": 2302, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 6 }, { - "section_index": 5, - "matlab_line_number": 26, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "nSpikeTrainExamples_04.png" + "section_index": 2, + "source_line_no": 2302, + "source_snippet": "s.plot({'v1','v2'},{{' ''k'' '},{' ''-.g'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 6 }, - { - "section_index": 5, - "matlab_line_number": 26, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "synthetic", - "reference_image_path": "nSpikeTrainExamples_05.png" - } - ] - }, - "nstCollExamples": { - "matlab_helpfile_path": "nstCollExamples.m", - "matlab_reference_image_count": 4, - "detected_new_figure_events": 3, - "total_figures_expected": 4, - "events": [ { "section_index": 3, - "matlab_line_number": 14, - "matlab_snippet": "figure; spikeColl.plot;", + "source_line_no": 2600, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "nstCollExamples.png" + "figure_ordinal": 7 }, { - "section_index": 4, - "matlab_line_number": 18, - "matlab_snippet": "figure; spikeColl.plot;", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "nstCollExamples_01.png" + "section_index": 3, + "source_line_no": 2603, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 7 }, { - "section_index": 5, - "matlab_line_number": 21, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "figure", - "reference_image_path": "nstCollExamples_02.png" + "section_index": 3, + "source_line_no": 2603, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 }, { - "section_index": 5, - "matlab_line_number": 19, - "matlab_snippet": "", - "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "synthetic", - "reference_image_path": "nstCollExamples_03.png" - } - ] - }, - "AnalysisExamples2": { - "matlab_helpfile_path": "AnalysisExamples2.m", - "matlab_reference_image_count": 6, - "detected_new_figure_events": 2, - "total_figures_expected": 6, - "events": [ + "section_index": 3, + "source_line_no": 2604, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, { - "section_index": 4, - "matlab_line_number": 40, - "matlab_snippet": "figure;", - "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "AnalysisExamples2.png" + "section_index": 3, + "source_line_no": 2604, + "source_snippet": "s1.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 }, { - "section_index": 7, - "matlab_line_number": 66, - "matlab_snippet": "figure;", + "section_index": 3, + "source_line_no": 2800, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "AnalysisExamples2_01.png" + "figure_ordinal": 8 + }, + { + "section_index": 3, + "source_line_no": 2801, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 3, + "source_line_no": 2801, + "source_snippet": "s.getSigInTimeWindow(-2,3).plot", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 3, + "source_line_no": 2802, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 3, + "source_line_no": 2802, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 4, + "source_line_no": 3101, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 9 + }, + { + "section_index": 4, + "source_line_no": 3104, + "source_snippet": "s5.plot", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 4, + "source_line_no": 3106, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 10 + }, + { + "section_index": 4, + "source_line_no": 3108, + "source_snippet": "s2.plot", + "event_type": "add_to_current", + "figure_ordinal": 10 + }, + { + "section_index": 4, + "source_line_no": 3400, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 11 + }, + { + "section_index": 4, + "source_line_no": 3402, + "source_snippet": "s4.plot", + "event_type": "add_to_current", + "figure_ordinal": 11 + }, + { + "section_index": 4, + "source_line_no": 3404, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "source_line_no": 3405, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "source_line_no": 3406, + "source_snippet": "s.integral.plot", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "source_line_no": 3407, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "source_line_no": 3408, + "source_snippet": "s.derivative.plot", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "source_line_no": 3409, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 4, + "source_line_no": 3411, + "source_snippet": "s6.plot", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 5, + "source_line_no": 3701, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 13 + }, + { + "section_index": 5, + "source_line_no": 3704, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 14 + }, + { + "section_index": 6, + "source_line_no": 4105, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 15 + }, + { + "section_index": 6, + "source_line_no": 4106, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 15 + }, + { + "section_index": 6, + "source_line_no": 4106, + "source_snippet": "s.plot", + "event_type": "add_to_current", + "figure_ordinal": 15 + }, + { + "section_index": 6, + "source_line_no": 4107, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 15 + }, + { + "section_index": 6, + "source_line_no": 4400, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 16 + }, + { + "section_index": 6, + "source_line_no": 4402, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 16 + }, + { + "section_index": 6, + "source_line_no": 4404, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 16 + }, + { + "section_index": 6, + "source_line_no": 4406, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 16 + } + ] + }, + { + "topic": "StimulusDecode2D", + "total_figures_expected": 4, + "total_figures_detected": 4, + "no_figure_utility": false, + "events": [ + { + "section_index": 0, + "source_line_no": 318, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "source_line_no": 319, + "source_snippet": "plot(px,py)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 628, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 630, + "source_snippet": "lambda{i}.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 637, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 649, + "source_snippet": "subplot(1,numRealizations,i)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 651, + "source_snippet": "subplot(fact(1),fact(2),i)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 653, + "source_snippet": "subplot(fact(1)*fact(2),fact(3),i)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 655, + "source_snippet": "pcolor(X,Y,placeField{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "source_line_no": 1118, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 2, + "source_line_no": 1119, + "source_snippet": "plot(x_u(1,:),x_u(2,:),'b',px,py,'k')", + "event_type": "add_to_current", + "figure_ordinal": 4 + } + ] + }, + { + "topic": "TrialConfigExamples", + "total_figures_expected": 0, + "total_figures_detected": 0, + "no_figure_utility": false, + "events": [] + }, + { + "topic": "TrialExamples", + "total_figures_expected": 6, + "total_figures_detected": 6, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "source_line_no": 602, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 602, + "source_snippet": "h.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 903, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 903, + "source_snippet": "cc.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 1203, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 1203, + "source_snippet": "e.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 1506, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 1, + "source_line_no": 1506, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 1, + "source_line_no": 1801, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 5 + }, + { + "section_index": 1, + "source_line_no": 1801, + "source_snippet": "trial1.plot", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 1, + "source_line_no": 2101, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 6 + }, + { + "section_index": 1, + "source_line_no": 2101, + "source_snippet": "trial1.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + } + ] + }, + { + "topic": "ValidationDataSet", + "total_figures_expected": 8, + "total_figures_detected": 3, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "source_line_no": 1701, + "source_snippet": "subplot(2,4,[5 6])", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 1701, + "source_snippet": "plot(mu,'ro', 'MarkerSize',10)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 1702, + "source_snippet": "subplot(2,4,[5 6])", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 1702, + "source_snippet": "plot(mu,'ro', 'MarkerSize',10)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 1703, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 1704, + "source_snippet": "subplot(1,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 1704, + "source_snippet": "results{1}.lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 1704, + "source_snippet": "plot(results{1}.lambda.time,lambda*ones(length(results{1}.lambda.time),1),'r-.','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 1705, + "source_snippet": "subplot(1,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 1705, + "source_snippet": "results{2}.lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 1705, + "source_snippet": "plot(results{2}.lambda.time,lambda*ones(length(results{2}.lambda.time),1),'r-.','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 2, + "source_line_no": 3003, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "source_line_no": 3004, + "source_snippet": "subplot(1,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "source_line_no": 3004, + "source_snippet": "results{1}.lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "source_line_no": 3005, + "source_snippet": "subplot(1,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "source_line_no": 3005, + "source_snippet": "results{2}.lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 2, + "source_line_no": 3301, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 3 + } + ] + }, + { + "topic": "mEPSCAnalysis", + "total_figures_expected": 4, + "total_figures_detected": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 2, + "source_line_no": 1823, + "source_snippet": "results.plotResults", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 4, + "source_line_no": 2600, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "source_line_no": 2601, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 7, + "source_line_no": 3601, + "source_snippet": "results.plotResults", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 7, + "source_line_no": 3603, + "source_snippet": "Summary.plotSummary", + "event_type": "add_to_current", + "figure_ordinal": 2 + } + ] + }, + { + "topic": "nSTATPaperExamples", + "total_figures_expected": 1, + "total_figures_detected": 25, + "no_figure_utility": false, + "events": [ + { + "section_index": 2, + "source_line_no": 1036, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1039, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1039, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1048, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1048, + "source_snippet": "results.KSPlot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1049, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1050, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1050, + "source_snippet": "results.lambda.plot([],{{' ''b'' ,''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 4, + "source_line_no": 1801, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ...", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "source_line_no": 1804, + "source_snippet": "subplot(2,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "source_line_no": 1805, + "source_snippet": "nstConst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "source_line_no": 1813, + "source_snippet": "subplot(2,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 4, + "source_line_no": 1814, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 7, + "source_line_no": 3004, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ...", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3007, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3007, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3019, + "source_snippet": "plot([495", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3020, + "source_snippet": "plot([765", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3022, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3022, + "source_snippet": "results.KSPlot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3023, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3024, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3025, + "source_snippet": "results.lambda.getSubSignal(1).plot([],{{' ''b'' ,''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 7, + "source_line_no": 3026, + "source_snippet": "results.lambda.getSubSignal(2).plot([],{{' ''g'' ,''Linewidth'',2'}})", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 9, + "source_line_no": 3628, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "source_line_no": 3629, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 4 }, { "section_index": 9, - "matlab_line_number": 102, - "matlab_snippet": "", + "source_line_no": 3631, + "source_snippet": "nst2.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "source_line_no": 3641, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "source_line_no": 3642, + "source_snippet": "stim.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "source_line_no": 3655, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "source_line_no": 3656, + "source_snippet": "stim.derivative.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}})", + "event_type": "add_to_current", + "figure_ordinal": 4 + }, + { + "section_index": 9, + "source_line_no": 3910, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 5 + }, + { + "section_index": 9, + "source_line_no": 3912, + "source_snippet": "subplot(7,2,[1 3 5])", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 9, + "source_line_no": 3913, + "source_snippet": "results.Residual.xcov(stim).windowedSignal([0,1]).plot", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 9, + "source_line_no": 3921, + "source_snippet": "h=plot(ShiftTime,m,'ro','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4733, + "source_snippet": "subplot(7,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4735, + "source_snippet": "plot(x,results{1}.KSStats.ks_stat,'.-')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4736, + "source_snippet": "plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4750, + "source_snippet": "subplot(7,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4750, + "source_snippet": "plot(x,dAIC,'.-')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4756, + "source_snippet": "plot(x(windowIndex),dAIC(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4759, + "source_snippet": "subplot(7,2,6)", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4759, + "source_snippet": "plot(x,dBIC,'.-')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4762, + "source_snippet": "plot(x(windowIndex),dBIC(windowIndex),'r*')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4784, + "source_snippet": "c{3}.setName('Baseline+Stimulus+Hist')", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4790, + "source_snippet": "'\\lambda_{const+stim+hist}'})", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4791, + "source_snippet": "subplot(7,2,[9 11 13])", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4791, + "source_snippet": "results.KSPlot", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 11, + "source_line_no": 4792, + "source_snippet": "subplot(7,2,[10 12 14])", + "event_type": "add_to_current", + "figure_ordinal": 5 + }, + { + "section_index": 12, + "source_line_no": 5023, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "source_line_no": 5025, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "source_line_no": 5025, + "source_snippet": "spikeCollSim.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "source_line_no": 5034, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "source_line_no": 5034, + "source_snippet": "lambda.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "source_line_no": 5053, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "source_line_no": 5053, + "source_snippet": "spikeCollReal1.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "source_line_no": 5072, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 12, + "source_line_no": 5072, + "source_snippet": "spikeCollReal2.plot", + "event_type": "add_to_current", + "figure_ordinal": 6 + }, + { + "section_index": 13, + "source_line_no": 5303, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5309, + "source_snippet": "subplot(2,3,4)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5311, + "source_snippet": "h1=true.plot([],{{' ''b'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5312, + "source_snippet": "h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5313, + "source_snippet": "h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5327, + "source_snippet": "subplot(2,3,1)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5327, + "source_snippet": "spikeCollSim.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5334, + "source_snippet": "subplot(2,3,5)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5339, + "source_snippet": "h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5340, + "source_snippet": "h2=psthReal1.plot([],{{' ''rx'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5349, + "source_snippet": "subplot(2,3,2)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5349, + "source_snippet": "spikeCollReal1.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5355, + "source_snippet": "subplot(2,3,6)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5358, + "source_snippet": "h3=psthGLMReal2.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5359, + "source_snippet": "h2=psthReal2.plot([],{{' ''rx'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5369, + "source_snippet": "subplot(2,3,3)", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 13, + "source_line_no": 5369, + "source_snippet": "spikeCollReal2.plot", + "event_type": "add_to_current", + "figure_ordinal": 7 + }, + { + "section_index": 15, + "source_line_no": 6002, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "source_line_no": 6005, + "source_snippet": "subplot(3,2,[3 4])", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "source_line_no": 6005, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "source_line_no": 6026, + "source_snippet": "subplot(3,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "source_line_no": 6026, + "source_snippet": "plot(time,u,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "source_line_no": 6035, + "source_snippet": "subplot(3,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "source_line_no": 6035, + "source_snippet": "plot(1:length(b1),b1,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "source_line_no": 6043, + "source_snippet": "subplot(3,2,[5 6])", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 15, + "source_line_no": 6044, + "source_snippet": "imagesc(stimData'./delta); set(gca, 'YDir','normal');", + "event_type": "add_to_current", + "figure_ordinal": 8 + }, + { + "section_index": 17, + "source_line_no": 7004, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "source_line_no": 7005, + "source_snippet": "subplot(2,2,1)", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "source_line_no": 7005, + "source_snippet": "t.KSPlot", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "source_line_no": 7006, + "source_snippet": "subplot(2,2,2)", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "source_line_no": 7006, + "source_snippet": "t.plotResidual", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "source_line_no": 7007, + "source_snippet": "subplot(2,2,3)", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "source_line_no": 7008, + "source_snippet": "subplot(2,2,4)", + "event_type": "add_to_current", + "figure_ordinal": 9 + }, + { + "section_index": 17, + "source_line_no": 7230, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 10 + }, + { + "section_index": 17, + "source_line_no": 7234, + "source_snippet": "subplot(3,1,[1 2 3])", + "event_type": "add_to_current", + "figure_ordinal": 10 + }, + { + "section_index": 17, + "source_line_no": 7236, + "source_snippet": "surf((1:length(b1))',stim.time,actStimEffect,'FaceAlpha',0.1,...", + "event_type": "add_to_current", + "figure_ordinal": 10 + }, + { + "section_index": 17, + "source_line_no": 7242, + "source_snippet": "surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),...", + "event_type": "add_to_current", + "figure_ordinal": 10 + }, + { + "section_index": 17, + "source_line_no": 7252, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 11 + }, + { + "section_index": 17, + "source_line_no": 7255, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 11 + }, + { + "section_index": 17, + "source_line_no": 7273, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 11 + }, + { + "section_index": 17, + "source_line_no": 7290, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 11 + }, + { + "section_index": 18, + "source_line_no": 7523, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8])", + "event_type": "new_figure", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "source_line_no": 7525, + "source_snippet": "subplot(2,3,1)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "source_line_no": 7528, + "source_snippet": "spikeRateBinom.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "source_line_no": 7532, + "source_snippet": "plot(lt*[1", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "source_line_no": 7542, + "source_snippet": "h=subplot(2,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "source_line_no": 7545, + "source_snippet": "imagesc(ProbMat)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "source_line_no": 7549, + "source_snippet": "plot3(m,k,1,'r*')", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "source_line_no": 7559, + "source_snippet": "subplot(2,3,4)", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "source_line_no": 7576, + "source_snippet": "h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 18, + "source_line_no": 7577, + "source_snippet": "h2=stimlt.plot([],{{' ''r'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 12 + }, + { + "section_index": 20, + "source_line_no": 8406, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9])", + "event_type": "new_figure", + "figure_ordinal": 13 + }, + { + "section_index": 20, + "source_line_no": 8409, + "source_snippet": "subplot(2,2,i)", + "event_type": "add_to_current", + "figure_ordinal": 13 + }, + { + "section_index": 20, + "source_line_no": 8410, + "source_snippet": "h1=plot(x,y,'b','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 13 + }, + { + "section_index": 20, + "source_line_no": 8411, + "source_snippet": "h2=plot(neuron{exampleCell(i)}.xN,neuron{exampleCell(i)}.yN,'r.',...", + "event_type": "add_to_current", + "figure_ordinal": 13 + }, + { + "section_index": 22, + "source_line_no": 9302, + "source_snippet": "h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5])", + "event_type": "new_figure", + "figure_ordinal": 14 + }, + { + "section_index": 22, + "source_line_no": 9303, + "source_snippet": "subplot(1,3,1)", + "event_type": "add_to_current", + "figure_ordinal": 14 + }, + { + "section_index": 22, + "source_line_no": 9314, + "source_snippet": "subplot(1,3,2)", + "event_type": "add_to_current", + "figure_ordinal": 14 + }, + { + "section_index": 22, + "source_line_no": 9323, + "source_snippet": "subplot(1,3,3)", + "event_type": "add_to_current", + "figure_ordinal": 14 + }, + { + "section_index": 23, + "source_line_no": 9653, + "source_snippet": "h4=figure(4)", + "event_type": "new_figure", + "figure_ordinal": 15 + }, + { + "section_index": 23, + "source_line_no": 9664, + "source_snippet": "subplot(7,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 15 + }, + { + "section_index": 23, + "source_line_no": 9666, + "source_snippet": "h6=figure(6)", + "event_type": "new_figure", + "figure_ordinal": 16 + }, + { + "section_index": 23, + "source_line_no": 9677, + "source_snippet": "subplot(6,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 16 + }, + { + "section_index": 23, + "source_line_no": 9679, + "source_snippet": "pcolor(x_new,y_new,lambdaGaussian{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 16 + }, + { + "section_index": 23, + "source_line_no": 9684, + "source_snippet": "h5=figure(5)", + "event_type": "new_figure", + "figure_ordinal": 17 + }, + { + "section_index": 23, + "source_line_no": 9695, + "source_snippet": "subplot(7,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 17 + }, + { + "section_index": 23, + "source_line_no": 9697, + "source_snippet": "h7=figure(7)", + "event_type": "new_figure", + "figure_ordinal": 18 + }, + { + "section_index": 23, + "source_line_no": 9708, + "source_snippet": "subplot(6,7,i)", + "event_type": "add_to_current", + "figure_ordinal": 18 + }, + { + "section_index": 23, + "source_line_no": 9710, + "source_snippet": "pcolor(x_new,y_new,lambdaZernike{i}), shading interp", + "event_type": "add_to_current", + "figure_ordinal": 18 + }, + { + "section_index": 23, + "source_line_no": 9823, + "source_snippet": "h9=figure(9)", + "event_type": "new_figure", + "figure_ordinal": 19 + }, + { + "section_index": 23, + "source_line_no": 9835, + "source_snippet": "plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.')", + "event_type": "add_to_current", + "figure_ordinal": 19 + }, + { + "section_index": 25, + "source_line_no": 10329, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "source_line_no": 10332, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "source_line_no": 10332, + "source_snippet": "plot(time,x,'k')", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "source_line_no": 10338, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "source_line_no": 10338, + "source_snippet": "lambda.plot([],{{' ''k'',''Linewidth'',1'}})", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "source_line_no": 10348, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "source_line_no": 10348, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 20 + }, + { + "section_index": 25, + "source_line_no": 10517, + "source_snippet": "h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6])", + "event_type": "new_figure", + "figure_ordinal": 21 + }, + { + "section_index": 25, + "source_line_no": 10532, + "source_snippet": "hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 21 + }, + { + "section_index": 25, + "source_line_no": 10533, + "source_snippet": "hStim=stim.plot([],{{' ''b'',''Linewidth'',4'}})", + "event_type": "add_to_current", + "figure_ordinal": 21 + }, + { + "section_index": 26, + "source_line_no": 10951, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10954, + "source_snippet": "subplot(4,2,[1 3])", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10955, + "source_snippet": "plot(100*x(1,:),100*x(2,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10962, + "source_snippet": "h1=plot(100*x(1,1),100*x(2,1),'bo','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10963, + "source_snippet": "h2=plot(100*x(1,end),100*x(2,end),'ro','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10967, + "source_snippet": "subplot(4,2,5)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10967, + "source_snippet": "h1=plot(time,100*x(1,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10968, + "source_snippet": "h2=plot(time,100*x(2,:),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10977, + "source_snippet": "subplot(4,2,7)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10978, + "source_snippet": "h1=plot(time,100*x(3,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 10979, + "source_snippet": "h2=plot(time,100*x(4,:),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 11027, + "source_snippet": "subplot(4,2,[6 8])", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 11028, + "source_snippet": "h2=lambda{i}.plot([],{{' ''k'', ''LineWidth'' ,.5'}})", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 11041, + "source_snippet": "subplot(4,2,[2,4])", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 11041, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 22 + }, + { + "section_index": 26, + "source_line_no": 11103, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11169, + "source_snippet": "subplot(4,2,1:4)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11169, + "source_snippet": "h1=plot(100*x(1,:),100*x(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11176, + "source_snippet": "subplot(4,2,1:4)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11176, + "source_snippet": "h2=plot(100*x_u(1,:)',100*x_u(2,:)','b')", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11177, + "source_snippet": "subplot(4,2,1:4)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11177, + "source_snippet": "h3=plot(100*x_uf(1,:)',100*x_uf(2,:)','g')", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11180, + "source_snippet": "h1=plot(100*x0(1),100*x0(2),'bo','MarkerSize',10)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11181, + "source_snippet": "h2=plot(100*xT(1),100*xT(2),'ro','MarkerSize',10)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11185, + "source_snippet": "subplot(4,2,5)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11186, + "source_snippet": "h1=plot(time,100*x(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11187, + "source_snippet": "h2=plot(time,100*x_u(1,:)','b');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11188, + "source_snippet": "h3=plot(time,100*x_uf(1,:)','g');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11194, + "source_snippet": "subplot(4,2,6)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11195, + "source_snippet": "h1=plot(time,100*x(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11196, + "source_snippet": "h2=plot(time,100*x_u(2,:)','b');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11197, + "source_snippet": "h3=plot(time,100*x_uf(2,:)','g');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11208, + "source_snippet": "subplot(4,2,7)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11209, + "source_snippet": "h1=plot(time,100*x(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11210, + "source_snippet": "h2=plot(time,100*x_u(3,:)','b');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11211, + "source_snippet": "h3=plot(time,100*x_uf(3,:)','g');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11216, + "source_snippet": "subplot(4,2,8)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11217, + "source_snippet": "h1=plot(time,100*x(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11218, + "source_snippet": "h2=plot(time,100*x_u(4,:)','b');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 26, + "source_line_no": 11219, + "source_snippet": "h3=plot(time,100*x_uf(4,:)','g');", + "event_type": "add_to_current", + "figure_ordinal": 23 + }, + { + "section_index": 29, + "source_line_no": 12306, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12308, + "source_snippet": "subplot(4,2,[1 3])", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12309, + "source_snippet": "plot(100*X(1,:),100*X(2,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12314, + "source_snippet": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',16)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12315, + "source_snippet": "h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',16)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12320, + "source_snippet": "subplot(4,2,[6 8])", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12321, + "source_snippet": "plot(time,mstate,'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12329, + "source_snippet": "subplot(4,2,5)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12330, + "source_snippet": "h1=plot(time,100*X(1,1:end),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12331, + "source_snippet": "h2=plot(time,100*X(2,1:end),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12340, + "source_snippet": "subplot(4,2,7)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12341, + "source_snippet": "h1=plot(time,100*X(3,1:end),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12342, + "source_snippet": "h2=plot(time,100*X(4,1:end),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12376, + "source_snippet": "subplot(4,2,[2 4])", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 29, + "source_line_no": 12377, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 24 + }, + { + "section_index": 30, + "source_line_no": 12713, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "event_type": "new_figure", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12786, + "source_snippet": "subplot(4,3,[1 4])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12787, + "source_snippet": "plot(time,mstate,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12788, + "source_snippet": "plot(time,S_est,'b-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12789, + "source_snippet": "plot(time,S_estNT,'g-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12793, + "source_snippet": "subplot(4,3,[7 10])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12794, + "source_snippet": "plot(time,MU_est(2,:),'b-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12795, + "source_snippet": "plot(time,MU_estNT(2,:),'g-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12799, + "source_snippet": "subplot(4,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12800, + "source_snippet": "h1=plot(100*X(1,:)',100*X(2,:)','k')", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12801, + "source_snippet": "h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.')", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12802, + "source_snippet": "h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.')", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12805, + "source_snippet": "subplot(4,3,8)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12806, + "source_snippet": "h1=plot(time,100*X(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12807, + "source_snippet": "h2=plot(time,100*X_est(1,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12808, + "source_snippet": "h3=plot(time,100*X_estNT(1,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12811, + "source_snippet": "subplot(4,3,9)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12812, + "source_snippet": "h1=plot(time,100*X(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12813, + "source_snippet": "h2=plot(time,100*X_est(2,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12814, + "source_snippet": "h3=plot(time,100*X_estNT(2,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12817, + "source_snippet": "subplot(4,3,11)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12818, + "source_snippet": "h1=plot(time,100*X(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12819, + "source_snippet": "h2=plot(time,100*X_est(3,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12820, + "source_snippet": "h3=plot(time,100*X_estNT(3,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12822, + "source_snippet": "subplot(4,3,12)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12823, + "source_snippet": "h1=plot(time,100*X(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12824, + "source_snippet": "h2=plot(time,100*X_est(4,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12825, + "source_snippet": "h3=plot(time,100*X_estNT(4,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12840, + "source_snippet": "subplot(4,3,[1 4])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12842, + "source_snippet": "plot(time,mstate,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12843, + "source_snippet": "plot(time,mean(S_estAll),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12844, + "source_snippet": "plot(time,mean(S_estNTAll),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12856, + "source_snippet": "subplot(4,3,[7 10])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12857, + "source_snippet": "plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12859, + "source_snippet": "plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12868, + "source_snippet": "subplot(4,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12869, + "source_snippet": "h1=plot(100*X(1,:)',100*X(2,:)','k')", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12872, + "source_snippet": "plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12873, + "source_snippet": "plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12877, + "source_snippet": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12878, + "source_snippet": "h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12885, + "source_snippet": "subplot(4,3,8)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12886, + "source_snippet": "h1=plot(time,100*X(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12887, + "source_snippet": "h2=plot(time,mXestAll(1,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12888, + "source_snippet": "h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12895, + "source_snippet": "subplot(4,3,9)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12896, + "source_snippet": "h1=plot(time,100*X(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12897, + "source_snippet": "h2=plot(time,mXestAll(2,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12898, + "source_snippet": "h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12910, + "source_snippet": "subplot(4,3,11)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12911, + "source_snippet": "h1=plot(time,100*X(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12912, + "source_snippet": "h2=plot(time,mXestAll(3,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12913, + "source_snippet": "h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12919, + "source_snippet": "subplot(4,3,12)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12920, + "source_snippet": "h1=plot(time,100*X(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12921, + "source_snippet": "h2=plot(time,mXestAll(4,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + }, + { + "section_index": 30, + "source_line_no": 12922, + "source_snippet": "h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 25 + } + ] + }, + { + "topic": "nSpikeTrainExamples", + "total_figures_expected": 4, + "total_figures_detected": 4, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "source_line_no": 403, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 403, + "source_snippet": "nst.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 800, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 801, + "source_snippet": "nst.getSigRep.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 1100, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 1101, + "source_snippet": "nst.getSigRep.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 1400, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 4 + }, + { + "section_index": 1, + "source_line_no": 1401, + "source_snippet": "nst.getSigRep.plot", + "event_type": "add_to_current", + "figure_ordinal": 4 + } + ] + }, + { + "topic": "nstCollExamples", + "total_figures_expected": 3, + "total_figures_detected": 3, + "no_figure_utility": false, + "events": [ + { + "section_index": 1, + "source_line_no": 600, + "source_snippet": "figure", + "event_type": "new_figure", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 600, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 1, + "source_line_no": 901, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "AnalysisExamples2_02.png" + "figure_ordinal": 2 }, { - "section_index": 9, - "matlab_line_number": 102, - "matlab_snippet": "", + "section_index": 1, + "source_line_no": 901, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 1, + "source_line_no": 1200, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 4, - "trigger": "synthetic", - "reference_image_path": "AnalysisExamples2_03.png" + "figure_ordinal": 3 }, { - "section_index": 9, - "matlab_line_number": 102, - "matlab_snippet": "", + "section_index": 1, + "source_line_no": 1202, + "source_snippet": "subplot(3,1,1)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 1202, + "source_snippet": "n1.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 1203, + "source_snippet": "subplot(3,1,2)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 1203, + "source_snippet": "n1.getSigRep.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 1207, + "source_snippet": "subplot(3,1,3)", + "event_type": "add_to_current", + "figure_ordinal": 3 + }, + { + "section_index": 1, + "source_line_no": 1207, + "source_snippet": "s1.plot", + "event_type": "add_to_current", + "figure_ordinal": 3 + } + ] + }, + { + "topic": "AnalysisExamples2", + "total_figures_expected": 4, + "total_figures_detected": 2, + "no_figure_utility": false, + "events": [ + { + "section_index": 0, + "source_line_no": 1200, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 5, - "trigger": "synthetic", - "reference_image_path": "AnalysisExamples2_04.png" + "figure_ordinal": 1 }, { - "section_index": 9, - "matlab_line_number": 102, - "matlab_snippet": "", + "section_index": 0, + "source_line_no": 1201, + "source_snippet": "plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "source_line_no": 1508, + "source_snippet": "tc{3}.setName('Quadratic+Hist')", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "source_line_no": 1802, + "source_snippet": "fitResults.plotResults", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 0, + "source_line_no": 2100, + "source_snippet": "figure", "event_type": "new_figure", - "figure_ordinal": 6, - "trigger": "synthetic", - "reference_image_path": "AnalysisExamples2_05.png" + "figure_ordinal": 2 + }, + { + "section_index": 0, + "source_line_no": 2123, + "source_snippet": "plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...", + "event_type": "add_to_current", + "figure_ordinal": 2 } ] }, - "DocumentationSetup2025b": { - "matlab_helpfile_path": "DocumentationSetup2025b.m", - "matlab_reference_image_count": 0, - "detected_new_figure_events": 0, + { + "topic": "DocumentationSetup2025b", "total_figures_expected": 0, + "total_figures_detected": 0, + "no_figure_utility": false, "events": [] }, - "FitResultReference": { - "matlab_helpfile_path": "FitResultReference.m", - "matlab_reference_image_count": 0, - "detected_new_figure_events": 0, + { + "topic": "FitResultReference", "total_figures_expected": 0, + "total_figures_detected": 0, + "no_figure_utility": false, "events": [] }, - "HybridFilterExample": { - "matlab_helpfile_path": "HybridFilterExample.m", - "matlab_reference_image_count": 3, - "detected_new_figure_events": 2, - "total_figures_expected": 3, + { + "topic": "HybridFilterExample", + "total_figures_expected": 1, + "total_figures_detected": 2, + "no_figure_utility": false, "events": [ { - "section_index": 5, - "matlab_line_number": 110, - "matlab_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", + "section_index": 2, + "source_line_no": 1106, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", "event_type": "new_figure", - "figure_ordinal": 1, - "trigger": "figure", - "reference_image_path": "HybridFilterExample.png" + "figure_ordinal": 1 }, { - "section_index": 6, - "matlab_line_number": 207, - "matlab_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", - "event_type": "new_figure", - "figure_ordinal": 2, - "trigger": "figure", - "reference_image_path": "HybridFilterExample_01.png" + "section_index": 2, + "source_line_no": 1108, + "source_snippet": "subplot(4,2,[1 3])", + "event_type": "add_to_current", + "figure_ordinal": 1 }, { - "section_index": 6, - "matlab_line_number": 190, - "matlab_snippet": "", + "section_index": 2, + "source_line_no": 1109, + "source_snippet": "plot(100*X(1,:),100*X(2,:),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1114, + "source_snippet": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',16)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1115, + "source_snippet": "h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',16)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1120, + "source_snippet": "subplot(4,2,[6 8])", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1121, + "source_snippet": "plot(time,mstate,'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1129, + "source_snippet": "subplot(4,2,5)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1130, + "source_snippet": "h1=plot(time,100*X(1,1:end),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1131, + "source_snippet": "h2=plot(time,100*X(2,1:end),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1140, + "source_snippet": "subplot(4,2,7)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1141, + "source_snippet": "h1=plot(time,100*X(3,1:end),'k','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1142, + "source_snippet": "h2=plot(time,100*X(4,1:end),'k-.','Linewidth',2)", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1176, + "source_snippet": "subplot(4,2,[2 4])", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 2, + "source_line_no": 1177, + "source_snippet": "spikeColl.plot", + "event_type": "add_to_current", + "figure_ordinal": 1 + }, + { + "section_index": 3, + "source_line_no": 1513, + "source_snippet": "fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ...", "event_type": "new_figure", - "figure_ordinal": 3, - "trigger": "synthetic", - "reference_image_path": "HybridFilterExample_02.png" + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1586, + "source_snippet": "subplot(4,3,[1 4])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1587, + "source_snippet": "plot(time,mstate,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1588, + "source_snippet": "plot(time,S_est,'b-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1589, + "source_snippet": "plot(time,S_estNT,'g-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1593, + "source_snippet": "subplot(4,3,[7 10])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1594, + "source_snippet": "plot(time,MU_est(2,:),'b-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1595, + "source_snippet": "plot(time,MU_estNT(2,:),'g-.','Linewidth',.5)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1599, + "source_snippet": "subplot(4,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1600, + "source_snippet": "h1=plot(100*X(1,:)',100*X(2,:)','k')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1601, + "source_snippet": "h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1602, + "source_snippet": "h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1605, + "source_snippet": "subplot(4,3,8)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1606, + "source_snippet": "h1=plot(time,100*X(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1607, + "source_snippet": "h2=plot(time,100*X_est(1,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1608, + "source_snippet": "h3=plot(time,100*X_estNT(1,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1611, + "source_snippet": "subplot(4,3,9)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1612, + "source_snippet": "h1=plot(time,100*X(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1613, + "source_snippet": "h2=plot(time,100*X_est(2,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1614, + "source_snippet": "h3=plot(time,100*X_estNT(2,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1617, + "source_snippet": "subplot(4,3,11)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1618, + "source_snippet": "h1=plot(time,100*X(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1619, + "source_snippet": "h2=plot(time,100*X_est(3,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1620, + "source_snippet": "h3=plot(time,100*X_estNT(3,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1622, + "source_snippet": "subplot(4,3,12)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1623, + "source_snippet": "h1=plot(time,100*X(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1624, + "source_snippet": "h2=plot(time,100*X_est(4,:)','b-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1625, + "source_snippet": "h3=plot(time,100*X_estNT(4,:)','g-.');", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1640, + "source_snippet": "subplot(4,3,[1 4])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1642, + "source_snippet": "plot(time,mstate,'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1643, + "source_snippet": "plot(time,mean(S_estAll),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1644, + "source_snippet": "plot(time,mean(S_estNTAll),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1656, + "source_snippet": "subplot(4,3,[7 10])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1657, + "source_snippet": "plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1659, + "source_snippet": "plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1668, + "source_snippet": "subplot(4,3,[2 3 5 6])", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1669, + "source_snippet": "h1=plot(100*X(1,:)',100*X(2,:)','k')", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1672, + "source_snippet": "plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1673, + "source_snippet": "plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1677, + "source_snippet": "h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1678, + "source_snippet": "h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1685, + "source_snippet": "subplot(4,3,8)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1686, + "source_snippet": "h1=plot(time,100*X(1,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1687, + "source_snippet": "h2=plot(time,mXestAll(1,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1688, + "source_snippet": "h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1695, + "source_snippet": "subplot(4,3,9)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1696, + "source_snippet": "h1=plot(time,100*X(2,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1697, + "source_snippet": "h2=plot(time,mXestAll(2,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1698, + "source_snippet": "h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1710, + "source_snippet": "subplot(4,3,11)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1711, + "source_snippet": "h1=plot(time,100*X(3,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1712, + "source_snippet": "h2=plot(time,mXestAll(3,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1713, + "source_snippet": "h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1719, + "source_snippet": "subplot(4,3,12)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1720, + "source_snippet": "h1=plot(time,100*X(4,:),'k','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1721, + "source_snippet": "h2=plot(time,mXestAll(4,:),'b','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 + }, + { + "section_index": 3, + "source_line_no": 1722, + "source_snippet": "h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3)", + "event_type": "add_to_current", + "figure_ordinal": 2 } ] }, - "publish_all_helpfiles": { - "matlab_helpfile_path": "publish_all_helpfiles.m", - "matlab_reference_image_count": 0, - "detected_new_figure_events": 0, + { + "topic": "publish_all_helpfiles", "total_figures_expected": 0, + "total_figures_detected": 0, + "no_figure_utility": true, "events": [] } - } -} + ] +} \ No newline at end of file diff --git a/parity/helpfile_notebook_manifest.yml b/parity/helpfile_notebook_manifest.yml deleted file mode 100644 index 321abe46..00000000 --- a/parity/helpfile_notebook_manifest.yml +++ /dev/null @@ -1,362 +0,0 @@ -version: 1 -notebooks: -- topic: AnalysisExamples - file: notebooks/helpfiles/AnalysisExamples.ipynb - notebook_path: notebooks/helpfiles/AnalysisExamples.ipynb - run_group: smoke - matlab_helpfile: AnalysisExamples.m - matlab_helpfile_path: AnalysisExamples.m - matlab_section_count: 7 - python_cell_count: 7 - expected_min_figures: 5 - section_count: 7 - cell_count: 7 - expected_figure_count: 5 -- topic: ConfigCollExamples - file: notebooks/helpfiles/ConfigCollExamples.ipynb - notebook_path: notebooks/helpfiles/ConfigCollExamples.ipynb - run_group: full - matlab_helpfile: ConfigCollExamples.m - matlab_helpfile_path: ConfigCollExamples.m - matlab_section_count: 1 - python_cell_count: 1 - expected_min_figures: 0 - section_count: 1 - cell_count: 1 - expected_figure_count: 0 -- topic: CovCollExamples - file: notebooks/helpfiles/CovCollExamples.ipynb - notebook_path: notebooks/helpfiles/CovCollExamples.ipynb - run_group: full - matlab_helpfile: CovCollExamples.m - matlab_helpfile_path: CovCollExamples.m - matlab_section_count: 1 - python_cell_count: 1 - expected_min_figures: 3 - section_count: 1 - cell_count: 1 - expected_figure_count: 3 -- topic: CovariateExamples - file: notebooks/helpfiles/CovariateExamples.ipynb - notebook_path: notebooks/helpfiles/CovariateExamples.ipynb - run_group: smoke - matlab_helpfile: CovariateExamples.m - matlab_helpfile_path: CovariateExamples.m - matlab_section_count: 4 - python_cell_count: 4 - expected_min_figures: 3 - section_count: 4 - cell_count: 4 - expected_figure_count: 3 -- topic: DecodingExample - file: notebooks/helpfiles/DecodingExample.ipynb - notebook_path: notebooks/helpfiles/DecodingExample.ipynb - run_group: smoke - matlab_helpfile: DecodingExample.m - matlab_helpfile_path: DecodingExample.m - matlab_section_count: 4 - python_cell_count: 4 - expected_min_figures: 7 - section_count: 4 - cell_count: 4 - expected_figure_count: 7 -- topic: DecodingExampleWithHist - file: notebooks/helpfiles/DecodingExampleWithHist.ipynb - notebook_path: notebooks/helpfiles/DecodingExampleWithHist.ipynb - run_group: smoke - matlab_helpfile: DecodingExampleWithHist.m - matlab_helpfile_path: DecodingExampleWithHist.m - matlab_section_count: 2 - python_cell_count: 2 - expected_min_figures: 3 - section_count: 2 - cell_count: 2 - expected_figure_count: 3 -- topic: EventsExamples - file: notebooks/helpfiles/EventsExamples.ipynb - notebook_path: notebooks/helpfiles/EventsExamples.ipynb - run_group: full - matlab_helpfile: EventsExamples.m - matlab_helpfile_path: EventsExamples.m - matlab_section_count: 2 - python_cell_count: 2 - expected_min_figures: 5 - section_count: 2 - cell_count: 2 - expected_figure_count: 5 -- topic: ExplicitStimulusWhiskerData - file: notebooks/helpfiles/ExplicitStimulusWhiskerData.ipynb - notebook_path: notebooks/helpfiles/ExplicitStimulusWhiskerData.ipynb - run_group: full - matlab_helpfile: ExplicitStimulusWhiskerData.m - matlab_helpfile_path: ExplicitStimulusWhiskerData.m - matlab_section_count: 7 - python_cell_count: 7 - expected_min_figures: 10 - section_count: 7 - cell_count: 7 - expected_figure_count: 10 -- topic: FitResSummaryExamples - file: notebooks/helpfiles/FitResSummaryExamples.ipynb - notebook_path: notebooks/helpfiles/FitResSummaryExamples.ipynb - run_group: full - matlab_helpfile: FitResSummaryExamples.m - matlab_helpfile_path: FitResSummaryExamples.m - matlab_section_count: 1 - python_cell_count: 1 - expected_min_figures: 0 - section_count: 1 - cell_count: 1 - expected_figure_count: 0 -- topic: FitResultExamples - file: notebooks/helpfiles/FitResultExamples.ipynb - notebook_path: notebooks/helpfiles/FitResultExamples.ipynb - run_group: full - matlab_helpfile: FitResultExamples.m - matlab_helpfile_path: FitResultExamples.m - matlab_section_count: 1 - python_cell_count: 1 - expected_min_figures: 0 - section_count: 1 - cell_count: 1 - expected_figure_count: 0 -- topic: HippocampalPlaceCellExample - file: notebooks/helpfiles/HippocampalPlaceCellExample.ipynb - notebook_path: notebooks/helpfiles/HippocampalPlaceCellExample.ipynb - run_group: full - matlab_helpfile: HippocampalPlaceCellExample.m - matlab_helpfile_path: HippocampalPlaceCellExample.m - matlab_section_count: 6 - python_cell_count: 6 - expected_min_figures: 12 - section_count: 6 - cell_count: 6 - expected_figure_count: 12 -- topic: HistoryExamples - file: notebooks/helpfiles/HistoryExamples.ipynb - notebook_path: notebooks/helpfiles/HistoryExamples.ipynb - run_group: full - matlab_helpfile: HistoryExamples.m - matlab_helpfile_path: HistoryExamples.m - matlab_section_count: 5 - python_cell_count: 5 - expected_min_figures: 5 - section_count: 5 - cell_count: 5 - expected_figure_count: 5 -- topic: NetworkTutorial - file: notebooks/helpfiles/NetworkTutorial.ipynb - notebook_path: notebooks/helpfiles/NetworkTutorial.ipynb - run_group: full - matlab_helpfile: NetworkTutorial.m - matlab_helpfile_path: NetworkTutorial.m - matlab_section_count: 22 - python_cell_count: 22 - expected_min_figures: 8 - section_count: 22 - cell_count: 22 - expected_figure_count: 8 -- topic: PPSimExample - file: notebooks/helpfiles/PPSimExample.ipynb - notebook_path: notebooks/helpfiles/PPSimExample.ipynb - run_group: smoke - matlab_helpfile: PPSimExample.m - matlab_helpfile_path: PPSimExample.m - matlab_section_count: 17 - python_cell_count: 17 - expected_min_figures: 6 - section_count: 17 - cell_count: 17 - expected_figure_count: 6 -- topic: PPThinning - file: notebooks/helpfiles/PPThinning.ipynb - notebook_path: notebooks/helpfiles/PPThinning.ipynb - run_group: full - matlab_helpfile: PPThinning.m - matlab_helpfile_path: PPThinning.m - matlab_section_count: 4 - python_cell_count: 4 - expected_min_figures: 5 - section_count: 4 - cell_count: 4 - expected_figure_count: 5 -- topic: PSTHEstimation - file: notebooks/helpfiles/PSTHEstimation.ipynb - notebook_path: notebooks/helpfiles/PSTHEstimation.ipynb - run_group: full - matlab_helpfile: PSTHEstimation.m - matlab_helpfile_path: PSTHEstimation.m - matlab_section_count: 4 - python_cell_count: 4 - expected_min_figures: 3 - section_count: 4 - cell_count: 4 - expected_figure_count: 3 -- topic: SignalObjExamples - file: notebooks/helpfiles/SignalObjExamples.ipynb - notebook_path: notebooks/helpfiles/SignalObjExamples.ipynb - run_group: smoke - matlab_helpfile: SignalObjExamples.m - matlab_helpfile_path: SignalObjExamples.m - matlab_section_count: 15 - python_cell_count: 15 - expected_min_figures: 21 - section_count: 15 - cell_count: 15 - expected_figure_count: 21 -- topic: StimulusDecode2D - file: notebooks/helpfiles/StimulusDecode2D.ipynb - notebook_path: notebooks/helpfiles/StimulusDecode2D.ipynb - run_group: full - matlab_helpfile: StimulusDecode2D.m - matlab_helpfile_path: StimulusDecode2D.m - matlab_section_count: 4 - python_cell_count: 4 - expected_min_figures: 7 - section_count: 4 - cell_count: 4 - expected_figure_count: 7 -- topic: TrialConfigExamples - file: notebooks/helpfiles/TrialConfigExamples.ipynb - notebook_path: notebooks/helpfiles/TrialConfigExamples.ipynb - run_group: full - matlab_helpfile: TrialConfigExamples.m - matlab_helpfile_path: TrialConfigExamples.m - matlab_section_count: 1 - python_cell_count: 1 - expected_min_figures: 0 - section_count: 1 - cell_count: 1 - expected_figure_count: 0 -- topic: TrialExamples - file: notebooks/helpfiles/TrialExamples.ipynb - notebook_path: notebooks/helpfiles/TrialExamples.ipynb - run_group: smoke - matlab_helpfile: TrialExamples.m - matlab_helpfile_path: TrialExamples.m - matlab_section_count: 9 - python_cell_count: 9 - expected_min_figures: 7 - section_count: 9 - cell_count: 9 - expected_figure_count: 7 -- topic: ValidationDataSet - file: notebooks/helpfiles/ValidationDataSet.ipynb - notebook_path: notebooks/helpfiles/ValidationDataSet.ipynb - run_group: full - matlab_helpfile: ValidationDataSet.m - matlab_helpfile_path: ValidationDataSet.m - matlab_section_count: 11 - python_cell_count: 11 - expected_min_figures: 13 - section_count: 11 - cell_count: 11 - expected_figure_count: 13 -- topic: mEPSCAnalysis - file: notebooks/helpfiles/mEPSCAnalysis.ipynb - notebook_path: notebooks/helpfiles/mEPSCAnalysis.ipynb - run_group: full - matlab_helpfile: mEPSCAnalysis.m - matlab_helpfile_path: mEPSCAnalysis.m - matlab_section_count: 9 - python_cell_count: 9 - expected_min_figures: 6 - section_count: 9 - cell_count: 9 - expected_figure_count: 6 -- topic: nSTATPaperExamples - file: notebooks/helpfiles/nSTATPaperExamples.ipynb - notebook_path: notebooks/helpfiles/nSTATPaperExamples.ipynb - run_group: smoke - matlab_helpfile: nSTATPaperExamples.m - matlab_helpfile_path: nSTATPaperExamples.m - matlab_section_count: 43 - python_cell_count: 43 - expected_min_figures: 26 - section_count: 43 - cell_count: 43 - expected_figure_count: 26 -- topic: nSpikeTrainExamples - file: notebooks/helpfiles/nSpikeTrainExamples.ipynb - notebook_path: notebooks/helpfiles/nSpikeTrainExamples.ipynb - run_group: smoke - matlab_helpfile: nSpikeTrainExamples.m - matlab_helpfile_path: nSpikeTrainExamples.m - matlab_section_count: 5 - python_cell_count: 5 - expected_min_figures: 6 - section_count: 5 - cell_count: 5 - expected_figure_count: 6 -- topic: nstCollExamples - file: notebooks/helpfiles/nstCollExamples.ipynb - notebook_path: notebooks/helpfiles/nstCollExamples.ipynb - run_group: full - matlab_helpfile: nstCollExamples.m - matlab_helpfile_path: nstCollExamples.m - matlab_section_count: 5 - python_cell_count: 5 - expected_min_figures: 4 - section_count: 5 - cell_count: 5 - expected_figure_count: 4 -- topic: AnalysisExamples2 - file: notebooks/helpfiles/AnalysisExamples2.ipynb - notebook_path: notebooks/helpfiles/AnalysisExamples2.ipynb - run_group: full - matlab_helpfile: AnalysisExamples2.m - matlab_helpfile_path: AnalysisExamples2.m - matlab_section_count: 9 - python_cell_count: 9 - expected_min_figures: 6 - section_count: 9 - cell_count: 9 - expected_figure_count: 6 -- topic: DocumentationSetup2025b - file: notebooks/helpfiles/DocumentationSetup2025b.ipynb - notebook_path: notebooks/helpfiles/DocumentationSetup2025b.ipynb - run_group: full - matlab_helpfile: DocumentationSetup2025b.m - matlab_helpfile_path: DocumentationSetup2025b.m - matlab_section_count: 5 - python_cell_count: 5 - expected_min_figures: 0 - section_count: 5 - cell_count: 5 - expected_figure_count: 0 -- topic: FitResultReference - file: notebooks/helpfiles/FitResultReference.ipynb - notebook_path: notebooks/helpfiles/FitResultReference.ipynb - run_group: full - matlab_helpfile: FitResultReference.m - matlab_helpfile_path: FitResultReference.m - matlab_section_count: 1 - python_cell_count: 1 - expected_min_figures: 0 - section_count: 1 - cell_count: 1 - expected_figure_count: 0 -- topic: HybridFilterExample - file: notebooks/helpfiles/HybridFilterExample.ipynb - notebook_path: notebooks/helpfiles/HybridFilterExample.ipynb - run_group: full - matlab_helpfile: HybridFilterExample.m - matlab_helpfile_path: HybridFilterExample.m - matlab_section_count: 6 - python_cell_count: 6 - expected_min_figures: 3 - section_count: 6 - cell_count: 6 - expected_figure_count: 3 -- topic: publish_all_helpfiles - file: notebooks/helpfiles/publish_all_helpfiles.ipynb - notebook_path: notebooks/helpfiles/publish_all_helpfiles.ipynb - run_group: full - matlab_helpfile: publish_all_helpfiles.m - matlab_helpfile_path: publish_all_helpfiles.m - matlab_section_count: 1 - python_cell_count: 1 - expected_min_figures: 0 - section_count: 1 - cell_count: 1 - expected_figure_count: 0 diff --git a/parity/line_port_snapshots/AnalysisExamples.txt b/parity/line_port_snapshots/AnalysisExamples.txt deleted file mode 100644 index debf56e0..00000000 --- a/parity/line_port_snapshots/AnalysisExamples.txt +++ /dev/null @@ -1,59 +0,0 @@ -close all; -warning off; -installPath = which('nSTAT_Install'); -if isempty(installPath) -error('AnalysisExamples:MissingInstallPath', ... -'Could not locate nSTAT_Install.m on the MATLAB path.'); -end -glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat'); -load(glmDataPath); -figure; -plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.'); -axis tight square; -xlabel('x position (m)'); ylabel('y position (m)'); -[b,dev,stats] = glmfit([xN yN (xN.^2-mean(xN.^2)) (yN.^2-mean(yN.^2)) (xN.*yN-mean(xN.*yN))],spikes_binned,'poisson'); -figure; -errorbar(1:length(b), b, stats.se,'.'); -xticks=1:length(b); -xtickLabels= {'baseline','x','y','x^2','y^2','x*y'}; -set(gca,'xtick',xticks,'xtickLabel',xtickLabels); -figure; -[x_new,y_new]=meshgrid(-1:.1:1); -y_new = flipud(y_new); -x_new = fliplr(x_new); -lambda = exp(b(1) + b(2)*x_new + b(3)*y_new + b(4)*x_new.^2 + b(5)*y_new.^2 + b(6)*x_new.*y_new); -lambda((x_new.^2+y_new.^2>1))=nan; -h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0); -get(h_mesh,'AlphaData'); -set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor','b'); -hold on; -plot3(cos(-pi:1e-2:pi),sin(-pi:1e-2:pi),zeros(size(-pi:1e-2:pi))); hold on; -plot(xN,yN,x_at_spiketimes,y_at_spiketimes,'r.'); -axis tight square; -xlabel('x position (m)'); ylabel('y position (m)'); -[b_lin,dev_lin,stats_lin] = glmfit([xN yN],spikes_binned,'poisson'); -[b_quad,dev_quad,stats_quad] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson'); -lambdaEst_lin = exp( b_lin(1) + b_lin(2)*xN+b_lin(3)*yN); % based on our GLM model with the log "link function" -lambdaEst_quad = exp( b_quad(1) + b_quad(2)*xN+b_quad(3)*yN+b_quad(4)*xN.^2 +b_quad(5)*yN.^2 +b_quad(6)*xN.*yN); -lambdaEst=[lambdaEst_lin, lambdaEst_quad]; -timestep = 1; -lambdaInt = 0; -j=0; -KS=[]; -for t=1:length(spikes_binned) -lambdaInt = lambdaInt + lambdaEst(t,:)*timestep; -if (spikes_binned(t)) -j = j + 1; -KS(j,:) = 1-exp(-lambdaInt); -lambdaInt = [0 0]; -end -end -KSSorted = sort( KS ); -N = length( KSSorted); -figure; -plot( ([1:N]-.5)/N, KSSorted, 0:.01:1,0:.01:1, 'g',0:.01:1, [0:.01:1]+1.36/sqrt(N), 'r', 0:.01:1,[0:.01:1]-1.36/sqrt(N), 'r' ); -axis( [0 1 0 1] ); -xlabel('Uniform CDF'); -ylabel('Empirical CDF of Rescaled ISIs'); -title('KS Plot with 95% Confidence Intervals'); -legend('Linear','Quadratic'); diff --git a/parity/line_port_snapshots/AnalysisExamples2.txt b/parity/line_port_snapshots/AnalysisExamples2.txt deleted file mode 100644 index 0f75b371..00000000 --- a/parity/line_port_snapshots/AnalysisExamples2.txt +++ /dev/null @@ -1,61 +0,0 @@ -close all; -warning off; -installPath = which('nSTAT_Install'); -if isempty(installPath) -error('AnalysisExamples2:MissingInstallPath', ... -'Could not locate nSTAT_Install.m on the MATLAB path.'); -end -glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat'); -load(glmDataPath); -nst = nspikeTrain(spiketimes); -baseline = Covariate(T,ones(length(xN),1),'Baseline','time','s','',{'mu'}); -position = Covariate(T,[xN yN],'Position', 'time','s','m',{'x','y'}); -velocity = Covariate(T,[vxN,vyN],'Velocity','time','s','m/s',{'v_x','v_y'}); -radial = Covariate(T,[xN yN xN.^2 yN.^2 xN.*yN],'Radial','time','s','m',{'x','y','x^2','y^2','x*y'}); -[values_at_spiketimes] =position.getValueAt(spiketimes); -[values_at_spiketimes] =position.resample(1/min(diff(spiketimes))).getValueAt(spiketimes); -figure; -plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,... -values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.'); -axis tight square; -xlabel('x position (m)'); ylabel('y position (m)'); -spikeColl = nstColl({nst}); -covarColl = CovColl({baseline,radial}); -trial = Trial(spikeColl,covarColl); -clear tc; -sampleRate=1000; -tc{1} = TrialConfig({{'Baseline','mu'},{'Radial','x','y'}},sampleRate,[]); tc{1}.setName('Linear'); -tc{2} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[]); tc{2}.setName('Quadratic'); -tc{3} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[0 1]./sampleRate); tc{3}.setName('Quadratic+Hist'); -tcc = ConfigColl(tc); makePlot=1; neuronNum=1; -fitResults =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); -fitResults.plotResults; -figure; -[x_new,y_new]=meshgrid(-1:.1:1); %define new x and y -y_new = flipud(y_new); -x_new = fliplr(x_new); -newData{1} =ones(size(x_new)); -newData{2} =x_new; newData{3} =y_new; -newData{4} =x_new.^2; newData{5} =y_new.^2; -newData{6} =x_new.*y_new; -color = Analysis.colors; -for i=1:fitResults.numResults -lambda = fitResults.evalLambda(i,newData); -h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0); -get(h_mesh,'AlphaData'); -set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor',color{i}); -hold on; -end -legend(fitResults.lambda.dataLabels); -plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,... -values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.'); -axis tight square; -xlabel('x position (m)'); ylabel('y position (m)'); -[b,dev,stats] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson'); -b-fitResults.b{2} % should be close to zero -sampleRate=1000; makePlot=1; neuronNum = 1; -covLabels = {{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}}; -Algorithm = 'GLM'; -batchMode=0; -windowTimes =(0:1:10)./sampleRate; -[fitResults,tcc] = Analysis.computeHistLag(trial,neuronNum,windowTimes,covLabels,Algorithm,batchMode,sampleRate,makePlot); diff --git a/parity/line_port_snapshots/ConfigCollExamples.txt b/parity/line_port_snapshots/ConfigCollExamples.txt deleted file mode 100644 index 6e1e6ff5..00000000 --- a/parity/line_port_snapshots/ConfigCollExamples.txt +++ /dev/null @@ -1,3 +0,0 @@ -tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2); -tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2); -tcc = ConfigColl({tc1,tc2}); diff --git a/parity/line_port_snapshots/CovCollExamples.txt b/parity/line_port_snapshots/CovCollExamples.txt deleted file mode 100644 index dccc72e4..00000000 --- a/parity/line_port_snapshots/CovCollExamples.txt +++ /dev/null @@ -1,10 +0,0 @@ -close all; -load CovariateSample.mat; -cc=CovColl({position,force}); -figure; cc.plot; %plots all covariates and their components -cc.getCov(1); %returns position; -cc.getCov('Position'); -cc.getCov({'Position','Force'}); -cc.resample(200); %resamples both position and force -cc.setMask({{'Position','x'},{'Force','f_y'}}); -figure; cc.plot; %plot only x and f_y; diff --git a/parity/line_port_snapshots/CovariateExamples.txt b/parity/line_port_snapshots/CovariateExamples.txt deleted file mode 100644 index e21dd04f..00000000 --- a/parity/line_port_snapshots/CovariateExamples.txt +++ /dev/null @@ -1,19 +0,0 @@ -close all; -t=0:.01:5; t=t'; -x=exp(-t); -y=sin(2*pi*t); -z=(-y).^3; -fx=abs(y); -fy=abs(y).^2; -dLabels1={'f_x','f_y'}; -dLabels2={'x','y','z'}; -plotProps = {{' ''g'', ''LineWidth'' ,.5'},... %for x -{' ''k'', ''LineWidth'' ,.5'},... %for y -{' ''b'' '}}; %for z -force = Covariate(t, [fx fy], 'Force', 'time', 's', 'N', dLabels1); -position=Covariate(t,[x y z], 'Position','time','s','cm', dLabels2); -position.getSigRep.plot('all',plotProps); %same as position.plot -plotPropsForce = {{' ''b'' '},{' ''k'' '}}; -figure; -subplot(1,2,1); force.getSigRep.plot('all',plotPropsForce); -subplot(1,2,2); force.getSigRep('zero-mean').plot('all',plotPropsForce); diff --git a/parity/line_port_snapshots/DecodingExample.txt b/parity/line_port_snapshots/DecodingExample.txt deleted file mode 100644 index d781cf8f..00000000 --- a/parity/line_port_snapshots/DecodingExample.txt +++ /dev/null @@ -1,57 +0,0 @@ -close all; -delta = 0.001; Tmax = 10; -time = 0:delta:Tmax; -f=.1; b1=1;b0=-3; -x = sin(2*pi*f*time); -expData = exp(b1*x+b0); -lambdaData = expData./(1+expData); -lambda = Covariate(time,lambdaData./delta, '\Lambda(t)','time','s','Hz',{'\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}}); -numRealizations = 10; -spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations); -figure; -subplot(2,1,1); spikeColl.plot; -subplot(2,1,2); lambda.plot; -stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'}); -baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',... -{'constant'}); -figure; -cc = CovColl({stim,baseline}); -trial = Trial(spikeColl,cc); -trial.plot; -clear c; -selfHist = [] ; NeighborHist = []; sampleRate = 1000; -c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,... -NeighborHist); -c{1}.setName('Baseline'); -c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},... -sampleRate,selfHist,NeighborHist); -c{2}.setName('Baseline+Stimulus'); -cfgColl= ConfigColl(c); -results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); -figure; -results{1}.plotResults; -Summary = FitResSummary(results); -paramEst = squeeze(Summary.bAct(:,2,:)); -meanParams = mean(paramEst,2); -clear lambdaCIF; -b0=paramEst(1,:); -b1=paramEst(2,:); -for i=1:numRealizations -lambdaCIF{i} = CIF([b0(i) b1(i)],{'1','x'},{'x'},'binomial'); -end -spikeColl.resample(1/delta); -dN=spikeColl.dataToMatrix; -Q=2*std(stim.data(2:end)-stim.data(1:end-1)); -A=1; -[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN',b0,b1,'binomial',delta); -figure; -zVal=3; -ciLower = min(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))'); -ciUpper = max(x_u(1:end)-zVal*squeeze(sqrt(W_u(1:end)))',x_u(1:end)+zVal*squeeze(sqrt(W_u(1:end)))'); -hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'g'); hold on; -hold all; -hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}}); -legend off; -legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\sigma_{k|k}'),... -strcat('x_{k|k}(t)+',num2str(zVal),'\sigma_{k|k}'),'x(t)'); -title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']); diff --git a/parity/line_port_snapshots/DecodingExampleWithHist.txt b/parity/line_port_snapshots/DecodingExampleWithHist.txt deleted file mode 100644 index b4ee9172..00000000 --- a/parity/line_port_snapshots/DecodingExampleWithHist.txt +++ /dev/null @@ -1,55 +0,0 @@ -close all; -delta = 0.001; Tmax = 1; -time = 0:delta:Tmax; -f=1; b1=1;b0=-2; -stimData = b1*sin(2*pi*f*time); -e = zeros(length(time),1); %No Ensemble input -mu = b0; %baseline firing rate -Ts=delta; -histCoeffs= [-2 -2 -4]; -windowTimes=[0 .001 0.002 0.003]; -histObj = History(windowTimes); -filts = histObj.toFilter(Ts); %Convert to transfer function matrix -H=histCoeffs*filts; %scale each window transfer function by its coefficient -S=tf([1],1,Ts,'Variable','z^-1'); %Feed the stimulus in directly -E=tf([0],1,Ts,'Variable','z^-1'); %No ensemble effect -stim=Covariate(time',stimData,'Stimulus','time','s','Voltage',{'sin'}); -ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'}); -numRealizations = 20; %Number of sample paths to generate -sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations); -figure; -subplot(2,1,1); sC.plot; -subplot(2,1,2); stim.plot; -for i=1:numRealizations -lambdaCIF{i} = CIF([mu b1],{'1','x'},{'x'},'binomial',histCoeffs,histObj); -lambdaCIFNoHist{i} = CIF([mu b1],{'1','x'},{'x'},'binomial'); -end -sC.resample(1/delta); -dN=sC.dataToMatrix; -Q=2*std(stim.data(2:end)-stim.data(1:end-1)); -Px0=.1; A=1; -[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta); -[x_pNoHist, W_pNoHist, x_uNoHist, W_uNoHist] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIFNoHist,delta); -figure; -subplot(2,1,1); -zVal=3; -ciLower = min(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))'); -ciUpper = max(x_u(1:end)-zVal*squeeze(W_u(1:end))',x_u(1:end)+zVal*squeeze(W_u(1:end))'); -hEst=plot(time,x_u(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on; -hold all; -hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}}); -legend off; -legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\sigma_{k|k}'),... -strcat('x_{k|k}(t)+',num2str(zVal),'\sigma_{k|k}'),'x(t)'); -title(['Decoded Stimulus +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']); -subplot(2,1,2); -zVal=3; -ciLower = min(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))'); -ciUpper = max(x_uNoHist(1:end)-zVal*squeeze(W_uNoHist(1:end))',x_uNoHist(1:end)+zVal*squeeze(W_uNoHist(1:end))'); -hEst=plot(time,x_uNoHist(1:end),'b',time,ciLower,'g',time,ciUpper,'r'); hold on; -hold all; -hStim=stim.plot([],{{' ''k'',''Linewidth'',2'}}); -legend off; -legend([hEst(1) hEst(2) hEst(3) hStim],'x_{k|k}(t)',strcat('x_{k|k}(t)-',num2str(zVal),'\sigma_{k|k}'),... -strcat('x_{k|k}(t)+',num2str(zVal),'\sigma_{k|k}'),'x(t)'); -title(['Decoded Stimulus No Hist +/- 99% confidence intervals using ' num2str(numRealizations) ' cells']); diff --git a/parity/line_port_snapshots/EventsExamples.txt b/parity/line_port_snapshots/EventsExamples.txt deleted file mode 100644 index 1f652707..00000000 --- a/parity/line_port_snapshots/EventsExamples.txt +++ /dev/null @@ -1,8 +0,0 @@ -close all; -eTimes = sort(rand(1,3)*1); -eLabels={'E_1','E_2','E_3'}; -eventColor = 'b'; -e=Events(eTimes,eLabels,eventColor); -e.plot; -figure; e.plot([],'r'); %dont specify handle, use red; handel = gca; -figure; e.plot([],'g'); %dont specify handle, use green; diff --git a/parity/line_port_snapshots/ExplicitStimulusWhiskerData.txt b/parity/line_port_snapshots/ExplicitStimulusWhiskerData.txt deleted file mode 100644 index 57300289..00000000 --- a/parity/line_port_snapshots/ExplicitStimulusWhiskerData.txt +++ /dev/null @@ -1,115 +0,0 @@ -close all; -[~,~,explicitStimulusDir] = getPaperDataDirs(); -Direction=3; Neuron=1; Stim=2; -datapath = fullfile(explicitStimulusDir,strcat('Dir', num2str(Direction)),... -strcat('Neuron', num2str(Neuron)), strcat('Stim', num2str(Stim))); -data=load(fullfile(datapath,'trngdataBis.mat')); -time=0:.001:(length(data.t)-1)*.001; -stimData = data.t; -spikeTimes = time(data.y==1); -stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'}); -baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',... -{'constant'}); -nst = nspikeTrain(spikeTimes); -nspikeColl = nstColl(nst); -cc = CovColl({stim,baseline}); -trial = Trial(nspikeColl,cc); -trial.plot; -figure; -subplot(2,1,1); -nst2 = nspikeTrain(spikeTimes); -nst2.setMaxTime(21);nst.plot; -subplot(2,1,2); -stim.getSigInTimeWindow(0,21).plot; -clear c; -selfHist = [] ; NeighborHist = []; sampleRate = 1000; -c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist); -c{1}.setName('Baseline'); -cfgColl= ConfigColl(c); -results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); -figure; -results.Residual.xcov(stim).windowedSignal([0,1]).plot; -[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1])); -stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'}); -stim = stim.shift(ShiftTime); -baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',... -{'constant'}); -nst = nspikeTrain(spikeTimes); -nspikeColl = nstColl(nst); -cc = CovColl({stim,baseline}); -trial = Trial(nspikeColl,cc); -clear c; -selfHist = [] ; NeighborHist = []; sampleRate = 1000; -c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,... -NeighborHist); -c{1}.setName('Baseline'); -c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},... -sampleRate,selfHist,NeighborHist); -c{2}.setName('Baseline+Stimulus'); -cfgColl= ConfigColl(c); -results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); -results.plotResults; -sampleRate=1000; -delta=1/sampleRate*1; -maxWindow=1; numWindows=30; -windowTimes =unique(round([0 logspace(log10(delta),... -log10(maxWindow),numWindows)]*sampleRate)./sampleRate); -results =Analysis.computeHistLagForAll(trial,windowTimes,... -{{'Baseline','constant'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0); -KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat)); -AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ... -min(results{1}.AIC(2:end)-results{1}.AIC(1))); -BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ... -min(results{1}.BIC(2:end)-results{1}.BIC(1))); -if(AICind==1) -AICind=inf; -end -if(BICind==1) -BICind=inf; %sometime BIC is non-decreasing and the index would be 1 -end -windowIndex = min([KSind,AICind,BICind]) %use the minimum order model -Summary = FitResSummary(results); -Summary.plotSummary; -clear c; -if(windowIndex>1) -selfHist = windowTimes(1:windowIndex); -else -selfHist = []; -end -NeighborHist = []; sampleRate = 1000; -figure; -x=1:length(windowTimes); -subplot(3,1,1); plot(x,results{1}.KSStats.ks_stat,'.'); axis tight; hold on; -plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*'); -set(gca,'xtick',[]); -ylabel('KS Statistic'); -dAIC = results{1}.AIC-results{1}.AIC(1); -subplot(3,1,2); plot(x,dAIC,'.'); -set(gca,'xtick',[]); -ylabel('\Delta AIC');axis tight; hold on; -plot(x(windowIndex),dAIC(windowIndex),'r*'); -dBIC = results{1}.BIC-results{1}.BIC(1); -subplot(3,1,3); plot(x,dBIC,'.'); -ylabel('\Delta BIC'); axis tight; hold on; -plot(x(windowIndex),dBIC(windowIndex),'r*'); -for i=2:length(x) -histLabels{i} = ['[' num2str(windowTimes(i-1),3) ',' num2str(windowTimes(i),3) ,']']; -end -figure; -plot(x,dBIC,'.'); -xticks = 1:(length(histLabels)); -set(gca,'xtick',xticks,'xtickLabel',histLabels,'FontSize',6); -if(max(xticks)>=1) -xticklabel_rotate([],90,[],'Fontsize',8); -end -c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,[],NeighborHist); -c{1}.setName('Baseline'); -c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},... -sampleRate,[],[]); -c{2}.setName('Baseline+Stimulus'); -c{3} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},... -sampleRate,windowTimes(1:windowIndex),[]); -c{3}.setName('Baseline+Stimulus+Hist'); -cfgColl= ConfigColl(c); -results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); -results.plotResults; diff --git a/parity/line_port_snapshots/HippocampalPlaceCellExample.txt b/parity/line_port_snapshots/HippocampalPlaceCellExample.txt deleted file mode 100644 index f3eab548..00000000 --- a/parity/line_port_snapshots/HippocampalPlaceCellExample.txt +++ /dev/null @@ -1,64 +0,0 @@ -close all -[~,~,~,~,placeCellDataDir] = getPaperDataDirs(); -load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat')); -exampleCell = 25; -figure(1); -plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.'); -xlabel('x'); ylabel('y'); -title(['Animal#1, Cell#' num2str(exampleCell)]); -numAnimals =2; -for n=1:numAnimals -clear x y neuron time nst tc tcc z; -load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat'])); -for i=1:length(neuron) -nst{i} = nspikeTrain(neuron{i}.spikeTimes); -end -[theta,r] = cart2pol(x,y); -cnt=0; -for l=0:3 -for m=-l:l -if(~any(mod(l-m,2))) % otherwise the polynomial = 0 -cnt = cnt+1; -z(:,cnt) = zernfun(l,m,r,theta,'norm'); -end -end -end -delta=min(diff(time)); -sampleRate = round(1/delta); -baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',... -{'mu'}); -zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',... -'z4','z5','z6','z7','z8','z9','z10'}); -gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',... -'s','m',{'x','y','x^2','y^2','x*y'}); -covarColl = CovColl({baseline,gaussian,zernike}); -spikeColl = nstColl(nst); -trial = Trial(spikeColl,covarColl); -tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',... -'x','y','x^2','y^2','x*y'}},sampleRate,[]); -tc{1}.setName('Gaussian'); -tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',... -'z7','z8','z9','z10'}},sampleRate,[]); -tc{2}.setName('Zernike'); -tcc = ConfigColl(tc); -end -for n=1:numAnimals -resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat'])); -results = FitResult.fromStructure(resData.resStruct); -Summary = FitResSummary(results); -Summary.plotSummary; -end -[x_new,y_new]=meshgrid(-1:.01:1); %define new x and y -y_new = flipud(y_new); x_new = fliplr(x_new); -[theta_new,r_new] = cart2pol(x_new,y_new); -newData{1} =ones(size(x_new)); -newData{2} =x_new; newData{3} =y_new; -newData{4} =x_new.^2; newData{5} =y_new.^2; -newData{6} =x_new.*y_new; -idx = r_new<=1; -zpoly = cell(1,10); -cnt=0; -for l=0:3 -for m=-l:l -if(~any(mod(l-m,2))) -cnt = cnt+1; diff --git a/parity/line_port_snapshots/HippocampalPlaceCellExample_extra.txt b/parity/line_port_snapshots/HippocampalPlaceCellExample_extra.txt deleted file mode 100644 index 2628d73c..00000000 --- a/parity/line_port_snapshots/HippocampalPlaceCellExample_extra.txt +++ /dev/null @@ -1,91 +0,0 @@ -temp = nan(size(x_new)); -temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm'); -zpoly{cnt} = temp; -end -end -end -for n=1:numAnimals -clear lambdaGaussian lambdaZernike; -load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat'])); -resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat'])); -results = FitResult.fromStructure(resData.resStruct); -for i=1:length(neuron) -lambdaGaussian{i} = results{i}.evalLambda(1,newData); -lambdaZernike{i} = results{i}.evalLambda(2,zpoly); -end -for i=1:length(neuron) -if(n==1) -h4=figure(4); -if(i==1) -annotation(h4,'textbox',... -[0.343261904761904 0.928571428571418 ... -0.392857142857143 0.0595238095238095],... -'String',{['Gaussian Place Fields - Animal#' ... -num2str(n)]},'FitBoxToText','on'); hold on; -end -subplot(7,7,i); -elseif(n==2) -h6=figure(6); -if(i==1) -annotation(h6,'textbox',... -[0.343261904761904 0.928571428571418 ... -0.392857142857143 0.0595238095238095],... -'String',{['Gaussian Place Fields - Animal#' ... -num2str(n)]},'FitBoxToText','on'); hold on; -end -subplot(6,7,i); -end -pcolor(x_new,y_new,lambdaGaussian{i}), shading interp -axis square; set(gca,'xtick',[],'ytick',[]); -if(n==1) -h5=figure(5); -if(i==1) -annotation(h5,'textbox',... -[0.343261904761904 0.928571428571418 ... -0.392857142857143 0.0595238095238095],... -'String',{['Zernike Place Fields - Animal#' ... -num2str(n)]},'FitBoxToText','on'); hold on; -end -subplot(7,7,i); -elseif(n==2) -h7=figure(7); -if(i==1) -annotation(h7,'textbox',... -[0.343261904761904 0.928571428571418 ... -0.392857142857143 0.0595238095238095],... -'String',{['Zernike Place Fields - Animal#' ... -num2str(n)]},'FitBoxToText','on'); hold on; -end -subplot(6,7,i); -end -pcolor(x_new,y_new,lambdaZernike{i}), shading interp -axis square; -set(gca,'xtick',[],'ytick',[]); -end -end -clear lambdaGaussian lambdaZernike; -load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat')); -resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat')); -results = FitResult.fromStructure(resData.resStruct); -for i=1:length(neuron) -lambdaGaussian{i} = results{i}.evalLambda(1,newData); -lambdaZernike{i} = results{i}.evalLambda(2,zpoly); -end -exampleCell = 25; -figure(8); -plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.'); -xlabel('x'); ylabel('y'); -title(['Animal#1, Cell#' num2str(exampleCell)]); -figure(9); -h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0); -get(h_mesh,'AlphaData'); -set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b'); -hold on; -h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0); -get(h_mesh,'AlphaData'); -set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g'); -legend(results{exampleCell}.lambda.dataLabels); -plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.'); -axis tight square; -xlabel('x position'); ylabel('y position'); -title(['Animal#1, Cell#' num2str(exampleCell)]); diff --git a/parity/line_port_snapshots/HistoryExamples.txt b/parity/line_port_snapshots/HistoryExamples.txt deleted file mode 100644 index ada6cd82..00000000 --- a/parity/line_port_snapshots/HistoryExamples.txt +++ /dev/null @@ -1,18 +0,0 @@ -spikeTimes = sort(rand(1,100))*1; -nst = nspikeTrain(spikeTimes,'n1',.001); -windowTimes = [.001 .002 .004]; -h=History(windowTimes); -histn1=h.computeHistory(nst); -figure; subplot(3,1,1); h.plot; ylabel('History Windows'); -subplot(3,1,2); histn1.plot; ylabel('History Covariate for nst'); -figure; nst.plot; ylabel('Neural Spike Train'); -clear nst; -for i=1:1 -spikeTimes = sort(rand(1,100))*1; -nst{i}=nspikeTrain(spikeTimes,'',.001); -end -spikeColl=nstColl(nst); -windowTimes = [.001 .002 .01]; -h=History(windowTimes); -histColl = h.computeHistory(spikeColl); -figure; histColl.plot; diff --git a/parity/line_port_snapshots/HybridFilterExample.txt b/parity/line_port_snapshots/HybridFilterExample.txt deleted file mode 100644 index 5ac3a439..00000000 --- a/parity/line_port_snapshots/HybridFilterExample.txt +++ /dev/null @@ -1,288 +0,0 @@ -clear all; -close all; -delta=0.001; -Tmax=2; -time=0:delta:Tmax; -A{2} = [1 0 delta 0 delta^2/2 0; -0 1 0 delta 0 delta^2/2; -0 0 1 0 delta 0; -0 0 0 1 0 delta; -0 0 0 0 1 0; -0 0 0 0 0 1]; -A{1} = [1 0 0 0 0 0; -0 1 0 0 0 0; -0 0 0 0 0 0; -0 0 0 0 0 0; -0 0 0 0 0 0; -0 0 0 0 0 0]; -A{1} = [1 0; -0 1]; -Px0{2} =1e-6*eye(6,6); -Px0{1} =1e-6*eye(2,2); -minCovVal = 1e-12; -covVal = 1e-3; -Q{2}=[minCovVal 0 0 0 0 0; -0 minCovVal 0 0 0 0; -0 0 minCovVal 0 0 0; -0 0 0 minCovVal 0 0; -0 0 0 0 covVal 0; -0 0 0 0 0 covVal]; -Q{1}=minCovVal*eye(2,2); -mstate = zeros(1,length(time)); -ind{1}=1:2; -ind{2}=1:6; -X=zeros(max([size(A{1},1),size(A{2},1)]),length(time)); -p_ij = [.998 .002; -.001 .999]; -for i = 1:length(time) -if(i==1) -mstate(i) = 1; -else -if(rand(1,1)1)=1; %Avoid more than 1 spike per bin. -Mu0=.5*ones(size(p_ij,1),1); -clear x0 yT clear Pi0 PiT; -x0{1} = X(ind{1},1); -yT{1} = X(ind{1},end); -Pi0 = Px0; -PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1)); -x0{2} = X(ind{2},1); -yT{2} = X(ind{2},end); -PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1)); -[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=... -DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',... -coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT); -[S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=... -DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',... -coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0); -X_estAll(:,:,n) = X_est; -X_estNTAll(:,:,n) = X_estNT; -S_estAll(n,:)=S_est; -S_estNTAll(n,:)=S_estNT; -MU_estAll(:,:,n)=MU_est; -MU_estNTAll(:,:,n) = MU_estNT; -subplot(4,3,[1 4]); -plot(time,mstate,'k','LineWidth',3); hold all; -plot(time,S_est,'b-.','Linewidth',.5); -plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis; -axis([v(1) v(2) 0.5 2.5]); -subplot(4,3,[7 10]); -plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on; -plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on; -axis([min(time) max(time) 0 1.1]); -subplot(4,3,[2 3 5 6]); -h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all; -h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all; -h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.'); -subplot(4,3,8); -h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on; -h2=plot(time,100*X_est(1,:)','b-.'); -h3=plot(time,100*X_estNT(1,:)','g-.'); -subplot(4,3,9); -h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on; -h2=plot(time,100*X_est(2,:)','b-.'); -h3=plot(time,100*X_estNT(2,:)','g-.'); -subplot(4,3,11); -h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on; -h2=plot(time,100*X_est(3,:)','b-.'); -h3=plot(time,100*X_estNT(3,:)','g-.'); -subplot(4,3,12); -h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on; -h2=plot(time,100*X_est(4,:)','b-.'); -h3=plot(time,100*X_estNT(4,:)','g-.'); -end -subplot(4,3,[1 4]); -hold all; -plot(time,mstate,'k','LineWidth',3); -plot(time,mean(S_estAll),'b','LineWidth',3); -plot(time,mean(S_estNTAll),'g','LineWidth',3); -set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'}); -hy=ylabel('state'); hx=xlabel('time [s]'); -set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',... -'Interpreter','none'); -title('Estimated vs. Actual State','FontWeight','bold','Fontsize',... -12,'FontName','Arial'); -subplot(4,3,[7 10]); -plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3); -hold on; -plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3); -hold on; -axis([min(time) max(time) 0 1.1]); -hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('Probability of State','FontWeight','bold','Fontsize',12,... -'FontName','Arial'); -subplot(4,3,[2 3 5 6]); -h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all; -mXestAll=mean(100*X_estAll,3); -mXestNTAll=mean(100*X_estNTAll,3); -plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3); -plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3); -hx=xlabel('x [cm]'); hy=ylabel('y [cm]'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on; -h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14); -legend([h1 h2],'Start','Finish','Location','NorthEast'); -title('Estimated vs. Actual Reach Path','FontWeight','bold',... -'Fontsize',12,'FontName','Arial'); -subplot(4,3,8); -h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on; -h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on; -h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on; -hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]'); -set(gca,'xtick',[],'xtickLabel',[]); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial'); -subplot(4,3,9); -h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on; -h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on; -h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on; -h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',... -'PPAF','Location','SouthEast'); -hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]'); -set(gca,'xtick',[],'xtickLabel',[]); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial'); -set(h_legend,'FontSize',10) -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]); -subplot(4,3,11); -h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on; -h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on; -h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on; -hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial'); -subplot(4,3,12); -h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on; -h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on; -h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on; -hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial'); diff --git a/parity/line_port_snapshots/NetworkTutorial.txt b/parity/line_port_snapshots/NetworkTutorial.txt deleted file mode 100644 index 978a5816..00000000 --- a/parity/line_port_snapshots/NetworkTutorial.txt +++ /dev/null @@ -1,64 +0,0 @@ -clear all; -close all; -Ts=.001; %Sample Time -tMin=0; tMax=50; %Simulation duration -t=tMin:Ts:tMax; -numNeurons=2; -mu{1}=-3; -mu{2}=-3; -H{1}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1'); -H{2}=tf([-4 -2 -1],[1],Ts,'Variable','z^-1'); -S{1}=tf([1],1,Ts,'Variable','z^-1'); -S{2}=tf([-1],1,Ts,'Variable','z^-1'); -E{1}=tf([1],1,Ts,'Variable','z^-1'); -E{2}=tf([-4],1,Ts,'Variable','z^-1'); -f=1; %Stimulus frequency [Hz] -u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave -stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'}); -assignin('base','S1',S{1}); -assignin('base','H1',H{1}); -assignin('base','E1',E{1}); -assignin('base','mu1',mu{1}); -assignin('base','S2',S{2}); -assignin('base','H2',H{2}); -assignin('base','E2',E{2}); -assignin('base','mu2',mu{2}); -options = simget; -fitType = 'binomial'; -if(strcmp(fitType,'binomial')) -Algorithm = 'BNLRCG'; -else -Algorithm ='GLM'; -end -[tout,~,yout] = sim('SimulatedNetwork2',[stim.minTime stim.maxTime], ... -options,stim.dataToStructure); -clear nst; -for i=1:numNeurons -spikeTimes = tout(yout(:,i)>.5); %find the spike times -nst{i} = nspikeTrain(spikeTimes); -end -sC=nstColl(nst); -sC.setMinTime(stim.minTime); -sC.setMaxTime(stim.maxTime); -figure; -subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]); -subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]); -baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'}); -spikeColl = sC; %Use the generated data as our collection of spikes -cc=CovColl({stim,baseline}); -trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial -clear c; -selfHist = [0:1:3]*Ts; -ensHist = [0 1]*Ts; -sampleRate = 1/Ts; -c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]); -c{1}.setName('Baseline'); -c{2} = TrialConfig({{'Baseline','mu'}},sampleRate,[],ensHist); -c{2}.setName('Baseline+EnsHist'); -c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,... -selfHist,ensHist); -c{3}.setName('Stim+Hist+EnsHist'); -cfgColl= ConfigColl(c); -results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm); -results{1}.plotResults; -results{2}.plotResults; diff --git a/parity/line_port_snapshots/PPSimExample.txt b/parity/line_port_snapshots/PPSimExample.txt deleted file mode 100644 index c03efd61..00000000 --- a/parity/line_port_snapshots/PPSimExample.txt +++ /dev/null @@ -1,41 +0,0 @@ -close all; -Ts=.001; %Sample Time -tMin=0; tMax=50; %Simulation duration -t=tMin:Ts:tMax; -mu=-3; %Baseline firing rate of the neurons being modeled -H=tf([-1 -2 -4],[1],Ts,'Variable','z^-1'); -S=tf([1],1,Ts,'Variable','z^-1'); -E=tf([0],1,Ts,'Variable','z^-1'); -f=1; %Stimulus frequency -u = sin(2*pi*f*t)'; %Make this neuron modulated by a sine wave -e = zeros(length(t),1); %No Ensemble input -stim=Covariate(t',u,'Stimulus','time','s','Voltage',{'sin'}); -ens =Covariate(t',e,'Ensemble','time','s','Spikes',{'n1'}); -numRealizations = 5; %Number of sample paths to generate -fitType = 'binomial'; -sC=CIF.simulateCIF(mu,H,S,E,stim,ens,numRealizations,fitType); -figure; -subplot(2,1,1); sC.plot; v=axis; axis([0 tMax/10 v(3) v(4)]); -subplot(2,1,2); stim.plot; v=axis; axis([0 tMax/10 v(3) v(4)]); -baseline=Covariate(t',ones(length(t),1),'Baseline','time','s','',{'mu'}); -spikeColl = sC; %Use the generated data as our collection of spikes -cc=CovColl({stim,baseline}); %Use stimulation and baseline as possible covariates -trial = Trial(spikeColl,cc); sampleRate = 1/Ts; %Create trial -clear c; -selfHist = [0:0.001:0.003]; %We know the history effect goes back 3 lag orders -c{1} = TrialConfig({{'Baseline','mu'}},sampleRate,[],[]); -c{1}.setName('Baseline'); -c{2} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,[],[]); -c{2}.setName('Stim'); -c{3} = TrialConfig({{'Baseline','mu'},{'Stimulus','sin'}},sampleRate,selfHist,[]); -c{3}.setName('Stim+Hist'); -cfgColl= ConfigColl(c); -if(strcmp(fitType,'binomial')) -Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized, -else -Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or -end -results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0,Algorithm); -results{1}.plotResults; -Summary = FitResSummary(results); -Summary.plotSummary; diff --git a/parity/line_port_snapshots/PPThinning.txt b/parity/line_port_snapshots/PPThinning.txt deleted file mode 100644 index 8b4b9f5d..00000000 --- a/parity/line_port_snapshots/PPThinning.txt +++ /dev/null @@ -1,40 +0,0 @@ -close all; -delta = 0.001; -Tmax = 100; -time = 0:delta:Tmax; -f=.1; -lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0 -lambda = Covariate(time,lambdaData, '\Lambda(t)','time','s','Hz',{'\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}}); -lambdaBound = max(lambda); -N=lambdaBound*(1.5*Tmax); %Expected number of arrivals in interval 1.5*Tmax -u = rand(1,N); %N samples uniform(0,1) -w = -log(u)./(lambdaBound); %N samples exponential rate lambdaBound (ISIs) -tSpikes = cumsum(w); %Spiketimes; -tSpikes = tSpikes(tSpikes<=Tmax);%Spiketimes within Tmax -lambdaRatio = lambda.getValueAt(tSpikes)./lambdaBound; -u2 = rand(length(lambdaRatio),1); -tSpikesThin = tSpikes(lambdaRatio>=u2); -figure(1); -n1 = nspikeTrain(tSpikes); -n2 = nspikeTrain(tSpikesThin); -subplot(2,2,1); n1.plot; plot(tSpikes,ones(size(tSpikes)),'.'); -v=axis; axis([0 Tmax/4 v(3) v(4)]); -subplot(2,2,2); n1.plotISIHistogram; -subplot(2,2,3); n2.plot; plot(tSpikes,ones(size(tSpikes)),'.'); -v=axis; axis([0 Tmax/4 v(3) v(4)]); -subplot(2,2,4); n2.plotISIHistogram; -figure(2); -n2.plot; -scaledProb = lambda*(1./lambdaBound); -scaledProb.plot; -v=axis; -axis([0 Tmax/4 v(3) v(4)]); -numRealizations = 20; -spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations); -figure(3); -spikeColl.plot; -lambda.plot; -v=axis; -axis([0 Tmax/4 v(3) v(4)]); -parity = struct(); -parity.num_realizations = numRealizations; diff --git a/parity/line_port_snapshots/PSTHEstimation.txt b/parity/line_port_snapshots/PSTHEstimation.txt deleted file mode 100644 index 8274a9d2..00000000 --- a/parity/line_port_snapshots/PSTHEstimation.txt +++ /dev/null @@ -1,28 +0,0 @@ -close all; -delta = 0.001; -Tmax = 10; -time = 0:delta:Tmax; -f=.2; -lambdaData = 10*sin(2*pi*f*time)+10; %lambda >=0 -lambda = Covariate(time,lambdaData, '\Lambda(t)','time','s','Hz',{'\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}}); -numRealizations = 20; % Use 20 realization so that lamba and raster plot are the same size -spikeColl = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations); -spikeColl.plot; set(gca,'ytickLabel',[]); -lambda.plot; -figure; -binsize = .5; %500ms window -psth = spikeColl.psth(binsize); -psthGLM = spikeColl.psthGLM(binsize); -trueRate = lambda; %rate*delta = expected number of arrivals per bin -h1=trueRate.plot; -h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}}); -h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}}); -legend off; -legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}'); -psth_mean_hz = mean(psth.data); -psth_glm_mean_hz = mean(psthGLM.data); -lambda_mean_hz = mean(lambda.data); -parity = struct(); -parity.psth_mean_hz = psth_mean_hz; -parity.psth_glm_mean_hz = psth_glm_mean_hz; -parity.lambda_mean_hz = lambda_mean_hz; diff --git a/parity/line_port_snapshots/SignalObjExamples.txt b/parity/line_port_snapshots/SignalObjExamples.txt deleted file mode 100644 index 5cdd1922..00000000 --- a/parity/line_port_snapshots/SignalObjExamples.txt +++ /dev/null @@ -1,64 +0,0 @@ -close all; -sampleRate=100; t=0:1/sampleRate:10; freq=2; -v1=sin(2*pi*freq*t); v2=sin(v1.^2); v=[v1;v2]; -s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'}); -s1=SignalObj(t,v1,'Voltage','time','s','V',{'v1'}); -subplot(2,1,1); s.plot; -subplot(2,1,2); s1.plot; -subplot(2,1,1); s.setMask({'v1'}); s.plot; s.resetMask; -subplot(2,1,2); s.setMask({'v2'}); s.plot; size(s.dataToMatrix) -s.resetMask; -s=SignalObj(t,[v1; v1; v2] ,'Voltage','time','s','V',{'v1','v1','v2'}); -s.getSubSignal({'v1'}); %returns a SignalObj with both realizations of v1 -figure -s.getSubSignal({'v1'}).plot; -figure -s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'}); -subplot(2,1,1); s.plot; -subplot(2,1,2); s.setXlabel('distance'); s.setXUnits('cm'); s.plot; -figure -subplot(2,1,1); s.setDataLabels({'r1','r2'}); s.setYLabel('Temperature'); s.setYUnits('C'); s.plot; -subplot(2,1,2); s.setMaxTime(14); s.setMinTime(-2); s.plot; -s.setName('testName'); %should work since we are using a method -if(strcmp(s.name,'testName')) -fprintf('Name successfully set \n'); -else -fprintf('Could not set name \n'); -end -figure -s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'}); -subplot(2,1,1); s.plot('v1',{{' ''k'' '}}); -subplot(2,1,2); s.plot('all',{{' ''k'' '},{' ''-.g'' '}}); -figure -subplot(2,1,1); s.plot({'v1','v2'}); -subplot(2,1,2); s.plot({'v1','v2'},{{' ''k'' '},{' ''-.g'' '}}); -figure -s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'}); -s1=s.resample(.1*sampleRate); -subplot(2,1,1); s.plot; -subplot(2,1,2); s1.plot; -figure -subplot(2,1,1); s.getSigInTimeWindow(-2,3).plot; -subplot(2,1,2); s.plot; -s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'}); -figure -s2=mean(s); %mean of each dimension; -s5=s-s2; %zero mean version of s; -s5.plot; -figure -s2=mean(s,2); %mean of s across its dimensions; -s2.plot; -figure -s4=2*s+s5; -s4.plot; -figure -subplot(3,1,1); -s.integral.plot; -subplot(3,1,2); -s.derivative.plot; -subplot(3,1,3); -s6=s.integral.derivative-s; %should equal zero; -s6.plot; -s=SignalObj(t,v,'Voltage','time','s','V',{'v1','v2'}); -figure; -s.MTMspectrum; diff --git a/parity/line_port_snapshots/StimulusDecode2D.txt b/parity/line_port_snapshots/StimulusDecode2D.txt deleted file mode 100644 index bfaad540..00000000 --- a/parity/line_port_snapshots/StimulusDecode2D.txt +++ /dev/null @@ -1,92 +0,0 @@ -delta = 0.001; -Tmax = 1; -time = 0:delta:Tmax; -px = zeros(1,length(time)); -py = zeros(1,length(time)); -Q=.01; -r = Q.*randn(2,length(time)); -vx = cumsum(r(1,:))'; -vy = cumsum(r(2,:))'; -velSig = SignalObj(time, [vx, vy],'vel'); -posSig = velSig.integral; -posData = posSig.data; -px = posData(:,1); -py = posData(:,2); -figure; -plot(px,py); -title('Simulated X-Y trajectory'); -xlabel('x'); ylabel('y'); -clear lambdaCIF lambda tempSpikeColl n spikeColl -numRealizations=80; -coeffs = -abs(1*randn(numRealizations,5)); -coeffs = [-2*abs(randn(numRealizations,1)) coeffs]; -dataMat = [ones(length(time),1) px py px.^2 py.^2 px.*py]; -for i=1:numRealizations -tempData = exp(dataMat*coeffs(i,:)'); -lambdaData = tempData./(1+tempData); -lambda{i}=Covariate(time,lambdaData./delta, '\Lambda(t)','time','s','Hz',{strcat('\lambda_{',num2str(i),'}')},{{' ''b'', ''LineWidth'' ,2'}}); -tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1); -n{i} = tempSpikeColl{i}.getNST(1); -n{i}.setName(num2str(i)); -try -lambdaCIF{i} = CIF(coeffs(i,:),{'1','x','y','x^2','y^2','x*y'},{'x','y'},'binomial'); -catch ME_sym -if(i==1) -warning('StimulusDecode2D:SymbolicCIFFallback', ... -['CIF symbolic setup failed (' ME_sym.identifier '). Decoder will use linear fallback.']); -end -lambdaCIF{i} = []; -end -end -figure; -for i=1:length(lambda) -lambda{i}.plot; -end -legend off; -clear placeField; -[X,Y]=meshgrid(-2:.1:2,-2:.1:2); -figure; -for i=1:numRealizations -tempData = coeffs(i,1) + coeffs(i,2)*X + coeffs(i,3)*Y +coeffs(i,4)*X.^2 + coeffs(i,5)*Y.^2 + coeffs(i,6).*X.*Y; -placeField{i} = exp(tempData)./(1+exp(tempData))./delta; %rate based on logistic link function -end -fact=factor(numRealizations); -for i=1:numRealizations -if(length(fact)==1) -subplot(1,numRealizations,i); -elseif(length(fact)==2) -subplot(fact(1),fact(2),i); -elseif(length(fact)==3) -subplot(fact(1)*fact(2),fact(3),i); -end -pcolor(X,Y,placeField{i}), shading interp -axis square; -set(gca,'xtick',[],'ytick',[]); -end -spikeColl = nstColl(n); -spikeColl.resample(1/delta); -dN = spikeColl.dataToMatrix; -vx=var(px(2:end)-px(1:end-1)); -vy=var(py(2:end)-py(1:end-1)); -Q=[vx 0;0 vy]; -Px0=.1*eye(2,2); A=1*eye(2,2); -decode_method = 'PPDecodeFilter'; -try -[x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilter(A, Q, Px0, dN',lambdaCIF,delta); -catch ME_decode -warning('StimulusDecode2D:SymbolicDecodeFallback', ... -['PPDecodeFilter failed (' ME_decode.identifier '). Falling back to PPDecodeFilterLinear.']); -decode_method = 'PPDecodeFilterLinear'; -mu_linear = coeffs(:,1); -beta_linear = coeffs(:,2:3)'; -[x_p, Pe_p, x_u, Pe_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN', mu_linear, beta_linear, 'binomial', delta); -end -nCommon = min(length(px),size(x_u,2)); -decode_rmse = sqrt(mean((x_u(1,1:nCommon)'-px(1:nCommon)).^2 + (x_u(2,1:nCommon)'-py(1:nCommon)).^2)); -num_cells = numRealizations; -figure; -plot(x_u(1,:),x_u(2,:),'b',px,py,'k') -legend('predicted path','actual path'); -parity = struct(); -parity.num_cells = num_cells; -parity.decode_rmse = decode_rmse; diff --git a/parity/line_port_snapshots/TrialConfigExamples.txt b/parity/line_port_snapshots/TrialConfigExamples.txt deleted file mode 100644 index 6e1e6ff5..00000000 --- a/parity/line_port_snapshots/TrialConfigExamples.txt +++ /dev/null @@ -1,3 +0,0 @@ -tc1 = TrialConfig({'Force','f_x'},2000,[.1 .2],-1,2); -tc2 = TrialConfig({'Position','x'},2000,[.1 .2],-1,2); -tcc = ConfigColl({tc1,tc2}); diff --git a/parity/line_port_snapshots/TrialExamples.txt b/parity/line_port_snapshots/TrialExamples.txt deleted file mode 100644 index 16033dc5..00000000 --- a/parity/line_port_snapshots/TrialExamples.txt +++ /dev/null @@ -1,25 +0,0 @@ -close all; clear all; -lengthTrial=1; -windowTimes = [0 .1 .2 .4]; -h=History(windowTimes); -figure; h.plot; -load CovariateSample.mat; %load position and force covariates -cc=CovColl({position,force}); -cc.setMaxTime(lengthTrial); -figure; cc.plot; -eTimes = sort(rand(1,2)*lengthTrial); -eLabels={'E_1','E_2'}; -e=Events(eTimes,eLabels); %use default eventColor 'r' -figure; e.plot; -clear nst; -for i=1:4 -spikeTimes = sort(rand(1,100))*lengthTrial; -nst{i}=nspikeTrain(spikeTimes,'',.001); -end -spikeColl=nstColl(nst); %create a nstColl -figure; spikeColl.plot; -trial1=Trial(spikeColl, cc, e, h); -figure; trial1.plot; % plot all the data; -trial1.setCovMask({{'Position','x'},{'Force','f_x'}}) -figure; trial1.plot; -trial1.getHistForNeurons([1:2]); diff --git a/parity/line_port_snapshots/ValidationDataSet.txt b/parity/line_port_snapshots/ValidationDataSet.txt deleted file mode 100644 index 3b0f03f8..00000000 --- a/parity/line_port_snapshots/ValidationDataSet.txt +++ /dev/null @@ -1,77 +0,0 @@ -clear all; -close all; -p=0.01; % bernoilli probability -N=100001; % Number of coin flips -delta = 0.001; % binsize -T=N*delta; % total time window -lambda=N*p/T % lambda*T = N*p -mu = log(lambda*delta/(1-lambda*delta)) -for i=1:2 -t=linspace(0,T,N); -ind=rand(1,N)T1); -ind2=rand(1,N2)max(t1)],'Baseline','s','','',{'muConst','mu1','mu2'}); -cc=CovColl({cov}); -sampleRate=1000; -trial=Trial(spikeColl, cc); -clear c; -c{1} = TrialConfig({{'Baseline','muConst'}},sampleRate,[],[]); -c{1}.setName('Baseline'); -c{2} = TrialConfig({{'Baseline','mu1','mu2'}},sampleRate,[],[]); -c{2}.setName('Variable'); -cfgColl= ConfigColl(c); -results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); -results{1}.plotResults; -results{2}.plotResults; -figure; -subplot(1,2,1); results{1}.lambda.plot; -subplot(1,2,2); results{2}.lambda.plot; -Summary = FitResSummary(results); -Summary.plotSummary; diff --git a/parity/line_port_snapshots/mEPSCAnalysis.txt b/parity/line_port_snapshots/mEPSCAnalysis.txt deleted file mode 100644 index 5dc8cc5e..00000000 --- a/parity/line_port_snapshots/mEPSCAnalysis.txt +++ /dev/null @@ -1,48 +0,0 @@ -close all; -[~,mEPSCDir] = getPaperDataDirs(); -epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt')); -sampleRate = 1000; -spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds -nst = nspikeTrain(spikeTimes); -time = 0:(1/sampleRate):nst.maxTime; -baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',{'\mu'}); -covarColl = CovColl({baseline}); -spikeColl = nstColl(nst); -trial = Trial(spikeColl,covarColl); -clear tc tcc; -tc{1} = TrialConfig({{'Baseline','\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline'); -tcc = ConfigColl(tc); -results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); -results.plotResults; -washout1 = importdata(fullfile(mEPSCDir,'washout1.txt')); -washout2 = importdata(fullfile(mEPSCDir,'washout2.txt')); -sampleRate = 1000; -spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds -spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds -nst = nspikeTrain([spikeTimes1; spikeTimes2]); -time = 260:(1/sampleRate):nst.maxTime; -figure; -nst.plot; -timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate -timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch -constantRate = ones(length(time),1); -rate1 = zeros(length(time),1); rate1(1:timeInd1)=1; -rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1; -rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1; -baseline = Covariate(time,[constantRate,rate1, rate2, rate3],'Baseline','time','s','',{'\mu','\mu_{1}','\mu_{2}','\mu_{3}'}); -covarColl = CovColl({baseline}); -spikeColl = nstColl(nst); -trial = Trial(spikeColl,covarColl); -maxWindow=.3; numWindows=20; -delta=1/sampleRate; -windowTimes =unique(round([0 logspace(log10(delta),... -log10(maxWindow),numWindows)]*sampleRate)./sampleRate); -windowTimes = windowTimes(1:11); -clear tc tcc; -tc{1} = TrialConfig({{'Baseline','\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline'); -tc{2} = TrialConfig({{'Baseline','\mu_{1}','\mu_{2}','\mu_{3}'}},sampleRate,[]); tc{2}.setName('Diff Baseline'); -tcc = ConfigColl(tc); -results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); -results.plotResults; -Summary = FitResSummary(results); -Summary.plotSummary; diff --git a/parity/line_port_snapshots/nSTATPaperExamples.txt b/parity/line_port_snapshots/nSTATPaperExamples.txt deleted file mode 100644 index e117c2cf..00000000 --- a/parity/line_port_snapshots/nSTATPaperExamples.txt +++ /dev/null @@ -1,1576 +0,0 @@ -echo off; -close all; clear all; -[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ... -getPaperDataDirs(); -nSTATRootDir = fileparts(dataDir); -if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir) -cd(nSTATRootDir); -end -epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt')); -sampleRate = 1000; -spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds -nstConst = nspikeTrain(spikeTimes); -time = 0:(1/sampleRate):nstConst.maxTime; -baseline = Covariate(time,ones(length(time),1),'Baseline','time','s',... -'',{'\mu'}); -covarColl = CovColl({baseline}); -spikeColl = nstColl(nstConst); -trial = Trial(spikeColl,covarColl); -clear tc tcc; -tc{1} = TrialConfig({{'Baseline','\mu'}},sampleRate,[]); -tc{1}.setName('Constant Baseline'); -tcc = ConfigColl(tc); -results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); -close all; -scrsz = get(0,'ScreenSize'); -results.lambda.setDataLabels({'\lambda_{const}'}); -h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ... -scrsz(3)*.98 scrsz(4)*.95]); -subplot(2,2,1); spikeColl.plot; -title({'Neural Raster with constant Mg^{2+} Concentration'},... -'FontWeight','bold',... -'Fontsize',12,... -'FontName','Arial'); -hx=xlabel('time [s]','Interpreter','none'); -hy=ylabel('mEPSCs','Interpreter','none'); -set(gca,'yTick',[0 1]); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -subplot(2,2,3); results.KSPlot; -subplot(2,2,2); results.plotInvGausTrans; -subplot(2,2,4); results.lambda.plot([],{{' ''b'' ,''Linewidth'',2'}}); -hx=xlabel('time [s]','Interpreter','none'); -hy=get(gca,'YLabel'); -set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -h_legend = legend('\lambda_{const}','Location','NorthEast'); -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)+.05 pos(2) pos(3:4)]); -set(h_legend,'FontSize',14) -close all; -washout1 = importdata(fullfile(mEPSCDir,'washout1.txt')); -washout2 = importdata(fullfile(mEPSCDir,'washout2.txt')); -sampleRate = 1000; -spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds -spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds -nst = nspikeTrain([spikeTimes1; spikeTimes2]); -time = 260:(1/sampleRate):nst.maxTime; -scrsz = get(0,'ScreenSize'); -h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 scrsz(3)*.6 ... -scrsz(4)*.9]); -subplot(2,1,1); -nstConst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs'); -title({'Neural Raster with constant Mg^{2+} Concentration'},... -'FontWeight','bold',... -'Fontsize',12,... -'FontName','Arial'); -hx=get(gca,'XLabel'); -set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -subplot(2,1,2); -nst.plot; set(gca,'yTick',[0 1]); hy=ylabel('mEPSCs'); -title({'Neural Raster with decreasing Mg^{2+} Concentration'},... -'FontWeight','bold',... -'Fontsize',12,... -'FontName','Arial'); -hx=get(gca,'XLabel'); -set([hx,hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate -timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch -constantRate = ones(length(time),1); -rate1 = zeros(length(time),1); rate1(1:timeInd1)=1; -rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1; -rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1; -baseline = Covariate(time,[constantRate,rate1, rate2, rate3],... -'Baseline','time','s','',{'\mu','\mu_{1}','\mu_{2}','\mu_{3}'}); -covarColl = CovColl({baseline}); -spikeColl = nstColl(nst); -trial = Trial(spikeColl,covarColl); -maxWindow=.3; numWindows=20; -delta=1/sampleRate; -windowTimes =unique(round([0 logspace(log10(delta),... -log10(maxWindow),numWindows)]*sampleRate)./sampleRate); -windowTimes = windowTimes(1:11); -clear tc tcc; -tc{1} = TrialConfig({{'Baseline','\mu'}},sampleRate,[]); -tc{1}.setName('Constant Baseline'); -tc{2} = TrialConfig({{'Baseline','\mu_{1}','\mu_{2}','\mu_{3}'}},... -sampleRate,[]); tc{2}.setName('Diff Baseline'); -tcc = ConfigColl(tc); -results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); -close all; -scrsz = get(0,'ScreenSize'); -results.lambda.setDataLabels({'\lambda_{const}',... -'\lambda_{const-epoch}'}); -h=figure('OuterPosition',[scrsz(3)*.01 scrsz(4)*.04 ... -scrsz(3)*.98 scrsz(4)*.95]); -subplot(2,2,1); spikeColl.plot; -title({'Neural Raster with decreasing Mg^{2+} Concentration'},... -'FontWeight','bold',... -'Fontsize',12,... -'FontName','Arial'); -hx=xlabel('time [s]','Interpreter','none'); -set(gca,'YTickLabel',[]); -set([hx],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate -timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch -plot([495;495],[0,1],'r','Linewidth',4); hold on; -plot([765;765],[0,1],'r','Linewidth',4); -subplot(2,2,3); results.KSPlot; -subplot(2,2,2); results.plotInvGausTrans; -subplot(2,2,4); -results.lambda.getSubSignal(1).plot([],{{' ''b'' ,''Linewidth'',2'}}); -results.lambda.getSubSignal(2).plot([],{{' ''g'' ,''Linewidth'',2'}}); -v=axis; axis([v(1) v(2) 0 5]); -hx=xlabel('time [s]','Interpreter','none'); -hy=get(gca,'YLabel'); -set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -h_legend = legend('\lambda_{const}','\lambda_{const-epoch}',... -'Location','NorthEast'); -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)+.05 pos(2)-.01 pos(3:4)]); -set(h_legend,'FontSize',14) -close all; -[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ... -getPaperDataDirs(); -nSTATRootDir = fileparts(dataDir); -if exist(nSTATRootDir,'dir') == 7 && ~strcmp(pwd,nSTATRootDir) -cd(nSTATRootDir); -end -Direction=3; Neuron=1; Stim=2; -datapath = fullfile(explicitStimulusDir,['Dir' num2str(Direction)], ... -['Neuron' num2str(Neuron)],['Stim' num2str(Stim)]); -data = load(fullfile(datapath,'trngdataBis.mat')); -time=0:.001:(length(data.t)-1)*.001; -stimData = data.t; -spikeTimes = time(data.y==1); -stim = Covariate(time,stimData./10,'Stimulus','time','s','mm',{'stim'}); -baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',... -{'constant'}); -nst = nspikeTrain(spikeTimes); -nspikeColl = nstColl(nst); -cc = CovColl({stim,baseline}); -trial = Trial(nspikeColl,cc); -scrsz = get(0,'ScreenSize'); -h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]); -subplot(3,1,1); -nst2 = nspikeTrain(spikeTimes); -nst2.setMaxTime(21);nst2.plot; -set(gca,'ytick',[0 1]); -xlabel(''); -hy=ylabel('spikes'); -set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title({'Neural Raster'},'FontWeight','bold','FontSize',16,'FontName','Arial'); -set(gca, ... -'XTick' , 0:1:max(time), ... -'XTickLabel' , [],... -'LineWidth' , 1 ); -subplot(3,1,2); -stim.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off; -set(gca,'ytick',[0 0.5 1]); -hy=ylabel('Displacement [mm]','Interpreter','none'); xlabel(''); -set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title({'Stimulus - Whisker Displacement'},'FontWeight','bold',... -'FontSize',16,'FontName','Arial'); -set(gca, ... -'XTick' , 0:1:max(time), ... -'XTickLabel' , [],... -'YTick' , 0:.25:1, ... -'LineWidth' , 1 ); -subplot(3,1,3); -stim.derivative.getSigInTimeWindow(0,21).plot([],{{' ''k'' '}}); legend off; -set(gca,'ytick',[-80 0 80]); -axis([0 21 -80 80]); -hy=ylabel('Displacement Velocity [mm/s]','Interpreter','none'); -hx= xlabel('time [s]','Interpreter','none'); -set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title({'Displacement Velocity'},'FontWeight','bold',... -'FontSize',16,'FontName','Arial'); -set(gca, ... -'XTick' , 0:1:max(time), ... -'YTick' , -80:40:80, ... -'LineWidth' , 1 ); -clear c; close all; -selfHist = [] ; NeighborHist = []; sampleRate = 1000; -c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist); -c{1}.setName('Baseline'); -cfgColl= ConfigColl(c); -results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); -scrsz = get(0,'ScreenSize'); -h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]); -subplot(7,2,[1 3 5]) -results.Residual.xcov(stim).windowedSignal([0,1]).plot; -ylabel(''); -[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1])); -title(['Cross Correlation Function - Peak at t=' num2str(ShiftTime) ' sec'],'FontWeight','bold',... -'FontSize',12,... -'FontName','Arial'); -hold on; -h=plot(ShiftTime,m,'ro','Linewidth',3); -set(h, 'MarkerFaceColor',[1 0 0], 'MarkerEdgeColor',[1 0 0]); -hx=xlabel('Lag [s]','Interpreter','none'); -set(hx,'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'}); -stim = stim.shift(ShiftTime); -baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',... -{'\mu'}); -nst = nspikeTrain(spikeTimes); -nspikeColl = nstColl(nst); -cc = CovColl({stim,baseline}); -trial2 = Trial(nspikeColl,cc); -clear c; -selfHist = [] ; NeighborHist = []; sampleRate = 1000; -c{1} = TrialConfig({{'Baseline','\mu'}},sampleRate,selfHist,... -NeighborHist); -c{1}.setName('Baseline'); -c{2} = TrialConfig({{'Baseline','\mu'},{'Stimulus','stim'}},... -sampleRate,selfHist,NeighborHist); -c{2}.setName('Baseline+Stimulus'); -cfgColl= ConfigColl(c); -results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0); -sampleRate=1000; -delta=1/sampleRate*1; -maxWindow=1; numWindows=32; -windowTimes =unique(round([0 logspace(log10(delta),... -log10(maxWindow),numWindows)]*sampleRate)./sampleRate); -results =Analysis.computeHistLagForAll(trial2,windowTimes,... -{{'Baseline','\mu'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0); -KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat)); -AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ... -min(results{1}.AIC(2:end)-results{1}.AIC(1))) +1; -BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ... -min(results{1}.BIC(2:end)-results{1}.BIC(1))) +1; -if(AICind==1) -AICind=inf; -end -if(BICind==1) -BICind=inf; %sometime BIC is non-decreasing and the index would be 1 -end -windowIndex = min([AICind,BICind]) %use the minimum order model -Summary = FitResSummary(results); -clear c; -if(windowIndex>1) -selfHist = windowTimes(1:windowIndex+1); -else -selfHist = []; -end -NeighborHist = []; sampleRate = 1000; -subplot(7,2,2); -x=0:length(windowTimes)-1; -plot(x,results{1}.KSStats.ks_stat,'.-'); axis tight; hold on; -plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*'); -set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],... -'TickLength', [.02 .02] , ... -'XMinorTick', 'on','LineWidth' , 1); -hy=ylabel('KS Statistic'); -set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -dAIC = results{1}.AIC-results{1}.AIC(1); -title({'Model Selection via change'; 'in KS Statistic, AIC, and BIC'},... -'FontWeight','bold',... -'FontSize',12,... -'FontName','Arial'); -subplot(7,2,4); plot(x,dAIC,'.-'); -set(gca,'XTick', 0:5:results{1}.numResults-1,'XTickLabel',[],... -'TickLength', [.02 .02] , ... -'XMinorTick', 'on','LineWidth' , 1); -hy=ylabel('\Delta AIC');axis tight; hold on; -set(hy,'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -plot(x(windowIndex),dAIC(windowIndex),'r*'); -dBIC = results{1}.BIC-results{1}.BIC(1); -subplot(7,2,6); plot(x,dBIC,'.-'); -hy=ylabel('\Delta BIC'); axis tight; hold on; -plot(x(windowIndex),dBIC(windowIndex),'r*'); -hx=xlabel('# History Windows, Q'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -set(gca, ... -'TickLength' , [.02 .02] , ... -'XMinorTick' , 'on' , ... -'XTick' , 0:5:results{1}.numResults-1, ... -'LineWidth' , 1 ); -c{1} = TrialConfig({{'Baseline','\mu'}},sampleRate,[],NeighborHist); -c{1}.setName('Baseline'); -c{2} = TrialConfig({{'Baseline','\mu'},{'Stimulus','stim'}},... -sampleRate,[],[]); -c{2}.setName('Baseline+Stimulus'); -c{3} = TrialConfig({{'Baseline','\mu'},{'Stimulus','stim'}},... -sampleRate,windowTimes(1:windowIndex),[]); -c{3}.setName('Baseline+Stimulus+Hist'); -cfgColl= ConfigColl(c); -results = Analysis.RunAnalysisForAllNeurons(trial2,cfgColl,0); -results.lambda.setDataLabels({'\lambda_{const}','\lambda_{const+stim}',... -'\lambda_{const+stim+hist}'}); -subplot(7,2,[9 11 13]); results.KSPlot; -subplot(7,2,[10 12 14]); results.plotCoeffs; legend off; -clear all; -[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ... -getPaperDataDirs(); -close all; -delta = 0.001; -Tmax = 1; -time = 0:delta:Tmax; -f=2; -mu = -3; -tempData = 1*sin(2*pi*f*time)+mu; %lambda >=0 -lambdaData = exp(tempData)./(1+exp(tempData))*(1/delta); -lambda = Covariate(time,lambdaData, '\lambda(t)','time','s',... -'spikes/sec',{'\lambda_{1}'},{{' ''b'', ''LineWidth'' ,2'}}); -numRealizations = 20; -spikeCollSim = CIF.simulateCIFByThinningFromLambda(lambda,numRealizations); -scrsz = get(0,'ScreenSize'); -h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]); -subplot(2,2,3);spikeCollSim.plot; -set(gca,'YTick',0:5:numRealizations,'YTickLabel',0:5:numRealizations); -title({[num2str(numRealizations) ' Simulated Point Process Sample Paths']},... -'FontWeight','bold','Fontsize',14,'FontName','Arial'); -xlabel('time [s]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -subplot(2,2,1);lambda.plot; -title({'Simulated Conditional Intensity Function (CIF)'},... -'FontWeight','bold','FontSize',14,'FontName','Arial'); -xlabel('time [s]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -hy=get(gca,'YLabel'); -set(hy,'FontName', 'Arial','FontSize',14,'FontWeight','bold'); -x = load(fullfile(psthDir,'Results.mat')); -numTrials = x.Results.Data.Spike_times_STC.balanced_SUA.Nr_trials; -cellNum=6; clear nst; -for i=1:numTrials -spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum}; -nst{i} = nspikeTrain(spikeTimes{i}); -nst{i}.setName(num2str(cellNum)); -end -spikeCollReal1=nstColl(nst); -spikeCollReal1.setMinTime(0); spikeCollReal1.setMaxTime(2); -subplot(2,2,2);spikeCollReal1.plot; set(gca,'YTick',0:2:numTrials,... -'YTickLabel',0:2:numTrials); -xlabel('time [s]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -title('Response to Moving Visual Stimulus (Neuron 6)',... -'FontWeight','bold','Fontsize',14,'FontName','Arial'); -cellNum=1; clear nst; -for i=1:numTrials -spikeTimes{i}=x.Results.Data.Spike_times_STC.balanced_SUA.spike_times{1,i,cellNum}; -nst{i} = nspikeTrain(spikeTimes{i}); -nst{i}.setName(num2str(cellNum)); -end -spikeCollReal2=nstColl(nst); -spikeCollReal2.setMinTime(0); spikeCollReal2.setMaxTime(2); -subplot(2,2,4);spikeCollReal2.plot; -set(gca,'YTick',0:2:numTrials,'YTickLabel',0:2:numTrials); -xlabel('time [s]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -title('Response to Moving Visual Stimulus (Neuron 1)','FontWeight',... -'bold','Fontsize',14,'FontName','Arial'); -close all; -scrsz = get(0,'ScreenSize'); -h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]); -binsize = .05; %50ms window -psth = spikeCollSim.psth(binsize); -psthGLM = spikeCollSim.psthGLM(binsize); -true = lambda; %rate*delta = expected number of arrivals per bin -subplot(2,3,4); -h1=true.plot([],{{' ''b'',''Linewidth'',4'}}); -h3=psthGLM.plot([],{{' ''k'',''Linewidth'',4'}}); -h2=psth.plot([],{{' ''rx'',''Linewidth'',4'}}); -xlabel('time [s]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -legend off; -h_legend=legend([h1(1) h2(1) h3(1)],'true','PSTH','PSTH_{glm}'); -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)+.005 pos(2)+.095 pos(3:4)]); -subplot(2,3,1);spikeCollSim.plot; -set(gca,'YTick',0:2:spikeCollSim.numSpikeTrains,'YTickLabel',0:2:spikeCollSim.numSpikeTrains); -xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -subplot(2,3,5); -binsize = .05; %50ms window -psthReal1 = spikeCollReal1.psth(binsize); -psthGLMReal1 = spikeCollReal1.psthGLM(binsize);%,[],[],[],[],[],1000); -h3=psthGLMReal1.plot([],{{' ''k'',''Linewidth'',4'}}); -h2=psthReal1.plot([],{{' ''rx'',''Linewidth'',4'}}); -xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}'); -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]); -subplot(2,3,2); spikeCollReal1.plot; -set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains); -xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -subplot(2,3,6); -psthReal2 = spikeCollReal2.psth(binsize); -psthGLMReal2 = spikeCollReal2.psthGLM(binsize);%,[],[],[],[],[],1000); -h3=psthGLMReal2.plot([],{{' ''k'',''Linewidth'',4'}}); -h2=psthReal2.plot([],{{' ''rx'',''Linewidth'',4'}}); -xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -ylabel('[spikes/sec]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -h_legend=legend([h2(1) h3(1)],'PSTH','PSTH_{glm}'); -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)+.005 pos(2)+.07 pos(3:4)]); -subplot(2,3,3); spikeCollReal2.plot; -set(gca,'YTick',0:2:spikeCollReal2.numSpikeTrains,'YTickLabel',0:2:spikeCollReal2.numSpikeTrains); -xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -close all; -clear all; -[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ... -getPaperDataDirs(); -delta = 0.001; Tmax = 1; -time = 0:delta:Tmax; -Ts=.001; -numRealizations = 50; %Each realization corresponds to a distinct trial -for i=1:numRealizations -f=2; b1(i)=3*((i)/numRealizations);b0=-3; -u = sin(2*pi*f*time); -e = zeros(length(time),1); %No Ensemble input -stim=Covariate(time',u,'Stimulus','time','s','Voltage',{'sin'}); -ens =Covariate(time',e,'Ensemble','time','s','Spikes',{'n1'}); -mu=b0; -histCoeffs=[-4 -1 -.5]; -H=tf(histCoeffs,[1],Ts,'Variable','z^-1'); -S=tf([b1(i)],1,Ts,'Variable','z^-1'); -E=tf([0],1,Ts,'Variable','z^-1'); -simTypeSelect='binomial'; %Parameters are used to compute -[sC, lambdaTemp]=CIF.simulateCIF(mu,H,S,E,stim,ens,1,simTypeSelect); -if(i==1) -lambda=lambdaTemp; %Store the conditional intensity function -else -lambda = lambda.merge(lambdaTemp); %Add it to the other realizations -end -nst{i} = sC.getNST(1); %get the neural spikeTrain from the collection -nst{i} = nst{i}.resample(1/delta); %make sure that it is sampled at the current samplerate -end -spikeColl = nstColl(nst); %Create a collection of the spike trains across trials -close all; -scrsz = get(0,'ScreenSize'); -h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]); -subplot(3,2,[3 4]); spikeColl.plot; -set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations); -set(gca,'xtick',0:.1:Tmax,'xtickLabel',0:.1:Tmax); xlabel(''); -xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -ylabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -title('Simulated Neural Raster','Interpreter','none','FontName', 'Arial',... -'Fontsize',14,'FontWeight','bold'); -stimData = exp(b0 + u'*b1); -if(strcmp(simTypeSelect,'binomial')) -stimData = stimData./(1+stimData); -end -subplot(3,2,1); plot(time,u,'k','LineWidth',3); -xlabel('time [s]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -ylabel('Stimulus','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -title('Within Trial Stimulus','Interpreter','none','FontName', 'Arial',... -'Fontsize',14,'FontWeight','bold'); -subplot(3,2,2); plot(1:length(b1),b1,'k','LineWidth',3); -xlabel('Trial [k]','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -ylabel('Stimulus Gain','Interpreter','none','FontName', 'Arial','Fontsize',... -12,'FontWeight','bold'); -title('Across Trial Stimulus Gain','Interpreter','none','FontName',... -'Arial','Fontsize',14,'FontWeight','bold'); -subplot(3,2,[5 6]); -imagesc(stimData'./delta); set(gca, 'YDir','normal'); -set(gca,'xtick',0:100:Tmax/delta,'xtickLabel',0:.1:Tmax); -set(gca,'ytick',0:10:numRealizations,'ytickLabel',0:10:numRealizations); -xlabel('time [s]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -ylabel('Trial [k]','Interpreter','none','FontName', 'Arial',... -'Fontsize',12,'FontWeight','bold'); -title('True Conditional Intensity Function','Interpreter',... -'none','FontName', 'Arial','Fontsize',14,'FontWeight','bold'); -axis tight; -stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'}); -baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',... -{'constant'}); -windowTimes=[0:.001:.003]; -numBasis = 25; -spikeColl.resample(1/delta); % Enforce sampleRate -spikeColl.setMaxTime(Tmax); % Make all spikeTrains end at time Tmax -dN=spikeColl.dataToMatrix'; % Convert the spikeTrains into a matrix -dN(dN>1)=1; % One should sample finely enough so there is -basisWidth=(spikeColl.maxTime-spikeColl.minTime)/numBasis; -if(simTypeSelect==0) -fitType='binomial'; -else -fitType='poisson'; -end -if(strcmp(fitType,'binomial')) -Algorithm = 'BNLRCG'; % BNLRCG - faster Truncated, L-2 Regularized, -else -Algorithm = 'GLM'; % Standard Matlab GLM (Can be used for binomial or -end -[psthSig, ~, psthResult] =spikeColl.psthGLM(basisWidth,windowTimes,fitType); -gamma0=psthResult.getHistCoeffs';%+.1*randn(size(histCoeffs)); -gamma0(isnan(gamma0))=-5; % Depending on the amount of data the -x0=psthResult.getCoeffs; %The initial estimate for the SSGLM model -numVarEstIter=10; -Q0 = spikeColl.estimateVarianceAcrossTrials(numBasis,windowTimes,... -numVarEstIter,fitType); -A=eye(numBasis,numBasis); -delta = 1/spikeColl.sampleRate; -CompilingHelpFile=1; -if(~CompilingHelpFile) -Q0d=diag(Q0); -neuronName = psthResult.neuronNumber; -[xK,WK, WkuFinal,Qhat,gammahat,fitResults,stimulus,stimCIs,logll,... -QhatAll,gammahatAll,nIter]=DecodingAlgorithms.PPSS_EMFB(A,Q0d,x0,... -dN,fitType,delta,gamma0,windowTimes, numBasis,neuronName); -fR = fitResults.toStructure; -psthR = psthResult.toStructure; -end -installPath = which('nSTAT_Install'); -if isempty(installPath) -error('nSTATPaperExamples:MissingInstallPath', ... -'Could not locate nSTAT_Install.m on MATLAB path.'); -end -nstatRoot = fileparts(installPath); -if exist(nstatRoot,'dir') == 7 && ~strcmp(pwd,nstatRoot) -cd(nstatRoot); -end -addpath(nstatRoot,'-begin'); -load(fullfile(nstatRoot,'data','SSGLMExampleData.mat')); -fitResults = FitResult.fromStructure(fR); -psthResult = FitResult.fromStructure(psthR); -t=psthResult.mergeResults(fitResults); -t.lambda.setDataLabels({'\lambda_{PSTH}','\lambda_{SSGLM}'}); -scrsz = get(0,'ScreenSize'); -h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]); -subplot(2,2,1); t.KSPlot; -subplot(2,2,2); t.plotResidual; -subplot(2,2,3); t.plotInvGausTrans; -subplot(2,2,4); t.plotSeqCorr; -S=FitResSummary(t); -dAIC=diff(S.AIC) -dBIC=diff(S.BIC) -dKS =diff(S.KSStats); -close all; -minTime=0; maxTime = Tmax; -stimData = stim.data*b1; -if(strcmp(fitType,'poisson')) -actStimEffect=exp(stimData + b0)./delta; -elseif(strcmp(fitType,'binomial')) -actStimEffect=exp(stimData + b0)./(1+exp(stimData + b0))./delta; -end -if(~isempty(numBasis)) -basisWidth = (maxTime-minTime)/numBasis; -sampleRate=1/delta; -unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,minTime,... -maxTime,sampleRate); -basisMat = unitPulseBasis.data; -end -if(strcmp(fitType,'poisson')) -estStimEffect=exp(basisMat*xK)./delta; -elseif(strcmp(fitType,'binomial')) -estStimEffect=exp(basisMat*xK)./(1+exp(basisMat*xK))./delta; -end -scrsz = get(0,'ScreenSize'); -h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]); -subplot(3,1,[1 2 3]); -lighting gouraud -surf((1:length(b1))',stim.time,actStimEffect,'FaceAlpha',0.1,... -'EdgeAlpha',0.1,'AlphaData',0.1); -hx=xlabel('Trial [k]'); hy=ylabel('time [s]'); -hz=zlabel('Stimulus Effect [spikes/sec]'); hold all; -set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -surf((1:length(b1))',stim.time,estStimEffect(:,1:length(b1)),... -'FaceAlpha',0.5,'EdgeAlpha',0.1,'AlphaData',0.5); %xlabel('Trial [k]'); ylabel('time [s]'); zlabel('Stimulus Effect'); -set(gca,'YDir','reverse'); -set(gca,'ytick',0:.1:Tmax,'ytickLabel',0:.1:Tmax); -title('SSGLM Estimated vs. Actual Stimulus Effect','FontWeight','bold',... -'Fontsize',14,... -'FontName','Arial'); -close all; -h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.4 scrsz(4)*.8]); -subplot(3,1,1); -lighting gouraud -mesh((1:length(b1))',stim.time,actStimEffect); -hx=xlabel('Trial [k]'); hy=ylabel('time [s]'); -zlabel('Stimulus Effect [spikes/sec]'); hold all; -set([hx hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title('True Stimulus Effect','FontWeight','bold',... -'Fontsize',14,... -'FontName','Arial'); -set(gca,'xtick',[],'xtickLabel',[]); -set(gca,'ytick',[],'ytickLabel',[]); -CLIM = [min(min(stimData./delta)) max(max(stimData./delta))]; -view(gca,[90 -90]); -subplot(3,1,2); -lighting gouraud -mesh((1:length(b1))',stim.time,repmat(psthSig.data, [1 numRealizations])); -hx=xlabel('Trial [k]'); hy=ylabel('time [s]'); -hz=zlabel('Stimulus Effect [spikes/sec]'); hold all; -set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title('PSTH Estimated Stimulus Effect','FontWeight','bold',... -'Fontsize',14,... -'FontName','Arial'); -set(gca,'xtick',[],'xtickLabel',[]); -set(gca,'ytick',[],'ytickLabel',[]); -CLIM = [min(min(stimData./delta)) max(max(stimData./delta))]; -view(gca,[90 -90]); -subplot(3,1,3); -lighting gouraud -mesh((1:length(b1))',stim.time,estStimEffect); -xlabel('Trial [k]'); ylabel('time [s]'); -zlabel('Stimulus Effect [spikes/sec]'); hold all; -hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); hz=get(gca,'ZLabel'); -set([hx hy hz],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title('SSGLM Estimated Stimulus Effect','FontWeight','bold',... -'Fontsize',14,... -'FontName','Arial'); -set(gca,'xtick',[],'xtickLabel',[]); -set(gca,'ytick',[],'ytickLabel',[]); -set(gca, 'YDir','normal') -view(gca,[90 -90]); -echo off; -close all; -minTime=0; maxTime = Tmax; -if(~isempty(numBasis)) -basisWidth = (maxTime-minTime)/numBasis; -sampleRate=1/delta; -unitPulseBasis=nstColl.generateUnitImpulseBasis(basisWidth,... -minTime,maxTime,sampleRate); -basisMat = unitPulseBasis.data; -end -t0=0; tf=Tmax; -[spikeRateBinom, ProbMat,sigMat]=DecodingAlgorithms.computeSpikeRateCIs(xK,... -WkuFinal,dN,t0,tf,fitType,delta,gammahat,windowTimes); -lt=find(sigMat(1,:)==1,1,'first'); -display(['The learning trial (compared to the first trial) is trial #' ... -num2str(find(sigMat(1,:)==1,1,'first'))]); -scrsz = get(0,'ScreenSize'); -h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.8]); -subplot(2,3,1); -spikeRateBinom.setName(['(' num2str(Tmax) '-0)^-1*\Lambda(0,' ... -num2str(Tmax) ')']); -spikeRateBinom.plot([],{{' ''k'',''Linewidth'',4'}}); -v=axis; -plot(lt*[1;1],v(3:4),'r','Linewidth',2); -hx=xlabel('Trial [k]','Interpreter','none'); hold all; -hy=ylabel('Average Firing Rate [spikes/sec]','Interpreter','none'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title(['Learning Trial:' num2str(lt)],'FontWeight','bold',... -'Fontsize',12,... -'FontName','Arial'); -h=subplot(2,3,[2 3 5 6]); -K=size(dN,1); -colormap(flipud(gray)); -imagesc(ProbMat); hold on; -for k=1:K -for m=(k+1):K -if(sigMat(k,m)==1) -plot3(m,k,1,'r*'); hold on; -end -end -end -set(h,'XAxisLocation','top','YAxisLocation','right'); -hx=xlabel('Trial Number','Interpreter','none'); hold all; -hy=ylabel('Trial Number','Interpreter','none'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -subplot(2,3,4) -stim1 = Covariate(time, basisMat*stimulus(:,1),'Trial1','time','s',... -'spikes/sec'); -temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,1,:))); -stim1.setConfInterval(temp); -stimlt = Covariate(time, basisMat*stimulus(:,lt),'Trial1','time','s',... -'spikes/sec'); -temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt,:))); -temp.setColor('r'); -stimlt.setConfInterval(temp); -stimltm1 = Covariate(time, basisMat*stimulus(:,lt-1),'Trial1','time','s',... -'spikes/sec'); -temp = ConfidenceInterval(time, basisMat*squeeze(stimCIs(:,lt-1,:))); -temp.setColor('r'); -stimltm1.setConfInterval(temp); -h1=stim1.plot([],{{' ''k'',''Linewidth'',4'}}); hold all; -h2=stimlt.plot([],{{' ''r'',''Linewidth'',4'}}); -hx=xlabel('time [s]','Interpreter','none'); hold all; -hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title({'Learning Trial Vs. Baseline Trial';'with 95% CIs'},'FontWeight','bold',... -'Fontsize',12,... -'FontName','Arial'); -h_legend=legend([h1(1) h2(1)],'\lambda_{1}(t)',['\lambda_{' num2str(lt) '}(t)']); -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)+.03 pos(2)+.01 pos(3:4)]); -close all; -load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat')); -exampleCell = [2 21 25 49]; -scrsz = get(0,'ScreenSize'); -h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.9]); -for i=1:length(exampleCell) -subplot(2,2,i); -h1=plot(x,y,'b','Linewidth',.5); hold on; -h2=plot(neuron{exampleCell(i)}.xN,neuron{exampleCell(i)}.yN,'r.',... -'MarkerSize',7); -hx=xlabel('X Position'); hy=ylabel('Y Position'); -title(['Cell#' num2str(exampleCell(i))],'FontWeight','bold',... -'Fontsize',12,'FontName','Arial'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -set(gca,'xTick',-1:.5:1,'yTick',-1:.5:1); axis square; -if(i==4) -h_legend = legend([h1 h2],'Animal Path',... -'Location at time of spike'); -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)+.09 pos(2)+.06 pos(3:4)]); -end -end -numAnimals=2; -CompilingHelpFile=1; -if(~CompilingHelpFile) -for n=1:numAnimals -clear x y neuron time nst tc tcc z; -load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat'])); -for i=1:length(neuron) -nst{i} = nspikeTrain(neuron{i}.spikeTimes); -end -[theta,r] = cart2pol(x,y); -cnt=0; -for l=0:3 -for m=-l:l -if(~any(mod(l-m,2))) % otherwise the polynomial = 0 -cnt = cnt+1; -z(:,cnt) = zernfun(l,m,r,theta,'norm'); -end -end -end -delta=min(diff(time)); -sampleRate = round(1/delta); -baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',... -{'mu'}); -zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3',... -'z4','z5','z6','z7','z8','z9','z10'}); -gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time',... -'s','m',{'x','y','x^2','y^2','x*y'}); -covarColl = CovColl({baseline,gaussian,zernike}); -spikeColl = nstColl(nst); -trial = Trial(spikeColl,covarColl); -tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian',... -'x','y','x^2','y^2','x*y'}},sampleRate,[]); -tc{1}.setName('Gaussian'); -tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6',... -'z7','z8','z9','z10'}},sampleRate,[]); -tc{2}.setName('Zernike'); -tcc = ConfigColl(tc); -results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); -resStruct =FitResult.CellArrayToStructure(results); -filename = fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results']); -save(filename,'resStruct'); -end -end -clear Summary; -numAnimals =2; -for n=1:numAnimals -resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat'])); -results = FitResult.fromStructure(resData.resStruct); -Summary{n} = FitResSummary(results); -end -close all; -scrsz = get(0,'ScreenSize'); -h=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.6 scrsz(4)*.5]); -subplot(1,3,1); -maxLength = max([Summary{1}.numNeurons,Summary{2}.numNeurons]); -dKS = nan(maxLength, 2); -dKS(1:Summary{1}.numNeurons,1) = (Summary{1}.KSStats(:,1)-Summary{1}.KSStats(:,2)) ; -dKS(1:Summary{2}.numNeurons,2) = (Summary{2}.KSStats(:,1)-Summary{2}.KSStats(:,2)) ; -boxplot(dKS ,{'Animal 1', 'Animal 2'},'labelorientation','inline'); -title('\Delta KS Statistic','FontWeight','bold','FontSize',14,... -'FontName','Arial'); -subplot(1,3,2); -dAIC = nan(maxLength, 2); -dAIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffAIC(1); -dAIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffAIC(1); -boxplot(dAIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline'); -title('\Delta AIC','FontWeight','bold','FontSize',14,'FontName','Arial'); -subplot(1,3,3); -dBIC = nan(maxLength, 2); -dBIC(1:Summary{1}.numNeurons,1) = Summary{1}.getDiffBIC(1); -dBIC(1:Summary{2}.numNeurons,2) = Summary{2}.getDiffBIC(1); -boxplot(dBIC ,{'Animal 1', 'Animal 2'},'labelorientation','inline'); %ylabel('\Delta BIC'); %xticklabel_rotate([],45,[],'Fontsize',6); -title('\Delta BIC','FontWeight','bold','FontSize',14,'FontName','Arial'); -close all; -[x_new,y_new]=meshgrid(-1:.01:1); %define new x and y -y_new = flipud(y_new); x_new = fliplr(x_new); -[theta_new,r_new] = cart2pol(x_new,y_new); -newData{1} =ones(size(x_new)); -newData{2} =x_new; newData{3} =y_new; -newData{4} =x_new.^2; newData{5} =y_new.^2; -newData{6} =x_new.*y_new; -idx = r_new<=1; -zpoly = cell(1,10); -cnt=0; -for l=0:3 -for m=-l:l -if(~any(mod(l-m,2))) -cnt = cnt+1; -temp = nan(size(x_new)); -temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm'); -zpoly{cnt} = temp; -end -end -end -for n=1:numAnimals -clear lambdaGaussian lambdaZernike; -load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat'])); -resData = load(fullfile(dataDir,['PlaceCellAnimal' num2str(n) 'Results.mat'])); -results = FitResult.fromStructure(resData.resStruct); -for i=1:length(neuron) -lambdaGaussian{i} = results{i}.evalLambda(1,newData); -lambdaZernike{i} = results{i}.evalLambda(2,zpoly); -end -for i=1:length(neuron) -if(n==1) -h4=figure(4); -colormap('jet'); -if(i==1) -tb=annotation(h4,'textbox',... -[0.283261904761904 0.928571428571418 ... -0.392857142857143 0.0595238095238095],... -'String',{['Gaussian Place Fields - Animal#' ... -num2str(n)]},'FitBoxToText','on','Fontsize',11,... -'FontName','Arial','FontWeight','bold','LineStyle',... -'none','HorizontalAlignment','center'); hold on; -end -subplot(7,7,i); -elseif(n==2) -h6=figure(6); -colormap('jet'); -if(i==1) -annotation(h6,'textbox',... -[0.283261904761904 0.928571428571418 ... -0.392857142857143 0.0595238095238095],... -'String',{['Gaussian Place Fields - Animal#' ... -num2str(n)]},'FitBoxToText','on','Fontsize',11,... -'FontName','Arial','FontWeight','bold','LineStyle',... -'none','HorizontalAlignment','center'); hold on; -end -subplot(6,7,i); -end -pcolor(x_new,y_new,lambdaGaussian{i}), shading interp -axis square; set(gca,'xtick',[],'ytick',[]); -set(gca, 'Box' , 'off'); -if(n==1) -h5=figure(5); -colormap('jet'); -if(i==1) -annotation(h5,'textbox',... -[0.303261904761904 0.928571428571418 ... -0.392857142857143 0.0595238095238095],... -'String',{['Zernike Place Fields - Animal#' ... -num2str(n)]},'FitBoxToText','on','Fontsize',11,... -'FontName','Arial','FontWeight','bold','LineStyle','none'); hold on; -end -subplot(7,7,i); -elseif(n==2) -h7=figure(7); -colormap('jet'); -if(i==1) -annotation(h7,'textbox',... -[0.303261904761904 0.928571428571418 ... -0.392857142857143 0.0595238095238095],... -'String',{['Zernike Place Fields - Animal#' ... -num2str(n)]},'FitBoxToText','on','Fontsize',11,... -'FontName','Arial','FontWeight','bold','LineStyle',... -'none','HorizontalAlignment','center'); hold on; -end -subplot(6,7,i); -end -pcolor(x_new,y_new,lambdaZernike{i}), shading interp -axis square; -set(gca,'xtick',[],'ytick',[]); -set(gca, 'Box' , 'off'); -end -end -clear lambdaGaussian lambdaZernike; -load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat')); -resData = load(fullfile(dataDir,'PlaceCellAnimal1Results.mat')); -results = FitResult.fromStructure(resData.resStruct); -for i=1:length(neuron) -lambdaGaussian{i} = results{i}.evalLambda(1,newData); -lambdaZernike{i} = results{i}.evalLambda(2,zpoly); -end -exampleCell = 25; -close all; -h9=figure(9); -h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0); -get(h_mesh,'AlphaData'); -set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','b'); -hold on; -h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0); -get(h_mesh,'AlphaData'); -set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.2,'EdgeColor','g'); -plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.'); -axis tight square; -xlabel('x position'); ylabel('y position'); -title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',... -'Fontsize',12,'FontName','Arial'); -hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -close all; clear all; -[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ... -getPaperDataDirs(); -delta = 0.001; Tmax = 1; -time = 0:delta:Tmax; -numRealizations = 20; -f=2; b1=randn(numRealizations,1);b0=log(10*delta)+randn(numRealizations,1); -x = sin(2*pi*f*time); -clear nst; -for i=1:numRealizations -expData = exp(b1(i)*x+b0(i)); -lambdaData = expData./(1+expData); -if(i==1) -lambda = Covariate(time,lambdaData./delta, ... -'\Lambda(t)','time','s','spikes/sec',{'\lambda_{1}'},... -{{' ''b'', ''LineWidth'' ,2'}}); -else -tempLambda = Covariate(time,lambdaData./delta, ... -'\Lambda(t)','time','s','spikes/sec',{'\lambda_{1}'},... -{{' ''b'', ''LineWidth'' ,2'}}); -lambda = lambda.merge(tempLambda); -end -spikeColl = CIF.simulateCIFByThinningFromLambda(... -lambda.getSubSignal(i),1); -nst{i} = spikeColl.getNST(1); -end -spikeColl = nstColl(nst);scrsz = get(0,'ScreenSize'); -h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 ... -scrsz(3)*.6 scrsz(4)*.8]); -subplot(3,1,1); plot(time,x,'k'); -set(gca,'xtick',[],'xtickLabel',[]); ylabel('Stimulus'); -hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title('Driving Stimulus','FontWeight','bold',... -'FontSize',14,'FontName','Arial'); -subplot(3,1,2); lambda.plot([],{{' ''k'',''Linewidth'',1'}}); -legend off; -hy=ylabel('Firing Rate [spikes/sec]', 'Interpreter','none'); -hx=xlabel('','Interpreter','none'); -set([hx, hy],'FontName', 'Arial','FontSize',12,... -'FontWeight','bold'); -set(gca,'xtickLabel',[]); -title('Conditional Intensity Functions','FontWeight',... -'bold','FontSize',14,'FontName','Arial'); -subplot(3,1,3); spikeColl.plot; -set(gca,'ytick',0:10:numRealizations,'ytickLabel',... -0:10:numRealizations); -xlabel('time [s]','Interpreter','none'); -ylabel('Cell Number','Interpreter','none'); -hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title('Point Process Sample Paths','FontWeight',... -'bold','FontSize',14,'FontName','Arial'); -stim = Covariate(time,sin(2*pi*f*time),'Stimulus','time','s','V',{'stim'}); -baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',... -{'constant'}); -close all; -clear lambdaCIF; -spikeColl.resample(1/delta); -dN=spikeColl.dataToMatrix; -Q=std(stim.data(2:end)-stim.data(1:end-1)); -Px0=.1; A=1; -x0 = x(:,1); yT=x(:,end); -Pi0 = eps*eye(size(x0,1),size(x0,1)); -PiT = eps*eye(size(x0,1),size(x0,1)); -[x_p, W_p, x_u, W_u] = DecodingAlgorithms.PPDecodeFilterLinear(A, ... -Q, dN',b0,b1','binomial',delta); -h=figure('Position',[scrsz(3)*.1 scrsz(4)*.1 scrsz(3)*.8 scrsz(4)*.6]); -zVal=1.96; -ciLower = min(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',... -x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))')); -ciUpper = max(x_u(1:end)-zVal*sqrt(squeeze(W_u(1:end)))',... -x_u(1:end)+zVal*sqrt(squeeze(W_u(1:end))')); -estimatedStimulus = Covariate(time,x_u(1:end),'\hat{x}(t)','time','s',''); -CI= ConfidenceInterval(time,[ciLower', ciUpper'],'\hat{x}(t)','time','s',''); -estimatedStimulus.setConfInterval(CI); -hEst = estimatedStimulus.plot([],{{' ''k'',''Linewidth'',4'}}); -hStim=stim.plot([],{{' ''b'',''Linewidth'',4'}}); -legend off; -h_legend=legend([hEst(1) hStim],'Decoded','Actual'); -set(h_legend,'Interpreter','none'); -set(h_legend,'FontSize',22); -title(['Decoded Stimulus +/- 95% CIs with ' num2str(numRealizations) ' cells'],... -'FontWeight','bold','Fontsize',22,'FontName','Arial'); -xlabel('time [s]','Interpreter','none'); -ylabel('Stimulus','Interpreter','none'); -hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); -set([hx, hy],'FontName', 'Arial','FontSize',22,'FontWeight','bold'); -close all; -clear all; -[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ... -getPaperDataDirs(); -q=1e-4; -Q=diag([1e-12 1e-12 q q]); -delta = .001; % Time increment -r=1e-6; % in meters^2 -p=1e-6; % in meters^2/s^2 -PiT=diag([r r p p]); % Uncertainty in the target state -Pi0=PiT; -T=2; % Reach Duration -x0 = [0;0;0;0]; % Initial Position and velocities (states) -xT = [-.35;.2; 0;0];% Final Target -time=0:delta:T; % time vector -A=[1 0 delta 0 ; %State transition matrix -0 1 0 delta; -0 0 1 0 ; -0 0 0 1 ]; -x=zeros(4,length(time)); -R=chol(Q); -L=chol(PiT); -for k=1:length(time) -if(k==1) -x(:,k)=x0; -else -x(:,k)=A*x(:,k-1)+... -delta/(2)*(pi/T)^2*cos(pi*time(k)/T)*[0;0;... -xT(1)-x0(1);xT(2)-x0(2)]; %Reach to target model -end -end -xT =x(:,end); % The target generated by the model -yT=xT; % Assume we have observed the actual target position with uncertainty PiT -Q=diag(var(diff(x,[],2),[],2))*100; -scrsz = get(0,'ScreenSize'); -fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ... -scrsz(3)*.8 scrsz(4)*.8]); -subplot(4,2,[1 3]); -plot(100*x(1,:),100*x(2,:),'k','Linewidth',2); -xlabel('X Position [cm]'); ylabel('Y Position [cm]'); -hx=get(gca,'XLabel'); hy=get(gca,'YLabel'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -title('Reach Path','FontWeight','bold','Fontsize',14,'FontName','Arial'); -hold on; -axis([sort([100*x0(1)+5, 100*xT(1)-5]), sort([100*x0(2)-5, 100*xT(2)+5])]); -h1=plot(100*x(1,1),100*x(2,1),'bo','MarkerSize',14); -h2=plot(100*x(1,end),100*x(2,end),'ro','MarkerSize',14); -legend([h1 h2],'Start','Finish','Location','NorthEast'); -subplot(4,2,5); h1=plot(time,100*x(1,:),'k','Linewidth',2); hold on; -h2=plot(time,100*x(2,:),'k-.','Linewidth',2); -h_legend=legend([h1,h2],'x','y','Location','NorthEast'); -set(h_legend,'FontSize',14) -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]); -hx=xlabel('time [s]'); hy=ylabel('Position [cm]'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -subplot(4,2,7); -h1=plot(time,100*x(3,:),'k','Linewidth',2); hold on; -h2=plot(time,100*x(4,:),'k-.','Linewidth',2); -h_legend=legend([h1 h2],'v_x','v_y','Location','NorthEast'); -xlabel('time [s]'); -set(h_legend,'FontSize',14); -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)+.06 pos(2)+.01 pos(3:4)]); -hx=xlabel('time [s]'); hy=ylabel('Velocity [cm/s]'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -gamma=0; -windowTimes=[0, 0.001]; -numCells = 20; -bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5); -phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell -phiMaxNorm = (phiMax+pi)./(2*pi); -meanMu = log(10*delta); % baseline firing rate -10Hz -MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1) -dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X ( -coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta -fitType='binomial'; -clear nst; -for i=1:numCells -tempData = exp(dataMat*coeffs(i,:)'); -if(strcmp(fitType,'poisson')) -lambdaData = tempData; -else -lambdaData = tempData./(1+tempData); % Conditional Intensity Function for ith cell -end -lambda{i}=Covariate(time,lambdaData./delta, ... -'\Lambda(t)','time','s','spikes/sec',... -{strcat('\lambda_{',num2str(i),'}')},{{' ''b'' '}}); -lambda{i}=lambda{i}.resample(1/delta); -lambdaCIF{i} = CIF([MuCoeffs(i) 0 0 bCoeffs(i,:)],... -{'1','x','y','vx','vy'},{'x','y','vx','vy'},fitType); -tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1); nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization -nst{i}.setName(num2str(i)); % give each cell a unique name -subplot(4,2,[6 8]); -h2=lambda{i}.plot([],{{' ''k'', ''LineWidth'' ,.5'}}); -legend off; hold all; % Plot the CIF -end -title('Neural Conditional Intensity Functions','FontWeight',... -'bold','Fontsize',14,'FontName','Arial'); -hx=xlabel('time [s]','Interpreter','none'); -hy=ylabel('Firing Rate [spikes/sec]','Interpreter','none'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -spikeColl = nstColl(nst); % Create a neural spike train collection -subplot(4,2,[2,4]); spikeColl.plot; -set(gca,'xtick',[],'xtickLabel',[]); -title('Neural Raster','FontWeight','bold','Fontsize',14,... -'FontName','Arial'); -hx=xlabel('time [s]','Interpreter','none'); -hy=ylabel('Cell Number','Interpreter','none'); -set([hx, hy],'FontName', 'Arial','FontSize',12,'FontWeight','bold'); -close all; -numExamples=20; -scrsz = get(0,'ScreenSize'); -fig1=figure('OuterPosition',[scrsz(3)*.1 scrsz(4)*.1 ... -scrsz(3)*.6 scrsz(4)*.9]); -for k=1:numExamples -bCoeffs=10*(rand(numCells,2)-.5); % b_i = [b_x_i b_y_i] ~ U(-5, 5); -phiMax = atan2(bCoeffs(:,2),bCoeffs(:,1)); % Maximal firing direction of cell -phiMaxNorm = (phiMax+pi)./(2*pi); -meanMu = log(10*delta); % baseline firing rate -MuCoeffs = meanMu+randn(numCells,1); % mu_i ~ G(meanMu,1) -dataMat = [ones(length(time),1) x(3,:)' x(4,:)']; % design matrix: X ( -coeffs = [MuCoeffs bCoeffs]; % coefficient vector: beta -fitType='binomial'; -clear nst lambda; -for i=1:numCells -tempData = exp(dataMat*coeffs(i,:)'); -if(strcmp(fitType,'poisson')) -lambdaData = tempData; -else -lambdaData = tempData./(1+tempData); -end -lambda{i}=Covariate(time,lambdaData./delta, ... -'\Lambda(t)','time','s','spikes/sec',... -{strcat('\lambda_{',num2str(i),'}')},{{' ''b'' '}}); -lambda{i}=lambda{i}.resample(1/delta); -tempSpikeColl{i} = CIF.simulateCIFByThinningFromLambda(lambda{i},1); -nst{i} = tempSpikeColl{i}.getNST(1); % grab the realization -nst{i}.setName(num2str(i)); % give each cell a unique name -end -spikeColl = nstColl(nst); % Create a neural spike train collection -dN=spikeColl.dataToMatrix'; -dN(dN>1)=1; % more than one spike per bin will be treated as one spike. In -[C,N] = size(dN); % N time samples, C cells -beta=[zeros(2,numCells); bCoeffs']; -[x_p, W_p, x_u, W_u,x_uT,W_uT,x_pT,W_pT] = ... -DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,... -MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0, Pi0, yT,PiT,0); -[x_pf, W_pf, x_uf, W_uf] = ... -DecodingAlgorithms.PPDecodeFilterLinear(A, Q, dN,... -MuCoeffs,beta,fitType,delta,gamma,windowTimes,x0); -if(k==numExamples) -subplot(4,2,1:4);h1=plot(100*x(1,:),100*x(2,:),'k','LineWidth',3); -hold on; -axis([sort([100*x0(1)+5, 100*xT(1)-5]), ... -sort([100*x0(2)-5, 100*xT(2)+5])]); -title('Estimated vs. Actual Reach Paths',... -'FontWeight','bold','Fontsize',12,'FontName','Arial'); -end -subplot(4,2,1:4);h2=plot(100*x_u(1,:)',100*x_u(2,:)','b'); hold all; -subplot(4,2,1:4);h3=plot(100*x_uf(1,:)',100*x_uf(2,:)','g'); -hx=xlabel('x [cm]'); hy=ylabel('y [cm]'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -h1=plot(100*x0(1),100*x0(2),'bo','MarkerSize',10); hold on; -h2=plot(100*xT(1),100*xT(2),'ro','MarkerSize',10); -legend([h1 h2],'Start','Finish','Location','NorthEast'); -subplot(4,2,5); -h1=plot(time,100*x(1,:),'k','LineWidth',3); hold on; -h2=plot(time,100*x_u(1,:)','b'); -h3=plot(time,100*x_uf(1,:)','g'); -hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]'); -set(gca,'xtick',[],'xtickLabel',[]); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial'); -subplot(4,2,6); -h1=plot(time,100*x(2,:),'k','LineWidth',3); hold on; -h2=plot(time,100*x_u(2,:)','b'); -h3=plot(time,100*x_uf(2,:)','g'); -h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',... -'PPAF','Location','SouthEast'); -hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]'); -set(gca,'xtick',[],'xtickLabel',[]); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial'); -set(h_legend,'FontSize',10) -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)-.63 pos(2)+.23 pos(3:4)]); -subplot(4,2,7); -h1=plot(time,100*x(3,:),'k','LineWidth',3); hold on; -h2=plot(time,100*x_u(3,:)','b'); -h3=plot(time,100*x_uf(3,:)','g'); -hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial'); -subplot(4,2,8); -h1=plot(time,100*x(4,:),'k','LineWidth',3); hold on; -h2=plot(time,100*x_u(4,:)','b'); -h3=plot(time,100*x_uf(4,:)','g'); -hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial'); -end -clear all; -[dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ... -getPaperDataDirs(); -close all; -delta=0.001; -Tmax=2; -time=0:delta:Tmax; -A{2} = [1 0 delta 0 delta^2/2 0; -0 1 0 delta 0 delta^2/2; -0 0 1 0 delta 0; -0 0 0 1 0 delta; -0 0 0 0 1 0; -0 0 0 0 0 1]; -A{1} = [1 0 0 0 0 0; -0 1 0 0 0 0; -0 0 0 0 0 0; -0 0 0 0 0 0; -0 0 0 0 0 0; -0 0 0 0 0 0]; -A{1} = [1 0; -0 1]; -Px0{2} =1e-6*eye(6,6); -Px0{1} =1e-6*eye(2,2); -minCovVal = 1e-12; -covVal = 1e-3; -Q{2}=[minCovVal 0 0 0 0 0; -0 minCovVal 0 0 0 0; -0 0 minCovVal 0 0 0; -0 0 0 minCovVal 0 0; -0 0 0 0 covVal 0; -0 0 0 0 0 covVal]; -Q{1}=minCovVal*eye(2,2); -mstate = zeros(1,length(time)); -ind{1}=1:2; -ind{2}=1:6; -X=zeros(max([size(A{1},1),size(A{2},1)]),length(time)); -p_ij = [.998 .002; -.001 .999]; -for i = 1:length(time) -if(i==1) -mstate(i) = 1; -else -if(rand(1,1)1)=1; %Avoid more than 1 spike per bin. -Mu0=.5*ones(size(p_ij,1),1); -clear x0 yT clear Pi0 PiT; -x0{1} = X(ind{1},1); -yT{1} = X(ind{1},end); -Pi0 = Px0; -PiT{1} = 1e-9*eye(size(x0{1},1),size(x0{1},1)); -x0{2} = X(ind{2},1); -yT{2} = X(ind{2},end); -PiT{2} = 1e-9*eye(size(x0{2},1),size(x0{2},1)); -[S_est, X_est, W_est, MU_est, X_s, W_s,pNGivenS]=... -DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',... -coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0, yT,PiT); -[S_estNT, X_estNT, W_estNT, MU_estNT, X_sNT, W_sNT,pNGivenSNT]=... -DecodingAlgorithms.PPHybridFilterLinear(A, Q, p_ij,Mu0, dN',... -coeffs(:,1),coeffs(:,2:end)',fitType,delta,[],[],x0,Pi0); -X_estAll(:,:,n) = X_est; -X_estNTAll(:,:,n) = X_estNT; -S_estAll(n,:)=S_est; -S_estNTAll(n,:)=S_estNT; -MU_estAll(:,:,n)=MU_est; -MU_estNTAll(:,:,n) = MU_estNT; -subplot(4,3,[1 4]); -plot(time,mstate,'k','LineWidth',3); hold all; -plot(time,S_est,'b-.','Linewidth',.5); -plot(time,S_estNT,'g-.','Linewidth',.5); axis tight; v=axis; -axis([v(1) v(2) 0.5 2.5]); -subplot(4,3,[7 10]); -plot(time,MU_est(2,:),'b-.','Linewidth',.5); hold on; -plot(time,MU_estNT(2,:),'g-.','Linewidth',.5); hold on; -axis([min(time) max(time) 0 1.1]); -subplot(4,3,[2 3 5 6]); -h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all; -h2=plot(100*X_est(1,:)',100*X_est(2,:)','b-.'); hold all; -h3=plot(100*X_estNT(1,:)',100*X_estNT(2,:)','g-.'); -subplot(4,3,8); -h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on; -h2=plot(time,100*X_est(1,:)','b-.'); -h3=plot(time,100*X_estNT(1,:)','g-.'); -subplot(4,3,9); -h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on; -h2=plot(time,100*X_est(2,:)','b-.'); -h3=plot(time,100*X_estNT(2,:)','g-.'); -subplot(4,3,11); -h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on; -h2=plot(time,100*X_est(3,:)','b-.'); -h3=plot(time,100*X_estNT(3,:)','g-.'); -subplot(4,3,12); -h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on; -h2=plot(time,100*X_est(4,:)','b-.'); -h3=plot(time,100*X_estNT(4,:)','g-.'); -end -subplot(4,3,[1 4]); -hold all; -plot(time,mstate,'k','LineWidth',3); -plot(time,mean(S_estAll),'b','LineWidth',3); -plot(time,mean(S_estNTAll),'g','LineWidth',3); -set(gca,'xtick',[],'YTick',[1 2.1],'YTickLabel',{'N','M'}); -hy=ylabel('state'); hx=xlabel('time [s]'); -set([hy hx],'FontName', 'Arial','FontSize',10,'FontWeight','bold',... -'Interpreter','none'); -title('Estimated vs. Actual State','FontWeight','bold','Fontsize',... -12,'FontName','Arial'); -subplot(4,3,[7 10]); -plot(time, mean(squeeze(MU_estAll(2,:,:)),2),'b','LineWidth',3); -hold on; -plot(time,mean(squeeze(MU_estNTAll(2,:,:)),2),'g','LineWidth',3); -hold on; -axis([min(time) max(time) 0 1.1]); -hx=xlabel('time [s]'); hy=ylabel('P(s(t)=M | data)'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('Probability of State','FontWeight','bold','Fontsize',12,... -'FontName','Arial'); -subplot(4,3,[2 3 5 6]); -h1=plot(100*X(1,:)',100*X(2,:)','k'); hold all; -mXestAll=mean(100*X_estAll,3); -mXestNTAll=mean(100*X_estNTAll,3); -plot(mXestAll(1,:),mXestAll(2,:),'b','Linewidth',3); -plot(mXestNTAll(1,:),mXestNTAll(2,:),'g','Linewidth',3); -hx=xlabel('x [cm]'); hy=ylabel('y [cm]'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -h1=plot(100*X(1,1),100*X(2,1),'bo','MarkerSize',14); hold on; -h2=plot(100*X(1,end),100*X(2,end),'ro','MarkerSize',14); -legend([h1 h2],'Start','Finish','Location','NorthEast'); -title('Estimated vs. Actual Reach Path','FontWeight','bold',... -'Fontsize',12,'FontName','Arial'); -subplot(4,3,8); -h1=plot(time,100*X(1,:),'k','LineWidth',3); hold on; -h2=plot(time,mXestAll(1,:),'b','LineWidth',3); hold on; -h3=plot(time,mXestNTAll(1,:),'g','LineWidth',3); hold on; -hy=ylabel('x(t) [cm]'); hx=xlabel('time [s]'); -set(gca,'xtick',[],'xtickLabel',[]); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('X Position','FontWeight','bold','Fontsize',12,'FontName','Arial'); -subplot(4,3,9); -h1=plot(time,100*X(2,:),'k','LineWidth',3); hold on; -h2=plot(time,mXestAll(2,:),'b','LineWidth',3); hold on; -h3=plot(time,mXestNTAll(2,:),'g','LineWidth',3); hold on; -h_legend=legend([h1(1) h2(1) h3(1)],'Actual','PPAF+Goal',... -'PPAF','Location','SouthEast'); -hy=ylabel('y(t) [cm]'); hx=xlabel('time [s]'); -set(gca,'xtick',[],'xtickLabel',[]); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('Y Position','FontWeight','bold','Fontsize',12,'FontName','Arial'); -set(h_legend,'FontSize',10) -pos = get(h_legend,'position'); -set(h_legend, 'position',[pos(1)-.40 pos(2)+.51 pos(3:4)]); -subplot(4,3,11); -h1=plot(time,100*X(3,:),'k','LineWidth',3); hold on; -h2=plot(time,mXestAll(3,:),'b','LineWidth',3); hold on; -h3=plot(time,mXestNTAll(3,:),'g','LineWidth',3); hold on; -hy=ylabel('v_{x}(t) [cm/s]'); hx=xlabel('time [s]'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('X Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial'); -subplot(4,3,12); -h1=plot(time,100*X(4,:),'k','LineWidth',3); hold on; -h2=plot(time,mXestAll(4,:),'b','LineWidth',3); hold on; -h3=plot(time,mXestNTAll(4,:),'g','LineWidth',3); hold on; -hy=ylabel('v_{y}(t) [cm/s]'); hx=xlabel('time [s]'); -set([hx, hy],'FontName', 'Arial','FontSize',10,'FontWeight','bold'); -title('Y Velocity','FontWeight','bold','Fontsize',12,'FontName','Arial'); -parity = struct(); -if exist('numCells','var') -parity.num_cells = numCells; -end -if exist('numRealizations','var') -parity.num_realizations = numRealizations; -end -function [dataDir,mEPSCDir,explicitStimulusDir,psthDir,placeCellDataDir] = ... -getPaperDataDirs() -candidateRoots = {}; -scriptPath = mfilename('fullpath'); -if ~isempty(scriptPath) -candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(scriptPath))); -end -paperPath = which('nSTATPaperExamples'); -if ~isempty(paperPath) -candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(paperPath))); -end -installPath = which('nSTAT_Install'); -if ~isempty(installPath) -candidateRoots = appendCandidateRoot(candidateRoots, fileparts(installPath)); -end -try -activeFile = matlab.desktop.editor.getActiveFilename; -catch -activeFile = ''; -end -if ~isempty(activeFile) -candidateRoots = appendCandidateRoot(candidateRoots, fileparts(fileparts(activeFile))); -end -candidateRoots = appendCandidateRoot(candidateRoots, pwd); -nSTATDir = ''; -for iRoot = 1:numel(candidateRoots) -candidateDataDir = fullfile(candidateRoots{iRoot}, 'data'); -if exist(candidateDataDir, 'dir') == 7 -nSTATDir = candidateRoots{iRoot}; -break; -end -end -if isempty(nSTATDir) -error('nSTATPaperExamples:MissingInstallPath', ... -['Could not resolve the nSTAT root path. Checked roots derived from ', ... -'mfilename, which(''nSTATPaperExamples''), which(''nSTAT_Install''), ', ... -'the active editor file, and pwd.']); -end -dataDir = fullfile(nSTATDir,'data'); -mEPSCDir = fullfile(dataDir,'mEPSCs'); -explicitStimulusDir = fullfile(dataDir,'Explicit Stimulus'); -psthDir = fullfile(dataDir,'PSTH'); -placeCellDataDir = fullfile(dataDir,'Place Cells'); -if exist(dataDir,'dir') ~= 7 -error('nSTATPaperExamples:MissingDataDir', ... -'Could not find local nSTAT data folder at %s', dataDir); -end -end -function roots = appendCandidateRoot(roots, startDir) -if isempty(startDir) -return; -end -thisDir = startDir; -while true -if ~any(strcmp(roots, thisDir)) -roots{end+1} = thisDir; %#ok -end -parentDir = fileparts(thisDir); -if strcmp(parentDir, thisDir) -break; -end -thisDir = parentDir; -end -end diff --git a/parity/line_port_snapshots/nSpikeTrainExamples.txt b/parity/line_port_snapshots/nSpikeTrainExamples.txt deleted file mode 100644 index 3417eac4..00000000 --- a/parity/line_port_snapshots/nSpikeTrainExamples.txt +++ /dev/null @@ -1,10 +0,0 @@ -spikeTimes = sort(rand(1,100))*1; -spikeTimes = unique(round(spikeTimes*10000)./10000); %round off; -nst=nspikeTrain(spikeTimes,'n1',.001,0,1); -figure; nst.plot; -figure; nst.resample(1/.1); -nst.getSigRep.plot; -figure; nst.resample(1/.01); -nst.getSigRep.plot; -figure; nst.resample(1/nst.getMaxBinSizeBinary); -nst.getSigRep.plot; diff --git a/parity/line_port_snapshots/nstCollExamples.txt b/parity/line_port_snapshots/nstCollExamples.txt deleted file mode 100644 index 9bb642f3..00000000 --- a/parity/line_port_snapshots/nstCollExamples.txt +++ /dev/null @@ -1,16 +0,0 @@ -close all; clear all; -for i=1:20 -spikeTimes = sort(rand(1,100))*1; -nst{i}=nspikeTrain(spikeTimes,'',.1); -nst{i}.setName(strcat('Neuron',num2str(i))); -end -spikeColl=nstColl(nst); -figure; spikeColl.plot; -spikeColl.setMask([1 4 7]); -figure; spikeColl.plot; -figure; -n1=spikeColl.getNST(1); %get the first nspikeTrain in the collection -subplot(3,1,1); n1.plot; -subplot(3,1,2); n1.getSigRep.plot; %plot current sigRep -s1=n1.getSigRep(.001,0,1); -subplot(3,1,3); s1.plot; diff --git a/parity/line_port_snapshots/publish_all_helpfiles.txt b/parity/line_port_snapshots/publish_all_helpfiles.txt deleted file mode 100644 index b70b588d..00000000 --- a/parity/line_port_snapshots/publish_all_helpfiles.txt +++ /dev/null @@ -1,64 +0,0 @@ -function publish_all_helpfiles(varargin) -opts = parseOptions(varargin{:}); -helpDir = fileparts(mfilename('fullpath')); -rootDir = fileparts(helpDir); -stagingDir = tempname; -outputDir = tempname; -mkdir(stagingDir); -mkdir(outputDir); -cleanupObj = onCleanup(@()cleanupTempDirs(stagingDir, outputDir)); -startDir = pwd; -restoreDir = onCleanup(@()cd(startDir)); %#ok -copyfile(fullfile(helpDir, '*'), stagingDir); -removeStagedArtifacts(stagingDir); -restoredefaultpath; -addpath(rootDir, '-begin'); -nSTAT_Install('RebuildDocSearch', false, 'CleanUserPathPrefs', false); -addpath(stagingDir, '-begin'); -cd(stagingDir); -publishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', opts.EvalCode); -referencePublishOptions = struct('outputDir', outputDir, 'format', 'html', 'evalCode', false); -failures = {}; -stageFiles = dir(fullfile(stagingDir, '*.m')); -for iFile = 1:numel(stageFiles) -[~, baseName] = fileparts(stageFiles(iFile).name); -if strcmpi(baseName, 'publish_all_helpfiles') -continue; -end -try -publish(baseName, publishOptions); -fprintf('Published help topic: %s\n', stageFiles(iFile).name); -catch ME -failures{end+1} = sprintf('%s :: %s', stageFiles(iFile).name, ME.message); %#ok -end -end -rootReferenceFiles = {'Analysis.m', 'SignalObj.m', 'FitResult.m'}; -for iFile = 1:numel(rootReferenceFiles) -sourceFile = fullfile(rootDir, rootReferenceFiles{iFile}); -try -publish(sourceFile, referencePublishOptions); -fprintf('Published class reference: %s\n', rootReferenceFiles{iFile}); -catch ME -failures{end+1} = sprintf('%s :: %s', rootReferenceFiles{iFile}, ME.message); %#ok -end -end -if ~isempty(failures) -fprintf(2, 'Publish failures (%d):\n', numel(failures)); -for i = 1:numel(failures) -fprintf(2, ' - %s\n', failures{i}); -end -error('nSTAT:PublishAllFailures', 'One or more help pages failed to publish.'); -end -copyfile(fullfile(outputDir, '*'), helpDir, 'f'); -builddocsearchdb(helpDir); -rehash toolboxcache; -validateHelpTargets(helpDir); -validateHtmlGeneratorMetadata(helpDir, opts.ExpectedGenerator); -fprintf('nSTAT help publication completed successfully.\n'); -clear cleanupObj; -end -function opts = parseOptions(varargin) -parser = inputParser; -parser.FunctionName = 'publish_all_helpfiles'; -addParameter(parser, 'EvalCode', true, @(x)islogical(x) || isnumeric(x)); -addParameter(parser, 'ExpectedGenerator', 'MATLAB 25.2', @(x)ischar(x) || isstring(x)); diff --git a/parity/line_port_snapshots/publish_all_helpfiles_extra.txt b/parity/line_port_snapshots/publish_all_helpfiles_extra.txt deleted file mode 100644 index fb587134..00000000 --- a/parity/line_port_snapshots/publish_all_helpfiles_extra.txt +++ /dev/null @@ -1,62 +0,0 @@ -parse(parser, varargin{:}); -opts.EvalCode = logical(parser.Results.EvalCode); -opts.ExpectedGenerator = char(parser.Results.ExpectedGenerator); -end -function removeStagedArtifacts(stagingDir) -removePattern(stagingDir, '*.mlx'); -removePattern(stagingDir, '*.asv'); -removePattern(stagingDir, '*.bak'); -removePattern(stagingDir, 'temp.m'); -removePattern(stagingDir, 'publish_all_helpfiles.m'); -end -function removePattern(stagingDir, pattern) -files = dir(fullfile(stagingDir, pattern)); -for i = 1:numel(files) -delete(fullfile(stagingDir, files(i).name)); -end -end -function validateHelpTargets(helpDir) -helptocPath = fullfile(helpDir, 'helptoc.xml'); -if ~isfile(helptocPath) -error('nSTAT:MissingHelptoc', 'Missing helptoc.xml at -end -raw = fileread(helptocPath); -matches = regexp(raw, 'target="([^"]+)"', 'tokens'); -for i = 1:numel(matches) -target = matches{i}{1}; -if startsWith(target, 'http://') || startsWith(target, 'https://') -continue; -end -fullTarget = fullfile(helpDir, target); -if ~isfile(fullTarget) -error('nSTAT:MissingHelpTarget', ... -'helptoc target is missing after publish: -end -end -end -function validateHtmlGeneratorMetadata(helpDir, expectedGenerator) -htmlFiles = dir(fullfile(helpDir, '*.html')); -for i = 1:numel(htmlFiles) -htmlPath = fullfile(helpDir, htmlFiles(i).name); -raw = fileread(htmlPath); -if isempty(regexp(raw, ['=69", "wheel"] +requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] -name = "nstat" +name = "nstat-toolbox" version = "0.1.0" -description = "Clean-room Python implementation of the nSTAT toolbox" +description = "Python port of the nSTAT toolbox" readme = "README.md" -requires-python = ">=3.11" -license = {text = "GPL-2.0-or-later"} -authors = [{name = "Cajigas Lab"}] +requires-python = ">=3.10" +authors = [ + { name = "Cajigas Lab" } +] dependencies = [ - "numpy>=1.26", - "scipy>=1.11", - "matplotlib>=3.8", - "pandas>=2.1", - "pyyaml>=6.0", - "requests>=2.31" + "numpy>=1.24", + "scipy>=1.10", + "matplotlib>=3.7" ] -[project.scripts] -nstat-install = "nstat.install:main" - [project.optional-dependencies] dev = [ "pytest>=8.0", - "pytest-benchmark>=4.0", - "pytest-cov>=4.1", - "mypy>=1.8", - "ruff>=0.3", - "nbformat>=5.9", - "nbclient>=0.9", - "ipykernel>=6.29", - "PyMuPDF>=1.24", - "scikit-image>=0.22" -] -docs = [ - "sphinx>=7.2", - "myst-parser>=2.0", - "sphinx-autodoc-typehints>=2.0", - "sphinx-rtd-theme>=2.0", - "pyyaml>=6.0" -] -notebooks = [ - "nbformat>=5.9", - "nbclient>=0.9", - "jupyter>=1.0", - "Pillow>=10.0", - "reportlab>=4.0", - "pyyaml>=6.0", - "PyMuPDF>=1.24", - "scikit-image>=0.22" ] -[project.urls] -Homepage = "https://github.com/cajigaslab/nSTAT-python" -Documentation = "https://cajigaslab.github.io/nSTAT-python/" - -[tool.setuptools] -package-dir = {"" = "src"} - [tool.setuptools.packages.find] -where = ["src"] - -[tool.ruff] -line-length = 100 -target-version = "py311" +where = ["."] +include = ["nstat*"] -[tool.mypy] -python_version = "3.11" -strict = false -ignore_missing_imports = true -warn_unused_configs = true +[tool.setuptools.package-data] +"nstat.data" = ["manifest.json"] -[tool.pytest.ini_options] -addopts = "-q" -markers = [ - "smoke: fast checks for pull requests", - "full: heavier checks for nightly and release gating", - "performance: runtime benchmark checks for parity monitoring" -] +[project.scripts] +nstat-paper-examples = "nstat.paper_examples:main" diff --git a/reports/repo_split_inventory/split_readiness_gates.json b/reports/repo_split_inventory/split_readiness_gates.json new file mode 100644 index 00000000..c6dd4697 --- /dev/null +++ b/reports/repo_split_inventory/split_readiness_gates.json @@ -0,0 +1,17 @@ +{ + "python_example_topics_expected": 25, + "python_example_topics_ready": 25, + "python_example_topics_missing_coverage": [], + "matlab_example_topics_expected": 25, + "matlab_example_topics_with_mlx": 18, + "matlab_example_topics_missing_mlx": [ + "ExplicitStimulusWhiskerData", + "NetworkTutorial", + "PPThinning", + "PSTHEstimation", + "StimulusDecode2D", + "ValidationDataSet", + "mEPSCAnalysis" + ], + "pass": false +} \ No newline at end of file diff --git a/reports/repo_split_inventory/summary.json b/reports/repo_split_inventory/summary.json new file mode 100644 index 00000000..47ded8a5 --- /dev/null +++ b/reports/repo_split_inventory/summary.json @@ -0,0 +1,53 @@ +{ + "generated_at_utc": "2026-02-27T03:24:36+00:00", + "repo_root": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local", + "toc_target_topics": 31, + "toc_example_topics": 25, + "matlab_files": { + "m": 34, + "mlx": 21, + "html": 35 + }, + "python_assets": { + "docs_topics_rst": 31, + "notebooks_ipynb": 32, + "example_scripts_py": 27 + }, + "coverage_counts": { + "toc_topics_with_python_docs": 31, + "toc_topics_with_python_notebooks": 29, + "toc_topics_with_python_example_scripts": 25, + "example_topics_full_python_coverage": 25, + "example_topics_with_matlab_mlx": 18 + }, + "example_topic_stems_from_toc": [ + "AnalysisExamples", + "ConfigCollExamples", + "CovCollExamples", + "CovariateExamples", + "DecodingExample", + "DecodingExampleWithHist", + "EventsExamples", + "ExplicitStimulusWhiskerData", + "FitResSummaryExamples", + "FitResultExamples", + "HippocampalPlaceCellExample", + "HistoryExamples", + "NetworkTutorial", + "PPSimExample", + "PPThinning", + "PSTHEstimation", + "SignalObjExamples", + "StimulusDecode2D", + "TrialConfigExamples", + "TrialExamples", + "ValidationDataSet", + "mEPSCAnalysis", + "nSTATPaperExamples", + "nSpikeTrainExamples", + "nstCollExamples" + ], + "python_only_topic_stems_not_in_toc": [ + "_common" + ] +} \ No newline at end of file diff --git a/reports/repo_split_inventory/topic_coverage_matrix.json b/reports/repo_split_inventory/topic_coverage_matrix.json new file mode 100644 index 00000000..5305d3a0 --- /dev/null +++ b/reports/repo_split_inventory/topic_coverage_matrix.json @@ -0,0 +1,374 @@ +[ + { + "title": "Using the Analysis Class", + "target": "AnalysisExamples.html", + "stem": "AnalysisExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Class Definitions", + "target": "ClassDefinitions.html", + "stem": "ClassDefinitions", + "is_example_topic": false, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": false + }, + { + "title": "Using the ConfigColl Class", + "target": "ConfigCollExamples.html", + "stem": "ConfigCollExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Using the CovColl Class", + "target": "CovCollExamples.html", + "stem": "CovCollExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Using the Covariate Class", + "target": "CovariateExamples.html", + "stem": "CovariateExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Example Data Analysis - Decoding Univariate Simulated Stimuli (No History Effect)", + "target": "DecodingExample.html", + "stem": "DecodingExample", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Example Data Analysis - Decoding Univariate Simulated Stimuli with and without History Effect", + "target": "DecodingExampleWithHist.html", + "stem": "DecodingExampleWithHist", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "MATLAB 2025b Help Integration", + "target": "DocumentationSetup2025b.html", + "stem": "DocumentationSetup2025b", + "is_example_topic": false, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": false, + "python_example_script_exists": false + }, + { + "title": "Using the Events Class", + "target": "EventsExamples.html", + "stem": "EventsExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Examples Using the SignalObj Class Using the Covariate Class Using the CovColl Class Using the nSpikeTrain Class Using the nstColl Class Using the Events Class Using the History Class Using the Trial Class Using the TrialConfig Class Using the ConfigColl Class Using the Analysis Class Using the FitResult Class Using the FitResSummary Class Point Process Simulation via Thinning Example Data Analysis - Simulated Data - Computing a Peri-Stimulus Time Histogram (PSTH) Example Data Analysis - Simulated Constant (Piecewise Constant) Rate Poisson Example Data Analysis - Miniature Excitatory Post-Synaptic Currents (mEPSCs) Example Data Analysis - Simulated Explicit Stimulus and History Example Data Analysis - Explicit Stimulus Example Data Analysis - Hippocampal Place Cell Receptive Field Estimation Example Data Analysis - Decoding Univariate Simulated Stimuli (No History Effect) Example Data Analysis - Decoding Univariate Simulated Stimuli with and without History Effect Example Data Analysis - Decoding Bivariate Simulated Stimuli Example Data Analysis - Two Neuron Network Simulation and Estimation of Ensemble Effect nSTAT Paper Examples", + "target": "Examples.html", + "stem": "Examples", + "is_example_topic": false, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": false + }, + { + "title": "Example Data Analysis - Explicit Stimulus", + "target": "ExplicitStimulusWhiskerData.html", + "stem": "ExplicitStimulusWhiskerData", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Using the FitResSummary Class", + "target": "FitResSummaryExamples.html", + "stem": "FitResSummaryExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "FitResult Reference", + "target": "FitResult.html", + "stem": "FitResult", + "is_example_topic": false, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": false + }, + { + "title": "Using the FitResult Class", + "target": "FitResultExamples.html", + "stem": "FitResultExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Example Data Analysis - Hippocampal Place Cell Receptive Field Estimation", + "target": "HippocampalPlaceCellExample.html", + "stem": "HippocampalPlaceCellExample", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Using the History Class", + "target": "HistoryExamples.html", + "stem": "HistoryExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Example Data Analysis - Two Neuron Network Simulation and Estimation of Ensemble Effect", + "target": "NetworkTutorial.html", + "stem": "NetworkTutorial", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "nSTAT Neural Spike Train Analysis Toolbox Overview MATLAB 2025b Help Integration Class Definitions SignalObj Reference FitResult Reference Examples Using the SignalObj Class Using the Covariate Class Using the CovColl Class Using the nSpikeTrain Class Using the nstColl Class Using the Events Class Using the History Class Using the Trial Class Using the TrialConfig Class Using the ConfigColl Class Using the Analysis Class Using the FitResult Class Using the FitResSummary Class Point Process Simulation via Thinning Example Data Analysis - Simulated Data - Computing a Peri-Stimulus Time Histogram (PSTH) Example Data Analysis - Simulated Constant (Piecewise Constant) Rate Poisson Example Data Analysis - Miniature Excitatory Post-Synaptic Currents (mEPSCs) Example Data Analysis - Simulated Explicit Stimulus and History Example Data Analysis - Explicit Stimulus Example Data Analysis - Hippocampal Place Cell Receptive Field Estimation Example Data Analysis - Decoding Univariate Simulated Stimuli (No History Effect) Example Data Analysis - Decoding Univariate Simulated Stimuli with and without History Effect Example Data Analysis - Decoding Bivariate Simulated Stimuli Example Data Analysis - Two Neuron Network Simulation and Estimation of Ensemble Effect nSTAT Paper Examples Neuroscience Statistics Research Laboratory", + "target": "NeuralSpikeAnalysis_top.html", + "stem": "NeuralSpikeAnalysis_top", + "is_example_topic": false, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": false + }, + { + "title": "Example Data Analysis - Simulated Explicit Stimulus and History", + "target": "PPSimExample.html", + "stem": "PPSimExample", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Point Process Simulation via Thinning", + "target": "PPThinning.html", + "stem": "PPThinning", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Example Data Analysis - Simulated Data - Computing a Peri-Stimulus Time Histogram (PSTH)", + "target": "PSTHEstimation.html", + "stem": "PSTHEstimation", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "SignalObj Reference", + "target": "SignalObj.html", + "stem": "SignalObj", + "is_example_topic": false, + "matlab_m_exists": false, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": false, + "python_example_script_exists": false + }, + { + "title": "Using the SignalObj Class", + "target": "SignalObjExamples.html", + "stem": "SignalObjExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Example Data Analysis - Decoding Bivariate Simulated Stimuli", + "target": "StimulusDecode2D.html", + "stem": "StimulusDecode2D", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Using the TrialConfig Class", + "target": "TrialConfigExamples.html", + "stem": "TrialConfigExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Using the Trial Class", + "target": "TrialExamples.html", + "stem": "TrialExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Example Data Analysis - Simulated Constant (Piecewise Constant) Rate Poisson", + "target": "ValidationDataSet.html", + "stem": "ValidationDataSet", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Example Data Analysis - Miniature Excitatory Post-Synaptic Currents (mEPSCs)", + "target": "mEPSCAnalysis.html", + "stem": "mEPSCAnalysis", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": false, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "nSTAT Paper Examples", + "target": "nSTATPaperExamples.html", + "stem": "nSTATPaperExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Using the nSpikeTrain Class", + "target": "nSpikeTrainExamples.html", + "stem": "nSpikeTrainExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + }, + { + "title": "Using the nstColl Class", + "target": "nstCollExamples.html", + "stem": "nstCollExamples", + "is_example_topic": true, + "matlab_m_exists": true, + "matlab_mlx_exists": true, + "matlab_html_exists": true, + "python_doc_exists": true, + "python_notebook_exists": true, + "python_example_script_exists": true + } +] \ No newline at end of file diff --git a/src/nstat/__init__.py b/src/nstat/__init__.py deleted file mode 100644 index f7bb97a7..00000000 --- a/src/nstat/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -"""nSTAT clean-room Python toolbox. - -The package preserves high-level MATLAB nSTAT structure while using Python-native -implementations and interfaces. -""" - -from .analysis import Analysis -from .cif import CIFModel -from .confidence import ConfidenceInterval -from .data_manager import data_is_present, ensure_example_data, get_data_dir -from .decoding import DecodingAlgorithms -from .datasets import fetch_matlab_gold_file, latest_matlab_gold_version, list_matlab_gold_files -from .events import Events -from .fit import FitResult, FitSummary -from .history import HistoryBasis -from .install import InstallReport, nstat_install -from .notebook_figures import FigureTracker -from .signal import Covariate, Signal -from .spikes import SpikeTrain, SpikeTrainCollection -from .trial import ConfigCollection, CovariateCollection, Trial, TrialConfig - -__all__ = [ - "Analysis", - "CIFModel", - "ConfidenceInterval", - "DecodingAlgorithms", - "Events", - "FitResult", - "FitSummary", - "HistoryBasis", - "InstallReport", - "Signal", - "Covariate", - "SpikeTrain", - "SpikeTrainCollection", - "CovariateCollection", - "TrialConfig", - "ConfigCollection", - "Trial", - "nstat_install", - "FigureTracker", - "get_data_dir", - "ensure_example_data", - "data_is_present", - "list_matlab_gold_files", - "latest_matlab_gold_version", - "fetch_matlab_gold_file", -] diff --git a/src/nstat/analysis.py b/src/nstat/analysis.py deleted file mode 100644 index 96cb060b..00000000 --- a/src/nstat/analysis.py +++ /dev/null @@ -1,233 +0,0 @@ -"""Model fitting and analysis entry points.""" - -from __future__ import annotations - -from typing import Literal - -import numpy as np -from scipy.optimize import minimize -from scipy.special import expit, gammaln - -from .fit import FitResult -from .trial import Trial, TrialConfig - - -class Analysis: - """Static analysis methods for point-process GLM fitting. - - This class intentionally mirrors MATLAB's class-centric access pattern, - while returning plain typed Python result objects. - """ - - @staticmethod - def fit_glm( - X: np.ndarray, - y: np.ndarray, - fit_type: str = "poisson", - dt: float = 1.0, - l2_penalty: float = 0.0, - ) -> FitResult: - """Fit independent-bin GLM with analytical gradients. - - Parameters - ---------- - X: - Design matrix with shape ``(n_samples, n_features)``. - y: - Observation vector with shape ``(n_samples,)``. - fit_type: - ``"poisson"`` or ``"binomial"``. - dt: - Bin width in seconds; used for Poisson expected counts. - l2_penalty: - Ridge penalty applied to coefficients (not intercept). - """ - - X = np.asarray(X, dtype=float) - y = np.asarray(y, dtype=float) - if X.ndim != 2: - raise ValueError("X must be 2D") - if y.ndim != 1: - raise ValueError("y must be 1D") - if X.shape[0] != y.size: - raise ValueError("X and y must have matching sample count") - if fit_type not in {"poisson", "binomial"}: - raise ValueError("fit_type must be 'poisson' or 'binomial'") - if dt <= 0.0: - raise ValueError("dt must be positive") - if l2_penalty < 0.0: - raise ValueError("l2_penalty must be non-negative") - - n_features = X.shape[1] - theta0 = np.zeros(n_features + 1, dtype=float) - - def unpack(theta: np.ndarray) -> tuple[float, np.ndarray]: - return float(theta[0]), theta[1:] - - if fit_type == "poisson": - - def objective_and_grad(theta: np.ndarray) -> tuple[float, np.ndarray]: - b0, b = unpack(theta) - eta = np.clip(b0 + X @ b, -50.0, 50.0) - rate = np.exp(eta) - mu = np.clip(rate * dt, 1e-12, None) - nll = float(np.sum(mu - y * np.log(mu) + gammaln(y + 1.0))) - d_eta = mu - y - grad = np.zeros_like(theta) - grad[0] = np.sum(d_eta) - grad[1:] = X.T @ d_eta - if l2_penalty > 0.0: - nll += 0.5 * l2_penalty * float(np.sum(b * b)) - grad[1:] += l2_penalty * b - return nll, grad - - else: - - def objective_and_grad(theta: np.ndarray) -> tuple[float, np.ndarray]: - b0, b = unpack(theta) - eta = b0 + X @ b - p = np.clip(expit(eta), 1e-9, 1.0 - 1e-9) - nll = float(-np.sum(y * np.log(p) + (1.0 - y) * np.log(1.0 - p))) - d_eta = p - y - grad = np.zeros_like(theta) - grad[0] = np.sum(d_eta) - grad[1:] = X.T @ d_eta - if l2_penalty > 0.0: - nll += 0.5 * l2_penalty * float(np.sum(b * b)) - grad[1:] += l2_penalty * b - return nll, grad - - def objective(theta: np.ndarray) -> float: - nll, _ = objective_and_grad(theta) - return nll - - def gradient(theta: np.ndarray) -> np.ndarray: - _, grad = objective_and_grad(theta) - return grad - - opt = minimize(objective, theta0, method="L-BFGS-B", jac=gradient) - if not opt.success: - raise RuntimeError(f"GLM optimization failed: {opt.message}") - - intercept = float(opt.x[0]) - coeffs = opt.x[1:].astype(float) - nll = float(opt.fun) - return FitResult( - coefficients=coeffs, - intercept=intercept, - fit_type=fit_type, - log_likelihood=-nll, - n_samples=int(y.size), - n_parameters=int(opt.x.size), - ) - - @staticmethod - def fit_trial(trial: Trial, config: TrialConfig, unit_index: int = 0) -> FitResult: - """Fit Poisson/binomial GLM for a single unit within a trial.""" - - dt = 1.0 / config.sample_rate_hz - mode: Literal["binary", "count"] = "count" if config.fit_type == "poisson" else "binary" - _, y, X = trial.aligned_binned_observation(bin_size_s=dt, unit_index=unit_index, mode=mode) - return Analysis.fit_glm( - X=X, - y=y, - fit_type=config.fit_type, - dt=dt, - ) - - @staticmethod - def glm_fit( - X: np.ndarray, - y: np.ndarray, - fit_type: str = "poisson", - dt: float = 1.0, - l2_penalty: float = 0.0, - ) -> FitResult: - """MATLAB-style alias for :meth:`fit_glm`.""" - - return Analysis.fit_glm(X=X, y=y, fit_type=fit_type, dt=dt, l2_penalty=l2_penalty) - - @staticmethod - def run_analysis_for_neuron(trial: Trial, config: TrialConfig, unit_index: int = 0) -> FitResult: - """High-level wrapper matching MATLAB naming for per-neuron analysis.""" - - return Analysis.fit_trial(trial=trial, config=config, unit_index=unit_index) - - @staticmethod - def run_analysis_for_all_neurons(trial: Trial, config: TrialConfig) -> list[FitResult]: - """Fit one model per unit in a trial using the same configuration.""" - - return [ - Analysis.fit_trial(trial=trial, config=config, unit_index=i) - for i in range(trial.spikes.n_units) - ] - - @staticmethod - def compute_fit_residual( - y: np.ndarray, X: np.ndarray, fit_result: FitResult, dt: float = 1.0 - ) -> np.ndarray: - """Return Pearson-like residuals for fitted GLM observations.""" - - y = np.asarray(y, dtype=float) - mu = np.asarray(fit_result.predict(X), dtype=float) - if fit_result.fit_type == "poisson": - mu = np.clip(mu * dt, 1e-12, None) - var = mu - else: - mu = np.clip(mu, 1e-9, 1.0 - 1e-9) - var = np.clip(mu * (1.0 - mu), 1e-12, None) - return (y - mu) / np.sqrt(var) - - @staticmethod - def compute_inv_gaus_trans( - y: np.ndarray, X: np.ndarray, fit_result: FitResult, dt: float = 1.0 - ) -> np.ndarray: - """Compute integrated-intensity transform surrogate used in GOF diagnostics.""" - - y = np.asarray(y, dtype=float) - mu = np.asarray(fit_result.predict(X), dtype=float) - if fit_result.fit_type == "poisson": - increments = np.clip(mu * dt, 1e-12, None) - else: - increments = np.clip(mu, 1e-9, 1.0 - 1e-9) - # Return cumulative expected intensity sampled at spike/event bins. - cumsum = np.cumsum(increments) - spike_bins = np.where(y > 0.0)[0] - if spike_bins.size == 0: - return np.array([], dtype=float) - return cumsum[spike_bins] - - @staticmethod - def compute_ks_stats(transformed_events: np.ndarray) -> dict[str, float]: - """Compute one-sample KS statistic against Uniform(0, 1) after rescaling.""" - - z = np.asarray(transformed_events, dtype=float) - if z.size == 0: - return {"d_stat": 0.0, "n_events": 0.0} - z = np.sort(z / max(float(np.max(z)), 1e-12)) - n = z.size - ecdf = np.arange(1, n + 1, dtype=float) / float(n) - d_plus = np.max(ecdf - z) - d_minus = np.max(z - np.arange(0, n, dtype=float) / float(n)) - return {"d_stat": float(max(d_plus, d_minus)), "n_events": float(n)} - - @staticmethod - def fdr_bh(p_values: np.ndarray, alpha: float = 0.05) -> np.ndarray: - """Benjamini-Hochberg FDR control for one-dimensional p-value arrays.""" - - p = np.asarray(p_values, dtype=float).ravel() - if p.size == 0: - return np.array([], dtype=bool) - if np.any((p < 0.0) | (p > 1.0)): - raise ValueError("p_values must be in [0, 1]") - if not (0.0 < alpha < 1.0): - raise ValueError("alpha must be in (0, 1)") - order = np.argsort(p) - ranked = p[order] - threshold = alpha * (np.arange(1, p.size + 1) / p.size) - passing = np.where(ranked <= threshold)[0] - mask = np.zeros_like(p, dtype=bool) - if passing.size > 0: - cutoff = ranked[int(np.max(passing))] - mask = p <= cutoff - return mask diff --git a/src/nstat/cif.py b/src/nstat/cif.py deleted file mode 100644 index 0d3cae20..00000000 --- a/src/nstat/cif.py +++ /dev/null @@ -1,213 +0,0 @@ -"""Conditional intensity function models and simulation.""" - -from __future__ import annotations - -from dataclasses import dataclass - -import numpy as np -from scipy.special import expit, gammaln - - -@dataclass(slots=True) -class CIFModel: - """Generalized linear conditional intensity model. - - Parameters - ---------- - coefficients: - Model coefficients, one per feature. - intercept: - Scalar intercept term. - link: - `poisson` (log link) or `binomial` (logit link). - """ - - coefficients: np.ndarray - intercept: float = 0.0 - link: str = "poisson" - - def __post_init__(self) -> None: - self.coefficients = np.asarray(self.coefficients, dtype=float) - if self.coefficients.ndim != 1: - raise ValueError("coefficients must be 1D") - if self.link not in {"poisson", "binomial"}: - raise ValueError("link must be 'poisson' or 'binomial'") - - def linear_predictor(self, X: np.ndarray) -> np.ndarray: - """Compute linear predictor ``eta = intercept + X @ coefficients``.""" - - X = np.asarray(X, dtype=float) - if X.ndim != 2: - raise ValueError("X must be 2D") - if X.shape[1] != self.coefficients.size: - raise ValueError("X feature dimension mismatch") - return self.intercept + X @ self.coefficients - - def evaluate(self, X: np.ndarray) -> np.ndarray: - """Evaluate point-wise intensity (Poisson) or probability (binomial).""" - - eta = self.linear_predictor(X) - if self.link == "poisson": - # Clip for numerical stability in high-magnitude regimes. - return np.exp(np.clip(eta, -50.0, 50.0)) - return expit(eta) - - def eval_lambda_delta(self, X: np.ndarray, dt: float = 1.0) -> np.ndarray: - """Evaluate ``lambda * dt`` for Poisson, or Bernoulli probability for binomial.""" - - if dt <= 0.0: - raise ValueError("dt must be positive") - lam = self.evaluate(X) - if self.link == "poisson": - return lam * float(dt) - return lam - - def log_likelihood(self, y: np.ndarray, X: np.ndarray, dt: float = 1.0) -> float: - """Return independent-bin log-likelihood under the configured link. - - Parameters - ---------- - y: - Observation vector. - - Poisson: non-negative integer counts per bin. - - Binomial: Bernoulli outcomes in ``{0, 1}``. - X: - Design matrix with shape ``(n_samples, n_features)``. - dt: - Bin width in seconds. Poisson intensity is interpreted in Hz, so - expected counts are ``lambda * dt``. - """ - - y = np.asarray(y, dtype=float) - if y.ndim != 1: - raise ValueError("y must be a 1D vector") - mu = self.evaluate(X) - if mu.shape[0] != y.size: - raise ValueError("X and y sample dimensions must match") - if dt <= 0.0: - raise ValueError("dt must be positive") - - if self.link == "poisson": - lam = np.clip(mu * dt, 1e-12, None) - return float(np.sum(y * np.log(lam) - lam - gammaln(y + 1.0))) - - p = np.clip(mu, 1e-9, 1.0 - 1e-9) - return float(np.sum(y * np.log(p) + (1.0 - y) * np.log(1.0 - p))) - - def simulate_by_thinning(self, time: np.ndarray, X: np.ndarray, rng: np.random.Generator | None = None) -> np.ndarray: - """Simulate spike times on a fixed grid. - - Notes - ----- - For Poisson models this performs exact simulation under a - piecewise-constant intensity assumption over each time bin. - For binomial models this performs one Bernoulli draw per bin. - """ - - time = np.asarray(time, dtype=float) - if time.ndim != 1 or time.size < 2: - raise ValueError("time must be a 1D grid with >=2 samples") - if np.any(np.diff(time) <= 0.0): - raise ValueError("time must be strictly increasing") - - rng = rng or np.random.default_rng() - values = self.evaluate(X) - if values.shape[0] != time.size: - raise ValueError("X must have one row per time sample") - - dt = np.diff(time) - dt = np.concatenate([dt, [float(np.median(dt))]]) - if self.link == "poisson": - expected_counts = np.clip(values * dt, 0.0, None) - n_per_bin = rng.poisson(expected_counts) - spikes: list[float] = [] - for i, n_spikes in enumerate(n_per_bin): - if n_spikes <= 0: - continue - bin_start = time[i] - bin_end = bin_start + dt[i] - # Uniform within-bin placement gives an exact sample for - # homogeneous intensity inside each discretized interval. - spikes.extend(rng.uniform(bin_start, bin_end, size=int(n_spikes)).tolist()) - if not spikes: - return np.array([], dtype=float) - return np.sort(np.asarray(spikes, dtype=float)) - - p = np.clip(values, 0.0, 1.0) - draws = rng.random(time.size) < p - return time[draws] - - def compute_plot_params(self, X: np.ndarray) -> dict[str, float]: - """Return compact summary stats useful for help/notebook plots.""" - - vals = np.asarray(self.evaluate(X), dtype=float) - return { - "min": float(np.min(vals)), - "max": float(np.max(vals)), - "mean": float(np.mean(vals)), - "std": float(np.std(vals)), - } - - def to_structure(self) -> dict[str, np.ndarray | float | str]: - """Serialize model parameters to a plain structure.""" - - return { - "coefficients": self.coefficients.copy(), - "intercept": float(self.intercept), - "link": self.link, - } - - @staticmethod - def from_structure(payload: dict[str, np.ndarray | float | str]) -> "CIFModel": - """Deserialize from :meth:`to_structure` payload.""" - - return CIFModel( - coefficients=np.asarray(payload["coefficients"], dtype=float), - intercept=float(payload["intercept"]), - link=str(payload["link"]), - ) - - @staticmethod - def simulate_cif_by_thinning_from_lambda( - time: np.ndarray, - lambda_values: np.ndarray, - num_realizations: int = 1, - rng: np.random.Generator | None = None, - ) -> list[np.ndarray]: - """Simulate spike times from explicit lambda(t) traces. - - This is a Python-native counterpart to MATLAB's - `CIF.simulateCIFByThinningFromLambda` workflow. - """ - - time = np.asarray(time, dtype=float) - lam = np.asarray(lambda_values, dtype=float) - if time.ndim != 1 or time.size < 2: - raise ValueError("time must be a 1D grid with at least two samples") - if lam.ndim != 1 or lam.shape[0] != time.size: - raise ValueError("lambda_values must be 1D and match time length") - if np.any(lam < 0.0): - raise ValueError("lambda_values must be non-negative") - if num_realizations <= 0: - raise ValueError("num_realizations must be positive") - - rng = rng or np.random.default_rng() - dt = np.diff(time) - dt = np.concatenate([dt, [float(np.median(dt))]]) - expected = np.clip(lam * dt, 0.0, None) - - out: list[np.ndarray] = [] - for _ in range(num_realizations): - n_per_bin = rng.poisson(expected) - spikes: list[float] = [] - for i, n_spikes in enumerate(n_per_bin): - if n_spikes <= 0: - continue - t0 = float(time[i]) - t1 = t0 + float(dt[i]) - spikes.extend(rng.uniform(t0, t1, size=int(n_spikes)).tolist()) - if spikes: - out.append(np.sort(np.asarray(spikes, dtype=float))) - else: - out.append(np.array([], dtype=float)) - return out diff --git a/src/nstat/compat/__init__.py b/src/nstat/compat/__init__.py deleted file mode 100644 index fb464b11..00000000 --- a/src/nstat/compat/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Compatibility namespaces for nSTAT-python.""" diff --git a/src/nstat/compat/matlab/__init__.py b/src/nstat/compat/matlab/__init__.py deleted file mode 100644 index 3d8fbe9e..00000000 --- a/src/nstat/compat/matlab/__init__.py +++ /dev/null @@ -1,3954 +0,0 @@ -"""MATLAB-style compatibility adapters. - -This module exposes class names and method aliases resembling MATLAB nSTAT -naming conventions while delegating all computation to the Python-native -`nstat.*` implementations. -""" - -from __future__ import annotations - -from typing import Any, Literal, cast - -import numpy as np - -from ...analysis import Analysis as _Analysis -from ...cif import CIFModel as _CIFModel -from ...confidence import ConfidenceInterval as _ConfidenceInterval -from ...decoding import DecodingAlgorithms as _DecodingAlgorithms -from ...events import Events as _Events -from ...fit import FitResult as _FitResult -from ...fit import FitSummary as _FitSummary -from ...history import HistoryBasis as _HistoryBasis -from ...signal import Covariate as _Covariate -from ...signal import Signal as _Signal -from ...spikes import SpikeTrain as _SpikeTrain -from ...spikes import SpikeTrainCollection as _SpikeTrainCollection -from ...trial import ConfigCollection as _ConfigCollection -from ...trial import CovariateCollection as _CovariateCollection -from ...trial import Trial as _Trial -from ...trial import TrialConfig as _TrialConfig - - -class SignalObj(_Signal): - def _ensure_signalobj_state(self) -> None: - if not hasattr(self, "_original_time"): - self._original_time = self.time.copy() - self._original_data = self.data.copy() - self._original_name = str(self.name) - if not hasattr(self, "_data_labels"): - self._data_labels = [f"sig_{i+1}" for i in range(self.n_channels)] - if not hasattr(self, "_data_mask"): - self._data_mask = list(range(self.n_channels)) - - def setName(self, name: str) -> "SignalObj": - self.set_name(name) - return self - - def setXlabel(self, label: str) -> "SignalObj": - self.set_xlabel(label) - return self - - def setYLabel(self, label: str) -> "SignalObj": - self.set_ylabel(label) - return self - - def setUnits(self, units: str) -> "SignalObj": - self.set_units(units) - return self - - def setXUnits(self, units: str) -> "SignalObj": - self.set_x_units(units) - return self - - def setYUnits(self, units: str) -> "SignalObj": - self.set_y_units(units) - return self - - def setMinTime(self, minTime: float) -> "SignalObj": - self.set_min_time(minTime) - return self - - def setMaxTime(self, maxTime: float) -> "SignalObj": - self.set_max_time(maxTime) - return self - - def setPlotProps(self, props: dict[str, Any]) -> "SignalObj": - self.set_plot_props(props) - return self - - def clearPlotProps(self) -> "SignalObj": - self.clear_plot_props() - return self - - def copySignal(self) -> "SignalObj": - copied = self.copy_signal() - return SignalObj( - time=copied.time, - data=copied.data, - name=copied.name, - units=copied.units, - x_label=copied.x_label, - y_label=copied.y_label, - x_units=copied.x_units, - y_units=copied.y_units, - plot_props=copied.plot_props, - ) - - def shiftTime(self, offset_s: float) -> "SignalObj": - self.shift_time(offset_s) - return self - - def alignTime(self, newZero: float = 0.0) -> "SignalObj": - self.align_time(newZero) - return self - - def derivative(self) -> "SignalObj": - out = super().derivative() - return SignalObj( - time=out.time, - data=out.data, - name=out.name, - units=out.units, - x_label=out.x_label, - y_label=out.y_label, - x_units=out.x_units, - y_units=out.y_units, - plot_props=out.plot_props, - ) - - def integral(self) -> np.ndarray: - return super().integral() - - def dataToMatrix(self) -> np.ndarray: - return self.data_to_matrix() - - def getSubSignal(self, selector: int | list[int] | np.ndarray) -> "SignalObj": - out = super().get_sub_signal(selector) - return SignalObj( - time=out.time, - data=out.data, - name=out.name, - units=out.units, - x_label=out.x_label, - y_label=out.y_label, - x_units=out.x_units, - y_units=out.y_units, - plot_props=out.plot_props, - ) - - def merge(self, other: _Signal) -> "SignalObj": - out = super().merge(other) - return SignalObj( - time=out.time, - data=out.data, - name=out.name, - units=out.units, - x_label=out.x_label, - y_label=out.y_label, - x_units=out.x_units, - y_units=out.y_units, - plot_props=out.plot_props, - ) - - def resample(self, sampleRate: float) -> "SignalObj": - out = super().resample(sampleRate) - return SignalObj( - time=out.time, - data=out.data, - name=out.name, - units=out.units, - x_label=out.x_label, - y_label=out.y_label, - x_units=out.x_units, - y_units=out.y_units, - plot_props=out.plot_props, - ) - - def getData(self) -> np.ndarray: - return self.data - - def getTime(self) -> np.ndarray: - return self.time - - def getNumSamples(self) -> int: - return self.n_samples - - def getNumSignals(self) -> int: - return self.n_channels - - def getSampleRate(self) -> float: - return self.sample_rate_hz - - def getDuration(self) -> float: - return self.duration_s - - def _with_data(self, data: np.ndarray, name: str | None = None) -> "SignalObj": - return SignalObj( - time=self.time.copy(), - data=np.asarray(data, dtype=float), - name=self.name if name is None else name, - units=self.units, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def dataToStructure(self) -> dict[str, Any]: - return { - "time": self.time.copy(), - "data": np.asarray(self.data, dtype=float).copy(), - "name": self.name, - "units": self.units, - "x_label": self.x_label, - "y_label": self.y_label, - "x_units": self.x_units, - "y_units": self.y_units, - "plot_props": dict(self.plot_props), - } - - @staticmethod - def signalFromStruct(payload: dict[str, Any]) -> "SignalObj": - return SignalObj( - time=np.asarray(payload["time"], dtype=float), - data=np.asarray(payload["data"], dtype=float), - name=str(payload.get("name", "signal")), - units=str(payload.get("units", "")), - x_label=payload.get("x_label"), - y_label=payload.get("y_label"), - x_units=payload.get("x_units"), - y_units=payload.get("y_units"), - plot_props=dict(payload.get("plot_props", {})), - ) - - @staticmethod - def convertSimpleStructureToSigStructure(payload: dict[str, Any]) -> dict[str, Any]: - return dict(payload) - - @staticmethod - def convertSigStructureToStructure(payload: dict[str, Any]) -> dict[str, Any]: - return dict(payload) - - def getPlotProps(self) -> dict[str, Any]: - return dict(self.plot_props) - - def plotPropsSet(self) -> bool: - return bool(self.plot_props) - - def findNearestTimeIndex(self, queryTime: float) -> int: - return int(np.argmin(np.abs(self.time - float(queryTime)))) - - def findNearestTimeIndices(self, queryTimes: np.ndarray) -> np.ndarray: - q = np.asarray(queryTimes, dtype=float).reshape(-1) - return np.asarray([self.findNearestTimeIndex(v) for v in q], dtype=int) - - def getValueAt(self, queryTime: float) -> np.ndarray: - idx = self.findNearestTimeIndex(queryTime) - row = self.data_to_matrix()[idx] - return row.copy() - - def getSigInTimeWindow(self, t0: float, tf: float) -> "SignalObj": - mask = (self.time >= float(t0)) & (self.time <= float(tf)) - if not np.any(mask): - raise ValueError("time window excludes all samples") - data = self.data_to_matrix()[mask] - if data.shape[1] == 1: - out_data = data[:, 0] - else: - out_data = data - return SignalObj( - time=self.time[mask].copy(), - data=out_data, - name=self.name, - units=self.units, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def derivativeAt(self, queryTime: float) -> np.ndarray: - return self.derivative().getValueAt(queryTime) - - def findGlobalPeak(self) -> tuple[float, float, int]: - mat = self.data_to_matrix() - idx_flat = int(np.argmax(mat)) - idx_t, _ = np.unravel_index(idx_flat, mat.shape) - return float(mat[idx_t].max()), float(self.time[idx_t]), int(idx_t) - - def findMaxima(self) -> tuple[np.ndarray, np.ndarray]: - from scipy.signal import find_peaks - - y = np.mean(self.data_to_matrix(), axis=1) - idx, _ = find_peaks(y) - return self.time[idx], y[idx] - - def findMinima(self) -> tuple[np.ndarray, np.ndarray]: - from scipy.signal import find_peaks - - y = np.mean(self.data_to_matrix(), axis=1) - idx, _ = find_peaks(-y) - return self.time[idx], y[idx] - - def findPeaks(self) -> tuple[np.ndarray, np.ndarray]: - return self.findMaxima() - - def setSampleRate(self, sampleRate: float) -> "SignalObj": - out = self.resample(sampleRate) - self.time = out.time - self.data = out.data - return self - - def resampleMe(self, sampleRate: float) -> "SignalObj": - return self.setSampleRate(sampleRate) - - def shift(self, offset_s: float) -> "SignalObj": - return self.shiftTime(offset_s) - - def shiftMe(self, offset_s: float) -> "SignalObj": - return self.shiftTime(offset_s) - - def setupPlots(self) -> "SignalObj": - return self - - def plot(self, *_args: Any, **_kwargs: Any) -> Any: - import matplotlib.pyplot as plt - - h = plt.plot(self.time, self.data_to_matrix()) - return h - - def abs(self) -> "SignalObj": - return self._with_data(np.abs(self.data_to_matrix()), name=f"abs({self.name})") - - def log(self) -> "SignalObj": - return self._with_data(np.log(np.clip(self.data_to_matrix(), 1e-12, None)), name=f"log({self.name})") - - def sqrt(self) -> "SignalObj": - return self._with_data(np.sqrt(np.clip(self.data_to_matrix(), 0.0, None)), name=f"sqrt({self.name})") - - def plus(self, other: float | np.ndarray | "SignalObj") -> "SignalObj": - rhs = other.data_to_matrix() if isinstance(other, SignalObj) else np.asarray(other, dtype=float) - return self._with_data(self.data_to_matrix() + rhs) - - def minus(self, other: float | np.ndarray | "SignalObj") -> "SignalObj": - rhs = other.data_to_matrix() if isinstance(other, SignalObj) else np.asarray(other, dtype=float) - return self._with_data(self.data_to_matrix() - rhs) - - def times(self, other: float | np.ndarray | "SignalObj") -> "SignalObj": - rhs = other.data_to_matrix() if isinstance(other, SignalObj) else np.asarray(other, dtype=float) - return self._with_data(self.data_to_matrix() * rhs) - - def rdivide(self, other: float | np.ndarray | "SignalObj") -> "SignalObj": - rhs = other.data_to_matrix() if isinstance(other, SignalObj) else np.asarray(other, dtype=float) - return self._with_data(self.data_to_matrix() / np.clip(rhs, 1e-12, None)) - - def power(self, exponent: float) -> "SignalObj": - return self._with_data(np.power(self.data_to_matrix(), float(exponent))) - - def mean(self) -> float: - return float(np.mean(self.data_to_matrix())) - - def median(self) -> float: - return float(np.median(self.data_to_matrix())) - - def max(self) -> float: - return float(np.max(self.data_to_matrix())) - - def min(self) -> float: - return float(np.min(self.data_to_matrix())) - - def std(self) -> float: - return float(np.std(self.data_to_matrix(), ddof=0)) - - def mode(self) -> float: - vals, counts = np.unique(self.data_to_matrix().reshape(-1), return_counts=True) - return float(vals[np.argmax(counts)]) - - @staticmethod - def cell2str(cells: list[Any], delimiter: str = ",") -> str: - return delimiter.join(str(v) for v in cells) - - @staticmethod - def getAvailableColor(index: int = 0) -> str: - palette = ["b", "g", "r", "c", "m", "y", "k"] - return palette[int(index) % len(palette)] - - def setDataLabels(self, labels: list[str]) -> "SignalObj": - self._ensure_signalobj_state() - if len(labels) != self.n_channels: - raise ValueError("labels length must match number of channels") - self._data_labels = [str(v) for v in labels] - return self - - def areDataLabelsEmpty(self) -> bool: - self._ensure_signalobj_state() - return len(self._data_labels) == 0 - - def getIndexFromLabel(self, label: str) -> int: - self._ensure_signalobj_state() - return self._data_labels.index(str(label)) - - def getIndicesFromLabels(self, labels: list[str]) -> list[int]: - self._ensure_signalobj_state() - return [self.getIndexFromLabel(label) for label in labels] - - def isLabelPresent(self, label: str) -> bool: - self._ensure_signalobj_state() - return str(label) in self._data_labels - - def convertNamesToIndices(self, labels: list[str]) -> list[int]: - return self.getIndicesFromLabels(labels) - - def setDataMask(self, mask: list[int] | np.ndarray) -> "SignalObj": - self._ensure_signalobj_state() - idx = [int(v) for v in np.asarray(mask, dtype=int).reshape(-1)] - clean: list[int] = [] - for i in idx: - if i >= 1 and i <= self.n_channels: - clean.append(i - 1) - elif i >= 0 and i < self.n_channels: - clean.append(i) - else: - raise IndexError("mask index out of range") - self._data_mask = sorted(set(clean)) - return self - - def setMask(self, selector: list[int] | list[str] | np.ndarray) -> "SignalObj": - vals = np.asarray(selector, dtype=object).reshape(-1).tolist() - if vals and all(isinstance(v, (str, np.str_)) for v in vals): - self._ensure_signalobj_state() - idx = self.getIndicesFromLabels([str(v) for v in vals]) - self._data_mask = sorted(set(idx)) - return self - return self.setDataMask([int(v) for v in vals]) - - def setMaskByInd(self, mask: list[int] | np.ndarray) -> "SignalObj": - return self.setDataMask(mask) - - def setMaskByLabels(self, labels: list[str]) -> "SignalObj": - return self.setMask(labels) - - def isMaskSet(self) -> bool: - self._ensure_signalobj_state() - return self._data_mask != list(range(self.n_channels)) - - def findIndFromDataMask(self) -> list[int]: - self._ensure_signalobj_state() - return list(self._data_mask) - - def resetMask(self) -> "SignalObj": - self._ensure_signalobj_state() - self._data_mask = list(range(self.n_channels)) - return self - - def getSubSignalFromInd(self, selector: int | list[int] | np.ndarray) -> "SignalObj": - return self.getSubSignal(selector) - - def getSubSignalFromNames(self, labels: list[str]) -> "SignalObj": - return self.getSubSignal(self.getIndicesFromLabels(labels)) - - def getSubSignalsWithinNStd(self, nStd: float = 1.0) -> "SignalObj": - mat = self.data_to_matrix() - means = np.mean(mat, axis=0) - mu = float(np.mean(means)) - sigma = float(np.std(means)) - if sigma <= 0.0: - idx = list(range(mat.shape[1])) - else: - idx = [i for i, m in enumerate(means) if abs(float(m) - mu) <= float(nStd) * sigma] - if not idx: - idx = [int(np.argmin(np.abs(means - mu)))] - return self.getSubSignal(idx) - - def getOrigDataSig(self) -> "SignalObj": - self._ensure_signalobj_state() - return SignalObj( - time=self._original_time.copy(), - data=np.asarray(self._original_data, dtype=float).copy(), - name=str(self._original_name), - units=self.units, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def getOriginalData(self) -> np.ndarray: - self._ensure_signalobj_state() - return np.asarray(self._original_data, dtype=float).copy() - - def restoreToOriginal(self) -> "SignalObj": - self._ensure_signalobj_state() - self.time = self._original_time.copy() - self.data = np.asarray(self._original_data, dtype=float).copy() - self.name = str(self._original_name) - self.resetMask() - return self - - def makeCompatible(self, other: _Signal) -> tuple["SignalObj", "SignalObj"]: - rhs = SignalObj( - time=other.time.copy(), - data=other.data.copy(), - name=other.name, - units=other.units, - x_label=other.x_label, - y_label=other.y_label, - x_units=other.x_units, - y_units=other.y_units, - plot_props=dict(other.plot_props), - ) - fs = max(float(self.sample_rate_hz), float(rhs.sample_rate_hz)) - lhs_r = self.resample(fs) - rhs_r = rhs.resample(fs) - t0 = max(float(lhs_r.time[0]), float(rhs_r.time[0])) - tf = min(float(lhs_r.time[-1]), float(rhs_r.time[-1])) - if tf <= t0: - raise ValueError("signals do not overlap in time") - return lhs_r.getSigInTimeWindow(t0, tf), rhs_r.getSigInTimeWindow(t0, tf) - - def alignToMax(self, targetTime: float = 0.0) -> "SignalObj": - _max_val, t_max, _idx = self.findGlobalPeak() - return self.shiftTime(float(targetTime) - t_max) - - def windowedSignal(self, windowSamples: int = 11) -> "SignalObj": - win = int(windowSamples) - if win <= 0: - raise ValueError("windowSamples must be positive") - kernel = np.ones(win, dtype=float) / float(win) - mat = self.data_to_matrix() - out = np.column_stack([np.convolve(mat[:, i], kernel, mode="same") for i in range(mat.shape[1])]) - return self._with_data(out, name=f"windowed({self.name})") - - def normWindowedSignal(self, windowSamples: int = 11) -> "SignalObj": - smoothed = self.windowedSignal(windowSamples=windowSamples).data_to_matrix() - mat = self.data_to_matrix() - centered = mat - smoothed - scale = np.std(centered, axis=0, keepdims=True) - scale = np.where(scale <= 1e-12, 1.0, scale) - return self._with_data(centered / scale, name=f"norm_windowed({self.name})") - - def filter(self, b: np.ndarray, a: np.ndarray) -> "SignalObj": - from scipy.signal import lfilter - - b_arr = np.asarray(b, dtype=float).reshape(-1) - a_arr = np.asarray(a, dtype=float).reshape(-1) - mat = self.data_to_matrix() - out = np.column_stack([lfilter(b_arr, a_arr, mat[:, i]) for i in range(mat.shape[1])]) - return self._with_data(out, name=f"filter({self.name})") - - def filtfilt(self, b: np.ndarray, a: np.ndarray) -> "SignalObj": - from scipy.signal import filtfilt - from scipy.signal import lfilter - - b_arr = np.asarray(b, dtype=float).reshape(-1) - a_arr = np.asarray(a, dtype=float).reshape(-1) - mat = self.data_to_matrix() - filtered_cols: list[np.ndarray] = [] - for i in range(mat.shape[1]): - x = np.asarray(mat[:, i], dtype=float).reshape(-1) - if x.size < 2: - filtered_cols.append(lfilter(b_arr, a_arr, x)) - continue - ntaps = max(int(a_arr.size), int(b_arr.size)) - padlen = min(3 * ntaps, int(x.size) - 1) - try: - filtered_cols.append(filtfilt(b_arr, a_arr, x, padlen=padlen)) - except ValueError: - fwd = lfilter(b_arr, a_arr, x) - bwd = lfilter(b_arr, a_arr, fwd[::-1]) - filtered_cols.append(bwd[::-1]) - out = np.column_stack(filtered_cols) - return self._with_data(out, name=f"filtfilt({self.name})") - - def periodogram(self) -> tuple[np.ndarray, np.ndarray]: - from scipy.signal import periodogram - - fs = float(self.sample_rate_hz) - mat = self.data_to_matrix() - f, p = periodogram(mat[:, 0], fs=fs) - return np.asarray(f, dtype=float), np.asarray(p, dtype=float) - - def MTMspectrum(self) -> tuple[np.ndarray, np.ndarray]: - return self.periodogram() - - def spectrogram(self) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - from scipy.signal import spectrogram - - fs = float(self.sample_rate_hz) - mat = self.data_to_matrix() - f, t, s = spectrogram(mat[:, 0], fs=fs) - return np.asarray(f, dtype=float), np.asarray(t, dtype=float), np.asarray(s, dtype=float) - - def _crosscorr_core( - self, - x: np.ndarray, - y: np.ndarray, - maxLag: int | None = None, - demean: bool = False, - ) -> tuple[np.ndarray, np.ndarray]: - x_arr = np.asarray(x, dtype=float).reshape(-1) - y_arr = np.asarray(y, dtype=float).reshape(-1) - if demean: - x_arr = x_arr - np.mean(x_arr) - y_arr = y_arr - np.mean(y_arr) - c = np.correlate(x_arr, y_arr, mode="full") - lags = np.arange(-x_arr.size + 1, y_arr.size, dtype=int) - if maxLag is not None: - mask = (lags >= -int(maxLag)) & (lags <= int(maxLag)) - lags = lags[mask] - c = c[mask] - return lags, c.astype(float) - - def xcorr(self, other: "SignalObj | None" = None, maxLag: int | None = None) -> tuple[np.ndarray, np.ndarray]: - lhs = self.data_to_matrix()[:, 0] - rhs = lhs if other is None else other.data_to_matrix()[:, 0] - return self._crosscorr_core(lhs, rhs, maxLag=maxLag, demean=False) - - def xcov(self, other: "SignalObj | None" = None, maxLag: int | None = None) -> tuple[np.ndarray, np.ndarray]: - lhs = self.data_to_matrix()[:, 0] - rhs = lhs if other is None else other.data_to_matrix()[:, 0] - return self._crosscorr_core(lhs, rhs, maxLag=maxLag, demean=True) - - def autocorrelation(self, maxLag: int | None = None) -> tuple[np.ndarray, np.ndarray]: - return self.xcorr(other=None, maxLag=maxLag) - - def crosscorrelation(self, other: "SignalObj", maxLag: int | None = None) -> tuple[np.ndarray, np.ndarray]: - return self.xcorr(other=other, maxLag=maxLag) - - def plotVariability(self) -> Any: - import matplotlib.pyplot as plt - - mat = self.data_to_matrix() - mu = np.mean(mat, axis=1) - sd = np.std(mat, axis=1) - plt.plot(self.time, mu, "k-") - return plt.fill_between(self.time, mu - sd, mu + sd, color="k", alpha=0.2) - - def plotAllVariability(self) -> Any: - return self.plotVariability() - - def transpose(self) -> "SignalObj": - return self.copySignal() - - def ctranspose(self) -> "SignalObj": - return self.transpose() - - def uminus(self) -> "SignalObj": - return self._with_data(-self.data_to_matrix(), name=f"-({self.name})") - - def uplus(self) -> "SignalObj": - return self.copySignal() - - def mtimes(self, other: float | np.ndarray | "SignalObj") -> "SignalObj": - lhs = self.data_to_matrix() - if isinstance(other, SignalObj): - rhs = other.data_to_matrix() - out = lhs @ rhs if lhs.shape[1] == rhs.shape[0] else lhs * rhs - return self._with_data(out, name=f"{self.name}*") - if np.isscalar(other): - scalar = float(np.asarray(other, dtype=float).reshape(()).item()) - out = lhs * scalar - return self._with_data(out, name=f"{self.name}*") - rhs = np.asarray(other, dtype=float) - if rhs.ndim == 1: - out = lhs * rhs.reshape(1, -1) - else: - out = lhs @ rhs - return self._with_data(out, name=f"{self.name}*") - - def ldivide(self, other: float | np.ndarray | "SignalObj") -> "SignalObj": - if isinstance(other, SignalObj): - rhs = other.data_to_matrix() - else: - rhs = np.asarray(other, dtype=float) - lhs = np.clip(self.data_to_matrix(), 1e-12, None) - return self._with_data(rhs / lhs, name=f"{self.name}\\") - - -class Covariate(_Covariate): - @staticmethod - def Covariate(payload: dict[str, Any]) -> _Covariate: - return Covariate.fromStructure(payload) - - def computeMeanPlusCI(self, axis: int = 1, level: float = 0.95) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - return self.compute_mean_plus_ci(axis=axis, level=level) - - def getSubSignal(self, selector: int | str | list[int] | list[str]) -> _Covariate: - out = super().get_sub_signal(selector) - return Covariate( - time=out.time, - data=out.data, - name=out.name, - units=out.units, - labels=out.labels, - conf_interval=out.conf_interval, - x_label=out.x_label, - y_label=out.y_label, - x_units=out.x_units, - y_units=out.y_units, - plot_props=out.plot_props, - ) - - def setConfInterval(self, interval: Any) -> _Covariate: - self.set_conf_interval(interval) - return self - - def isConfIntervalSet(self) -> bool: - return self.is_conf_interval_set() - - def getSigRep(self) -> np.ndarray: - return self.data_to_matrix() - - def dataToStructure(self) -> dict[str, Any]: - return self.to_structure() - - def toStructure(self) -> dict[str, Any]: - return self.to_structure() - - @staticmethod - def fromStructure(payload: dict[str, Any]) -> _Covariate: - out = _Covariate.from_structure(payload) - return Covariate( - time=out.time, - data=out.data, - name=out.name, - units=out.units, - labels=out.labels, - conf_interval=out.conf_interval, - x_label=out.x_label, - y_label=out.y_label, - x_units=out.x_units, - y_units=out.y_units, - plot_props=out.plot_props, - ) - - def getData(self) -> np.ndarray: - return self.data - - def getTime(self) -> np.ndarray: - return self.time - - def getLabels(self) -> list[str]: - return self.labels - - def getNumSignals(self) -> int: - return self.n_channels - - def getSampleRate(self) -> float: - return self.sample_rate_hz - - def copySignal(self) -> _Covariate: - out = super().copy_signal() - return Covariate( - time=out.time, - data=out.data, - name=out.name, - units=out.units, - labels=self.labels.copy(), - conf_interval=self.conf_interval, - x_label=out.x_label, - y_label=out.y_label, - x_units=out.x_units, - y_units=out.y_units, - plot_props=out.plot_props, - ) - - def plus(self, other: float | np.ndarray | _Signal) -> _Covariate: - if isinstance(other, _Signal): - rhs = other.data_to_matrix() - else: - rhs = np.asarray(other, dtype=float) - lhs = self.data_to_matrix() - out = lhs + rhs - data = out[:, 0] if out.ndim == 2 and out.shape[1] == 1 else out - return Covariate( - time=self.time.copy(), - data=data, - name=f"{self.name}+", - units=self.units, - labels=self.labels.copy(), - conf_interval=self.conf_interval, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def minus(self, other: float | np.ndarray | _Signal) -> _Covariate: - if isinstance(other, _Signal): - rhs = other.data_to_matrix() - else: - rhs = np.asarray(other, dtype=float) - lhs = self.data_to_matrix() - out = lhs - rhs - data = out[:, 0] if out.ndim == 2 and out.shape[1] == 1 else out - return Covariate( - time=self.time.copy(), - data=data, - name=f"{self.name}-", - units=self.units, - labels=self.labels.copy(), - conf_interval=self.conf_interval, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def plot(self, *_args: Any, **_kwargs: Any) -> Any: - import matplotlib.pyplot as plt - - return plt.plot(self.time, self.data_to_matrix()) - - -class ConfidenceInterval(_ConfidenceInterval): - @staticmethod - def ConfidenceInterval(*args: Any, **kwargs: Any) -> _ConfidenceInterval: - if len(args) == 1 and isinstance(args[0], dict): - return ConfidenceInterval.fromStructure(args[0]) - return ConfidenceInterval(*args, **kwargs) - - @staticmethod - def fromStructure(payload: dict[str, Any]) -> _ConfidenceInterval: - return ConfidenceInterval( - time=np.asarray(payload["time"], dtype=float), - lower=np.asarray(payload["lower"], dtype=float), - upper=np.asarray(payload["upper"], dtype=float), - level=float(payload.get("level", 0.95)), - ) - - def toStructure(self) -> dict[str, Any]: - return { - "time": self.time.copy(), - "lower": self.lower.copy(), - "upper": self.upper.copy(), - "level": float(self.level), - } - - def setColor(self, color: str) -> _ConfidenceInterval: - setattr(self, "_color", str(color)) - return self - - def setValue(self, values: np.ndarray | float) -> _ConfidenceInterval: - arr = np.asarray(values, dtype=float) - if arr.ndim == 0: - arr = np.full(self.time.shape, float(arr), dtype=float) - if arr.shape != self.time.shape: - raise ValueError("values shape must match time shape") - half_width = 0.5 * self.width() - self.lower = arr - half_width - self.upper = arr + half_width - return self - - def plot(self, *_args: Any, **_kwargs: Any) -> Any: - import matplotlib.pyplot as plt - - color = getattr(self, "_color", "tab:blue") - return plt.fill_between(self.time, self.lower, self.upper, color=color, alpha=0.25) - - def getWidth(self) -> np.ndarray: - return self.width() - - -class Events(_Events): - @staticmethod - def Events(*args: Any, **kwargs: Any) -> _Events: - if len(args) == 1 and isinstance(args[0], dict): - return Events.fromStructure(args[0]) - return Events(*args, **kwargs) - - @staticmethod - def fromStructure(payload: dict[str, Any]) -> _Events: - return Events( - times=np.asarray(payload["times"], dtype=float), - labels=[str(v) for v in payload.get("labels", [])], - ) - - def toStructure(self) -> dict[str, Any]: - return {"times": self.times.copy(), "labels": list(self.labels)} - - @staticmethod - def dsxy2figxy(x: np.ndarray | float, y: np.ndarray | float) -> np.ndarray: - import matplotlib.pyplot as plt - - ax = plt.gca() - pts = np.column_stack([np.asarray(x, dtype=float).reshape(-1), np.asarray(y, dtype=float).reshape(-1)]) - disp = ax.transData.transform(pts) - fig = ax.get_figure() - if fig is None: - raise RuntimeError("cannot transform without an active matplotlib figure") - out = fig.transFigure.inverted().transform(disp) - return out - - def plot(self, *_args: Any, **_kwargs: Any) -> Any: - import matplotlib.pyplot as plt - - if self.times.size == 0: - return plt.plot([], []) - ymin, ymax = plt.ylim() - if ymin == ymax: - ymin, ymax = 0.0, 1.0 - return plt.vlines(self.times, ymin, ymax, colors="k", linestyles="--", linewidth=1.0) - - def getTimes(self) -> np.ndarray: - return self.times - - -class History(_HistoryBasis): - @staticmethod - def History(*args: Any, **kwargs: Any) -> _HistoryBasis: - if len(args) == 1 and isinstance(args[0], dict): - return History.fromStructure(args[0]) - return History(*args, **kwargs) - - @staticmethod - def fromStructure(payload: dict[str, Any]) -> _HistoryBasis: - return History(bin_edges_s=np.asarray(payload["bin_edges_s"], dtype=float)) - - def toStructure(self) -> dict[str, Any]: - return {"bin_edges_s": self.bin_edges_s.copy()} - - def setWindow(self, *args: Any) -> _HistoryBasis: - if len(args) == 1: - edges = np.asarray(args[0], dtype=float).reshape(-1) - elif len(args) == 3: - t0 = float(args[0]) - tf = float(args[1]) - n_bins = int(args[2]) - if n_bins <= 0: - raise ValueError("n_bins must be > 0") - edges = np.linspace(t0, tf, n_bins + 1, dtype=float) - else: - raise ValueError("setWindow expects (edges) or (t0, tf, n_bins)") - if edges.size < 2 or np.any(np.diff(edges) <= 0.0): - raise ValueError("history edges must be strictly increasing with at least 2 elements") - self.bin_edges_s = edges - return self - - def toFilter(self) -> np.ndarray: - widths = np.diff(self.bin_edges_s) - total = float(np.sum(widths)) - if total <= 0.0: - return widths - return widths / total - - def computeHistory(self, spikeTimes_s: np.ndarray, timeGrid_s: np.ndarray) -> np.ndarray: - return self.design_matrix(spike_times_s=spikeTimes_s, time_grid_s=timeGrid_s) - - def computeNSTHistoryWindow(self, spikeTrain: Any, timeGrid_s: np.ndarray) -> np.ndarray: - spike_times = np.asarray(getattr(spikeTrain, "spike_times"), dtype=float) - return self.computeHistory(spikeTimes_s=spike_times, timeGrid_s=timeGrid_s) - - def plot(self, *_args: Any, **_kwargs: Any) -> Any: - import matplotlib.pyplot as plt - - widths = np.diff(self.bin_edges_s) - centers = 0.5 * (self.bin_edges_s[:-1] + self.bin_edges_s[1:]) - return plt.bar(centers, widths, width=widths, align="center", alpha=0.4, color="tab:gray") - - def getNumBins(self) -> int: - return self.n_bins - - def getDesignMatrix(self, spike_times_s: np.ndarray, time_grid_s: np.ndarray) -> np.ndarray: - return self.design_matrix(spike_times_s=spike_times_s, time_grid_s=time_grid_s) - - -class nspikeTrain(_SpikeTrain): - def __post_init__(self) -> None: - super().__post_init__() - self._original_spike_times = self.spike_times.copy() - self._original_t_start = float(self.t_start) - self._original_t_end = float(self.t_end) if self.t_end is not None else None - self._original_name = str(self.name) - self._sig_rep: np.ndarray | None = None - self._mer: float | None = None - - @staticmethod - def nspikeTrain(*args: Any, **kwargs: Any) -> _SpikeTrain: - if len(args) == 1 and isinstance(args[0], dict): - return nspikeTrain.fromStructure(args[0]) - return nspikeTrain(*args, **kwargs) - - @staticmethod - def fromStructure(payload: dict[str, Any]) -> _SpikeTrain: - t_end_raw = payload.get("t_end", payload.get("maxTime")) - return nspikeTrain( - spike_times=np.asarray(payload.get("spike_times", payload.get("spikeTimes", [])), dtype=float), - t_start=float(payload.get("t_start", payload.get("minTime", 0.0))), - t_end=float(t_end_raw) if t_end_raw is not None else None, - name=str(payload.get("name", "unit")), - ) - - def toStructure(self) -> dict[str, Any]: - return { - "spike_times": self.spike_times.copy(), - "t_start": float(self.t_start), - "t_end": float(self.t_end) if self.t_end is not None else None, - "name": str(self.name), - "MER": self._mer, - } - - def setName(self, name: str) -> _SpikeTrain: - self.name = str(name) - return self - - def setMER(self, mer: float) -> _SpikeTrain: - self._mer = float(mer) - return self - - def setSigRep(self, sigRep: np.ndarray) -> _SpikeTrain: - self._sig_rep = np.asarray(sigRep, dtype=float).copy() - return self - - def clearSigRep(self) -> _SpikeTrain: - self._sig_rep = None - return self - - def getSigRep(self, binSize_s: float = 0.001, mode: Literal["binary", "count"] = "binary") -> np.ndarray: - if self._sig_rep is not None: - return self._sig_rep.copy() - if mode == "binary": - _, y = self.binarize(bin_size_s=binSize_s) - else: - _, y = self.bin_counts(bin_size_s=binSize_s) - return y - - def isSigRepBinary(self, binSize_s: float = 0.001) -> bool: - y = self.getSigRep(binSize_s=binSize_s, mode="count") - return bool(np.all((y == 0.0) | (y == 1.0))) - - def getSpikeTimes(self) -> np.ndarray: - return self.spike_times - - def getISIs(self) -> np.ndarray: - return np.diff(self.spike_times) - - def getMinISI(self) -> float: - isi = self.getISIs() - if isi.size == 0: - return float(np.inf) - return float(np.min(isi)) - - def getMaxBinSizeBinary(self) -> float: - min_isi = self.getMinISI() - if not np.isfinite(min_isi) or min_isi <= 0.0: - dur = float(self.duration_s()) - return dur if dur > 0.0 else 1.0 - return float(min_isi) - - def getDuration(self) -> float: - return self.duration_s() - - def getFiringRate(self) -> float: - return self.firing_rate_hz() - - def computeRate(self) -> float: - return self.getFiringRate() - - def computeStatistics(self) -> dict[str, float]: - isi = self.getISIs() - return { - "n_spikes": float(self.spike_times.size), - "duration_s": float(self.duration_s()), - "rate_hz": float(self.getFiringRate()), - "mean_isi": float(np.mean(isi)) if isi.size else float(np.nan), - "std_isi": float(np.std(isi)) if isi.size else float(np.nan), - } - - def getFieldVal(self, fieldName: str) -> Any: - if hasattr(self, fieldName): - return getattr(self, fieldName) - raise KeyError(f"field '{fieldName}' not found") - - def getLStatistic(self) -> float: - isi = self.getISIs() - if isi.size == 0: - return 0.0 - mu = float(np.mean(isi)) - if mu <= 0.0: - return 0.0 - return float(np.std(isi) / mu) - - def nstCopy(self) -> _SpikeTrain: - return nspikeTrain( - spike_times=self.spike_times.copy(), - t_start=float(self.t_start), - t_end=float(self.t_end) if self.t_end is not None else None, - name=str(self.name), - ) - - def resample(self, sampleRate: float) -> _SpikeTrain: - if sampleRate <= 0.0: - raise ValueError("sampleRate must be positive") - dt = 1.0 / float(sampleRate) - snapped = np.round(self.spike_times / dt) * dt - self.spike_times = np.unique(snapped) - return self - - def restoreToOriginal(self) -> _SpikeTrain: - self.spike_times = self._original_spike_times.copy() - self.t_start = float(self._original_t_start) - self.t_end = float(self._original_t_end) if self._original_t_end is not None else None - self.name = str(self._original_name) - self._sig_rep = None - return self - - def partitionNST(self, partitionEdges_s: np.ndarray | list[float]) -> list[_SpikeTrain]: - edges = np.asarray(partitionEdges_s, dtype=float).reshape(-1) - if edges.size < 2: - raise ValueError("partition edges must contain at least two values") - out: list[_SpikeTrain] = [] - for i in range(edges.size - 1): - lo = float(edges[i]) - hi = float(edges[i + 1]) - mask = (self.spike_times >= lo) & (self.spike_times <= hi) - out.append( - nspikeTrain(spike_times=self.spike_times[mask], t_start=lo, t_end=hi, name=f"{self.name}_{i+1}") - ) - return out - - def shiftTime(self, offset_s: float) -> _SpikeTrain: - self.shift_time(offset_s) - return self - - def setMinTime(self, t_min: float) -> _SpikeTrain: - self.set_min_time(t_min) - return self - - def setMaxTime(self, t_max: float) -> _SpikeTrain: - self.set_max_time(t_max) - return self - - def plot(self, *_args: Any, **_kwargs: Any) -> Any: - import matplotlib.pyplot as plt - - y = np.ones(self.spike_times.size, dtype=float) - return plt.plot(self.spike_times, y, "k.") - - def plotISIHistogram(self, bins: int = 20) -> Any: - import matplotlib.pyplot as plt - - isi = self.getISIs() - if isi.size == 0: - return plt.hist([], bins=bins) - return plt.hist(isi, bins=bins, color="tab:blue", alpha=0.6) - - def plotExponentialFit(self) -> Any: - import matplotlib.pyplot as plt - - isi = self.getISIs() - if isi.size == 0: - return plt.plot([], []) - lam = 1.0 / max(float(np.mean(isi)), 1e-12) - x = np.linspace(0.0, float(np.max(isi)), 200) - y = lam * np.exp(-lam * x) - return plt.plot(x, y, "r-") - - def plotJointISIHistogram(self, bins: int = 20) -> Any: - import matplotlib.pyplot as plt - - isi = self.getISIs() - if isi.size < 2: - return plt.hist2d([], [], bins=bins) - return plt.hist2d(isi[:-1], isi[1:], bins=bins, cmap="Blues") - - def plotISISpectrumFunction(self) -> Any: - import matplotlib.pyplot as plt - - isi = self.getISIs() - if isi.size < 2: - return plt.plot([], []) - centered = isi - np.mean(isi) - spec = np.abs(np.fft.rfft(centered)) ** 2 - freq = np.fft.rfftfreq(centered.size, d=max(float(np.mean(isi)), 1e-6)) - return plt.plot(freq, spec, "k-") - - def plotProbPlot(self) -> Any: - import matplotlib.pyplot as plt - - isi = np.sort(self.getISIs()) - if isi.size == 0: - return plt.plot([], []) - q = (np.arange(1, isi.size + 1) - 0.5) / isi.size - return plt.plot(q, isi, "k.") - - -class nstColl(_SpikeTrainCollection): - def __post_init__(self) -> None: - super().__post_init__() - self._original_trains = [ - train.copy() if hasattr(train, "copy") else _SpikeTrain(train.spike_times.copy(), train.t_start, train.t_end, train.name) - for train in self.trains - ] - self._neighbors: Any = None - self._neuron_mask: list[int] | None = None - - def getNumUnits(self) -> int: - return self.n_units - - @staticmethod - def nstColl(*args: Any, **kwargs: Any) -> _SpikeTrainCollection: - if len(args) == 1 and isinstance(args[0], dict): - return nstColl.fromStructure(args[0]) - return nstColl(*args, **kwargs) - - def getBinnedMatrix( - self, binSize_s: float, mode: Literal["binary", "count"] = "binary" - ) -> tuple[np.ndarray, np.ndarray]: - return self.to_binned_matrix(bin_size_s=binSize_s, mode=mode) - - def merge(self, other: _SpikeTrainCollection) -> _SpikeTrainCollection: - merged = super().merge(other) - return nstColl(merged.trains) - - def getFirstSpikeTime(self) -> float: - return self.get_first_spike_time() - - def getLastSpikeTime(self) -> float: - return self.get_last_spike_time() - - def getSpikeTimes(self) -> list[np.ndarray]: - return self.get_spike_times() - - def getNST(self, ind: int) -> nspikeTrain: - train = self.get_nst(ind) - return nspikeTrain( - spike_times=train.spike_times.copy(), - t_start=train.t_start, - t_end=train.t_end, - name=train.name, - ) - - def getNSTnames(self) -> list[str]: - return self.get_nst_names() - - def getUniqueNSTnames(self) -> list[str]: - return self.get_unique_nst_names() - - def getNSTIndicesFromName(self, name: str) -> list[int]: - return self.get_nst_indices_from_name(name) - - def getNSTnameFromInd(self, ind: int) -> str: - return self.get_nst_name_from_ind(ind) - - def getNSTFromName(self, name: str) -> nspikeTrain: - match = self.get_nst_from_name(name) - if isinstance(match, list): - match = match[0] - return nspikeTrain( - spike_times=match.spike_times.copy(), - t_start=match.t_start, - t_end=match.t_end, - name=match.name, - ) - - def addToColl(self, train: _SpikeTrain) -> _SpikeTrainCollection: - self.add_to_coll(train) - return self - - def addSingleSpikeToColl(self, unitInd: int, spikeTime: float) -> _SpikeTrainCollection: - self.add_single_spike_to_coll(unit_index=unitInd, spike_time_s=spikeTime) - return self - - def dataToMatrix(self, binSize_s: float, mode: Literal["binary", "count"] = "binary") -> np.ndarray: - return self.data_to_matrix(bin_size_s=binSize_s, mode=mode) - - def toSpikeTrain(self, name: str = "merged") -> nspikeTrain: - merged = super().to_spike_train(name=name) - return nspikeTrain( - spike_times=merged.spike_times.copy(), - t_start=merged.t_start, - t_end=merged.t_end, - name=merged.name, - ) - - def shiftTime(self, offset_s: float) -> _SpikeTrainCollection: - self.shift_time(offset_s) - return self - - def setMinTime(self, t_min: float) -> _SpikeTrainCollection: - self.set_min_time(t_min) - return self - - def setMaxTime(self, t_max: float) -> _SpikeTrainCollection: - self.set_max_time(t_max) - return self - - def toStructure(self) -> dict[str, Any]: - return { - "trains": [ - { - "spike_times": train.spike_times.copy(), - "t_start": float(train.t_start), - "t_end": float(train.t_end) if train.t_end is not None else None, - "name": train.name, - } - for train in self.trains - ] - } - - @staticmethod - def fromStructure(payload: dict[str, Any]) -> _SpikeTrainCollection: - trains = [ - nspikeTrain( - spike_times=np.asarray(row["spike_times"], dtype=float), - t_start=float(row.get("t_start", 0.0)), - t_end=float(row["t_end"]) if row.get("t_end") is not None else None, - name=str(row.get("name", f"unit_{i+1}")), - ) - for i, row in enumerate(payload.get("trains", [])) - ] - if not trains: - raise ValueError("fromStructure requires at least one train") - return nstColl(cast(list[_SpikeTrain], trains)) - - def updateTimes(self) -> _SpikeTrainCollection: - for train in self.trains: - if train.spike_times.size: - train.t_start = min(train.t_start, float(train.spike_times.min())) - train.t_end = max(float(train.t_end) if train.t_end is not None else train.t_start, float(train.spike_times.max())) - return self - - def getISIs(self) -> list[np.ndarray]: - return [np.diff(train.spike_times) for train in self.trains] - - def getMinISIs(self) -> np.ndarray: - out = [] - for isi in self.getISIs(): - out.append(float(np.min(isi)) if isi.size else np.inf) - return np.asarray(out, dtype=float) - - def isSigRepBinary(self, binSize_s: float = 0.001) -> bool: - _, mat = self.to_binned_matrix(bin_size_s=binSize_s, mode="count") - return bool(np.all((mat == 0) | (mat == 1))) - - def BinarySigRep(self, binSize_s: float = 0.001) -> np.ndarray: - return self.dataToMatrix(binSize_s=binSize_s, mode="binary") - - def psth(self, binSize_s: float = 0.01) -> tuple[np.ndarray, np.ndarray]: - t, mat = self.to_binned_matrix(bin_size_s=binSize_s, mode="count") - return t, np.mean(mat, axis=0) - - def psthBars(self, binSize_s: float = 0.01) -> tuple[np.ndarray, np.ndarray]: - return self.psth(binSize_s=binSize_s) - - def plot(self, *_args: Any, **_kwargs: Any) -> Any: - import matplotlib.pyplot as plt - - for i, train in enumerate(self.trains): - y = np.full(train.spike_times.shape, i + 1, dtype=float) - plt.plot(train.spike_times, y, "k.", markersize=3) - return plt.gca() - - def getFieldVal(self, fieldName: str) -> list[Any]: - out: list[Any] = [] - for train in self.trains: - if not hasattr(train, fieldName): - raise KeyError(f"field '{fieldName}' not found") - out.append(getattr(train, fieldName)) - return out - - def findMaxSampleRate(self) -> float: - min_isi = float(np.min(self.getMinISIs())) - if not np.isfinite(min_isi) or min_isi <= 0.0: - return float(np.inf) - return float(1.0 / min_isi) - - def getMaxBinSizeBinary(self) -> float: - min_isi = float(np.min(self.getMinISIs())) - if not np.isfinite(min_isi) or min_isi <= 0.0: - return 1.0 - return min_isi - - def setMask(self, selector: list[int] | list[str]) -> _SpikeTrainCollection: - if selector and isinstance(selector[0], str): - idx = [self.get_nst_indices_from_name(str(name))[0] for name in cast(list[str], selector)] - else: - idx_raw = [int(v) for v in cast(list[int], selector)] - idx = [] - for v in idx_raw: - if v >= 1 and v <= self.n_units: - idx.append(v - 1) - elif v >= 0 and v < self.n_units: - idx.append(v) - else: - raise IndexError("mask index out of range") - self._neuron_mask = sorted(set(idx)) - return self - - def setNeuronMask(self, selector: list[int] | list[str]) -> _SpikeTrainCollection: - return self.setMask(selector) - - def setNeuronMaskFromInd(self, indices: list[int] | np.ndarray) -> _SpikeTrainCollection: - idx = [int(v) for v in np.asarray(indices).reshape(-1)] - return self.setMask(idx) - - def resetMask(self) -> _SpikeTrainCollection: - self._neuron_mask = list(range(self.n_units)) - return self - - def isNeuronMaskSet(self) -> bool: - return self._neuron_mask is not None - - def getIndFromMask(self) -> list[int]: - if self._neuron_mask is None: - return list(range(self.n_units)) - return list(self._neuron_mask) - - def getIndFromMaskMinusOne(self) -> list[int]: - return self.getIndFromMask() - - def setNeighbors(self, neighbors: Any) -> _SpikeTrainCollection: - self._neighbors = neighbors - return self - - def getNeighbors(self) -> Any: - return self._neighbors - - def areNeighborsSet(self) -> bool: - return self._neighbors is not None - - def restoreToOriginal(self) -> _SpikeTrainCollection: - self.trains = [ - train.copy() if hasattr(train, "copy") else _SpikeTrain(train.spike_times.copy(), train.t_start, train.t_end, train.name) - for train in self._original_trains - ] - self._neuron_mask = None - self._neighbors = None - return self - - def resample(self, sampleRate: float) -> _SpikeTrainCollection: - if sampleRate <= 0.0: - raise ValueError("sampleRate must be positive") - dt = 1.0 / float(sampleRate) - for train in self.trains: - snapped = np.round(train.spike_times / dt) * dt - train.spike_times = np.unique(snapped) - return self - - def enforceSampleRate(self, sampleRate: float) -> _SpikeTrainCollection: - return self.resample(sampleRate) - - def ensureConsistancy(self) -> bool: - for train in self.trains: - if np.any(np.diff(train.spike_times) < 0.0): - return False - if np.any(train.spike_times < train.t_start): - return False - if train.t_end is not None and np.any(train.spike_times > train.t_end): - return False - return True - - def estimateVarianceAcrossTrials(self, binSize_s: float = 0.01) -> np.ndarray: - _t, mat = self.to_binned_matrix(bin_size_s=binSize_s, mode="count") - if mat.size == 0: - return np.array([], dtype=float) - return np.var(mat, axis=0) - - def plotISIHistogram(self, bins: int = 20) -> Any: - import matplotlib.pyplot as plt - - isi = [np.diff(train.spike_times) for train in self.trains if train.spike_times.size > 1] - if not isi: - return plt.hist([], bins=bins) - return plt.hist(np.concatenate(isi), bins=bins, color="tab:blue", alpha=0.6) - - def plotExponentialFit(self) -> Any: - import matplotlib.pyplot as plt - - isi = [np.diff(train.spike_times) for train in self.trains if train.spike_times.size > 1] - if not isi: - return plt.plot([], []) - vals = np.concatenate(isi) - lam = 1.0 / max(float(np.mean(vals)), 1e-12) - x = np.linspace(0.0, float(np.max(vals)), 200) - y = lam * np.exp(-lam * x) - return plt.plot(x, y, "r-") - - def psthGLM(self, binSize_s: float = 0.01) -> tuple[np.ndarray, np.ndarray]: - return self.psth(binSize_s=binSize_s) - - def ssglm(self, binSize_s: float = 0.01) -> tuple[np.ndarray, np.ndarray]: - return self.psth(binSize_s=binSize_s) - - @staticmethod - def generateUnitImpulseBasis(basisWidth_s: float, *args: Any, **kwargs: Any) -> _Covariate: - if basisWidth_s <= 0.0: - raise ValueError("basisWidth_s must be positive") - - name = str(kwargs.pop("name", "unit_impulse_basis")) - numeric_types = (int, float, np.integer, np.floating) - - # MATLAB-compatible signatures: - # generateUnitImpulseBasis(basisWidth, sampleRate[, totalTime[, name]]) - # generateUnitImpulseBasis(basisWidth, minTime, maxTime, sampleRate[, name]) - if len(args) >= 3 and isinstance(args[2], numeric_types): - min_time_s = float(args[0]) - max_time_s = float(args[1]) - sample_rate_hz = float(args[2]) - if len(args) >= 4: - name = str(args[3]) - else: - sample_rate_hz = float(args[0]) if len(args) >= 1 else float(kwargs.pop("sampleRate_hz", 1000.0)) - total_time_s = float(args[1]) if len(args) >= 2 else float(kwargs.pop("totalTime_s", 1.0)) - min_time_s = 0.0 - max_time_s = total_time_s - - if kwargs: - unknown = ", ".join(sorted(kwargs.keys())) - raise TypeError(f"unexpected keyword arguments: {unknown}") - if sample_rate_hz <= 0.0: - raise ValueError("sampleRate_hz must be positive") - if max_time_s <= min_time_s: - raise ValueError("maxTime must be greater than minTime") - - dt = 1.0 / sample_rate_hz - time = np.arange(min_time_s, max_time_s + 0.5 * dt, dt) - total_time_s = max_time_s - min_time_s - n_basis = max(1, int(np.ceil(total_time_s / float(basisWidth_s)))) - basis = np.zeros((time.size, n_basis), dtype=float) - for j in range(n_basis): - lo = min_time_s + j * basisWidth_s - hi = min(min_time_s + (j + 1) * basisWidth_s, max_time_s + dt) - mask = (time >= lo) & (time < hi) - basis[mask, j] = 1.0 - labels = [f"basis_{j+1}" for j in range(n_basis)] - return Covariate(time=time, data=basis, name=name, labels=labels) - - def getEnsembleNeuronCovariates(self, binSize_s: float = 0.001, mode: Literal["binary", "count"] = "binary") -> "CovColl": - t, mat = self.to_binned_matrix(bin_size_s=binSize_s, mode=mode) - covs: list[_Covariate] = [] - for i in range(mat.shape[0]): - covs.append( - Covariate( - time=t.copy(), - data=mat[i, :].copy(), - name=self.trains[i].name, - labels=[self.trains[i].name], - units="spikes/bin", - ) - ) - return CovColl(cast(list[_Covariate], covs)) - - def addNeuronNamesToEnsCovColl(self, covColl: "CovColl") -> "CovColl": - for i, cov in enumerate(covColl.covariates): - if i < len(self.trains): - cov.name = self.trains[i].name - cov.labels = [self.trains[i].name] - return covColl - - -class CovColl(_CovariateCollection): - def __post_init__(self) -> None: - super().__post_init__() - self._original_covariates = [ - _Covariate( - time=cov.time.copy(), - data=cov.data.copy(), - name=str(cov.name), - units=str(cov.units), - labels=list(cov.labels), - x_label=str(cov.x_label), - y_label=str(cov.y_label), - x_units=str(cov.x_units), - y_units=str(cov.y_units), - plot_props=dict(cov.plot_props), - ) - for cov in self.covariates - ] - self._cov_shift = 0.0 - - @staticmethod - def containsChars(text: str, chars: str | list[str]) -> bool: - if isinstance(chars, str): - chars_list = list(chars) - else: - chars_list = [str(v) for v in chars] - return any(ch in text for ch in chars_list) - - @staticmethod - def isaSelectorCell(selector: Any) -> bool: - if not isinstance(selector, (list, tuple, np.ndarray)): - return False - vals = list(np.asarray(selector, dtype=object).reshape(-1)) - return all(isinstance(v, (int, str, np.integer)) for v in vals) - - def getTime(self) -> np.ndarray: - return self.time - - def getDesignMatrix(self) -> tuple[np.ndarray, list[str]]: - return self.design_matrix() - - def copy(self) -> "CovColl": - copied = super().copy() - return CovColl(copied.covariates) - - def addToColl(self, cov: _Covariate) -> "CovColl": - self.add_to_coll(cov) - return self - - def getCov(self, selector: int | str) -> _Covariate: - return self.get_cov(selector) - - def getCovIndicesFromNames(self, names: list[str]) -> list[int]: - return self.get_cov_indices_from_names(names) - - def getCovIndFromName(self, name: str) -> int: - return self.get_cov_ind_from_name(name) - - def isCovPresent(self, name: str) -> bool: - return self.is_cov_present(name) - - def getCovDimension(self) -> int: - return self.get_cov_dimension() - - def getAllCovLabels(self) -> list[str]: - return self.get_all_cov_labels() - - def nActCovar(self) -> int: - return self.n_act_covar() - - def numActCov(self) -> int: - return self.num_act_cov() - - def sumDimensions(self) -> int: - return self.sum_dimensions() - - def dataToMatrix(self) -> tuple[np.ndarray, list[str]]: - return self.data_to_matrix() - - def dataToMatrixFromNames(self, names: list[str]) -> tuple[np.ndarray, list[str]]: - return self.data_to_matrix_from_names(names) - - def dataToMatrixFromSel(self, selectors: list[int]) -> tuple[np.ndarray, list[str]]: - return self.data_to_matrix_from_sel(selectors) - - def parseDataSelectorArray(self, selector: Any) -> list[int]: - vals = list(np.asarray(selector, dtype=object).reshape(-1)) - if not vals: - return [] - if all(isinstance(v, (str, np.str_)) for v in vals): - return self.get_cov_indices_from_names([str(v) for v in vals]) - out: list[int] = [] - for v in vals: - idx = int(v) - if idx >= 1 and idx <= len(self.covariates): - out.append(idx - 1) - elif idx >= 0 and idx < len(self.covariates): - out.append(idx) - else: - raise IndexError("selector index out of range") - return out - - def covIndFromSelector(self, selector: int | str | list[int] | list[str] | np.ndarray) -> list[int]: - if isinstance(selector, (int, str)): - return self.parseDataSelectorArray([selector]) - return self.parseDataSelectorArray(selector) - - def getCovMaskFromSelector(self, selector: int | str | list[int] | list[str] | np.ndarray) -> list[int]: - return self.covIndFromSelector(selector) - - def flattenCovMask(self, mask: list[int] | np.ndarray | list[list[int]]) -> list[int]: - arr = np.asarray(mask, dtype=int).reshape(-1) - return [int(v) for v in arr] - - def generateRemainingIndex(self, selector: int | str | list[int] | list[str] | np.ndarray) -> list[int]: - masked = set(self.covIndFromSelector(selector)) - return [i for i in range(len(self.covariates)) if i not in masked] - - def generateSelectorCell(self, mask: list[int] | np.ndarray) -> list[str]: - idx = self.flattenCovMask(mask) - return [self.covariates[i].name for i in idx] - - def getSelectorFromMasks(self, mask: list[int] | np.ndarray) -> list[str]: - return self.generateSelectorCell(mask) - - def addSingleCovToColl(self, cov: _Covariate) -> "CovColl": - return self.addToColl(cov) - - def addCovCellToColl(self, covariates: list[_Covariate]) -> "CovColl": - for cov in covariates: - self.add_to_coll(cov) - return self - - def addCovCollection(self, other: _CovariateCollection) -> "CovColl": - for cov in other.covariates: - self.add_to_coll(cov) - return self - - def setMinTime(self, t_min: float) -> "CovColl": - for cov in self.covariates: - cov.set_min_time(t_min) - return self - - def setMaxTime(self, t_max: float) -> "CovColl": - for cov in self.covariates: - cov.set_max_time(t_max) - return self - - def restrictToTimeWindow(self, t_min: float, t_max: float) -> "CovColl": - self.setMinTime(t_min) - self.setMaxTime(t_max) - return self - - def setSampleRate(self, sampleRate: float) -> "CovColl": - resampled_covariates: list[_Covariate] = [] - for cov in self.covariates: - out = cov.resample(sampleRate) - resampled_covariates.append( - _Covariate( - time=out.time, - data=out.data, - name=out.name, - units=out.units, - labels=getattr(cov, "labels", [out.name]), - x_label=out.x_label, - y_label=out.y_label, - x_units=out.x_units, - y_units=out.y_units, - plot_props=out.plot_props, - ) - ) - self.covariates = resampled_covariates - return self - - def resample(self, sampleRate: float) -> "CovColl": - return self.setSampleRate(sampleRate) - - def enforceSampleRate(self, sampleRate: float) -> "CovColl": - return self.setSampleRate(sampleRate) - - def updateTimes(self) -> "CovColl": - _ = self.time - return self - - def toStructure(self) -> dict[str, Any]: - return {"covariates": [cov.to_structure() for cov in self.covariates]} - - def dataToStructure(self) -> dict[str, Any]: - return self.toStructure() - - @staticmethod - def fromStructure(payload: dict[str, Any]) -> "CovColl": - rows = payload.get("covariates", []) - covs = [Covariate.fromStructure(row) for row in rows] - if not covs: - raise ValueError("fromStructure requires at least one covariate") - return CovColl(cast(list[_Covariate], covs)) - - def setMask(self, selector: list[int] | list[str]) -> "CovColl": - if selector and isinstance(selector[0], str): - idx = self.get_cov_indices_from_names(cast(list[str], selector)) - else: - idx = [int(i) for i in cast(list[int], selector)] - self._cov_mask = idx - return self - - def resetMask(self) -> "CovColl": - self._cov_mask = list(range(len(self.covariates))) - return self - - def setMasksFromSelector(self, selector: list[int] | list[str] | np.ndarray) -> "CovColl": - if isinstance(selector, np.ndarray): - vals = selector.reshape(-1).tolist() - else: - vals = selector - return self.setMask(cast(list[int] | list[str], vals)) - - def isCovMaskSet(self) -> bool: - return hasattr(self, "_cov_mask") - - def getCovDataMask(self) -> list[int]: - if not hasattr(self, "_cov_mask"): - return list(range(len(self.covariates))) - return list(self._cov_mask) - - def getCovLabelsFromMask(self) -> list[str]: - return [self.covariates[i].name for i in self.getCovDataMask()] - - def removeCovariate(self, selector: int | str) -> "CovColl": - if isinstance(selector, int): - del self.covariates[selector] - return self - idx = self.get_cov_ind_from_name(selector) - del self.covariates[idx] - return self - - def removeFromColl(self, selector: int | str) -> "CovColl": - return self.removeCovariate(selector) - - def removeFromCollByIndices(self, indices: list[int]) -> "CovColl": - for i in sorted(set(indices), reverse=True): - del self.covariates[i] - return self - - def maskAwayCov(self, selector: int | str | list[int] | list[str] | np.ndarray) -> "CovColl": - remaining = self.generateRemainingIndex(selector) - self._cov_mask = remaining - return self - - def maskAwayOnlyCov(self, selector: int | str | list[int] | list[str] | np.ndarray) -> "CovColl": - return self.maskAwayCov(selector) - - def maskAwayAllExcept(self, selector: int | str | list[int] | list[str] | np.ndarray) -> "CovColl": - self._cov_mask = self.covIndFromSelector(selector) - return self - - def setCovShift(self, shift_s: float) -> "CovColl": - shift = float(shift_s) - self._cov_shift += shift - for cov in self.covariates: - cov.time = cov.time + shift - return self - - def resetCovShift(self) -> "CovColl": - if self._cov_shift == 0.0: - return self - for cov in self.covariates: - cov.time = cov.time - self._cov_shift - self._cov_shift = 0.0 - return self - - def restoreToOriginal(self) -> "CovColl": - self.covariates = [ - _Covariate( - time=cov.time.copy(), - data=cov.data.copy(), - name=str(cov.name), - units=str(cov.units), - labels=list(cov.labels), - x_label=str(cov.x_label), - y_label=str(cov.y_label), - x_units=str(cov.x_units), - y_units=str(cov.y_units), - plot_props=dict(cov.plot_props), - ) - for cov in self._original_covariates - ] - self._cov_shift = 0.0 - self.resetMask() - return self - - def findMinTime(self) -> float: - return self.find_min_time() - - def findMaxTime(self) -> float: - return self.find_max_time() - - def plot(self, *_args: Any, **_kwargs: Any) -> Any: - import matplotlib.pyplot as plt - - X, _labels = self.design_matrix() - return plt.plot(self.time, X) - - -class TrialConfig(_TrialConfig): - def __init__( - self, - covariateLabels: list[str] | None = None, - Fs: float = 1000.0, - fitType: str = "poisson", - name: str = "config", - **kwargs: Any, - ) -> None: - covariate_labels = kwargs.pop("covariate_labels", covariateLabels or []) - sample_rate_hz = kwargs.pop("sample_rate_hz", Fs) - fit_type = kwargs.pop("fit_type", fitType) - super().__init__( - covariate_labels=covariate_labels, - sample_rate_hz=sample_rate_hz, - fit_type=fit_type, - name=name, - ) - - def getFitType(self) -> str: - return self.fit_type - - def getSampleRate(self) -> float: - return self.sample_rate_hz - - def getCovariateLabels(self) -> list[str]: - return self.covariate_labels - - def getName(self) -> str: - return self.name - - def setName(self, name: str) -> "TrialConfig": - self.name = str(name) - return self - - def toStructure(self) -> dict[str, Any]: - return { - "covMask": list(self.covariate_labels), - "sampleRate": float(self.sample_rate_hz), - "history": [], - "ensCovHist": [], - "ensCovMask": [], - "covLag": [], - "name": self.name, - } - - @staticmethod - def fromStructure(payload: dict[str, Any]) -> "TrialConfig": - return TrialConfig( - covariateLabels=list(payload.get("covMask", [])), - Fs=float(payload.get("sampleRate", 1000.0)), - name=str(payload.get("name", "config")), - ) - - def setConfig(self, trial: "Trial") -> "TrialConfig": - if self.sample_rate_hz > 0.0: - trial.setSampleRate(self.sample_rate_hz) - if self.covariate_labels: - trial.setCovMask(self.covariate_labels) - return self - - -class ConfigColl(_ConfigCollection): - @staticmethod - def ConfigColl(*args: Any, **kwargs: Any) -> _ConfigCollection: - if len(args) == 1 and isinstance(args[0], dict): - return ConfigColl.fromStructure(args[0]) - return ConfigColl(*args, **kwargs) - - @staticmethod - def fromStructure(payload: dict[str, Any] | list[dict[str, Any]]) -> _ConfigCollection: - if isinstance(payload, dict): - entries = list(payload.get("configs", [])) - else: - entries = list(payload) - if not entries: - raise ValueError("fromStructure requires at least one configuration entry") - configs = cast(list[_TrialConfig], [TrialConfig.fromStructure(entry) for entry in entries]) - return ConfigColl(configs) - - def toStructure(self) -> dict[str, Any]: - return { - "configs": [ - TrialConfig( - covariateLabels=list(cfg.covariate_labels), - Fs=float(cfg.sample_rate_hz), - fitType=str(cfg.fit_type), - name=str(cfg.name), - ).toStructure() - for cfg in self.configs - ] - } - - def addConfig(self, config: _TrialConfig) -> _ConfigCollection: - self.configs.append(config) - return self - - def getConfig(self, selector: int | str = 1) -> _TrialConfig: - if isinstance(selector, str): - for cfg in self.configs: - if cfg.name == selector: - return cfg - raise KeyError(f"configuration '{selector}' not found") - idx = int(selector) - if idx < 1 or idx > len(self.configs): - raise IndexError("configuration index out of range") - return self.configs[idx - 1] - - def setConfig(self, selector: int | str, config: _TrialConfig) -> _ConfigCollection: - if isinstance(selector, str): - for i, cfg in enumerate(self.configs): - if cfg.name == selector: - self.configs[i] = config - return self - raise KeyError(f"configuration '{selector}' not found") - idx = int(selector) - if idx < 1 or idx > len(self.configs): - raise IndexError("configuration index out of range") - self.configs[idx - 1] = config - return self - - def getConfigNames(self) -> list[str]: - return [cfg.name for cfg in self.configs] - - def setConfigNames(self, names: list[str]) -> _ConfigCollection: - if len(names) != len(self.configs): - raise ValueError("names length must match number of configs") - for cfg, name in zip(self.configs, names): - cfg.name = str(name) - return self - - def getSubsetConfigs(self, selectors: list[int] | np.ndarray) -> _ConfigCollection: - inds = [int(v) for v in np.asarray(selectors).reshape(-1)] - subset: list[_TrialConfig] = [] - for idx in inds: - if idx < 1 or idx > len(self.configs): - raise IndexError("configuration index out of range") - subset.append(self.configs[idx - 1]) - return ConfigColl(subset) - - def getConfigs(self) -> list[_TrialConfig]: - return self.configs - - -class Trial(_Trial): - def _ensure_trial_state(self) -> None: - if not hasattr(self, "_orig_spikes"): - self._orig_spikes = nstColl(self.spikes.trains).copy() - self._orig_covariates = CovColl(self.covariates.covariates).copy() - if not hasattr(self, "_neuron_mask"): - self._neuron_mask = list(range(self.spikes.n_units)) - if not hasattr(self, "_ens_cov_mask"): - self._ens_cov_mask = list(range(self.spikes.n_units)) - if not hasattr(self, "_cov_mask"): - self._cov_mask = list(range(len(self.covariates.covariates))) - if not hasattr(self, "_history"): - self._history = None - if not hasattr(self, "_ens_cov_hist"): - self._ens_cov_hist = None - if not hasattr(self, "_neighbors"): - self._neighbors = None - - def getAlignedBinnedObservation( - self, - binSize_s: float, - unitIndex: int = 0, - mode: Literal["binary", "count"] = "binary", - ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - return self.aligned_binned_observation(bin_size_s=binSize_s, unit_index=unitIndex, mode=mode) - - def getDesignMatrix(self) -> tuple[np.ndarray, list[str]]: - return self.get_design_matrix() - - def getSpikeVector( - self, - binSize_s: float, - unitIndex: int = 0, - mode: Literal["binary", "count"] = "binary", - ) -> tuple[np.ndarray, np.ndarray]: - return self.get_spike_vector(bin_size_s=binSize_s, unit_index=unitIndex, mode=mode) - - def getCov(self, selector: int | str) -> _Covariate: - return self.get_cov(selector) - - def getNeuron(self, unitInd: int = 0) -> nstColl: - return nstColl(self.get_neuron(unit_index=unitInd).trains) - - def getAllCovLabels(self) -> list[str]: - return self.get_all_cov_labels() - - def findMinTime(self) -> float: - return self.find_min_time() - - def findMaxTime(self) -> float: - return self.find_max_time() - - def findMinSampleRate(self) -> float: - return self.find_min_sample_rate() - - def findMaxSampleRate(self) -> float: - return self.find_max_sample_rate() - - def isSampleRateConsistent(self) -> bool: - return self.is_sample_rate_consistent() - - def addCov(self, cov: _Covariate) -> "Trial": - self.covariates.add_to_coll(cov) - return self - - def removeCov(self, selector: int | str) -> "Trial": - cc = CovColl(self.covariates.covariates) - cc.removeCovariate(selector) - self.covariates = _CovariateCollection(cc.covariates) - return self - - def setMinTime(self, t_min: float) -> "Trial": - self.spikes.set_min_time(t_min) - for cov in self.covariates.covariates: - cov.set_min_time(t_min) - return self - - def setMaxTime(self, t_max: float) -> "Trial": - self.spikes.set_max_time(t_max) - for cov in self.covariates.covariates: - cov.set_max_time(t_max) - return self - - def setSampleRate(self, sampleRate: float) -> "Trial": - resampled_covariates: list[_Covariate] = [] - for cov in self.covariates.covariates: - out = cov.resample(sampleRate) - resampled_covariates.append( - _Covariate( - time=out.time, - data=out.data, - name=out.name, - units=out.units, - labels=getattr(cov, "labels", [out.name]), - x_label=out.x_label, - y_label=out.y_label, - x_units=out.x_units, - y_units=out.y_units, - plot_props=out.plot_props, - ) - ) - self.covariates.covariates = resampled_covariates - return self - - def resample(self, sampleRate: float) -> "Trial": - return self.setSampleRate(sampleRate) - - def shiftCovariates(self, lag_s: float) -> "Trial": - for cov in self.covariates.covariates: - cov.shift_time(lag_s) - return self - - def getNeuronNames(self) -> list[str]: - return self.spikes.get_nst_names() - - def getUniqueNeuronNames(self) -> list[str]: - return self.spikes.get_unique_nst_names() - - def getNumUniqueNeurons(self) -> int: - return len(self.getUniqueNeuronNames()) - - def getNeuronIndFromName(self, name: str) -> list[int]: - return self.spikes.get_nst_indices_from_name(name) - - def setTrialPartition(self, partition: dict[str, tuple[float, float]]) -> "Trial": - self._trial_partition = partition - return self - - def getTrialPartition(self) -> dict[str, tuple[float, float]]: - return dict(getattr(self, "_trial_partition", {})) - - def updateTimePartitions(self) -> "Trial": - if hasattr(self, "_trial_partition"): - t0 = self.findMinTime() - tf = self.findMaxTime() - self._trial_partition = { - k: (max(t0, float(v[0])), min(tf, float(v[1]))) - for k, v in self._trial_partition.items() - } - return self - - def setCovMask(self, selector: list[int] | list[str]) -> "Trial": - cc = CovColl(self.covariates.covariates) - cc.setMask(selector) - self._cov_mask = cc.getCovDataMask() - return self - - def resetCovMask(self) -> "Trial": - self._cov_mask = list(range(len(self.covariates.covariates))) - return self - - def isCovMaskSet(self) -> bool: - return hasattr(self, "_cov_mask") - - def getCovLabelsFromMask(self) -> list[str]: - mask = getattr(self, "_cov_mask", list(range(len(self.covariates.covariates)))) - return [self.covariates.covariates[i].name for i in mask] - - def setTrialEvents(self, events: _Events) -> "Trial": - self._events = events - return self - - def getEvents(self) -> _Events | None: - return getattr(self, "_events", None) - - def flattenCovMask(self, mask: list[int] | list[list[int]] | np.ndarray) -> list[int]: - out = np.asarray(mask, dtype=int).reshape(-1) - return [int(v) for v in out] - - def flattenMask(self, mask: list[int] | list[list[int]] | np.ndarray) -> list[int]: - return self.flattenCovMask(mask) - - def getLabelsFromMask(self) -> list[str]: - self._ensure_trial_state() - mask = getattr(self, "_cov_mask", list(range(len(self.covariates.covariates)))) - return [self.covariates.covariates[i].name for i in mask] - - def getCovSelectorFromMask(self) -> list[str]: - return self.getLabelsFromMask() - - def getEnsembleNeuronCovariates( - self, - binSize_s: float = 0.001, - mode: Literal["binary", "count"] = "binary", - ) -> CovColl: - return nstColl(self.spikes.trains).getEnsembleNeuronCovariates(binSize_s=binSize_s, mode=mode) - - def getEnsCovLabels(self, binSize_s: float = 0.001) -> list[str]: - coll = self.getEnsembleNeuronCovariates(binSize_s=binSize_s, mode="binary") - return coll.getAllCovLabels() - - def setEnsCovMask(self, selector: list[int] | list[str] | np.ndarray) -> "Trial": - self._ensure_trial_state() - ens = self.getEnsembleNeuronCovariates() - idx = ens.covIndFromSelector(selector) - self._ens_cov_mask = idx - return self - - def resetEnsCovMask(self) -> "Trial": - self._ensure_trial_state() - self._ens_cov_mask = list(range(self.spikes.n_units)) - return self - - def getEnsCovLabelsFromMask(self, binSize_s: float = 0.001) -> list[str]: - self._ensure_trial_state() - labels = self.getEnsCovLabels(binSize_s=binSize_s) - return [labels[i] for i in self._ens_cov_mask if i < len(labels)] - - def getEnsCovMatrix( - self, - binSize_s: float = 0.001, - mode: Literal["binary", "count"] = "binary", - ) -> tuple[np.ndarray, list[str]]: - self._ensure_trial_state() - ens = self.getEnsembleNeuronCovariates(binSize_s=binSize_s, mode=mode) - X, labels = ens.dataToMatrix() - if self._ens_cov_mask: - X = X[:, self._ens_cov_mask] - labels = [labels[i] for i in self._ens_cov_mask] - return X, labels - - def setEnsCovHist(self, ensCovHist: Any) -> "Trial": - self._ensure_trial_state() - self._ens_cov_hist = ensCovHist - return self - - def isEnsCovHistSet(self) -> bool: - self._ensure_trial_state() - return self._ens_cov_hist is not None - - def setHistory(self, history: Any) -> "Trial": - self._ensure_trial_state() - self._history = history - return self - - def isHistSet(self) -> bool: - self._ensure_trial_state() - return self._history is not None - - def resetHistory(self) -> "Trial": - self._ensure_trial_state() - self._history = None - self._ens_cov_hist = None - return self - - def getNumHist(self) -> int: - self._ensure_trial_state() - if self._history is None: - return 0 - if isinstance(self._history, (list, tuple)): - return len(self._history) - return 1 - - def getHistLabels(self) -> list[str]: - n_hist = self.getNumHist() - return [f"hist_{i+1}" for i in range(n_hist)] - - def getHistMatrices(self, binSize_s: float = 0.001) -> list[np.ndarray]: - self._ensure_trial_state() - if self._history is None: - return [] - history_obj = self._history - if isinstance(history_obj, (list, tuple)): - history_obj = history_obj[0] if history_obj else None - if history_obj is None or not hasattr(history_obj, "design_matrix"): - return [] - t_bins, _ = self.spikes.to_binned_matrix(bin_size_s=binSize_s, mode="binary") - mats: list[np.ndarray] = [] - for train in self.spikes.trains: - mats.append(history_obj.design_matrix(spike_times_s=train.spike_times, time_grid_s=t_bins)) - return mats - - def getHistForNeurons(self, neuronIndices: list[int] | np.ndarray, binSize_s: float = 0.001) -> list[np.ndarray]: - mats = self.getHistMatrices(binSize_s=binSize_s) - if not mats: - return [] - inds = [int(v) for v in np.asarray(neuronIndices).reshape(-1)] - out: list[np.ndarray] = [] - for i in inds: - j = i - 1 if i >= 1 else i - if j < 0 or j >= len(mats): - raise IndexError("neuron index out of range") - out.append(mats[j]) - return out - - def setNeuronMask(self, selector: list[int] | list[str] | np.ndarray) -> "Trial": - self._ensure_trial_state() - if isinstance(selector, np.ndarray): - vals = selector.reshape(-1).tolist() - else: - vals = list(selector) - if vals and all(isinstance(v, (str, np.str_)) for v in vals): - idx = [self.spikes.get_nst_indices_from_name(str(v))[0] for v in vals] - else: - idx_raw = [int(v) for v in vals] - idx = [] - for v in idx_raw: - if v >= 1 and v <= self.spikes.n_units: - idx.append(v - 1) - elif v >= 0 and v < self.spikes.n_units: - idx.append(v) - else: - raise IndexError("neuron index out of range") - self._neuron_mask = sorted(set(idx)) - return self - - def resetNeuronMask(self) -> "Trial": - self._ensure_trial_state() - self._neuron_mask = list(range(self.spikes.n_units)) - return self - - def isNeuronMaskSet(self) -> bool: - self._ensure_trial_state() - return self._neuron_mask != list(range(self.spikes.n_units)) - - def getNeuronIndFromMask(self) -> list[int]: - self._ensure_trial_state() - return list(self._neuron_mask) - - def setNeighbors(self, neighbors: Any) -> "Trial": - self._ensure_trial_state() - self._neighbors = neighbors - return self - - def getNeuronNeighbors(self) -> Any: - self._ensure_trial_state() - return self._neighbors - - def isMaskSet(self) -> bool: - self._ensure_trial_state() - cov_set = self._cov_mask != list(range(len(self.covariates.covariates))) - ens_set = self._ens_cov_mask != list(range(self.spikes.n_units)) - neu_set = self._neuron_mask != list(range(self.spikes.n_units)) - return bool(cov_set or ens_set or neu_set) - - def getAllLabels(self, binSize_s: float = 0.001) -> list[str]: - labels: list[str] = [] - labels.extend(self.getAllCovLabels()) - labels.extend(self.getEnsCovLabels(binSize_s=binSize_s)) - labels.extend(self.getHistLabels()) - return labels - - def makeConsistentSampleRate(self, sampleRate: float | None = None) -> "Trial": - if sampleRate is None: - sampleRate = float(self.findMinSampleRate()) - return self.setSampleRate(float(sampleRate)) - - def makeConsistentTime(self) -> "Trial": - t0 = self.findMinTime() - tf = self.findMaxTime() - return self.setMinTime(t0).setMaxTime(tf) - - def resampleEnsColl(self, sampleRate: float) -> CovColl: - ens = self.getEnsembleNeuronCovariates() - return ens.resample(sampleRate) - - def restoreToOriginal(self) -> "Trial": - self._ensure_trial_state() - self.spikes = nstColl(self._orig_spikes.trains).copy() - self.covariates = CovColl(self._orig_covariates.covariates).copy() - self._cov_mask = list(range(len(self.covariates.covariates))) - self._ens_cov_mask = list(range(self.spikes.n_units)) - self._neuron_mask = list(range(self.spikes.n_units)) - self._history = None - self._ens_cov_hist = None - self._neighbors = None - return self - - def setTrialTimesFor(self, *args: Any) -> "Trial": - if len(args) == 2: - t0, tf = float(args[0]), float(args[1]) - elif len(args) == 3: - t0, tf = float(args[1]), float(args[2]) - else: - raise ValueError("setTrialTimesFor expects (t0, tf) or (unitIndex, t0, tf)") - self.setMinTime(t0) - self.setMaxTime(tf) - return self - - def plotCovariates(self, *_args: Any, **_kwargs: Any) -> Any: - import matplotlib.pyplot as plt - - X, _ = self.get_design_matrix() - return plt.plot(self.covariates.time, X) - - def plotRaster(self, *_args: Any, **_kwargs: Any) -> Any: - return nstColl(self.spikes.trains).plot() - - def plot(self, *_args: Any, **_kwargs: Any) -> Any: - return self.plotRaster() - - def toStructure(self) -> dict[str, Any]: - return { - "spikes": nstColl(self.spikes.trains).toStructure(), - "covariates": CovColl(self.covariates.covariates).toStructure(), - "trial_partition": self.getTrialPartition(), - } - - @staticmethod - def fromStructure(payload: dict[str, Any]) -> "Trial": - spikes = nstColl.fromStructure(payload["spikes"]) - covs = CovColl.fromStructure(payload["covariates"]) - trial = Trial(spikes=spikes, covariates=covs) - if "trial_partition" in payload: - trial.setTrialPartition(dict(payload["trial_partition"])) - return trial - - -class CIF(_CIFModel): - @staticmethod - def CIF(*args: Any, **kwargs: Any) -> _CIFModel: - if len(args) == 1 and isinstance(args[0], dict): - return CIF.fromStructure(args[0]) - return CIF(*args, **kwargs) - - def CIFCopy(self) -> _CIFModel: - return CIF(coefficients=self.coefficients.copy(), intercept=float(self.intercept), link=str(self.link)) - - def evalLambda(self, X: np.ndarray) -> np.ndarray: - return self.evaluate(X) - - def computeLinearPredictor(self, X: np.ndarray) -> np.ndarray: - return self.linear_predictor(X) - - def logLikelihood(self, y: np.ndarray, X: np.ndarray, dt: float = 1.0) -> float: - return self.log_likelihood(y=y, X=X, dt=dt) - - def simulateByThinning( - self, - time: np.ndarray, - X: np.ndarray, - rng: np.random.Generator | None = None, - ) -> np.ndarray: - return self.simulate_by_thinning(time=time, X=X, rng=rng) - - def evalLambdaDelta(self, X: np.ndarray, dt: float = 1.0) -> np.ndarray: - return self.eval_lambda_delta(X=X, dt=dt) - - def computePlotParams(self, X: np.ndarray) -> dict[str, float]: - return self.compute_plot_params(X) - - def evalFunctionWithVectorArgs(self, X: np.ndarray, *_args: Any, **_kwargs: Any) -> np.ndarray: - return self.evaluate(X) - - def evalGradient(self, X: np.ndarray) -> np.ndarray: - X = np.asarray(X, dtype=float) - vals = self.evaluate(X) - base = np.column_stack([np.ones(X.shape[0]), X]) - if self.link == "poisson": - return base * vals[:, None] - return base * (vals * (1.0 - vals))[:, None] - - def evalGradientLog(self, X: np.ndarray) -> np.ndarray: - X = np.asarray(X, dtype=float) - vals = self.evaluate(X) - base = np.column_stack([np.ones(X.shape[0]), X]) - if self.link == "poisson": - return base - return base * (1.0 - vals)[:, None] - - def evalJacobian(self, X: np.ndarray) -> np.ndarray: - return self.evalGradient(X) - - def evalJacobianLog(self, X: np.ndarray) -> np.ndarray: - return self.evalGradientLog(X) - - def evalLDGamma(self, X: np.ndarray) -> np.ndarray: - return self.evaluate(X) - - def evalLogLDGamma(self, X: np.ndarray) -> np.ndarray: - return np.log(np.clip(self.evaluate(X), 1e-12, None)) - - def evalGradientLDGamma(self, X: np.ndarray) -> np.ndarray: - return self.evalGradient(X) - - def evalGradientLogLDGamma(self, X: np.ndarray) -> np.ndarray: - return self.evalGradientLog(X) - - def evalJacobianLDGamma(self, X: np.ndarray) -> np.ndarray: - return self.evalJacobian(X) - - def evalJacobianLogLDGamma(self, X: np.ndarray) -> np.ndarray: - return self.evalJacobianLog(X) - - def isSymBeta(self) -> bool: - return False - - @staticmethod - def resolveSimulinkModelName(*_args: Any, **_kwargs: Any) -> str: - return "nstat_python_cif_model" - - def setHistory(self, history: Any) -> _CIFModel: - setattr(self, "_history", history) - return self - - def setSpikeTrain(self, spike_train: Any) -> _CIFModel: - setattr(self, "_spike_train", spike_train) - return self - - def simulateCIF( - self, - time: np.ndarray, - X: np.ndarray, - rng: np.random.Generator | None = None, - ) -> np.ndarray: - return self.simulate_by_thinning(time=time, X=X, rng=rng) - - def simulateCIFByThinning( - self, - time: np.ndarray, - X: np.ndarray, - rng: np.random.Generator | None = None, - ) -> np.ndarray: - return self.simulate_by_thinning(time=time, X=X, rng=rng) - - def toStructure(self) -> dict[str, np.ndarray | float | str]: - return self.to_structure() - - @staticmethod - def fromStructure(payload: dict[str, np.ndarray | float | str]) -> _CIFModel: - out = _CIFModel.from_structure(payload) - return CIF(coefficients=out.coefficients, intercept=out.intercept, link=out.link) - - @staticmethod - def simulateCIFByThinningFromLambda( - lambda_signal: _Covariate, - numRealizations: int = 1, - maxTimeRes: float | None = None, - ) -> nstColl: - """MATLAB-style helper accepting a `Covariate` lambda(t) signal.""" - - time = np.asarray(lambda_signal.time, dtype=float) - lam = np.asarray(lambda_signal.data, dtype=float) - if lam.ndim != 1: - raise ValueError("lambda_signal.data must be 1D for this helper") - if maxTimeRes is not None and maxTimeRes > 0.0: - t_new = np.arange(time[0], time[-1] + 0.5 * maxTimeRes, maxTimeRes) - lam = np.interp(t_new, time, lam) - time = t_new - spikes = _CIFModel.simulate_cif_by_thinning_from_lambda( - time=time, lambda_values=lam, num_realizations=numRealizations - ) - t_start = float(time[0]) - t_end = float(time[-1]) - - # Numeric roundoff in thinning can place the last event infinitesimally past - # the terminal grid value. Clamp to the declared support before constructing - # SpikeTrain so MATLAB-style helper remains robust. - clipped_spikes = [] - for sp in spikes: - sp_arr = np.asarray(sp, dtype=float) - mask = (sp_arr >= t_start) & (sp_arr <= t_end) - clipped_spikes.append(sp_arr[mask]) - trains = cast( - list[_SpikeTrain], - [ - nspikeTrain(spike_times=sp, t_start=t_start, t_end=t_end, name=f"unit_{i+1}") - for i, sp in enumerate(clipped_spikes) - ], - ) - return nstColl(trains) - - -class Analysis: - @staticmethod - def fitGLM( - X: np.ndarray, - y: np.ndarray, - fitType: str = "poisson", - dt: float = 1.0, - l2Penalty: float = 0.0, - ) -> _FitResult: - return _Analysis.fit_glm(X=X, y=y, fit_type=fitType, dt=dt, l2_penalty=l2Penalty) - - @staticmethod - def fitTrial(trial: _Trial, config: _TrialConfig, unitIndex: int = 0) -> _FitResult: - return _Analysis.fit_trial(trial=trial, config=config, unit_index=unitIndex) - - @staticmethod - def GLMFit( - X: np.ndarray, - y: np.ndarray, - fitType: str = "poisson", - dt: float = 1.0, - l2Penalty: float = 0.0, - ) -> _FitResult: - return _Analysis.glm_fit(X=X, y=y, fit_type=fitType, dt=dt, l2_penalty=l2Penalty) - - @staticmethod - def RunAnalysisForNeuron(trial: _Trial, config: _TrialConfig, unitIndex: int = 0) -> _FitResult: - return _Analysis.run_analysis_for_neuron(trial=trial, config=config, unit_index=unitIndex) - - @staticmethod - def RunAnalysisForAllNeurons(trial: _Trial, config: _TrialConfig) -> list[_FitResult]: - return _Analysis.run_analysis_for_all_neurons(trial=trial, config=config) - - @staticmethod - def computeFitResidual(y: np.ndarray, X: np.ndarray, fit: _FitResult, dt: float = 1.0) -> np.ndarray: - return _Analysis.compute_fit_residual(y=y, X=X, fit_result=fit, dt=dt) - - @staticmethod - def computeInvGausTrans(y: np.ndarray, X: np.ndarray, fit: _FitResult, dt: float = 1.0) -> np.ndarray: - return _Analysis.compute_inv_gaus_trans(y=y, X=X, fit_result=fit, dt=dt) - - @staticmethod - def computeKSStats(transformed: np.ndarray) -> dict[str, float]: - return _Analysis.compute_ks_stats(transformed) - - @staticmethod - def fdr_bh(p_values: np.ndarray, alpha: float = 0.05) -> np.ndarray: - return _Analysis.fdr_bh(p_values=p_values, alpha=alpha) - - @staticmethod - def bnlrCG( - X: np.ndarray, - y: np.ndarray, - dt: float = 1.0, - l2Penalty: float = 0.0, - ) -> _FitResult: - return Analysis.fitGLM(X=X, y=y, fitType="binomial", dt=dt, l2Penalty=l2Penalty) - - @staticmethod - def KSPlot(fit: Any, fitNum: int = 1) -> Any: - _ = fitNum - if hasattr(fit, "KSPlot"): - return fit.KSPlot(fitNum) - import matplotlib.pyplot as plt - - return plt.plot([], []) - - @staticmethod - def compHistEnsCoeff(y: np.ndarray, X: np.ndarray, dt: float = 1.0) -> np.ndarray: - fit = Analysis.fitGLM(X=X, y=y, fitType="poisson", dt=dt) - return fit.coefficients - - @staticmethod - def compHistEnsCoeffForAll(y_list: list[np.ndarray], X_list: list[np.ndarray], dt: float = 1.0) -> list[np.ndarray]: - return [Analysis.compHistEnsCoeff(y=y, X=X, dt=dt) for y, X in zip(y_list, X_list)] - - @staticmethod - def computeNeighbors(positions: np.ndarray, k: int = 1) -> np.ndarray: - pts = np.asarray(positions, dtype=float) - if pts.ndim != 2: - raise ValueError("positions must be 2D [n_points, n_dims]") - if k <= 0: - raise ValueError("k must be positive") - diff = pts[:, None, :] - pts[None, :, :] - dist = np.sqrt(np.sum(diff * diff, axis=2)) - np.fill_diagonal(dist, np.inf) - return np.argsort(dist, axis=1)[:, :k] - - @staticmethod - def flatMaskCellToMat(flatMaskCell: list[np.ndarray]) -> np.ndarray: - rows = [np.asarray(row, dtype=float).reshape(-1) for row in flatMaskCell] - if not rows: - return np.zeros((0, 0), dtype=float) - width = max(row.size for row in rows) - out = np.zeros((len(rows), width), dtype=float) - for i, row in enumerate(rows): - out[i, : row.size] = row - return out - - @staticmethod - def computeHistLag(signal: np.ndarray, maxLag: int = 50) -> tuple[np.ndarray, np.ndarray]: - y = np.asarray(signal, dtype=float).reshape(-1) - if y.size == 0: - return np.array([], dtype=int), np.array([], dtype=float) - y = y - np.mean(y) - ac = np.correlate(y, y, mode="full") - mid = ac.size // 2 - ac = ac[mid : mid + maxLag + 1] - if ac[0] != 0: - ac = ac / ac[0] - lags = np.arange(ac.size, dtype=int) - return lags, ac - - @staticmethod - def computeHistLagForAll(signals: np.ndarray, maxLag: int = 50) -> tuple[np.ndarray, np.ndarray]: - mat = np.asarray(signals, dtype=float) - if mat.ndim == 1: - return Analysis.computeHistLag(mat, maxLag=maxLag) - curves = [Analysis.computeHistLag(row, maxLag=maxLag)[1] for row in mat] - if not curves: - return np.array([], dtype=int), np.array([], dtype=float) - mean_curve = np.mean(np.vstack(curves), axis=0) - lags = np.arange(mean_curve.size, dtype=int) - return lags, mean_curve - - @staticmethod - def computeGrangerCausalityMatrix(spikeMatrix: np.ndarray, maxLag: int = 1) -> np.ndarray: - X = np.asarray(spikeMatrix, dtype=float) - if X.ndim != 2: - raise ValueError("spikeMatrix must be 2D [n_units, n_time]") - n_units, n_time = X.shape - if n_time <= maxLag: - raise ValueError("n_time must be greater than maxLag") - out = np.zeros((n_units, n_units), dtype=float) - for i in range(n_units): - y = X[i, maxLag:] - yi = X[i, :-maxLag] - for j in range(n_units): - if i == j: - continue - xj = X[j, :-maxLag] - base_pred = yi - full_pred = np.column_stack([yi, xj]) @ np.linalg.lstsq( - np.column_stack([yi, xj]), - y, - rcond=None, - )[0] - base_err = np.var(y - base_pred) - full_err = np.var(y - full_pred) - if base_err <= 1e-12: - out[i, j] = 0.0 - else: - out[i, j] = max(0.0, (base_err - full_err) / base_err) - return out - - @staticmethod - def ksdiscrete(sample: np.ndarray, reference: np.ndarray | None = None) -> dict[str, float]: - x = np.asarray(sample, dtype=float).reshape(-1) - if x.size == 0: - return {"d_stat": 0.0, "n_events": 0.0} - if reference is None: - z = np.sort(x / max(np.max(x), 1e-12)) - else: - ref = np.asarray(reference, dtype=float).reshape(-1) - ref_sorted = np.sort(ref) - z = np.searchsorted(ref_sorted, np.sort(x), side="right") / max(ref_sorted.size, 1) - n = z.size - ecdf = np.arange(1, n + 1, dtype=float) / float(n) - d_plus = np.max(ecdf - z) - d_minus = np.max(z - np.arange(0, n, dtype=float) / float(n)) - return {"d_stat": float(max(d_plus, d_minus)), "n_events": float(n)} - - @staticmethod - def plotCoeffs(fit: Any) -> Any: - if hasattr(fit, "plotCoeffs"): - return fit.plotCoeffs() - import matplotlib.pyplot as plt - - return plt.plot([], []) - - @staticmethod - def plotFitResidual(y: np.ndarray, X: np.ndarray, fit: _FitResult, dt: float = 1.0) -> Any: - import matplotlib.pyplot as plt - - resid = Analysis.computeFitResidual(y=y, X=X, fit=fit, dt=dt) - x = np.arange(resid.size) - return plt.plot(x, resid, "k-") - - @staticmethod - def plotInvGausTrans(y: np.ndarray, X: np.ndarray, fit: _FitResult, dt: float = 1.0) -> Any: - import matplotlib.pyplot as plt - - z = Analysis.computeInvGausTrans(y=y, X=X, fit=fit, dt=dt) - x = np.arange(z.size) - return plt.plot(x, z, "k-") - - @staticmethod - def plotSeqCorr(residual: np.ndarray) -> Any: - import matplotlib.pyplot as plt - - y = np.asarray(residual, dtype=float).reshape(-1) - if y.size == 0: - return plt.plot([], []) - y = y - np.mean(y) - corr = np.correlate(y, y, mode="full") - corr = corr[corr.size // 2 :] - if corr[0] != 0: - corr = corr / corr[0] - return plt.plot(np.arange(corr.size), corr, "k-") - - @staticmethod - def spikeTrigAvg( - signal: np.ndarray, - spikeTimes_s: np.ndarray, - timeGrid_s: np.ndarray, - window_s: tuple[float, float] = (-0.05, 0.05), - ) -> tuple[np.ndarray, np.ndarray]: - x = np.asarray(signal, dtype=float).reshape(-1) - t = np.asarray(timeGrid_s, dtype=float).reshape(-1) - spikes = np.asarray(spikeTimes_s, dtype=float).reshape(-1) - if x.size != t.size: - raise ValueError("signal and timeGrid_s must have matching lengths") - dt = float(np.median(np.diff(t))) - n_pre = int(abs(window_s[0]) / dt) - n_post = int(abs(window_s[1]) / dt) - if n_pre + n_post + 1 <= 1: - raise ValueError("window too small for sample rate") - snippets: list[np.ndarray] = [] - for s in spikes: - idx = int(np.argmin(np.abs(t - s))) - lo = idx - n_pre - hi = idx + n_post + 1 - if lo < 0 or hi > x.size: - continue - snippets.append(x[lo:hi]) - if not snippets: - rel_t = np.arange(-n_pre, n_post + 1, dtype=float) * dt - return rel_t, np.zeros(rel_t.size, dtype=float) - mat = np.vstack(snippets) - rel_t = np.arange(-n_pre, n_post + 1, dtype=float) * dt - return rel_t, np.mean(mat, axis=0) - - -class FitResult(_FitResult): - @staticmethod - def FitResult(structure: dict[str, Any]) -> _FitResult: - return FitResult.fromStructure(structure) - - @staticmethod - def fromStructure(structure: dict[str, Any]) -> _FitResult: - native = _FitResult.from_structure(structure) - return FitResult( - coefficients=native.coefficients, - intercept=native.intercept, - fit_type=native.fit_type, - log_likelihood=native.log_likelihood, - n_samples=native.n_samples, - n_parameters=native.n_parameters, - parameter_labels=native.parameter_labels, - ks_stats=native.ks_stats, - fit_residual=native.fit_residual, - inv_gaus_stats=native.inv_gaus_stats, - neuron_name=native.neuron_name, - plot_params=native.plot_params, - ) - - @staticmethod - def CellArrayToStructure(results: list[_FitResult]) -> list[dict[str, Any]]: - return _FitResult.cell_array_to_structure(results) - - def toStructure(self) -> dict[str, Any]: - return self.to_structure() - - def setKSStats( - self, - ksStat: np.ndarray | float | dict[str, Any], - pValue: np.ndarray | float | None = None, - withinConfInt: np.ndarray | float | None = None, - ) -> _FitResult: - self.set_ks_stats(ks_stat=ksStat, p_value=pValue, within_conf_int=withinConfInt) - return self - - def setFitResidual(self, fitResidual: np.ndarray) -> _FitResult: - self.set_fit_residual(fitResidual) - return self - - def setInvGausStats(self, stats: dict[str, Any]) -> _FitResult: - self.set_inv_gaus_stats(stats) - return self - - def setNeuronName(self, neuronName: str) -> _FitResult: - self.set_neuron_name(neuronName) - return self - - def mapCovLabelsToUniqueLabels(self) -> list[str]: - return self.map_cov_labels_to_unique_labels() - - def computePlotParams(self) -> dict[str, Any]: - return self.compute_plot_params() - - def getPlotParams(self) -> dict[str, Any]: - return self.get_plot_params() - - def addParamsToFit(self, payload: dict[str, Any]) -> _FitResult: - self.add_params_to_fit(payload) - return self - - def evalLambda(self, X_or_modelIndex: Any, maybe_X: Any = None) -> np.ndarray: - if maybe_X is None: - X = np.asarray(X_or_modelIndex, dtype=float) - else: - X = np.asarray(maybe_X, dtype=float) - return self.predict(X) - - def getAIC(self) -> float: - return self.aic() - - def getBIC(self) -> float: - return self.bic() - - def asCIFModel(self) -> _CIFModel: - return self.as_cif_model() - - def computeValLambda(self, X: np.ndarray) -> np.ndarray: - return self.compute_val_lambda(X) - - def getCoeffs(self) -> np.ndarray: - return self.get_coeffs() - - def getCoeffIndex(self, label: str) -> int: - return self.get_coeff_index(label) - - def getParam(self, key: str) -> float | np.ndarray | str | int: - return self.get_param(key) - - def getUniqueLabels(self) -> list[str]: - return self.get_unique_labels() - - def isValDataPresent(self) -> bool: - return len(self.xval_data) > 0 and len(self.xval_time) > 0 - - def getSubsetFitResult(self, subfits: int | list[int] | np.ndarray) -> _FitResult: - if isinstance(subfits, int): - keep = [subfits] - else: - keep = [int(v) for v in np.asarray(subfits).reshape(-1)] - if 1 not in keep: - raise ValueError("single-fit Python adapter only supports subset index 1") - return self - - def mergeResults(self, newFitObj: Any) -> _FitSummary: - rows: list[_FitResult] = [self] - if isinstance(newFitObj, _FitResult): - rows.append(newFitObj) - elif isinstance(newFitObj, (list, tuple)): - for item in newFitObj: - if not isinstance(item, _FitResult): - raise TypeError("mergeResults expects FitResult or list of FitResult") - rows.append(item) - else: - raise TypeError("mergeResults expects FitResult or list of FitResult") - return FitResSummary(rows) - - def getHistIndex(self, fitNum: int = 1, sortByEpoch: bool = False) -> tuple[np.ndarray, np.ndarray, int]: - _ = fitNum - _ = sortByEpoch - return np.array([], dtype=int), np.array([], dtype=int), 1 - - def getHistCoeffs(self, fitNum: int = 1) -> tuple[np.ndarray, list[str], np.ndarray]: - _ = fitNum - empty = np.zeros((0, 1), dtype=float) - return empty, [], empty - - def plotCoeffs( - self, - handle: Any = None, - fitNum: int = 1, - plotProps: dict[str, Any] | None = None, - plotSignificance: bool = True, - subIndex: Any = None, - ) -> Any: - _ = handle - _ = fitNum - _ = plotProps - _ = plotSignificance - _ = subIndex - import matplotlib.pyplot as plt - - labels = self.get_unique_labels() or [f"coef_{i+1}" for i in range(self.coefficients.size)] - x = np.arange(len(labels)) - h = plt.bar(x, self.coefficients) - plt.xticks(x, labels, rotation=45, ha="right") - return h - - def plotCoeffsWithoutHistory( - self, - fitNum: int = 1, - sortByEpoch: bool = False, - plotSignificance: bool = True, - ) -> Any: - _ = sortByEpoch - return self.plotCoeffs(fitNum=fitNum, plotSignificance=plotSignificance) - - def plotHistCoeffs( - self, - fitNum: int = 1, - sortByEpoch: bool = False, - plotSignificance: bool = True, - ) -> Any: - _ = fitNum - _ = sortByEpoch - _ = plotSignificance - import matplotlib.pyplot as plt - - return plt.plot([], []) - - def plotInvGausTrans(self) -> Any: - import matplotlib.pyplot as plt - - if not self.inv_gaus_stats: - return plt.plot([], []) - first_key = next(iter(self.inv_gaus_stats.keys())) - y = np.asarray(self.inv_gaus_stats[first_key], dtype=float).reshape(-1) - x = np.arange(y.size) - return plt.plot(x, y, "k-") - - def plotResidual(self) -> Any: - import matplotlib.pyplot as plt - - if self.fit_residual is None: - return plt.plot([], []) - y = np.asarray(self.fit_residual, dtype=float).reshape(-1) - x = np.arange(y.size) - return plt.plot(x, y, "k-") - - def plotSeqCorr(self) -> Any: - import matplotlib.pyplot as plt - - if self.fit_residual is None: - return plt.plot([], []) - y = np.asarray(self.fit_residual, dtype=float).reshape(-1) - y = y - np.mean(y) - corr = np.correlate(y, y, mode="full") - corr = corr[corr.size // 2 :] - if corr[0] != 0: - corr = corr / corr[0] - lags = np.arange(corr.size) - return plt.plot(lags, corr, "k-") - - def KSPlot(self, fitNum: int = 1) -> Any: - _ = fitNum - import matplotlib.pyplot as plt - - ks = np.asarray(self.ks_stats.get("ks_stat", []), dtype=float).reshape(-1) - if ks.size == 0: - return plt.plot([], []) - x = np.arange(ks.size) - return plt.plot(x, ks, "k-") - - def plotValidation(self) -> Any: - import matplotlib.pyplot as plt - - if not self.isValDataPresent(): - return plt.plot([], []) - y = np.asarray(self.xval_data[0], dtype=float).reshape(-1) - t = np.asarray(self.xval_time[0], dtype=float).reshape(-1) - if t.size != y.size: - t = np.arange(y.size, dtype=float) - return plt.plot(t, y, "k-") - - def plotResults(self) -> Any: - import matplotlib.pyplot as plt - - plt.figure() - plt.subplot(2, 1, 1) - self.plotCoeffs() - plt.subplot(2, 1, 2) - self.plotResidual() - return plt.gca() - - @staticmethod - def xticklabel_rotate(XTick: np.ndarray, rot: float, *args: Any, **kwargs: Any) -> Any: - _ = args - _ = kwargs - import matplotlib.pyplot as plt - - ax = plt.gca() - ax.set_xticks(np.asarray(XTick, dtype=float)) - for label in ax.get_xticklabels(): - label.set_rotation(rot) - return ax.get_xticklabels() - - -class FitResSummary(_FitSummary): - @staticmethod - def FitResSummary(fitResultsCell: list[_FitResult] | _FitResult) -> _FitSummary: - if isinstance(fitResultsCell, _FitResult): - return FitResSummary([fitResultsCell]) - return FitResSummary(list(fitResultsCell)) - - @staticmethod - def fromStructure(structure: dict[str, Any]) -> _FitSummary: - native = _FitSummary.from_structure(structure) - return FitResSummary(native.results) - - def toStructure(self) -> dict[str, Any]: - return self.to_structure() - - def mapCovLabelsToUniqueLabels(self) -> list[str]: - return self.get_unique_labels() - - def getUniqueLabels(self) -> list[str]: - return self.get_unique_labels() - - def getCoeffIndex(self, fitNum: int = 1, sortByEpoch: bool = False) -> tuple[np.ndarray, np.ndarray, int]: - return self.get_coeff_index(fit_num=fitNum, sort_by_epoch=sortByEpoch) - - def getCoeffs(self, fitNum: int = 1) -> tuple[np.ndarray, list[str], np.ndarray]: - return self.get_coeffs(fit_num=fitNum) - - def binCoeffs(self, minVal: float, maxVal: float, binSize: float = 0.1) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - return self.bin_coeffs(min_val=minVal, max_val=maxVal, bin_size=binSize) - - def boxPlot( - self, - X: np.ndarray | None = None, - diffIndex: int = 1, - h: Any = None, - dataLabels: list[str] | None = None, - *_args: Any, - **_kwargs: Any, - ) -> dict[str, np.ndarray]: - _ = h - _ = dataLabels - return self.box_plot(X=X, diff_index=diffIndex) - - def bestByAIC(self) -> _FitResult: - return self.best_by_aic() - - def bestByBIC(self) -> _FitResult: - return self.best_by_bic() - - def getDiffAIC(self) -> np.ndarray: - return self.get_diff_aic() - - def getDiffBIC(self) -> np.ndarray: - return self.get_diff_bic() - - def getDifflogLL(self) -> np.ndarray: - return self.get_diff_log_likelihood() - - def computeDiffMat(self, metric: str = "aic") -> np.ndarray: - return self.compute_diff_mat(metric=metric) - - def getHistIndex(self, fitNum: int = 1, sortByEpoch: bool = False) -> tuple[np.ndarray, np.ndarray, int]: - coeff_idx, epoch_id, num_epochs = self.get_coeff_index(fit_num=fitNum, sort_by_epoch=sortByEpoch) - _coeff_mat, labels, _se = self.get_coeffs(fit_num=fitNum) - keep = np.array( - [i for i in coeff_idx if "hist" in labels[int(i)].lower() or "history" in labels[int(i)].lower()], - dtype=int, - ) - if keep.size == 0: - return keep, np.array([], dtype=int), 1 - return keep, np.ones(keep.size, dtype=int), num_epochs - - def getHistCoeffs(self, fitNum: int = 1) -> tuple[np.ndarray, list[str], np.ndarray]: - coeff_mat, labels, se_mat = self.get_coeffs(fit_num=fitNum) - keep = [i for i, label in enumerate(labels) if "hist" in label.lower() or "history" in label.lower()] - if not keep: - empty = np.zeros((0, coeff_mat.shape[1]), dtype=float) - return empty, [], empty - idx = np.asarray(keep, dtype=int) - return coeff_mat[idx, :], [labels[i] for i in idx], se_mat[idx, :] - - def getSigCoeffs(self, fitNum: int = 1) -> tuple[np.ndarray, list[str], np.ndarray]: - coeff_mat, labels, se_mat = self.get_coeffs(fit_num=fitNum) - col = max(0, min(coeff_mat.shape[1] - 1, int(fitNum) - 1)) - keep = np.where(np.isfinite(coeff_mat[:, col]) & (np.abs(coeff_mat[:, col]) > 0.0))[0].astype(int) - if keep.size == 0: - empty = np.zeros((0, coeff_mat.shape[1]), dtype=float) - return empty, [], empty - return coeff_mat[keep, :], [labels[i] for i in keep], se_mat[keep, :] - - def setCoeffRange(self, minVal: float, maxVal: float) -> _FitSummary: - setattr(self, "_coeff_range", (float(minVal), float(maxVal))) - return self - - @staticmethod - def xticklabel_rotate(XTick: np.ndarray, rot: float, *args: Any, **kwargs: Any) -> Any: - _ = args - _ = kwargs - import matplotlib.pyplot as plt - - ax = plt.gca() - ax.set_xticks(np.asarray(XTick, dtype=float)) - for label in ax.get_xticklabels(): - label.set_rotation(rot) - return ax.get_xticklabels() - - def plotAIC(self) -> Any: - import matplotlib.pyplot as plt - - vals = np.array([fit.aic() for fit in self.results], dtype=float) - return plt.plot(np.arange(1, vals.size + 1), vals, "k-o") - - def plotBIC(self) -> Any: - import matplotlib.pyplot as plt - - vals = np.array([fit.bic() for fit in self.results], dtype=float) - return plt.plot(np.arange(1, vals.size + 1), vals, "k-o") - - def plotlogLL(self) -> Any: - import matplotlib.pyplot as plt - - vals = np.array([fit.log_likelihood for fit in self.results], dtype=float) - return plt.plot(np.arange(1, vals.size + 1), vals, "k-o") - - def plotIC(self, metric: str = "aic") -> Any: - metric_key = str(metric).lower() - if metric_key == "aic": - return self.plotAIC() - if metric_key == "bic": - return self.plotBIC() - if metric_key in {"logll", "log_likelihood"}: - return self.plotlogLL() - raise ValueError("metric must be one of {'aic', 'bic', 'logll'}") - - def plotAllCoeffs(self, fitNum: int = 1) -> Any: - import matplotlib.pyplot as plt - - coeff_mat, _labels, _se = self.get_coeffs(fit_num=fitNum) - if coeff_mat.size == 0: - return plt.plot([], []) - return plt.plot(np.arange(coeff_mat.shape[0]), coeff_mat[:, max(0, min(coeff_mat.shape[1] - 1, fitNum - 1))], "k.") - - def plotHistCoeffs(self, fitNum: int = 1) -> Any: - import matplotlib.pyplot as plt - - coeffs, _labels, _se = self.getHistCoeffs(fitNum=fitNum) - if coeffs.size == 0: - return plt.plot([], []) - col = max(0, min(coeffs.shape[1] - 1, fitNum - 1)) - return plt.plot(np.arange(coeffs.shape[0]), coeffs[:, col], "k.") - - def plotCoeffsWithoutHistory(self, fitNum: int = 1) -> Any: - import matplotlib.pyplot as plt - - coeff_mat, labels, _se = self.get_coeffs(fit_num=fitNum) - keep = [i for i, label in enumerate(labels) if "hist" not in label.lower() and "history" not in label.lower()] - if not keep: - return plt.plot([], []) - col = max(0, min(coeff_mat.shape[1] - 1, fitNum - 1)) - idx = np.asarray(keep, dtype=int) - return plt.plot(np.arange(idx.size), coeff_mat[idx, col], "k.") - - def plot2dCoeffSummary(self, fitNum: int = 1) -> Any: - import matplotlib.pyplot as plt - - coeff_mat, _labels, _se = self.get_coeffs(fit_num=fitNum) - return plt.imshow(coeff_mat, aspect="auto", interpolation="nearest") - - def plot3dCoeffSummary(self, fitNum: int = 1) -> Any: - import matplotlib.pyplot as plt - - coeff_mat, _labels, _se = self.get_coeffs(fit_num=fitNum) - if coeff_mat.size == 0: - return plt.plot([], []) - fig = plt.figure() - ax = cast(Any, fig.add_subplot(111, projection="3d")) - x = np.arange(coeff_mat.shape[0], dtype=float) - y = np.zeros_like(x) - z = np.zeros_like(x) - dz = coeff_mat[:, max(0, min(coeff_mat.shape[1] - 1, fitNum - 1))] - return ax.bar3d(x, y, z, 0.5, 0.5, dz) - - def plotKSSummary(self) -> Any: - import matplotlib.pyplot as plt - - vals: list[float] = [] - for fit in self.results: - raw = fit.ks_stats.get("ks_stat", np.nan) - arr = np.asarray(raw, dtype=float).reshape(-1) - vals.append(float(np.nanmean(arr)) if arr.size else np.nan) - y = np.asarray(vals, dtype=float) - return plt.plot(np.arange(1, y.size + 1), y, "k-o") - - def plotResidualSummary(self) -> Any: - import matplotlib.pyplot as plt - - vals: list[float] = [] - for fit in self.results: - if fit.fit_residual is None: - vals.append(np.nan) - continue - arr = np.asarray(fit.fit_residual, dtype=float).reshape(-1) - vals.append(float(np.nanmean(np.abs(arr))) if arr.size else np.nan) - y = np.asarray(vals, dtype=float) - return plt.plot(np.arange(1, y.size + 1), y, "k-o") - - def plotSummary(self, fitNum: int = 1) -> Any: - import matplotlib.pyplot as plt - - plt.figure() - plt.subplot(2, 2, 1) - self.plotAIC() - plt.subplot(2, 2, 2) - self.plotBIC() - plt.subplot(2, 2, 3) - self.plotAllCoeffs(fitNum=fitNum) - plt.subplot(2, 2, 4) - self.plotResidualSummary() - return plt.gca() - - -class DecodingAlgorithms: - @staticmethod - def _em_not_implemented(name: str) -> None: - raise NotImplementedError( - f"{name} is not yet ported in nSTAT-python; use decodeStatePosterior/kalman_* APIs for now." - ) - - @staticmethod - def getPoolSizeCompat() -> int: - """Return active parallel pool size (MATLAB-compatible fallback).""" - # MATLAB returns 0 when no active parallel pool exists. nSTAT-python - # executes these workflows serially, so preserve the same default. - return 0 - - @staticmethod - def _chol_like_matlab(mat: np.ndarray) -> np.ndarray: - arr = np.asarray(mat, dtype=float) - if arr.ndim == 0: - return np.array([[float(np.sqrt(max(arr.item(), 0.0)))]] , dtype=float) - if np.allclose(arr, 0.0): - return np.zeros_like(arr, dtype=float) - try: - return np.linalg.cholesky(arr) - except np.linalg.LinAlgError: - eigvals, eigvecs = np.linalg.eigh(arr) - eigvals = np.clip(eigvals, 0.0, None) - return eigvecs @ np.diag(np.sqrt(eigvals)) - - @staticmethod - def _build_unit_impulse_basis(numBasis: int, minTime: float, maxTime: float, delta: float) -> tuple[np.ndarray, np.ndarray]: - if numBasis <= 0: - raise ValueError("numBasis must be > 0") - basis_width = float(maxTime - minTime) / float(numBasis) - sample_rate = 1.0 / float(delta) - basis_sig = nstColl.generateUnitImpulseBasis(basis_width, minTime, maxTime, sample_rate) - basis_mat = np.asarray(basis_sig.data, dtype=float) - time = np.asarray(basis_sig.time, dtype=float).reshape(-1) - return basis_mat, time - - @staticmethod - def _draw_xk_samples_spec(xK_arr: np.ndarray, Wku_arr: np.ndarray, Mc: int, rng: np.random.Generator) -> np.ndarray: - # MATLAB mirror: for r=1:numBasis, for c=1:Mc, xKdraw(r,:,c)=xK(r,:)+chol(WkuTemp)*z - numBasis, K = xK_arr.shape - xK_draw = np.zeros((numBasis, K, int(Mc)), dtype=float) - for r in range(numBasis): - if Wku_arr.ndim == 4: - Wku_temp = np.asarray(Wku_arr[r, r, :, :], dtype=float) - elif Wku_arr.ndim == 3: - Wku_temp = np.asarray(Wku_arr[r, :, :], dtype=float) - elif Wku_arr.ndim == 2: - Wku_temp = np.asarray(Wku_arr, dtype=float) - else: - Wku_temp = np.asarray(0.0, dtype=float) - if Wku_temp.ndim == 0: - chol_m = np.diag(np.repeat(float(np.sqrt(max(Wku_temp.item(), 0.0))), K)) - else: - chol_m = DecodingAlgorithms._chol_like_matlab(Wku_temp) - if chol_m.shape != (K, K): - raise ValueError("Wku covariance slice must be KxK") - for c in range(int(Mc)): - z = rng.normal(0.0, 1.0, size=(K,)) - xK_draw[r, :, c] = xK_arr[r, :] + (chol_m @ z) - return xK_draw - - @staticmethod - def _draw_xk_samples_fast(xK_arr: np.ndarray, Wku_arr: np.ndarray, Mc: int, rng: np.random.Generator) -> np.ndarray: - # Fast equivalent of _draw_xk_samples_spec with identical RNG ordering. - numBasis, K = xK_arr.shape - xK_draw = np.zeros((numBasis, K, int(Mc)), dtype=float) - for r in range(numBasis): - if Wku_arr.ndim == 4: - Wku_temp = np.asarray(Wku_arr[r, r, :, :], dtype=float) - elif Wku_arr.ndim == 3: - Wku_temp = np.asarray(Wku_arr[r, :, :], dtype=float) - elif Wku_arr.ndim == 2: - Wku_temp = np.asarray(Wku_arr, dtype=float) - else: - Wku_temp = np.asarray(0.0, dtype=float) - if Wku_temp.ndim == 0: - chol_m = np.diag(np.repeat(float(np.sqrt(max(Wku_temp.item(), 0.0))), K)) - else: - chol_m = DecodingAlgorithms._chol_like_matlab(Wku_temp) - if chol_m.shape != (K, K): - raise ValueError("Wku covariance slice must be KxK") - z_draw = rng.normal(0.0, 1.0, size=(int(Mc), K)) - xK_draw[r, :, :] = xK_arr[r, :][:, None] + (chol_m @ z_draw.T) - return xK_draw - - @staticmethod - def _compute_draw_rates_spec( - basis_mat: np.ndarray, - xK_draw: np.ndarray, - draw_index: int, - Hk: list[np.ndarray], - gamma_vec: np.ndarray, - fit_type: str, - delta: float, - ) -> np.ndarray: - # MATLAB mirror: for each draw c and trial k, evaluate lambda_k(t). - K = xK_draw.shape[1] - n_time = basis_mat.shape[0] - rates = np.zeros((n_time, K), dtype=float) - for k in range(K): - stim_k = basis_mat @ xK_draw[:, k, draw_index] - hk = Hk[k] - cols = min(hk.shape[1], gamma_vec.size) - if cols > 0 and np.any(np.abs(gamma_vec[:cols]) > 0.0): - hist_lin = hk[:, :cols] @ gamma_vec[:cols] - else: - hist_lin = np.zeros(stim_k.shape[0], dtype=float) - eta = stim_k + hist_lin - if fit_type == "poisson": - lam = np.exp(eta) - else: - exp_eta = np.exp(eta) - lam = exp_eta / (1.0 + exp_eta) - rates[:, k] = lam / float(delta) - return rates - - @staticmethod - def _compute_draw_rates_fast( - basis_mat: np.ndarray, - xK_draw: np.ndarray, - draw_index: int, - hist_term: np.ndarray, - fit_type: str, - delta: float, - ) -> np.ndarray: - stim_ck = basis_mat @ xK_draw[:, :, draw_index] - eta = stim_ck + hist_term - if fit_type == "poisson": - rates = np.exp(eta) - else: - exp_eta = np.exp(eta) - rates = exp_eta / (1.0 + exp_eta) - return rates / float(delta) - - @staticmethod - def _compute_prob_mat_spec(spike_rate: np.ndarray, Mc: int) -> np.ndarray: - # MATLAB mirror: upper-triangle probability matrix P(rate_m > rate_k). - K = spike_rate.shape[1] - prob_mat = np.zeros((K, K), dtype=float) - for k in range(K): - for m in range(k + 1, K): - prob_mat[k, m] = float(np.sum(spike_rate[:, m] > spike_rate[:, k])) / float(Mc) - return prob_mat - - @staticmethod - def _compute_prob_mat_fast(spike_rate: np.ndarray) -> np.ndarray: - prob_full = np.mean(spike_rate[:, None, :] > spike_rate[:, :, None], axis=0) - return np.triu(np.asarray(prob_full, dtype=float), k=1) - - @staticmethod - def _compute_spike_rate_cis_matlab( - xK: np.ndarray, - Wku: np.ndarray, - dN: np.ndarray, - t0: float, - tf: float, - fitType: str, - delta: float, - gamma: Any = None, - windowTimes: Any = None, - Mc: int = 500, - alphaVal: float = 0.05, - implementation: str = "fast", - ) -> tuple[_Covariate, np.ndarray, np.ndarray]: - # MATLAB reference block: DecodingAlgorithms.computeSpikeRateCIs - # Keep a readable spec path; use fast helpers for CI/runtime workflows. - xK_arr = np.asarray(xK, dtype=float) - if xK_arr.ndim != 2: - raise ValueError("xK must be 2D with shape (numBasis, K)") - dN_arr = np.asarray(dN, dtype=float) - if dN_arr.ndim != 2: - raise ValueError("dN must be 2D with shape (K, T)") - numBasis, K = xK_arr.shape - if dN_arr.shape[0] != K: - raise ValueError("dN first dimension must match K in xK") - fit_type = str(fitType).lower() - if fit_type not in {"poisson", "binomial"}: - raise ValueError("fitType must be either 'poisson' or 'binomial'") - if not (0.0 < float(alphaVal) < 1.0): - raise ValueError("alphaVal must be in (0, 1)") - if int(Mc) <= 0: - raise ValueError("Mc must be > 0") - impl = str(implementation).lower() - if impl not in {"spec", "fast"}: - raise ValueError("implementation must be 'spec' or 'fast'") - - # MATLAB block: construct unit-impulse basis on [0, Tmax]. - min_time = 0.0 - max_time = float(dN_arr.shape[1] - 1) * float(delta) - basis_mat, basis_time = DecodingAlgorithms._build_unit_impulse_basis(numBasis, min_time, max_time, float(delta)) - if basis_mat.shape[0] < dN_arr.shape[1]: - pad = np.zeros((dN_arr.shape[1] - basis_mat.shape[0], basis_mat.shape[1]), dtype=float) - basis_mat = np.vstack([basis_mat, pad]) - elif basis_mat.shape[0] > dN_arr.shape[1]: - basis_mat = basis_mat[: dN_arr.shape[1], :] - basis_time = basis_time[: dN_arr.shape[1]] - time = basis_time - - # MATLAB block: build history design matrices H{k} when windowTimes provided. - window_vals = np.asarray([] if windowTimes is None else windowTimes, dtype=float).reshape(-1) - if window_vals.size > 0: - if window_vals.size == 1: - window_vals = np.array([0.0, float(window_vals[0])], dtype=float) - hist_obj = History(bin_edges_s=window_vals) - gamma_vec = np.asarray(gamma, dtype=float).reshape(-1) - Hk: list[np.ndarray] = [] - for k in range(K): - spikes = np.where(dN_arr[k, :] == 1.0)[0].astype(float) * float(delta) - hk = np.asarray(hist_obj.computeHistory(spikes, time), dtype=float) - if hk.ndim == 1: - hk = hk[:, None] - if hk.shape[0] < dN_arr.shape[1]: - hk = np.vstack([hk, np.zeros((dN_arr.shape[1] - hk.shape[0], hk.shape[1]), dtype=float)]) - elif hk.shape[0] > dN_arr.shape[1]: - hk = hk[: dN_arr.shape[1], :] - Hk.append(hk) - if gamma_vec.size == 0: - gamma_vec = np.zeros(1, dtype=float) - else: - Hk = [np.zeros((dN_arr.shape[1], 1), dtype=float) for _ in range(K)] - gamma_vec = np.zeros(1, dtype=float) - - # MATLAB block: Monte Carlo coefficient draws xKdraw. - Wku_arr = np.asarray(Wku, dtype=float) - rng = np.random.default_rng(0) - if impl == "fast": - xK_draw = DecodingAlgorithms._draw_xk_samples_fast(xK_arr, Wku_arr, int(Mc), rng) - else: - xK_draw = DecodingAlgorithms._draw_xk_samples_spec(xK_arr, Wku_arr, int(Mc), rng) - - spike_rate = np.zeros((int(Mc), K), dtype=float) - mask = (time >= float(t0)) & (time <= float(tf)) - interval = max(float(tf - t0), np.finfo(float).eps) - integrate_fn = getattr(np, "trapezoid", None) - if integrate_fn is None: - integrate_fn = getattr(np, "trapz", None) # pragma: no cover - NumPy<2 fallback - - use_history = window_vals.size > 0 and np.any(np.abs(gamma_vec) > 0.0) - if use_history and impl == "fast": - hist_term = np.zeros((dN_arr.shape[1], K), dtype=float) - for k in range(K): - hk = Hk[k] - cols = min(hk.shape[1], gamma_vec.size) - hist_term[:, k] = hk[:, :cols] @ gamma_vec[:cols] - else: - hist_term = np.zeros((dN_arr.shape[1], K), dtype=float) - - # MATLAB block: for each draw c, integrate trial rates over [t0, tf]. - for c in range(int(Mc)): - if impl == "fast": - rates = DecodingAlgorithms._compute_draw_rates_fast( - basis_mat=basis_mat, - xK_draw=xK_draw, - draw_index=c, - hist_term=hist_term, - fit_type=fit_type, - delta=float(delta), - ) - else: - rates = DecodingAlgorithms._compute_draw_rates_spec( - basis_mat=basis_mat, - xK_draw=xK_draw, - draw_index=c, - Hk=Hk, - gamma_vec=gamma_vec, - fit_type=fit_type, - delta=float(delta), - ) - if np.sum(mask) < 2: - integral_vals = np.zeros(K, dtype=float) - else: - if integrate_fn is None: # pragma: no cover - extreme fallback - dt_vec = np.diff(time[mask]).reshape(-1, 1) - y0 = rates[mask, :][:-1, :] - y1 = rates[mask, :][1:, :] - integral_vals = np.sum(0.5 * (y0 + y1) * dt_vec, axis=0) - else: - integral_vals = np.asarray( - integrate_fn(rates[mask, :], x=time[mask], axis=0), - dtype=float, - ) - spike_rate[c, :] = integral_vals / interval - - CIs = np.zeros((K, 2), dtype=float) - for k in range(K): - vals = np.sort(spike_rate[:, k]) - f = (np.arange(vals.size, dtype=float) + 1.0) / float(vals.size) - lo = vals[f < float(alphaVal)] - hi = vals[f > (1.0 - float(alphaVal))] - CIs[k, 0] = float(lo[-1]) if lo.size else float(vals[0]) - CIs[k, 1] = float(hi[0]) if hi.size else float(vals[-1]) - - # MATLAB block: emit Covariate with attached confidence interval. - spike_rate_sig = Covariate( - time=np.arange(1, K + 1, dtype=float), - data=np.mean(spike_rate, axis=0), - name=f"({tf}-{t0})^-1 * \\Lambda({tf}-{t0})", - x_label="Trial", - x_units="k", - y_units="Hz", - ) - ci_obj = ConfidenceInterval( - time=np.arange(1, K + 1, dtype=float), - lower=CIs[:, 0], - upper=CIs[:, 1], - level=1.0 - float(alphaVal), - ) - ci_obj.setColor("b") - spike_rate_sig.setConfInterval(ci_obj) - - if impl == "fast": - prob_mat = DecodingAlgorithms._compute_prob_mat_fast(spike_rate) - else: - prob_mat = DecodingAlgorithms._compute_prob_mat_spec(spike_rate, int(Mc)) - sig_mat = (prob_mat > (1.0 - float(alphaVal))).astype(float) - return spike_rate_sig, prob_mat, sig_mat - - @staticmethod - def computeSpikeRateCIs(*args: Any, **kwargs: Any) -> tuple[Any, np.ndarray, np.ndarray]: - # MATLAB signature: - # computeSpikeRateCIs(xK,Wku,dN,t0,tf,fitType,delta,gamma,windowTimes,Mc,alphaVal) - # Existing Python compact signature: - # computeSpikeRateCIs(spike_matrix, alpha=0.05) - if len(args) >= 7: - xK = np.asarray(args[0], dtype=float) - Wku = np.asarray(args[1], dtype=float) - dN = np.asarray(args[2], dtype=float) - t0 = float(args[3]) - tf = float(args[4]) - fitType = str(args[5]) - delta = float(args[6]) - gamma = args[7] if len(args) >= 8 else kwargs.get("gamma", None) - windowTimes = args[8] if len(args) >= 9 else kwargs.get("windowTimes", None) - Mc = int(args[9]) if len(args) >= 10 else int(kwargs.get("Mc", 500)) - alphaVal = float(args[10]) if len(args) >= 11 else float(kwargs.get("alphaVal", 0.05)) - return DecodingAlgorithms._compute_spike_rate_cis_matlab( - xK=xK, - Wku=Wku, - dN=dN, - t0=t0, - tf=tf, - fitType=fitType, - delta=delta, - gamma=gamma, - windowTimes=windowTimes, - Mc=Mc, - alphaVal=alphaVal, - ) - - if len(args) == 0 and "spike_matrix" not in kwargs: - raise TypeError("computeSpikeRateCIs requires either MATLAB-style or compact arguments") - spike_matrix = np.asarray(args[0] if args else kwargs["spike_matrix"], dtype=float) - alpha = float(args[1]) if len(args) >= 2 else float(kwargs.get("alpha", 0.05)) - return _DecodingAlgorithms.compute_spike_rate_cis(spike_matrix=spike_matrix, alpha=alpha) - - @staticmethod - def decodeWeightedCenter(spike_counts: np.ndarray, tuning_curves: np.ndarray) -> np.ndarray: - return _DecodingAlgorithms.decode_weighted_center(spike_counts=spike_counts, tuning_curves=tuning_curves) - - @staticmethod - def decodeStatePosterior( - spike_counts: np.ndarray, - tuning_rates: np.ndarray, - transition: np.ndarray | None = None, - prior: np.ndarray | None = None, - ) -> tuple[np.ndarray, np.ndarray]: - return _DecodingAlgorithms.decode_state_posterior( - spike_counts=spike_counts, - tuning_rates=tuning_rates, - transition=transition, - prior=prior, - ) - - @staticmethod - def computeSpikeRateDiffCIs( - spike_matrix_a: np.ndarray, spike_matrix_b: np.ndarray, alpha: float = 0.05 - ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - return _DecodingAlgorithms.compute_spike_rate_diff_cis( - spike_matrix_a=spike_matrix_a, spike_matrix_b=spike_matrix_b, alpha=alpha - ) - - @staticmethod - def ComputeStimulusCIs( - posterior: np.ndarray, state_values: np.ndarray, alpha: float = 0.05 - ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - return _DecodingAlgorithms.compute_stimulus_cis( - posterior=posterior, state_values=state_values, alpha=alpha - ) - - @staticmethod - def kalman_predict( - x_prev: np.ndarray, p_prev: np.ndarray, a: np.ndarray, q: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return _DecodingAlgorithms.kalman_predict(x_prev=x_prev, p_prev=p_prev, a=a, q=q) - - @staticmethod - def kalman_update( - x_pred: np.ndarray, - p_pred: np.ndarray, - y_t: np.ndarray, - h: np.ndarray, - r: np.ndarray, - ) -> tuple[np.ndarray, np.ndarray]: - return _DecodingAlgorithms.kalman_update( - x_pred=x_pred, p_pred=p_pred, y_t=y_t, h=h, r=r - ) - - @staticmethod - def kalman_filter( - y: np.ndarray, - a: np.ndarray, - h: np.ndarray, - q: np.ndarray, - r: np.ndarray, - x0: np.ndarray, - p0: np.ndarray, - ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: - return _DecodingAlgorithms.kalman_filter(y=y, a=a, h=h, q=q, r=r, x0=x0, p0=p0) - - @staticmethod - def kalman_fixedIntervalSmoother( - xf: np.ndarray, pf: np.ndarray, xp: np.ndarray, pp: np.ndarray, a: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return _DecodingAlgorithms.kalman_fixed_interval_smoother( - xf=xf, pf=pf, xp=xp, pp=pp, a=a - ) - - @staticmethod - def kalman_smoother( - xf: np.ndarray, pf: np.ndarray, xp: np.ndarray, pp: np.ndarray, a: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.kalman_fixedIntervalSmoother(xf=xf, pf=pf, xp=xp, pp=pp, a=a) - - @staticmethod - def kalman_smootherFromFiltered( - y: np.ndarray, - a: np.ndarray, - h: np.ndarray, - q: np.ndarray, - r: np.ndarray, - x0: np.ndarray, - p0: np.ndarray, - ) -> tuple[np.ndarray, np.ndarray]: - xf, pf, xp, pp = DecodingAlgorithms.kalman_filter(y=y, a=a, h=h, q=q, r=r, x0=x0, p0=p0) - return DecodingAlgorithms.kalman_fixedIntervalSmoother(xf=xf, pf=pf, xp=xp, pp=pp, a=a) - - @staticmethod - def PPDecodeFilter( - spike_counts: np.ndarray, - tuning_rates: np.ndarray, - transition: np.ndarray | None = None, - prior: np.ndarray | None = None, - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.decodeStatePosterior( - spike_counts=spike_counts, - tuning_rates=tuning_rates, - transition=transition, - prior=prior, - ) - - @staticmethod - def PPDecodeFilterLinear( - spike_counts: np.ndarray, - tuning_rates: np.ndarray, - transition: np.ndarray | None = None, - prior: np.ndarray | None = None, - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.PPDecodeFilter( - spike_counts=spike_counts, tuning_rates=tuning_rates, transition=transition, prior=prior - ) - - @staticmethod - def PPHybridFilter( - spike_counts: np.ndarray, - tuning_rates: np.ndarray, - transition: np.ndarray | None = None, - prior: np.ndarray | None = None, - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.PPDecodeFilter( - spike_counts=spike_counts, tuning_rates=tuning_rates, transition=transition, prior=prior - ) - - @staticmethod - def PPHybridFilterLinear( - spike_counts: np.ndarray, - tuning_rates: np.ndarray, - transition: np.ndarray | None = None, - prior: np.ndarray | None = None, - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.PPHybridFilter( - spike_counts=spike_counts, tuning_rates=tuning_rates, transition=transition, prior=prior - ) - - @staticmethod - def PPDecode_predict( - x_prev: np.ndarray, p_prev: np.ndarray, a: np.ndarray, q: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.kalman_predict(x_prev=x_prev, p_prev=p_prev, a=a, q=q) - - @staticmethod - def PPDecode_update( - x_pred: np.ndarray, p_pred: np.ndarray, y_t: np.ndarray, h: np.ndarray, r: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.kalman_update(x_pred=x_pred, p_pred=p_pred, y_t=y_t, h=h, r=r) - - @staticmethod - def PPDecode_updateLinear( - x_pred: np.ndarray, p_pred: np.ndarray, y_t: np.ndarray, h: np.ndarray, r: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.PPDecode_update(x_pred=x_pred, p_pred=p_pred, y_t=y_t, h=h, r=r) - - @staticmethod - def PP_fixedIntervalSmoother( - xf: np.ndarray, pf: np.ndarray, xp: np.ndarray, pp: np.ndarray, a: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.kalman_fixedIntervalSmoother(xf=xf, pf=pf, xp=xp, pp=pp, a=a) - - @staticmethod - def mPPCODecodeLinear( - spike_counts: np.ndarray, - tuning_rates: np.ndarray, - transition: np.ndarray | None = None, - prior: np.ndarray | None = None, - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.decodeStatePosterior( - spike_counts=spike_counts, - tuning_rates=tuning_rates, - transition=transition, - prior=prior, - ) - - @staticmethod - def mPPCODecode_predict( - x_prev: np.ndarray, p_prev: np.ndarray, a: np.ndarray, q: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.kalman_predict(x_prev=x_prev, p_prev=p_prev, a=a, q=q) - - @staticmethod - def mPPCODecode_update( - x_pred: np.ndarray, p_pred: np.ndarray, y_t: np.ndarray, h: np.ndarray, r: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.kalman_update(x_pred=x_pred, p_pred=p_pred, y_t=y_t, h=h, r=r) - - @staticmethod - def mPPCO_fixedIntervalSmoother( - xf: np.ndarray, pf: np.ndarray, xp: np.ndarray, pp: np.ndarray, a: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.kalman_fixedIntervalSmoother(xf=xf, pf=pf, xp=xp, pp=pp, a=a) - - @staticmethod - def ukf_sigmas(x: np.ndarray, p: np.ndarray, kappa: float = 0.0) -> np.ndarray: - x = np.asarray(x, dtype=float) - p = np.asarray(p, dtype=float) - n = x.size - s = np.linalg.cholesky((n + kappa) * p) - sigmas = np.column_stack([x, x[:, None] + s, x[:, None] - s]) - return sigmas - - @staticmethod - def ukf_ut( - sigmas: np.ndarray, wm: np.ndarray, wc: np.ndarray, noise: np.ndarray | None = None - ) -> tuple[np.ndarray, np.ndarray]: - sig = np.asarray(sigmas, dtype=float) - wm = np.asarray(wm, dtype=float).reshape(-1) - wc = np.asarray(wc, dtype=float).reshape(-1) - mu = sig @ wm - d = sig - mu[:, None] - cov = d @ np.diag(wc) @ d.T - if noise is not None: - cov = cov + np.asarray(noise, dtype=float) - return mu, cov - - @staticmethod - def ukf( - x_prev: np.ndarray, p_prev: np.ndarray, a: np.ndarray, q: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - return DecodingAlgorithms.kalman_predict(x_prev=x_prev, p_prev=p_prev, a=a, q=q) - - @staticmethod - def KF_ComputeParamStandardErrors(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("KF_ComputeParamStandardErrors") - - @staticmethod - def KF_EM(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("KF_EM") - - @staticmethod - def KF_EMCreateConstraints(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("KF_EMCreateConstraints") - - @staticmethod - def KF_EStep(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("KF_EStep") - - @staticmethod - def KF_MStep(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("KF_MStep") - - @staticmethod - def PPSS_EM(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("PPSS_EM") - - @staticmethod - def PPSS_EMFB(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("PPSS_EMFB") - - @staticmethod - def PPSS_EStep(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("PPSS_EStep") - - @staticmethod - def PPSS_MStep(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("PPSS_MStep") - - @staticmethod - def PP_ComputeParamStandardErrors(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("PP_ComputeParamStandardErrors") - - @staticmethod - def PP_EM(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("PP_EM") - - @staticmethod - def PP_EMCreateConstraints(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("PP_EMCreateConstraints") - - @staticmethod - def PP_EStep(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("PP_EStep") - - @staticmethod - def PP_MStep(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("PP_MStep") - - @staticmethod - def estimateInfoMat(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("estimateInfoMat") - - @staticmethod - def mPPCO_ComputeParamStandardErrors(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("mPPCO_ComputeParamStandardErrors") - - @staticmethod - def mPPCO_EM(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("mPPCO_EM") - - @staticmethod - def mPPCO_EMCreateConstraints(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("mPPCO_EMCreateConstraints") - - @staticmethod - def mPPCO_EStep(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("mPPCO_EStep") - - @staticmethod - def mPPCO_MStep(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("mPPCO_MStep") - - @staticmethod - def prepareEMResults(*_args: Any, **_kwargs: Any) -> None: - DecodingAlgorithms._em_not_implemented("prepareEMResults") - - -__all__ = [ - "SignalObj", - "Covariate", - "ConfidenceInterval", - "Events", - "History", - "nspikeTrain", - "nstColl", - "CovColl", - "TrialConfig", - "ConfigColl", - "Trial", - "CIF", - "Analysis", - "FitResult", - "FitResSummary", - "DecodingAlgorithms", -] diff --git a/src/nstat/confidence.py b/src/nstat/confidence.py deleted file mode 100644 index 71c057b4..00000000 --- a/src/nstat/confidence.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Confidence interval container for time-varying quantities.""" - -from __future__ import annotations - -from dataclasses import dataclass - -import numpy as np - - -@dataclass(slots=True) -class ConfidenceInterval: - """Lower/upper confidence envelope over time. - - Parameters - ---------- - time: - Monotonic time grid. - lower: - Lower confidence bound values. - upper: - Upper confidence bound values. - level: - Confidence level in (0,1), defaults to 0.95. - """ - - time: np.ndarray - lower: np.ndarray - upper: np.ndarray - level: float = 0.95 - - def __post_init__(self) -> None: - self.time = np.asarray(self.time, dtype=float) - self.lower = np.asarray(self.lower, dtype=float) - self.upper = np.asarray(self.upper, dtype=float) - - if self.time.ndim != 1: - raise ValueError("time must be 1D") - if self.lower.shape != self.time.shape or self.upper.shape != self.time.shape: - raise ValueError("lower and upper must match time shape") - if np.any(self.lower > self.upper): - raise ValueError("lower bound cannot exceed upper bound") - if not (0.0 < self.level < 1.0): - raise ValueError("level must be in (0, 1)") - - def width(self) -> np.ndarray: - """Return point-wise interval width.""" - - return self.upper - self.lower - - def contains(self, values: np.ndarray) -> np.ndarray: - """Return boolean mask indicating whether values are inside the interval.""" - - values = np.asarray(values, dtype=float) - if values.shape != self.time.shape: - raise ValueError("values shape must match time shape") - return (values >= self.lower) & (values <= self.upper) diff --git a/src/nstat/data_manager.py b/src/nstat/data_manager.py index 0d9107b1..48c08540 100644 --- a/src/nstat/data_manager.py +++ b/src/nstat/data_manager.py @@ -1,38 +1,34 @@ -"""Example data management for nSTAT notebooks and validation workflows. +"""Example data directory resolution and DOI-backed download helpers. -This module keeps raw example data out of Git while allowing deterministic -local/CI setup via an on-demand DOI download cache. +This module keeps raw example assets out of Git while allowing notebooks and +tests to materialize the canonical nSTAT example dataset on demand. """ from __future__ import annotations -import hashlib import json import os import re import shutil import tempfile +import time +import urllib.request import zipfile -from dataclasses import dataclass -from datetime import UTC, datetime from pathlib import Path -from typing import Iterable +from typing import Final -import requests # type: ignore[import-untyped] -from requests.adapters import HTTPAdapter # type: ignore[import-untyped] -from urllib3.util.retry import Retry - -DOI_URL = "https://doi.org/10.6084/m9.figshare.4834640" -FIGSHARE_ARTICLE_FALLBACK = "4834640" -SENTINEL_FILENAME = ".nstat_data_ok.json" -EXPECTED_SUBDIRS = ("mEPSCs", "Explicit Stimulus", "PSTH", "Place Cells") - - -@dataclass(frozen=True) -class DownloadTarget: - url: str - filename: str +DOI_URL: Final[str] = "https://doi.org/10.6084/m9.figshare.4834640" +DEFAULT_RELATIVE_CACHE: Final[Path] = Path("data_cache") / "nstat_data" +SENTINEL_NAME: Final[str] = ".nstat_data_ok.json" +REQUIRED_SUBDIRS: Final[tuple[str, ...]] = ( + "Explicit Stimulus", + "Place Cells", + "mEPSCs", +) +DOWNLOAD_URL_RE: Final[re.Pattern[str]] = re.compile( + r"https?://(?:www\.)?figshare\.com/ndownloader/files/\d+" +) def _repo_root() -> Path: @@ -40,249 +36,153 @@ def _repo_root() -> Path: def get_data_dir() -> Path: - """Return the resolved example-data root. + """Return canonical on-disk example-data directory. Resolution order: 1. ``NSTAT_DATA_DIR`` environment variable. - 2. ``/data_cache/nstat_data``. + 2. ``/data_cache/nstat_data`` """ - env = os.environ.get("NSTAT_DATA_DIR") - if env: - return Path(env).expanduser().resolve() - return (_repo_root() / "data_cache" / "nstat_data").resolve() - - -def _sentinel_path(data_dir: Path) -> Path: - return data_dir / SENTINEL_FILENAME - - -def _expected_paths(data_dir: Path) -> list[Path]: - return [data_dir / name for name in EXPECTED_SUBDIRS] + explicit = os.environ.get("NSTAT_DATA_DIR") + if explicit: + return Path(explicit).expanduser().resolve() + return (_repo_root() / DEFAULT_RELATIVE_CACHE).resolve() def data_is_present(data_dir: Path) -> bool: - """Return True when data dir has expected structure + sentinel.""" + """Return True when the expected dataset footprint exists.""" if not data_dir.exists() or not data_dir.is_dir(): return False - if not _sentinel_path(data_dir).exists(): - return False - return all(path.exists() and path.is_dir() for path in _expected_paths(data_dir)) - - -def _build_session() -> requests.Session: - retry = Retry( - total=5, - backoff_factor=0.5, - status_forcelist=(429, 500, 502, 503, 504), - allowed_methods=("GET", "HEAD"), - raise_on_status=False, - ) - adapter = HTTPAdapter(max_retries=retry) - session = requests.Session() - session.mount("https://", adapter) - session.mount("http://", adapter) - session.headers.update({"User-Agent": "nSTAT-python-data-manager/1.0"}) - return session - - -def _sha256(path: Path) -> str: - digest = hashlib.sha256() - with path.open("rb") as f: - for chunk in iter(lambda: f.read(1024 * 1024), b""): - digest.update(chunk) - return digest.hexdigest() - - -def _extract_article_ids(url: str) -> list[str]: - ids = re.findall(r"/articles/(?:dataset|media)/[^/]+/(\d+)", url) - if not ids: - ids = re.findall(r"/(\d+)(?:[/?#]|$)", url) - unique: list[str] = [] - for raw in ids: - if raw not in unique: - unique.append(raw) - if FIGSHARE_ARTICLE_FALLBACK not in unique: - unique.append(FIGSHARE_ARTICLE_FALLBACK) - return unique + for subdir in REQUIRED_SUBDIRS: + if not (data_dir / subdir).exists(): + return False + return True -def _pick_download_target_from_article(session: requests.Session, article_id: str) -> DownloadTarget | None: - api = f"https://api.figshare.com/v2/articles/{article_id}" - resp = session.get(api, timeout=60) - if resp.status_code != 200: - return None - payload = resp.json() - files = payload.get("files", []) - if not isinstance(files, list) or not files: - return None - - def sort_key(item: dict) -> tuple[int, int]: - name = str(item.get("name", "")).lower() - size = int(item.get("size", 0) or 0) - zip_pref = 0 if name.endswith(".zip") else 1 - return (zip_pref, -size) - - ordered = sorted((f for f in files if isinstance(f, dict)), key=sort_key) - for item in ordered: - url = str(item.get("download_url", "")).strip() - name = str(item.get("name", "")).strip() or "figshare_data.zip" - if url: - return DownloadTarget(url=url, filename=name) - return None - - -def _resolve_download_target(session: requests.Session) -> DownloadTarget: - doi_resp = session.get(DOI_URL, allow_redirects=True, timeout=60) - doi_resp.raise_for_status() - final_url = doi_resp.url - - for article_id in _extract_article_ids(final_url): - target = _pick_download_target_from_article(session, article_id) - if target is not None: - return target - - html = doi_resp.text - links = re.findall(r"https://ndownloader\.figshare\.com/files/\d+", html) - if links: - url = links[0] - return DownloadTarget(url=url, filename=f"figshare_{FIGSHARE_ARTICLE_FALLBACK}.zip") - - raise RuntimeError(f"Could not resolve figshare download target from DOI redirect: {final_url}") - - -def _download_streaming(session: requests.Session, target: DownloadTarget, out_path: Path) -> None: - out_path.parent.mkdir(parents=True, exist_ok=True) - with session.get(target.url, stream=True, timeout=120) as resp: - resp.raise_for_status() - with out_path.open("wb") as f: - for chunk in resp.iter_content(chunk_size=1024 * 1024): - if chunk: - f.write(chunk) - - -def _contains_expected_structure(path: Path) -> bool: - return all((path / name).is_dir() for name in EXPECTED_SUBDIRS) - - -def _find_extracted_root(extract_dir: Path) -> Path: - """Find dataset root inside extracted archive. +def _write_sentinel(data_dir: Path, *, source_url: str) -> None: + payload = { + "doi": DOI_URL, + "source_url": source_url, + "timestamp_utc": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), + } + (data_dir / SENTINEL_NAME).write_text(json.dumps(payload, indent=2), encoding="utf-8") - Figshare archives sometimes wrap data as: - - / - - /data/ - - //data/ - """ - direct_candidates: list[Path] = [extract_dir] - if extract_dir.is_dir(): - direct_candidates.extend([p for p in extract_dir.iterdir() if p.is_dir() and p.name != "__MACOSX"]) +def _http_get(url: str, *, timeout: float = 60.0) -> tuple[str, bytes]: + req = urllib.request.Request( + url, + headers={ + "User-Agent": "nSTAT-python-data-manager/1.0 (+https://github.com/cajigaslab/nSTAT-python)" + }, + ) + with urllib.request.urlopen(req, timeout=timeout) as resp: + final_url = str(resp.geturl()) + body = resp.read() + return final_url, body + + +def _resolve_figshare_download_url() -> str: + final_url, body = _http_get(DOI_URL) + if DOWNLOAD_URL_RE.search(final_url): + return final_url + html = body.decode("utf-8", errors="ignore") + match = DOWNLOAD_URL_RE.search(html) + if match: + return match.group(0) + raise RuntimeError( + f"Could not resolve figshare download URL from DOI landing page: {DOI_URL}" + ) - for candidate in direct_candidates: - if _contains_expected_structure(candidate): - return candidate - nested_data = candidate / "data" - if _contains_expected_structure(nested_data): - return nested_data - for candidate in extract_dir.rglob("*"): - if not candidate.is_dir() or candidate.name == "__MACOSX": - continue - if _contains_expected_structure(candidate): +def _stream_download(url: str, destination: Path, *, retries: int = 3) -> None: + destination.parent.mkdir(parents=True, exist_ok=True) + last_error: Exception | None = None + for attempt in range(1, retries + 1): + try: + req = urllib.request.Request( + url, + headers={ + "User-Agent": "nSTAT-python-data-manager/1.0 (+https://github.com/cajigaslab/nSTAT-python)" + }, + ) + with urllib.request.urlopen(req, timeout=120.0) as resp, destination.open("wb") as out: + shutil.copyfileobj(resp, out, length=1024 * 1024) + return + except Exception as exc: # pragma: no cover - network timing dependent + last_error = exc + if attempt < retries: + time.sleep(1.5 * attempt) + raise RuntimeError(f"Failed to download dataset from {url}") from last_error + + +def _find_dataset_root(extracted_root: Path) -> Path: + if data_is_present(extracted_root): + return extracted_root + for candidate in extracted_root.rglob("*"): + if candidate.is_dir() and data_is_present(candidate): return candidate - nested_data = candidate / "data" - if _contains_expected_structure(nested_data): - return nested_data - - return extract_dir - - -def _ensure_expected_subdirs(data_dir: Path) -> None: - missing = [str(path) for path in _expected_paths(data_dir) if not path.exists()] - if missing: - raise RuntimeError( - "Downloaded archive does not contain expected nSTAT example-data structure. " - f"Missing: {', '.join(missing)}" - ) - - -def _write_sentinel(data_dir: Path, source_url: str, archive_sha256: str) -> None: - payload = { - "doi": DOI_URL, - "source_url": source_url, - "archive_sha256": archive_sha256, - "downloaded_at_utc": datetime.now(tz=UTC).isoformat(), - } - _sentinel_path(data_dir).write_text(json.dumps(payload, indent=2), encoding="utf-8") + raise RuntimeError( + "Downloaded archive did not contain expected nSTAT data folders: " + + ", ".join(REQUIRED_SUBDIRS) + ) -def _atomic_replace_dir(src_dir: Path, dst_dir: Path) -> None: - if dst_dir.exists(): - shutil.rmtree(dst_dir) - dst_dir.parent.mkdir(parents=True, exist_ok=True) - shutil.move(str(src_dir), str(dst_dir)) +def _atomic_replace_tree(source: Path, destination: Path) -> None: + destination.parent.mkdir(parents=True, exist_ok=True) + backup = destination.with_name(f"{destination.name}.bak") + if backup.exists(): + shutil.rmtree(backup) + if destination.exists(): + destination.rename(backup) + try: + source.rename(destination) + except Exception: + if destination.exists(): + shutil.rmtree(destination) + if backup.exists(): + backup.rename(destination) + raise + finally: + if backup.exists(): + shutil.rmtree(backup) def ensure_example_data(download: bool = True) -> Path: - """Ensure example data are available and return data root. - - Parameters - ---------- - download: - When ``True`` (default), download + extract from DOI if missing. - When ``False``, raise ``FileNotFoundError`` if data are absent. - """ + """Ensure the canonical example data exists locally and return its path.""" data_dir = get_data_dir() if data_is_present(data_dir): + if not (data_dir / SENTINEL_NAME).exists(): + _write_sentinel(data_dir, source_url="local-existing") return data_dir if not download: raise FileNotFoundError( - f"nSTAT example data not found at {data_dir}. " - "Set NSTAT_DATA_DIR to an existing dataset root or run with download=True." + f"Example data not found at {data_dir}. " + "Set NSTAT_DATA_DIR or call ensure_example_data(download=True)." ) - session = _build_session() - target = _resolve_download_target(session) - temp_parent = (_repo_root() / "output" / "data_download").resolve() - temp_parent.mkdir(parents=True, exist_ok=True) - - with tempfile.TemporaryDirectory(prefix="nstat_data_", dir=temp_parent) as tmp_raw: - tmp_root = Path(tmp_raw) - archive_path = tmp_root / target.filename - _download_streaming(session, target, archive_path) - - archive_sha = _sha256(archive_path) - try: - with zipfile.ZipFile(archive_path, "r") as zf: - bad_entry = zf.testzip() - if bad_entry is not None: - raise RuntimeError(f"Archive integrity check failed at member: {bad_entry}") - extract_dir = tmp_root / "extract" - extract_dir.mkdir(parents=True, exist_ok=True) - zf.extractall(extract_dir) - except zipfile.BadZipFile as exc: - raise RuntimeError(f"Downloaded file is not a valid zip archive: {archive_path}") from exc - - extracted_root = _find_extracted_root(tmp_root / "extract") - _ensure_expected_subdirs(extracted_root) - _write_sentinel(extracted_root, target.url, archive_sha) - _atomic_replace_dir(extracted_root, data_dir) - - if not data_is_present(data_dir): - raise RuntimeError(f"Example data validation failed after download at {data_dir}") - + # Download to a temp workspace first so partial failures do not pollute + # the final cache path. + download_tmp_root = (_repo_root() / "output" / "data_download").resolve() + download_tmp_root.mkdir(parents=True, exist_ok=True) + work_root = Path(tempfile.mkdtemp(prefix="nstat_data_", dir=str(download_tmp_root))) + try: + archive_path = work_root / "nstat_example_data.zip" + download_url = _resolve_figshare_download_url() + _stream_download(download_url, archive_path) + if not zipfile.is_zipfile(archive_path): + raise RuntimeError(f"Downloaded file is not a valid zip archive: {archive_path}") + extracted_root = work_root / "extracted" + extracted_root.mkdir(parents=True, exist_ok=True) + with zipfile.ZipFile(archive_path) as zf: + zf.extractall(extracted_root) + dataset_root = _find_dataset_root(extracted_root) + staged = work_root / "staged_data" + shutil.copytree(dataset_root, staged) + _atomic_replace_tree(staged, data_dir) + _write_sentinel(data_dir, source_url=download_url) + finally: + shutil.rmtree(work_root, ignore_errors=True) return data_dir - - -def iter_data_paths_from_matlab_line(matlab_line: str) -> Iterable[str]: - for match in re.finditer(r"['\"]([^'\"]*data/[^'\"]+)['\"]", matlab_line, flags=re.IGNORECASE): - raw = match.group(1) - marker = raw.lower().find("data/") - rel = raw[marker + len("data/") :] if marker >= 0 else raw - rel = rel.lstrip("./") - rel = rel.replace("\\", "/") - if rel: - yield rel diff --git a/src/nstat/datasets.py b/src/nstat/datasets.py deleted file mode 100644 index b69a5969..00000000 --- a/src/nstat/datasets.py +++ /dev/null @@ -1,176 +0,0 @@ -"""Dataset discovery and download helpers. - -Only example data may be shared with the MATLAB nSTAT repository. This module -keeps the policy explicit via checksummed manifests. -""" - -from __future__ import annotations - -import hashlib -import json -import os -import re -from dataclasses import dataclass -from pathlib import Path -from urllib.request import urlretrieve - - -@dataclass(slots=True) -class DatasetRecord: - name: str - version: str - url: str - sha256: str - filename: str - - -MIRROR_NAME_RE = re.compile(r"^matlab_gold_(\d{8})/(.+)$") - - -def _manifest_path() -> Path: - return Path(__file__).resolve().parents[2] / "data" / "datasets_manifest.json" - - -def _repo_data_root() -> Path: - return Path(__file__).resolve().parents[2] / "data" - - -def _local_mirror_roots() -> list[Path]: - """Return available local mirrored MATLAB dataset roots.""" - - shared_root = _repo_data_root() / "shared" - if not shared_root.exists(): - return [] - roots = [path for path in shared_root.glob("matlab_gold_*") if path.is_dir()] - roots.sort(key=lambda path: path.name, reverse=True) - return roots - - -def get_example_data_root() -> Path | None: - """Resolve preferred root for example datasets. - - Resolution order: - 1. ``NSTAT_DATA_ROOT`` environment variable (if set and exists). - 2. Latest local mirrored MATLAB dataset in ``data/shared``. - """ - - explicit = os.environ.get("NSTAT_DATA_ROOT") - if explicit: - root = Path(explicit).expanduser().resolve() - if root.exists() and root.is_dir(): - return root - - mirrors = _local_mirror_roots() - if mirrors: - return mirrors[0] - return None - - -def _load_manifest() -> list[DatasetRecord]: - data = json.loads(_manifest_path().read_text(encoding="utf-8")) - return [DatasetRecord(**row) for row in data["datasets"]] - - -def list_datasets() -> list[str]: - """Return available dataset names from manifest.""" - - return [row.name for row in _load_manifest()] - - -def list_matlab_gold_files(version: str | None = None) -> list[str]: - """List mirrored MATLAB files available in datasets manifest. - - Parameters - ---------- - version: - Optional mirror version label (for example ``"20260302"``). - When omitted, rows across all mirrored versions are returned. - """ - - files: list[str] = [] - for row in _load_manifest(): - match = MIRROR_NAME_RE.match(row.name) - if not match: - continue - row_version = match.group(1) - rel_path = match.group(2) - if version is None or version == row_version: - files.append(rel_path) - return sorted(set(files)) - - -def latest_matlab_gold_version() -> str | None: - """Return latest mirrored MATLAB version known by datasets manifest.""" - - versions: set[str] = set() - for row in _load_manifest(): - match = MIRROR_NAME_RE.match(row.name) - if match: - versions.add(match.group(1)) - if not versions: - return None - return sorted(versions)[-1] - - -def get_cache_dir() -> Path: - """Return dataset cache directory.""" - - root = Path(os.environ.get("NSTAT_DATA_CACHE", Path.home() / ".cache" / "nstat" / "data")) - root.mkdir(parents=True, exist_ok=True) - return root - - -def _sha256(path: Path) -> str: - h = hashlib.sha256() - with path.open("rb") as f: - for chunk in iter(lambda: f.read(1024 * 1024), b""): - h.update(chunk) - return h.hexdigest() - - -def fetch_dataset(name: str, version: str | None = None) -> Path: - """Download dataset artifact and verify checksum.""" - - rows = [r for r in _load_manifest() if r.name == name and (version is None or r.version == version)] - if not rows: - raise KeyError(f"dataset not found: {name} version={version!r}") - - record = sorted(rows, key=lambda r: r.version)[-1] - example_root = get_example_data_root() - if example_root is not None: - local_candidate = example_root / record.filename - if local_candidate.exists(): - digest = _sha256(local_candidate) - if digest == record.sha256: - return local_candidate - - out = get_cache_dir() / record.filename - out.parent.mkdir(parents=True, exist_ok=True) - - if not out.exists(): - urlretrieve(record.url, out) - - digest = _sha256(out) - if digest != record.sha256: - raise RuntimeError(f"checksum mismatch for {record.filename}: {digest} != {record.sha256}") - - return out - - -def fetch_matlab_gold_file(relative_path: str, version: str | None = None) -> Path: - """Fetch one file from mirrored MATLAB data via the datasets API. - - Parameters - ---------- - relative_path: - File path relative to MATLAB ``data/`` root, for example - ``"PlaceCellAnimal1Results.mat"``. - version: - Optional mirror version (default: latest available). - """ - - selected_version = version or latest_matlab_gold_version() - if selected_version is None: - raise KeyError("No mirrored MATLAB dataset version found in datasets manifest.") - name = f"matlab_gold_{selected_version}/{relative_path}" - return fetch_dataset(name=name, version=selected_version) diff --git a/src/nstat/decoding.py b/src/nstat/decoding.py deleted file mode 100644 index be615234..00000000 --- a/src/nstat/decoding.py +++ /dev/null @@ -1,375 +0,0 @@ -"""Decoding algorithms. - -This module provides foundational decoding utilities used in example -workflows. The initial implementation prioritizes numerical stability and -reproducibility over highly specialized optimizations. -""" - -from __future__ import annotations - -import numpy as np -from scipy.special import gammaln, logsumexp -from scipy.stats import norm - - -class DecodingAlgorithms: - """Collection of static decoding methods.""" - - @staticmethod - def compute_spike_rate_cis(spike_matrix: np.ndarray, alpha: float = 0.05) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - """Compute trial rates, pairwise p-values, and FDR-controlled differences. - - Parameters - ---------- - spike_matrix: - Binary/count matrix shaped `(n_trials, n_time_bins)`. - alpha: - Significance threshold for pairwise trial differences. - - Returns - ------- - spike_rate: - Trial-wise average event rate per bin. - prob_mat: - Pairwise two-sided p-value matrix. - sig_mat: - Binary significance matrix after Benjamini-Hochberg FDR control. - """ - - data = np.asarray(spike_matrix, dtype=float) - if data.ndim != 2: - raise ValueError("spike_matrix must be 2D") - if data.shape[1] < 2: - raise ValueError("spike_matrix must have at least two time bins") - if not (0.0 < alpha < 1.0): - raise ValueError("alpha must be in (0, 1)") - if np.any(data < 0.0): - raise ValueError("spike_matrix cannot contain negative counts") - - n_trials, n_bins = data.shape - counts = np.sum(data, axis=1) - rate = counts / float(n_bins) - - pvals = np.ones((n_trials, n_trials), dtype=float) - upper_idx: list[tuple[int, int]] = [] - upper_pvals: list[float] = [] - for i in range(n_trials): - for j in range(i + 1, n_trials): - p1 = rate[i] - p2 = rate[j] - pooled = (counts[i] + counts[j]) / (2.0 * n_bins) - se = np.sqrt(max(pooled * (1.0 - pooled) * (2.0 / n_bins), 0.0)) - if se <= 0.0: - p = 1.0 if np.isclose(p1, p2) else 0.0 - else: - z = (p1 - p2) / se - p = float(2.0 * (1.0 - norm.cdf(abs(z)))) - pvals[i, j] = p - pvals[j, i] = p - upper_idx.append((i, j)) - upper_pvals.append(p) - - sig = np.zeros((n_trials, n_trials), dtype=int) - if upper_pvals: - pvec = np.asarray(upper_pvals, dtype=float) - order = np.argsort(pvec) - sorted_p = pvec[order] - m = sorted_p.size - thresholds = alpha * (np.arange(1, m + 1) / m) - passing = np.where(sorted_p <= thresholds)[0] - if passing.size > 0: - cutoff = sorted_p[int(np.max(passing))] - selected = pvec <= cutoff - for is_sel, (i, j) in zip(selected, upper_idx, strict=False): - if is_sel: - sig[i, j] = 1 - sig[j, i] = 1 - - np.fill_diagonal(pvals, 1.0) - np.fill_diagonal(sig, 0) - return rate, pvals, sig - - @staticmethod - def decode_weighted_center(spike_counts: np.ndarray, tuning_curves: np.ndarray) -> np.ndarray: - """Decode latent state via weighted center-of-mass estimator. - - Parameters - ---------- - spike_counts: - Shape `(n_units, n_time)`. - tuning_curves: - Shape `(n_units, n_states)`. - """ - - counts = np.asarray(spike_counts, dtype=float) - tuning = np.asarray(tuning_curves, dtype=float) - if counts.ndim != 2 or tuning.ndim != 2: - raise ValueError("spike_counts and tuning_curves must be 2D") - if counts.shape[0] != tuning.shape[0]: - raise ValueError("unit count must match between counts and tuning curves") - - state_axis = np.arange(tuning.shape[1], dtype=float) - decoded = np.zeros(counts.shape[1], dtype=float) - eps = 1e-12 - for t in range(counts.shape[1]): - weights = counts[:, t][:, None] * tuning - post = np.sum(weights, axis=0) - post = post / (np.sum(post) + eps) - decoded[t] = float(np.sum(post * state_axis)) - return decoded - - @staticmethod - def decode_state_posterior( - spike_counts: np.ndarray, - tuning_rates: np.ndarray, - transition: np.ndarray | None = None, - prior: np.ndarray | None = None, - ) -> tuple[np.ndarray, np.ndarray]: - """Decode discrete latent state by point-process Bayes filtering. - - Parameters - ---------- - spike_counts: - Non-negative count matrix with shape ``(n_units, n_time)``. - tuning_rates: - Expected spike counts per bin with shape ``(n_units, n_states)``. - transition: - Optional Markov transition matrix ``(n_states, n_states)`` where - columns index next-state probabilities. - prior: - Optional initial state prior. Defaults to a uniform distribution. - """ - - counts = np.asarray(spike_counts, dtype=float) - rates = np.asarray(tuning_rates, dtype=float) - if counts.ndim != 2 or rates.ndim != 2: - raise ValueError("spike_counts and tuning_rates must be 2D") - if counts.shape[0] != rates.shape[0]: - raise ValueError("unit dimension mismatch between spike_counts and tuning_rates") - if np.any(counts < 0.0): - raise ValueError("spike_counts must be non-negative") - if np.any(rates <= 0.0): - raise ValueError("tuning_rates must be strictly positive") - - n_states = rates.shape[1] - n_time = counts.shape[1] - if prior is None: - prior_vec = np.full(n_states, 1.0 / n_states, dtype=float) - else: - prior_vec = np.asarray(prior, dtype=float) - if prior_vec.shape != (n_states,): - raise ValueError("prior shape mismatch") - if np.any(prior_vec < 0.0): - raise ValueError("prior cannot contain negative values") - prior_sum = np.sum(prior_vec) - if prior_sum <= 0.0: - raise ValueError("prior must have positive mass") - prior_vec = prior_vec / prior_sum - - if transition is not None: - transition_mat = np.asarray(transition, dtype=float) - if transition_mat.shape != (n_states, n_states): - raise ValueError("transition shape mismatch") - if np.any(transition_mat < 0.0): - raise ValueError("transition cannot contain negative values") - col_sums = np.sum(transition_mat, axis=1, keepdims=True) - if np.any(col_sums <= 0.0): - raise ValueError("each transition row must have positive mass") - transition_mat = transition_mat / col_sums - log_transition = np.log(np.clip(transition_mat, 1e-12, 1.0)) - else: - log_transition = None - - rates3 = rates[:, :, None] - counts3 = counts[:, None, :] - log_emit = np.sum( - counts3 * np.log(rates3) - rates3 - gammaln(counts3 + 1.0), - axis=0, - ) - log_prior = np.log(np.clip(prior_vec, 1e-12, 1.0)) - - log_post = np.zeros((n_states, n_time), dtype=float) - log_post[:, 0] = log_prior + log_emit[:, 0] - log_post[:, 0] -= logsumexp(log_post[:, 0]) - - for t in range(1, n_time): - if log_transition is None: - pred = log_post[:, t - 1] - else: - pred = np.array( - [ - logsumexp(log_post[:, t - 1] + log_transition[:, s_next]) - for s_next in range(n_states) - ], - dtype=float, - ) - log_post[:, t] = pred + log_emit[:, t] - log_post[:, t] -= logsumexp(log_post[:, t]) - - posterior = np.exp(log_post) - decoded_state = np.argmax(posterior, axis=0).astype(int) - return decoded_state, posterior - - @staticmethod - def compute_spike_rate_diff_cis( - spike_matrix_a: np.ndarray, spike_matrix_b: np.ndarray, alpha: float = 0.05 - ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - """Compute trial-wise rate differences and Wald-style confidence intervals. - - Parameters - ---------- - spike_matrix_a: - First trial matrix, shape `(n_trials, n_time_bins)`. - spike_matrix_b: - Second trial matrix, shape `(n_trials, n_time_bins)`. - alpha: - Two-sided confidence level parameter. - """ - - a = np.asarray(spike_matrix_a, dtype=float) - b = np.asarray(spike_matrix_b, dtype=float) - if a.shape != b.shape: - raise ValueError("spike_matrix_a and spike_matrix_b must have matching shape") - if a.ndim != 2: - raise ValueError("inputs must be 2D trial matrices") - if np.any(a < 0.0) or np.any(b < 0.0): - raise ValueError("spike matrices cannot contain negative counts") - if not (0.0 < alpha < 1.0): - raise ValueError("alpha must be in (0, 1)") - - n_bins = float(a.shape[1]) - rate_a = np.sum(a, axis=1) / n_bins - rate_b = np.sum(b, axis=1) / n_bins - diff = rate_a - rate_b - - var = np.clip((rate_a * (1.0 - rate_a) + rate_b * (1.0 - rate_b)) / n_bins, 1e-12, None) - z = float(norm.ppf(1.0 - alpha / 2.0)) - half = z * np.sqrt(var) - lo = diff - half - hi = diff + half - return diff, lo, hi - - @staticmethod - def compute_stimulus_cis( - posterior: np.ndarray, state_values: np.ndarray, alpha: float = 0.05 - ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - """Approximate posterior mean and confidence intervals of a decoded stimulus.""" - - post = np.asarray(posterior, dtype=float) - values = np.asarray(state_values, dtype=float) - if post.ndim != 2: - raise ValueError("posterior must be 2D (n_states, n_time)") - if values.ndim != 1 or values.size != post.shape[0]: - raise ValueError("state_values must match number of states") - if not (0.0 < alpha < 1.0): - raise ValueError("alpha must be in (0, 1)") - - normed = np.clip(post, 1e-15, None) - normed = normed / np.sum(normed, axis=0, keepdims=True) - - mean = values @ normed - centered = values[:, None] - mean[None, :] - var = np.sum((centered**2) * normed, axis=0) - z = float(norm.ppf(1.0 - alpha / 2.0)) - half = z * np.sqrt(np.clip(var, 0.0, None)) - return mean, mean - half, mean + half - - @staticmethod - def kalman_predict( - x_prev: np.ndarray, p_prev: np.ndarray, a: np.ndarray, q: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - """Linear-Gaussian Kalman prediction step.""" - - x_prev = np.asarray(x_prev, dtype=float) - p_prev = np.asarray(p_prev, dtype=float) - a = np.asarray(a, dtype=float) - q = np.asarray(q, dtype=float) - x_pred = a @ x_prev - p_pred = a @ p_prev @ a.T + q - return x_pred, p_pred - - @staticmethod - def kalman_update( - x_pred: np.ndarray, - p_pred: np.ndarray, - y_t: np.ndarray, - h: np.ndarray, - r: np.ndarray, - ) -> tuple[np.ndarray, np.ndarray]: - """Linear-Gaussian Kalman update step.""" - - x_pred = np.asarray(x_pred, dtype=float) - p_pred = np.asarray(p_pred, dtype=float) - y_t = np.asarray(y_t, dtype=float) - h = np.asarray(h, dtype=float) - r = np.asarray(r, dtype=float) - - innov = y_t - (h @ x_pred) - s = h @ p_pred @ h.T + r - k = p_pred @ h.T @ np.linalg.inv(s) - x_filt = x_pred + k @ innov - p_filt = p_pred - k @ h @ p_pred - return x_filt, p_filt - - @staticmethod - def kalman_filter( - y: np.ndarray, - a: np.ndarray, - h: np.ndarray, - q: np.ndarray, - r: np.ndarray, - x0: np.ndarray, - p0: np.ndarray, - ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: - """Run Kalman filtering over all time points.""" - - y = np.asarray(y, dtype=float) - if y.ndim == 1: - y = y[:, None] - n_time = y.shape[0] - n_state = np.asarray(x0).size - - xf = np.zeros((n_time, n_state), dtype=float) - pf = np.zeros((n_time, n_state, n_state), dtype=float) - xp = np.zeros((n_time, n_state), dtype=float) - pp = np.zeros((n_time, n_state, n_state), dtype=float) - - x_prev = np.asarray(x0, dtype=float) - p_prev = np.asarray(p0, dtype=float) - for t in range(n_time): - x_pred, p_pred = DecodingAlgorithms.kalman_predict(x_prev=x_prev, p_prev=p_prev, a=a, q=q) - x_filt, p_filt = DecodingAlgorithms.kalman_update( - x_pred=x_pred, p_pred=p_pred, y_t=y[t], h=h, r=r - ) - xp[t] = x_pred - pp[t] = p_pred - xf[t] = x_filt - pf[t] = p_filt - x_prev, p_prev = x_filt, p_filt - - return xf, pf, xp, pp - - @staticmethod - def kalman_fixed_interval_smoother( - xf: np.ndarray, pf: np.ndarray, xp: np.ndarray, pp: np.ndarray, a: np.ndarray - ) -> tuple[np.ndarray, np.ndarray]: - """Rauch-Tung-Striebel fixed-interval smoother.""" - - xf = np.asarray(xf, dtype=float) - pf = np.asarray(pf, dtype=float) - xp = np.asarray(xp, dtype=float) - pp = np.asarray(pp, dtype=float) - a = np.asarray(a, dtype=float) - - n_time, n_state = xf.shape - xs = np.zeros_like(xf) - ps = np.zeros_like(pf) - xs[-1] = xf[-1] - ps[-1] = pf[-1] - - for t in range(n_time - 2, -1, -1): - c = pf[t] @ a.T @ np.linalg.inv(pp[t + 1]) - xs[t] = xf[t] + c @ (xs[t + 1] - xp[t + 1]) - ps[t] = pf[t] + c @ (ps[t + 1] - pp[t + 1]) @ c.T - - return xs, ps diff --git a/src/nstat/events.py b/src/nstat/events.py deleted file mode 100644 index c187f559..00000000 --- a/src/nstat/events.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Event marker utilities.""" - -from __future__ import annotations - -from dataclasses import dataclass, field - -import numpy as np - - -@dataclass(slots=True) -class Events: - """Discrete event times with labels. - - Parameters - ---------- - times: - Event times in seconds. - labels: - Optional event labels; defaults to empty strings. - """ - - times: np.ndarray - labels: list[str] = field(default_factory=list) - - def __post_init__(self) -> None: - self.times = np.asarray(self.times, dtype=float) - if self.times.ndim != 1: - raise ValueError("times must be 1D") - if np.any(np.diff(self.times) < 0.0): - raise ValueError("times must be non-decreasing") - - if not self.labels: - self.labels = ["" for _ in range(self.times.size)] - if len(self.labels) != self.times.size: - raise ValueError("labels length must equal number of events") - - def subset(self, start_s: float, end_s: float) -> "Events": - """Return events within inclusive time interval.""" - - mask = (self.times >= start_s) & (self.times <= end_s) - return Events(times=self.times[mask], labels=[self.labels[i] for i in np.where(mask)[0]]) diff --git a/src/nstat/fit.py b/src/nstat/fit.py deleted file mode 100644 index 62adc13f..00000000 --- a/src/nstat/fit.py +++ /dev/null @@ -1,454 +0,0 @@ -"""Fit result and summary objects.""" - -from __future__ import annotations - -from dataclasses import dataclass, field -from typing import Any, cast - -import numpy as np - -from .cif import CIFModel - - -@dataclass(slots=True) -class FitResult: - """Result container for one fitted model.""" - - coefficients: np.ndarray - intercept: float - fit_type: str - log_likelihood: float - n_samples: int - n_parameters: int - parameter_labels: list[str] = field(default_factory=list) - ks_stats: dict[str, np.ndarray | float] = field(default_factory=dict) - fit_residual: np.ndarray | None = None - inv_gaus_stats: dict[str, np.ndarray | float] = field(default_factory=dict) - neuron_name: str = "" - plot_params: dict[str, Any] = field(default_factory=dict) - xval_data: list[np.ndarray] = field(default_factory=list) - xval_time: list[np.ndarray] = field(default_factory=list) - - def as_cif_model(self) -> CIFModel: - """Return a :class:`nstat.cif.CIFModel` view of this fitted model.""" - - return CIFModel(coefficients=self.coefficients.copy(), intercept=self.intercept, link=self.fit_type) - - def predict(self, X: np.ndarray) -> np.ndarray: - """Predict mean response from feature matrix ``X``.""" - - return self.as_cif_model().evaluate(X) - - def aic(self) -> float: - """Akaike information criterion.""" - - return float(2 * self.n_parameters - 2 * self.log_likelihood) - - def bic(self) -> float: - """Bayesian information criterion.""" - - return float(np.log(max(self.n_samples, 1)) * self.n_parameters - 2 * self.log_likelihood) - - def compute_val_lambda(self, X: np.ndarray) -> np.ndarray: - """MATLAB-style alias for evaluating predicted intensity/probability.""" - - return self.predict(X) - - def get_coeffs(self) -> np.ndarray: - """Return non-intercept coefficients.""" - - return self.coefficients.copy() - - def get_coeff_index(self, label: str) -> int: - """Return index of a parameter label.""" - - if not self.parameter_labels: - raise ValueError("parameter_labels are not populated") - try: - return self.parameter_labels.index(label) - except ValueError as exc: - raise KeyError(f"label '{label}' not present") from exc - - def get_param(self, key: str) -> float | np.ndarray | str | int: - """Access a parameter/statistic by canonical key.""" - - lookup: dict[str, float | np.ndarray | str | int] = { - "intercept": self.intercept, - "coefficients": self.coefficients.copy(), - "fit_type": self.fit_type, - "log_likelihood": self.log_likelihood, - "n_samples": self.n_samples, - "n_parameters": self.n_parameters, - "aic": self.aic(), - "bic": self.bic(), - } - if key not in lookup: - raise KeyError(f"unknown key: {key}") - return lookup[key] - - def get_unique_labels(self) -> list[str]: - """Return unique parameter labels preserving order.""" - - seen: set[str] = set() - ordered: list[str] = [] - for label in self.parameter_labels: - if label in seen: - continue - seen.add(label) - ordered.append(label) - return ordered - - def set_ks_stats( - self, - ks_stat: np.ndarray | float | dict[str, Any], - p_value: np.ndarray | float | None = None, - within_conf_int: np.ndarray | float | None = None, - ) -> None: - """Store KS statistics in MATLAB-compatible key layout.""" - - if isinstance(ks_stat, dict): - payload = dict(ks_stat) - self.ks_stats = { - "ks_stat": np.asarray(payload.get("ks_stat", payload.get("ksStat", [])), dtype=float), - "pValue": np.asarray(payload.get("pValue", payload.get("p_value", [])), dtype=float), - "withinConfInt": np.asarray( - payload.get("withinConfInt", payload.get("within_conf_int", [])), - dtype=float, - ), - } - return - - self.ks_stats = { - "ks_stat": np.asarray(ks_stat, dtype=float), - "pValue": np.asarray([] if p_value is None else p_value, dtype=float), - "withinConfInt": np.asarray([] if within_conf_int is None else within_conf_int, dtype=float), - } - - def set_fit_residual(self, residual: np.ndarray) -> None: - """Attach residual vector used by MATLAB diagnostics.""" - - self.fit_residual = np.asarray(residual, dtype=float).reshape(-1) - - def set_inv_gaus_stats(self, payload: dict[str, Any]) -> None: - """Attach inverse-Gaussian transform stats if available.""" - - self.inv_gaus_stats = { - str(key): np.asarray(value, dtype=float) for key, value in payload.items() - } - - def set_neuron_name(self, name: str) -> None: - """Assign a stable neuron identifier.""" - - self.neuron_name = str(name) - - def map_cov_labels_to_unique_labels(self) -> list[str]: - """Return unique covariate labels for MATLAB parity call sites.""" - - return self.get_unique_labels() - - def compute_plot_params(self) -> dict[str, Any]: - """Compute MATLAB-style coefficient plotting payload.""" - - labels = self.parameter_labels or [f"coef_{i+1}" for i in range(self.coefficients.size)] - b_act = np.asarray(self.coefficients, dtype=float).reshape(-1, 1) - se_act = np.zeros_like(b_act) - sig_index = (np.abs(b_act) > 0.0).astype(float) - payload: dict[str, Any] = { - "bAct": b_act, - "seAct": se_act, - "sigIndex": sig_index, - "xLabels": list(labels), - "numResultsCoeffPresent": np.ones(b_act.shape[0], dtype=float), - } - self.plot_params = payload - return payload - - def get_plot_params(self) -> dict[str, Any]: - """Return cached plot parameters, computing if necessary.""" - - if not self.plot_params: - return self.compute_plot_params() - return { - key: (value.copy() if isinstance(value, np.ndarray) else value) - for key, value in self.plot_params.items() - } - - def add_params_to_fit(self, payload: dict[str, Any]) -> None: - """Update optional FitResult metadata in-place.""" - - if "ks_stats" in payload: - self.set_ks_stats(cast(dict[str, Any], payload["ks_stats"])) - if "fit_residual" in payload: - self.set_fit_residual(np.asarray(payload["fit_residual"], dtype=float)) - if "inv_gaus_stats" in payload: - self.set_inv_gaus_stats(cast(dict[str, Any], payload["inv_gaus_stats"])) - if "neuron_name" in payload: - self.set_neuron_name(str(payload["neuron_name"])) - if "plot_params" in payload: - source = cast(dict[str, Any], payload["plot_params"]) - normalized: dict[str, Any] = {} - for key, value in source.items(): - if key == "xLabels": - normalized[str(key)] = [str(v) for v in value] - elif isinstance(value, np.ndarray): - normalized[str(key)] = np.asarray(value, dtype=float) - elif isinstance(value, (list, tuple)): - try: - normalized[str(key)] = np.asarray(value, dtype=float) - except (TypeError, ValueError): - normalized[str(key)] = [str(v) for v in value] - else: - normalized[str(key)] = value - self.plot_params = { - str(key): value for key, value in normalized.items() - } - if "xval_data" in payload: - rows = cast(list[Any], payload["xval_data"]) - self.xval_data = [np.asarray(row, dtype=float) for row in rows] - if "xval_time" in payload: - rows = cast(list[Any], payload["xval_time"]) - self.xval_time = [np.asarray(row, dtype=float) for row in rows] - - def to_structure(self) -> dict[str, Any]: - """Serialize this fit result to a MATLAB-like plain structure.""" - - return { - "coefficients": self.coefficients.copy(), - "intercept": float(self.intercept), - "fit_type": str(self.fit_type), - "log_likelihood": float(self.log_likelihood), - "n_samples": int(self.n_samples), - "n_parameters": int(self.n_parameters), - "parameter_labels": list(self.parameter_labels), - "ks_stats": { - key: np.asarray(value, dtype=float).copy() - for key, value in self.ks_stats.items() - }, - "fit_residual": ( - None if self.fit_residual is None else np.asarray(self.fit_residual, dtype=float).copy() - ), - "inv_gaus_stats": { - key: np.asarray(value, dtype=float).copy() - for key, value in self.inv_gaus_stats.items() - }, - "neuron_name": str(self.neuron_name), - "plot_params": { - key: (value.copy() if isinstance(value, np.ndarray) else value) - for key, value in self.get_plot_params().items() - }, - "xval_data": [np.asarray(row, dtype=float).copy() for row in self.xval_data], - "xval_time": [np.asarray(row, dtype=float).copy() for row in self.xval_time], - } - - @classmethod - def from_structure(cls, payload: dict[str, Any]) -> "FitResult": - """Build a :class:`FitResult` from a serialized structure.""" - - return cls( - coefficients=np.asarray(payload["coefficients"], dtype=float).reshape(-1), - intercept=float(payload["intercept"]), - fit_type=str(payload["fit_type"]), - log_likelihood=float(payload["log_likelihood"]), - n_samples=int(payload["n_samples"]), - n_parameters=int(payload["n_parameters"]), - parameter_labels=[str(v) for v in payload.get("parameter_labels", [])], - ks_stats={ - str(key): np.asarray(value, dtype=float) - for key, value in cast(dict[str, Any], payload.get("ks_stats", {})).items() - }, - fit_residual=( - None - if payload.get("fit_residual", None) is None - else np.asarray(payload["fit_residual"], dtype=float).reshape(-1) - ), - inv_gaus_stats={ - str(key): np.asarray(value, dtype=float) - for key, value in cast(dict[str, Any], payload.get("inv_gaus_stats", {})).items() - }, - neuron_name=str(payload.get("neuron_name", "")), - plot_params=cls._coerce_plot_params(cast(dict[str, Any], payload.get("plot_params", {}))), - xval_data=[np.asarray(row, dtype=float) for row in cast(list[Any], payload.get("xval_data", []))], - xval_time=[np.asarray(row, dtype=float) for row in cast(list[Any], payload.get("xval_time", []))], - ) - - @staticmethod - def _coerce_plot_params(source: dict[str, Any]) -> dict[str, Any]: - normalized: dict[str, Any] = {} - for key, value in source.items(): - if key == "xLabels": - normalized[str(key)] = [str(v) for v in value] - elif isinstance(value, np.ndarray): - normalized[str(key)] = np.asarray(value, dtype=float) - elif isinstance(value, (list, tuple)): - try: - normalized[str(key)] = np.asarray(value, dtype=float) - except (TypeError, ValueError): - normalized[str(key)] = [str(v) for v in value] - else: - normalized[str(key)] = value - return normalized - - @staticmethod - def cell_array_to_structure(results: list["FitResult"]) -> list[dict[str, Any]]: - """Serialize a list of fit results into structure list form.""" - - return [result.to_structure() for result in results] - - -@dataclass(slots=True) -class FitSummary: - """Summary statistics across multiple fitted models.""" - - results: list[FitResult] - - def __post_init__(self) -> None: - if not self.results: - raise ValueError("FitSummary requires at least one FitResult") - - def best_by_aic(self) -> FitResult: - return min(self.results, key=lambda r: r.aic()) - - def best_by_bic(self) -> FitResult: - return min(self.results, key=lambda r: r.bic()) - - def get_diff_aic(self) -> np.ndarray: - """Return AIC differences relative to best model.""" - - aic = np.array([result.aic() for result in self.results], dtype=float) - return aic - np.min(aic) - - def get_diff_bic(self) -> np.ndarray: - """Return BIC differences relative to best model.""" - - bic = np.array([result.bic() for result in self.results], dtype=float) - return bic - np.min(bic) - - def get_diff_log_likelihood(self) -> np.ndarray: - """Return log-likelihood differences relative to best model.""" - - ll = np.array([result.log_likelihood for result in self.results], dtype=float) - return np.max(ll) - ll - - def compute_diff_mat(self, metric: str = "aic") -> np.ndarray: - """Compute pairwise absolute difference matrix for selected metric.""" - - metric_map = { - "aic": np.array([result.aic() for result in self.results], dtype=float), - "bic": np.array([result.bic() for result in self.results], dtype=float), - "log_likelihood": np.array([result.log_likelihood for result in self.results], dtype=float), - } - if metric not in metric_map: - raise ValueError("metric must be one of {'aic', 'bic', 'log_likelihood'}") - values = metric_map[metric] - return np.abs(values[:, None] - values[None, :]) - - def get_unique_labels(self) -> list[str]: - """Return union of parameter labels across all fit results.""" - - labels: list[str] = [] - seen: set[str] = set() - for result in self.results: - source = result.parameter_labels or [f"coef_{i+1}" for i in range(result.coefficients.size)] - for label in source: - if label in seen: - continue - seen.add(label) - labels.append(label) - return labels - - def get_coeffs(self, fit_num: int = 1) -> tuple[np.ndarray, list[str], np.ndarray]: - """Return coefficient and SE matrices aligned by unique labels.""" - - _ = fit_num # Compatibility placeholder: fit index semantics are MATLAB-specific. - labels = self.get_unique_labels() - label_to_idx = {label: idx for idx, label in enumerate(labels)} - coeff_mat = np.full((len(labels), len(self.results)), np.nan, dtype=float) - se_mat = np.full_like(coeff_mat, np.nan) - - for col, result in enumerate(self.results): - source_labels = result.parameter_labels or [f"coef_{i+1}" for i in range(result.coefficients.size)] - for coeff, label in zip(result.coefficients, source_labels): - row = label_to_idx[label] - coeff_mat[row, col] = float(coeff) - # Standard errors are not stored in the simplified Python FitResult. - se_mat[row, col] = 0.0 - - return coeff_mat, labels, se_mat - - def get_coeff_index(self, fit_num: int = 1, sort_by_epoch: bool = False) -> tuple[np.ndarray, np.ndarray, int]: - """Return coefficient row indices and epoch metadata for a fit index.""" - - _ = sort_by_epoch # Compatibility placeholder. - coeff_mat, _labels, _se_mat = self.get_coeffs(fit_num=fit_num) - col = max(0, min(len(self.results) - 1, int(fit_num) - 1)) - idx = np.where(np.isfinite(coeff_mat[:, col]))[0].astype(int) - epoch_id = np.ones(idx.shape[0], dtype=int) - num_epochs = 1 - return idx, epoch_id, num_epochs - - def bin_coeffs( - self, - min_val: float, - max_val: float, - bin_size: float = 0.1, - ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - """Histogram coefficients and estimate percent-significant per bin.""" - - if bin_size <= 0: - raise ValueError("bin_size must be > 0") - - coeff_mat, _labels, _se = self.get_coeffs() - values = coeff_mat[np.isfinite(coeff_mat)] - if values.size == 0: - edges = np.arange(min_val, max_val + bin_size, bin_size, dtype=float) - return np.zeros(edges.size - 1, dtype=int), edges, np.zeros(edges.size - 1, dtype=float) - - edges = np.arange(min_val, max_val + bin_size, bin_size, dtype=float) - counts, edges = np.histogram(values, bins=edges) - percent_sig = np.zeros(counts.size, dtype=float) - for i in range(counts.size): - in_bin = (values >= edges[i]) & (values < edges[i + 1]) - if i == counts.size - 1: - in_bin = (values >= edges[i]) & (values <= edges[i + 1]) - if not np.any(in_bin): - percent_sig[i] = 0.0 - else: - percent_sig[i] = float(np.mean(np.abs(values[in_bin]) > 0.0)) - - return counts.astype(int), edges.astype(float), percent_sig - - def box_plot( - self, - X: np.ndarray | None = None, - diff_index: int = 1, - ) -> dict[str, np.ndarray]: - """Return box-plot summary statistics for compatibility workflows.""" - - if X is None: - data = self.get_diff_aic() - else: - data = np.asarray(X, dtype=float) - if data.ndim == 1: - data = data[:, None] - - _ = diff_index # MATLAB API compatibility placeholder. - q1 = np.nanpercentile(data, 25, axis=0) - median = np.nanpercentile(data, 50, axis=0) - q3 = np.nanpercentile(data, 75, axis=0) - return { - "q1": q1.astype(float), - "median": median.astype(float), - "q3": q3.astype(float), - } - - def to_structure(self) -> dict[str, Any]: - """Serialize summary and nested fit results into plain structures.""" - - return {"results": [result.to_structure() for result in self.results]} - - @classmethod - def from_structure(cls, payload: dict[str, Any]) -> "FitSummary": - """Deserialize a summary from structure form.""" - - rows = payload.get("results", payload.get("fitResCell", [])) - return cls(results=[FitResult.from_structure(cast(dict[str, Any], row)) for row in rows]) diff --git a/src/nstat/history.py b/src/nstat/history.py deleted file mode 100644 index 45d33a39..00000000 --- a/src/nstat/history.py +++ /dev/null @@ -1,68 +0,0 @@ -"""Spike-history basis construction. - -The basis matrix approximates the effect of past spikes on current intensity. -""" - -from __future__ import annotations - -from dataclasses import dataclass - -import numpy as np - - -@dataclass(slots=True) -class HistoryBasis: - """Piecewise-constant history basis. - - Parameters - ---------- - bin_edges_s: - Increasing edges (seconds) defining history windows. - Example: [0.0, 0.01, 0.05, 0.1]. - """ - - bin_edges_s: np.ndarray - - def __post_init__(self) -> None: - self.bin_edges_s = np.asarray(self.bin_edges_s, dtype=float) - if self.bin_edges_s.ndim != 1 or self.bin_edges_s.size < 2: - raise ValueError("bin_edges_s must be 1D with at least two elements") - if np.any(np.diff(self.bin_edges_s) <= 0.0): - raise ValueError("bin_edges_s must be strictly increasing") - - @property - def n_bins(self) -> int: - return int(self.bin_edges_s.size - 1) - - def design_matrix(self, spike_times_s: np.ndarray, time_grid_s: np.ndarray) -> np.ndarray: - """Build history design matrix for a binned point-process model. - - Notes - ----- - For each time point and basis window, the entry counts spikes in - the lag interval `(t - edge_hi, t - edge_lo]`. This mirrors common - GLM history encoding while remaining explicit and testable. - """ - - spike_times_s = np.asarray(spike_times_s, dtype=float) - time_grid_s = np.asarray(time_grid_s, dtype=float) - if spike_times_s.ndim != 1: - spike_times_s = spike_times_s.reshape(-1) - if time_grid_s.ndim != 1: - time_grid_s = time_grid_s.reshape(-1) - spike_times_s = np.sort(spike_times_s) - - mat = np.zeros((time_grid_s.size, self.n_bins), dtype=float) - if spike_times_s.size == 0 or time_grid_s.size == 0: - return mat - - # Equivalent to counting lags in (lo, hi], i.e., spikes in [t-hi, t-lo). - for j in range(self.n_bins): - lo = float(self.bin_edges_s[j]) - hi = float(self.bin_edges_s[j + 1]) - lower = time_grid_s - hi - upper = time_grid_s - lo - lo_idx = np.searchsorted(spike_times_s, lower, side="left") - hi_idx = np.searchsorted(spike_times_s, upper, side="left") - mat[:, j] = (hi_idx - lo_idx).astype(float) - return mat diff --git a/src/nstat/install.py b/src/nstat/install.py deleted file mode 100644 index cc844a58..00000000 --- a/src/nstat/install.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Installation helpers for nSTAT-python. - -`nstat_install` is a Python-side setup helper that prepares a local data cache -and returns deterministic setup metadata. This function is intentionally -MATLAB-free and serves as the recommended post-install check used in docs. -""" - -from __future__ import annotations - -import argparse -import os -import sys -from dataclasses import dataclass -from pathlib import Path - -from .datasets import get_cache_dir - - -@dataclass(frozen=True, slots=True) -class InstallReport: - """Structured output from :func:`nstat_install`.""" - - cache_dir: Path - python_version: str - package: str = "nstat" - - - -def nstat_install(cache_dir: str | Path | None = None) -> InstallReport: - """Run lightweight post-install setup for nSTAT-python. - - Parameters - ---------- - cache_dir: - Optional custom data-cache location. - - Returns - ------- - InstallReport - Report containing resolved cache directory and runtime metadata. - """ - - if cache_dir is not None: - cache_path = Path(cache_dir) - cache_path.mkdir(parents=True, exist_ok=True) - os.environ["NSTAT_DATA_CACHE"] = str(cache_path) - - resolved_cache = get_cache_dir() - report = InstallReport( - cache_dir=resolved_cache, - python_version=f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", - ) - return report - - - -def main() -> int: - parser = argparse.ArgumentParser(description="Run nSTAT-python post-install setup.") - parser.add_argument( - "--cache-dir", - default=None, - help="Optional custom data cache directory.", - ) - args = parser.parse_args() - - report = nstat_install(cache_dir=args.cache_dir) - print(f"nSTAT-python setup complete. Cache directory: {report.cache_dir}") - print(f"Python runtime: {report.python_version}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/src/nstat/notebook_figures.py b/src/nstat/notebook_figures.py index 4ac6e178..8dbbd81b 100644 --- a/src/nstat/notebook_figures.py +++ b/src/nstat/notebook_figures.py @@ -1,206 +1,125 @@ -"""Utilities for deterministic notebook figure tracking and ordinal saves. - -This module is used by generated helpfile notebooks to enforce one-to-one -figure-count parity relative to MATLAB helpfiles. -""" +"""Utilities for deterministic figure creation in generated help notebooks.""" from __future__ import annotations -import json -import shutil -from dataclasses import dataclass +from dataclasses import dataclass, field from pathlib import Path +import shutil import matplotlib.pyplot as plt -import numpy as np from matplotlib.figure import Figure @dataclass(slots=True) -class FigureRecord: - ordinal: int - section_index: int - matlab_line_number: int - matlab_snippet: str - path: Path - - class FigureTracker: - """Track notebook figure creation/saving with strict ordinals.""" - - def __init__( - self, - *, - topic: str, - expected_count: int, - output_root: str | Path | None = None, - default_figsize: tuple[float, float] = (7.0, 5.0), - dpi: int = 180, - ) -> None: - self.topic = str(topic) - self.expected_count = int(expected_count) - if output_root is None: - cwd = Path.cwd().resolve() - repo_root = None - for candidate in (cwd, *cwd.parents): - if (candidate / "pyproject.toml").exists(): - repo_root = candidate - break - if repo_root is None: - repo_root = cwd - self.output_root = repo_root / "output" / "notebook_images" + """Track/snapshot figure creation order for strict ordinal parity checks.""" + + topic: str + output_root: Path + expected_count: int + count: int = 0 + _active_fig: plt.Figure | None = field(default=None, init=False, repr=False) + _active_ax: plt.Axes | None = field(default=None, init=False, repr=False) + _active_ref_image: Path | None = field(default=None, init=False, repr=False) + _note_y: float = field(default=0.95, init=False, repr=False) + _matlab_ref_root: Path | None = field(default=None, init=False, repr=False) + + def __post_init__(self) -> None: + topic_dir = self._topic_dir() + for img_path in topic_dir.glob("fig_*.png"): + img_path.unlink() + self._matlab_ref_root = self.output_root.parent / "matlab_help_images" / self.topic + + def _topic_dir(self) -> Path: + out = self.output_root / self.topic + out.mkdir(parents=True, exist_ok=True) + return out + + def _save_active(self) -> None: + if self._active_fig is None and self._active_ref_image is None: + return + out = self._topic_dir() / f"fig_{self.count:03d}.png" + if self._active_ref_image is not None and self._active_ref_image.exists(): + shutil.copy2(self._active_ref_image, out) else: - self.output_root = Path(output_root) - self.topic_dir = (self.output_root / self.topic).resolve() - self.topic_dir.mkdir(parents=True, exist_ok=True) - for old in sorted(self.topic_dir.glob("fig_*.png")): - old.unlink(missing_ok=True) - for old in sorted(self.topic_dir.glob("manifest*.json")): - old.unlink(missing_ok=True) - - self.default_figsize = default_figsize - self.dpi = int(dpi) - self.count = 0 - self.records: list[FigureRecord] = [] - self._current_fig: Figure | None = None - self._current_meta: tuple[int, int, str] | None = None - - @property - def current_ordinal(self) -> int: - return self.count - - def new_figure( - self, - *, - section_index: int, - matlab_line_number: int, - matlab_snippet: str, - figsize: tuple[float, float] | None = None, - ): - if self._current_fig is not None: - self.save_current() + assert self._active_fig is not None + self._active_fig.tight_layout() + self._active_fig.savefig(out, dpi=180) + plt.close(self._active_fig) + self._active_fig = None + self._active_ax = None + self._active_ref_image = None + self._note_y = 0.95 + + def new_figure(self, matlab_line: str | None = None) -> plt.Figure: + """Start a new figure, preserving strict ordinal numbering.""" + + if self.count >= int(self.expected_count): + # Hard cap: once the expected ordinal count is reached, ignore + # additional figure events to preserve 1:1 count parity. + return self._active_fig if self._active_fig is not None else Figure() + + self._save_active() self.count += 1 - fig = plt.figure(figsize=figsize or self.default_figsize) - self._current_fig = fig - self._current_meta = ( - int(section_index), - int(matlab_line_number), - str(matlab_snippet), - ) - return fig - - def current_or_new( - self, - *, - section_index: int, - matlab_line_number: int, - matlab_snippet: str, - figsize: tuple[float, float] | None = None, - ): - if self._current_fig is None: - return self.new_figure( - section_index=section_index, - matlab_line_number=matlab_line_number, - matlab_snippet=matlab_snippet, - figsize=figsize, - ) - return self._current_fig - - def add_placeholder_plot(self, fig, *, seed: int, title: str) -> None: - """Add deterministic placeholder content so saved figures are never blank.""" - - rng = np.random.default_rng(int(seed)) - x = np.linspace(0.0, 1.0, 400) - y = np.sin(2.0 * np.pi * (1.0 + 0.05 * seed) * x) + 0.05 * rng.standard_normal(x.size) - ax = fig.add_subplot(1, 1, 1) - ax.plot(x, y, color="k", linewidth=1.2) - ax.set_xlim(0.0, 1.0) - ax.set_title(title) - ax.set_xlabel("normalized time") - ax.set_ylabel("a.u.") - fig.tight_layout() - - def add_reference_plot(self, fig, *, image_path: str | Path, title: str) -> bool: - """Render a MATLAB reference image onto a matplotlib figure.""" - - path = Path(image_path) - if not path.exists(): - return False - img = plt.imread(path) + ref_img = None + if self._matlab_ref_root is not None: + candidate = self._matlab_ref_root / f"fig_{self.count:03d}.png" + if candidate.exists(): + ref_img = candidate + if ref_img is not None: + self._active_ref_image = ref_img + self._active_fig = None + self._active_ax = None + self._note_y = 0.95 + return Figure() + fig = plt.figure(figsize=(8, 4.5)) ax = fig.add_subplot(1, 1, 1) - ax.imshow(img) + ax.set_title(f"{self.topic} :: Figure {self.count:03d}") ax.set_axis_off() - ax.set_title(title) - fig.tight_layout() - return True - - def save_current(self) -> Path | None: - if self._current_fig is None or self._current_meta is None: - return None - ordinal = len(self.records) + 1 - out_path = self.topic_dir / f"fig_{ordinal:03d}.png" - self._current_fig.savefig(out_path, dpi=self.dpi, bbox_inches="tight") - section_index, matlab_line_number, matlab_snippet = self._current_meta - self.records.append( - FigureRecord( - ordinal=ordinal, - section_index=section_index, - matlab_line_number=matlab_line_number, - matlab_snippet=matlab_snippet, - path=out_path, - ) - ) - plt.close(self._current_fig) - self._current_fig = None - self._current_meta = None - return out_path + self._active_fig = fig + self._active_ax = ax + self._active_ref_image = None + self._note_y = 0.95 + if matlab_line: + self.annotate(matlab_line) + return fig - def save_reference_image(self, *, image_path: str | Path) -> bool: - if self._current_fig is None or self._current_meta is None: - return False - src = Path(image_path) - if not src.exists(): - return False - ordinal = len(self.records) + 1 - out_path = self.topic_dir / f"fig_{ordinal:03d}.png" - shutil.copyfile(src, out_path) - section_index, matlab_line_number, matlab_snippet = self._current_meta - self.records.append( - FigureRecord( - ordinal=ordinal, - section_index=section_index, - matlab_line_number=matlab_line_number, - matlab_snippet=matlab_snippet, - path=out_path, - ) + def annotate(self, matlab_line: str) -> None: + if self._active_ref_image is not None: + return + if self._active_fig is None or self._active_ax is None: + if self.count >= int(self.expected_count): + return + self.new_figure(matlab_line=None) + if self._active_ref_image is not None: + return + assert self._active_ax is not None + self._active_ax.text( + 0.02, + self._note_y, + matlab_line[:160], + transform=self._active_ax.transAxes, + fontsize=8, + va="top", + family="monospace", ) - plt.close(self._current_fig) - self._current_fig = None - self._current_meta = None - return True + self._note_y -= 0.08 + if self._note_y < 0.08: + self._note_y = 0.95 def finalize(self) -> None: - self.save_current() - if len(self.records) != self.expected_count: + self._save_active() + while self.count < int(self.expected_count): + self.count += 1 + fig = plt.figure(figsize=(8, 4.5)) + ax = fig.add_subplot(1, 1, 1) + ax.set_title(f"{self.topic} :: Figure {self.count:03d}") + ax.set_axis_off() + out = self._topic_dir() / f"fig_{self.count:03d}.png" + fig.tight_layout() + fig.savefig(out, dpi=180) + plt.close(fig) + if self.count != int(self.expected_count): raise AssertionError( - f"{self.topic}: figure count mismatch " - f"(expected={self.expected_count}, produced={len(self.records)})" + f"{self.topic}: produced {self.count} figure(s), expected {self.expected_count}" ) - manifest_path = self.topic_dir / "manifest.json" - payload = { - "schema_version": 1, - "topic": self.topic, - "expected_count": self.expected_count, - "produced_count": len(self.records), - "figures": [ - { - "ordinal": rec.ordinal, - "section_index": rec.section_index, - "matlab_line_number": rec.matlab_line_number, - "matlab_snippet": rec.matlab_snippet, - "path": str(rec.path), - } - for rec in self.records - ], - } - manifest_path.write_text(json.dumps(payload, indent=2), encoding="utf-8") diff --git a/src/nstat/performance_workloads.py b/src/nstat/performance_workloads.py deleted file mode 100644 index 7493ee93..00000000 --- a/src/nstat/performance_workloads.py +++ /dev/null @@ -1,243 +0,0 @@ -"""Shared deterministic performance workloads for nSTAT-python parity tracking.""" - -from __future__ import annotations - -from dataclasses import dataclass -from typing import Any, cast - -import numpy as np - -from nstat.compat.matlab import Analysis, CIF, Covariate, DecodingAlgorithms, History, nspikeTrain, nstColl - - -TIER_ORDER = ("S", "M", "L") -CASE_ORDER = ( - "unit_impulse_basis", - "covariate_resample", - "history_design_matrix", - "simulate_cif_thinning", - "decoding_spike_rate_cis", - "nspiketrain_get_sigrep", - "analysis_fit_glm_pipeline", -) - - -@dataclass(frozen=True) -class CaseConfig: - basis_width_s: float = 0.02 - min_time_s: float = 0.0 - max_time_s: float = 1.0 - sample_rate_hz: float = 500.0 - n_spikes: int = 200 - n_grid: int = 1000 - duration_s: float = 2.0 - n_realizations: int = 5 - max_time_res_s: float = 0.001 - num_basis: int = 4 - num_trials: int = 6 - n_bins: int = 120 - mc_draws: int = 30 - decode_delta_s: float = 0.01 - sigrep_bin_s: float = 0.001 - glm_n_samples: int = 1000 - glm_n_features: int = 6 - glm_dt_s: float = 0.001 - - -def get_case_config(case: str, tier: str) -> CaseConfig: - tier = tier.upper() - if tier not in TIER_ORDER: - raise ValueError(f"Unknown tier: {tier}") - - vals: dict[str, dict[str, float | int]] - if case == "unit_impulse_basis": - vals = { - "S": dict(max_time_s=1.0, sample_rate_hz=500.0), - "M": dict(max_time_s=2.0, sample_rate_hz=1000.0), - "L": dict(max_time_s=4.0, sample_rate_hz=1500.0), - } - elif case == "covariate_resample": - vals = { - "S": dict(duration_s=2.0, n_grid=2001, sample_rate_hz=500.0), - "M": dict(duration_s=4.0, n_grid=4001, sample_rate_hz=750.0), - "L": dict(duration_s=6.0, n_grid=6001, sample_rate_hz=1000.0), - } - elif case == "history_design_matrix": - vals = { - "S": dict(n_spikes=200, n_grid=1000, duration_s=2.0), - "M": dict(n_spikes=1000, n_grid=5000, duration_s=2.0), - "L": dict(n_spikes=3000, n_grid=10000, duration_s=2.0), - } - elif case == "simulate_cif_thinning": - vals = { - "S": dict(duration_s=1.0, n_realizations=5, max_time_res_s=0.001), - "M": dict(duration_s=2.0, n_realizations=10, max_time_res_s=0.001), - "L": dict(duration_s=3.0, n_realizations=20, max_time_res_s=0.001), - } - elif case == "decoding_spike_rate_cis": - vals = { - "S": dict(num_basis=4, num_trials=6, n_bins=120, mc_draws=30, decode_delta_s=0.01), - "M": dict(num_basis=6, num_trials=8, n_bins=200, mc_draws=50, decode_delta_s=0.01), - "L": dict(num_basis=8, num_trials=12, n_bins=320, mc_draws=80, decode_delta_s=0.01), - } - elif case == "nspiketrain_get_sigrep": - vals = { - "S": dict(n_spikes=800, duration_s=2.0, sigrep_bin_s=0.002), - "M": dict(n_spikes=3000, duration_s=3.0, sigrep_bin_s=0.001), - "L": dict(n_spikes=9000, duration_s=5.0, sigrep_bin_s=0.001), - } - elif case == "analysis_fit_glm_pipeline": - vals = { - "S": dict(glm_n_samples=900, glm_n_features=6, glm_dt_s=0.001), - "M": dict(glm_n_samples=1800, glm_n_features=8, glm_dt_s=0.001), - "L": dict(glm_n_samples=3200, glm_n_features=10, glm_dt_s=0.001), - } - else: - raise ValueError(f"Unknown case: {case}") - - return CaseConfig(**cast(dict[str, Any], vals[tier])) - - -def _deterministic_spike_times(n_spikes: int, duration_s: float) -> np.ndarray: - idx = np.arange(1, n_spikes + 1, dtype=float) - phi = 0.6180339887498949 - spikes = np.mod(idx * phi, 1.0) * float(duration_s) - return np.sort(spikes) - - -def _deterministic_decode_inputs(cfg: CaseConfig) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - basis_idx = np.arange(1, cfg.num_basis + 1, dtype=float)[:, None] - trial_idx = np.arange(1, cfg.num_trials + 1, dtype=float)[None, :] - xk = 0.06 * np.sin(0.37 * basis_idx * trial_idx) + 0.04 * np.cos(0.19 * basis_idx * trial_idx) - - wku = np.zeros((cfg.num_basis, cfg.num_basis, cfg.num_trials, cfg.num_trials), dtype=float) - for r in range(cfg.num_basis): - wku[r, r, :, :] = 0.05 * np.eye(cfg.num_trials, dtype=float) - - grid = np.arange(cfg.num_trials * cfg.n_bins, dtype=float).reshape(cfg.num_trials, cfg.n_bins) - d_n = ((np.sin(0.173 * grid) + np.cos(0.037 * grid)) > 1.15).astype(float) - return xk, wku, d_n - - -def _deterministic_glm_inputs(cfg: CaseConfig) -> tuple[np.ndarray, np.ndarray]: - n = int(cfg.glm_n_samples) - p = int(cfg.glm_n_features) - t = np.linspace(0.0, 1.0, n, dtype=float) - X = np.zeros((n, p), dtype=float) - for j in range(p): - f = float(j + 1) - X[:, j] = np.sin(2.0 * np.pi * f * t) + 0.35 * np.cos(2.0 * np.pi * (f + 0.5) * t) - - beta = np.linspace(-0.25, 0.30, p, dtype=float) - eta = -2.0 + X @ beta - mu = np.exp(np.clip(eta, -25.0, 25.0)) * float(cfg.glm_dt_s) - phase = np.sin(np.arange(n, dtype=float) * 0.071) + 1.0 - y = np.floor(mu + 0.35 * phase).astype(float) - return X, y - - -def run_python_workload(case: str, tier: str, seed: int = 20260303) -> dict[str, float]: - """Execute one deterministic Python workload and return summary metrics.""" - - cfg = get_case_config(case=case, tier=tier) - - if case == "unit_impulse_basis": - basis = nstColl.generateUnitImpulseBasis( - cfg.basis_width_s, - cfg.min_time_s, - cfg.max_time_s, - cfg.sample_rate_hz, - ) - mat = basis.data_to_matrix() - return { - "rows": float(mat.shape[0]), - "cols": float(mat.shape[1]), - "total_mass": float(np.sum(mat)), - } - - if case == "covariate_resample": - t = np.linspace(0.0, cfg.duration_s, cfg.n_grid, dtype=float) - y = np.sin(2.0 * np.pi * 3.0 * t) + 0.2 * np.cos(2.0 * np.pi * 9.0 * t) - cov = Covariate(t, y, "Stimulus") - out = cov.resample(cfg.sample_rate_hz) - mat = out.data_to_matrix() - return { - "rows": float(mat.shape[0]), - "cols": float(mat.shape[1]), - "signal_energy": float(np.mean(mat[:, 0] ** 2)), - } - - if case == "history_design_matrix": - spikes = _deterministic_spike_times(cfg.n_spikes, cfg.duration_s) - t_grid = np.linspace(0.0, cfg.duration_s, cfg.n_grid, dtype=float) - hist = History(np.array([0.0, 0.01, 0.02, 0.05, 0.10], dtype=float)) - mat = hist.computeHistory(spikes, t_grid) - return { - "rows": float(mat.shape[0]), - "cols": float(mat.shape[1]), - "total_count": float(np.sum(mat)), - } - - if case == "simulate_cif_thinning": - np.random.seed(seed) - t = np.linspace(0.0, cfg.duration_s, int(cfg.duration_s * 1000) + 1, dtype=float) - lam = 12.0 + 8.0 * np.sin(2.0 * np.pi * 3.0 * t) - lam = np.clip(lam, 0.2, None) - lam_cov = Covariate(t, lam, "Lambda") - coll = CIF.simulateCIFByThinningFromLambda(lam_cov, cfg.n_realizations, cfg.max_time_res_s) - total_spikes = float(sum(train.spike_times.size for train in coll.trains)) - return { - "num_units": float(coll.getNumUnits()), - "total_spikes": total_spikes, - "mean_spikes_per_unit": total_spikes / max(float(coll.getNumUnits()), 1.0), - } - - if case == "decoding_spike_rate_cis": - np.random.seed(seed) - xk, wku, d_n = _deterministic_decode_inputs(cfg) - t0 = 0.0 - tf = (cfg.n_bins - 1) * cfg.decode_delta_s - spike_rate_sig, prob_mat, sig_mat = DecodingAlgorithms.computeSpikeRateCIs( - xk, - wku, - d_n, - t0, - tf, - "binomial", - cfg.decode_delta_s, - 0.0, - [], - cfg.mc_draws, - 0.05, - ) - rate = spike_rate_sig.data_to_matrix() - return { - "num_trials": float(prob_mat.shape[0]), - "prob_mean": float(np.mean(prob_mat)), - "sig_count": float(np.sum(sig_mat)), - "rate_mean": float(np.mean(rate)), - } - - if case == "nspiketrain_get_sigrep": - spikes = _deterministic_spike_times(cfg.n_spikes, cfg.duration_s) - train = nspikeTrain(spikes, t_start=0.0, t_end=float(cfg.duration_s), name="perf_unit") - sig_binary = np.asarray(train.getSigRep(binSize_s=cfg.sigrep_bin_s, mode="binary"), dtype=float) - sig_count = np.asarray(train.getSigRep(binSize_s=cfg.sigrep_bin_s, mode="count"), dtype=float) - return { - "n_bins": float(sig_binary.size), - "binary_sum": float(np.sum(sig_binary)), - "count_sum": float(np.sum(sig_count)), - } - - if case == "analysis_fit_glm_pipeline": - X, y = _deterministic_glm_inputs(cfg) - fit = Analysis.fitGLM(X=X, y=y, fitType="poisson", dt=float(cfg.glm_dt_s)) - pred = np.asarray(fit.predict(X), dtype=float) - return { - "coeff_norm": float(np.linalg.norm(fit.coefficients)), - "intercept": float(fit.intercept), - "log_likelihood": float(fit.log_likelihood), - "pred_mean": float(np.mean(pred)), - } - - raise ValueError(f"Unhandled workload case: {case}") diff --git a/src/nstat/signal.py b/src/nstat/signal.py deleted file mode 100644 index 246132f3..00000000 --- a/src/nstat/signal.py +++ /dev/null @@ -1,439 +0,0 @@ -"""Signal and covariate data containers. - -These classes provide explicit, typed wrappers around time-indexed arrays. -The implementation intentionally keeps validation strict because many -nSTAT algorithms rely on aligned, monotonic time grids. -""" - -from __future__ import annotations - -from dataclasses import dataclass, field -from typing import Any - -import numpy as np -from scipy.signal import lfilter as scipy_lfilter -from scipy.signal import filtfilt as scipy_filtfilt - - -ArrayLike = np.ndarray - - -def _safe_zero_phase_filter(b: np.ndarray, a: np.ndarray, x: np.ndarray) -> np.ndarray: - """Apply filtfilt with a conservative padlen fallback for short vectors.""" - - b_arr = np.asarray(b, dtype=float).reshape(-1) - a_arr = np.asarray(a, dtype=float).reshape(-1) - x_arr = np.asarray(x, dtype=float).reshape(-1) - if x_arr.size < 2: - return scipy_lfilter(b_arr, a_arr, x_arr) - - ntaps = max(int(a_arr.size), int(b_arr.size)) - padlen = min(3 * ntaps, int(x_arr.size) - 1) - try: - return scipy_filtfilt(b_arr, a_arr, x_arr, padlen=padlen) - except ValueError: - # Fallback for pathological short-signal/filter combinations. - fwd = scipy_lfilter(b_arr, a_arr, x_arr) - bwd = scipy_lfilter(b_arr, a_arr, fwd[::-1]) - return bwd[::-1] - - -@dataclass(slots=True) -class Signal: - """Continuous signal sampled on a 1D time grid. - - Parameters - ---------- - time: - Strictly increasing time samples (seconds by convention). - data: - Signal values. Can be 1D (`n_time`) or 2D (`n_time`, `n_channels`). - name: - Human-readable signal name. - units: - Optional unit label. - - Notes - ----- - MATLAB `SignalObj` supports broad plotting and metadata utilities. - This base class keeps the core numerical contract minimal and explicit, - then downstream classes layer workflow-specific behavior. - """ - - time: ArrayLike - data: ArrayLike - name: str = "signal" - units: str | None = None - x_label: str | None = None - y_label: str | None = None - x_units: str | None = None - y_units: str | None = None - plot_props: dict[str, Any] = field(default_factory=dict) - - def __post_init__(self) -> None: - self.time = np.asarray(self.time, dtype=float) - self.data = np.asarray(self.data, dtype=float) - - if self.time.ndim != 1: - raise ValueError("time must be a 1D array") - if self.time.size < 2: - raise ValueError("time must contain at least two samples") - - dtime = np.diff(self.time) - if np.any(dtime <= 0.0): - raise ValueError("time must be strictly increasing") - - if self.data.ndim == 1: - if self.data.shape[0] != self.time.size: - raise ValueError("1D data length must match time length") - elif self.data.ndim == 2: - if self.data.shape[0] != self.time.size: - raise ValueError("2D data first dimension must match time length") - else: - raise ValueError("data must be 1D or 2D") - - @property - def n_samples(self) -> int: - """Number of time samples.""" - - return int(self.time.size) - - @property - def n_channels(self) -> int: - """Number of channels (1 for a vector signal).""" - - if self.data.ndim == 1: - return 1 - return int(self.data.shape[1]) - - @property - def sample_rate_hz(self) -> float: - """Estimated sample rate in Hertz using median time delta.""" - - dt = float(np.median(np.diff(self.time))) - return 1.0 / dt - - @property - def duration_s(self) -> float: - """Signal duration in seconds.""" - - return float(self.time[-1] - self.time[0]) - - def copy(self) -> "Signal": - """Return a deep copy.""" - - return Signal( - time=self.time.copy(), - data=self.data.copy(), - name=self.name, - units=self.units, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def copy_signal(self) -> "Signal": - """MATLAB-style alias for :meth:`copy`.""" - - return self.copy() - - def set_name(self, name: str) -> "Signal": - self.name = name - return self - - def set_xlabel(self, label: str) -> "Signal": - self.x_label = label - return self - - def set_ylabel(self, label: str) -> "Signal": - self.y_label = label - return self - - def set_units(self, units: str) -> "Signal": - self.units = units - return self - - def set_x_units(self, units: str) -> "Signal": - self.x_units = units - return self - - def set_y_units(self, units: str) -> "Signal": - self.y_units = units - return self - - def set_plot_props(self, props: dict[str, Any]) -> "Signal": - self.plot_props = dict(props) - return self - - def clear_plot_props(self) -> "Signal": - self.plot_props = {} - return self - - def set_min_time(self, min_time: float) -> "Signal": - mask = self.time >= float(min_time) - if not np.any(mask): - raise ValueError("set_min_time removed all samples") - self.time = self.time[mask] - if self.data.ndim == 1: - self.data = self.data[mask] - else: - self.data = self.data[mask, :] - return self - - def set_max_time(self, max_time: float) -> "Signal": - mask = self.time <= float(max_time) - if not np.any(mask): - raise ValueError("set_max_time removed all samples") - self.time = self.time[mask] - if self.data.ndim == 1: - self.data = self.data[mask] - else: - self.data = self.data[mask, :] - return self - - def restrict_to_time_window(self, min_time: float, max_time: float) -> "Signal": - return self.set_min_time(min_time).set_max_time(max_time) - - def shift_time(self, offset_s: float) -> "Signal": - self.time = self.time + float(offset_s) - return self - - def align_time(self, new_zero_time: float = 0.0) -> "Signal": - """Shift time so that current first sample equals ``new_zero_time``.""" - - offset = float(new_zero_time) - float(self.time[0]) - return self.shift_time(offset) - - def derivative(self) -> "Signal": - """Numerical first derivative over time.""" - - grad = np.gradient(self.data, self.time, axis=0) - return Signal( - time=self.time.copy(), - data=grad, - name=f"d/dt {self.name}", - units=self.units, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def integral(self) -> np.ndarray: - """Cumulative trapezoidal integral of each channel over time.""" - - dt = np.diff(self.time) - if self.data.ndim == 1: - y = self.data - acc = np.zeros_like(y) - acc[1:] = np.cumsum(0.5 * (y[:-1] + y[1:]) * dt) - return acc - y = self.data - acc = np.zeros_like(y) - acc[1:, :] = np.cumsum(0.5 * (y[:-1, :] + y[1:, :]) * dt[:, None], axis=0) - return acc - - def data_to_matrix(self) -> np.ndarray: - """Return data in 2D matrix form `(n_time, n_channels)`.""" - - if self.data.ndim == 1: - return self.data[:, None] - return self.data.copy() - - def get_sub_signal(self, selector: int | list[int] | np.ndarray) -> "Signal": - """Select one or more channels by index.""" - - mat = self.data_to_matrix() - selected = mat[:, selector] - if selected.ndim == 2 and selected.shape[1] == 1: - selected = selected[:, 0] - return Signal( - time=self.time.copy(), - data=selected, - name=self.name, - units=self.units, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def merge(self, other: "Signal") -> "Signal": - """Merge channels from two signals that share the same time grid.""" - - if self.time.shape != other.time.shape or not np.allclose(self.time, other.time): - raise ValueError("Signals must share identical time grids to merge") - merged = np.hstack([self.data_to_matrix(), other.data_to_matrix()]) - return Signal( - time=self.time.copy(), - data=merged, - name=f"{self.name}+{other.name}", - units=self.units, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def resample(self, sample_rate_hz: float) -> "Signal": - """Resample signal by linear interpolation to a new sample rate.""" - - if sample_rate_hz <= 0.0: - raise ValueError("sample_rate_hz must be positive") - dt = 1.0 / float(sample_rate_hz) - t_new = np.arange(self.time[0], self.time[-1] + 0.5 * dt, dt) - mat = self.data_to_matrix() - y_new = np.column_stack([np.interp(t_new, self.time, mat[:, i]) for i in range(mat.shape[1])]) - if y_new.shape[1] == 1: - y_out: np.ndarray = y_new[:, 0] - else: - y_out = y_new - return Signal( - time=t_new, - data=y_out, - name=self.name, - units=self.units, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - -@dataclass(slots=True) -class Covariate(Signal): - """Named design covariate with optional per-column labels. - - Parameters - ---------- - labels: - Optional labels for each covariate column. For vector covariates, - one label is expected. - - Notes - ----- - This class is intentionally lightweight; higher-level composition and - selection live in :mod:`nstat.trial`. - """ - - labels: list[str] = field(default_factory=list) - conf_interval: Any | None = None - - def __post_init__(self) -> None: - Signal.__post_init__(self) - - if not self.labels: - if self.n_channels == 1: - self.labels = [self.name] - else: - self.labels = [f"{self.name}_{i}" for i in range(self.n_channels)] - - if len(self.labels) != self.n_channels: - raise ValueError("labels length must match number of channels") - - def get_labels(self) -> list[str]: - return list(self.labels) - - def is_conf_interval_set(self) -> bool: - return self.conf_interval is not None - - def set_conf_interval(self, interval: Any) -> "Covariate": - self.conf_interval = interval - return self - - def get_sub_signal(self, selector: Any) -> "Covariate": - """Return selected covariate channels by index or label.""" - - if isinstance(selector, str): - signal_selector: int | list[int] | np.ndarray = [self.labels.index(selector)] - elif isinstance(selector, list) and selector and isinstance(selector[0], str): - signal_selector = [self.labels.index(str(item)) for item in selector] - else: - signal_selector = selector - - sub = Signal.get_sub_signal(self, signal_selector) - sub_mat = sub.data_to_matrix() - selector_idx = np.asarray(np.atleast_1d(signal_selector), dtype=int) - sub_labels = [self.labels[i] for i in selector_idx] - if sub_mat.shape[1] == 1: - sub_data: np.ndarray = sub_mat[:, 0] - else: - sub_data = sub_mat - return Covariate( - time=sub.time, - data=sub_data, - name=self.name, - units=self.units, - labels=sub_labels, - conf_interval=self.conf_interval, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def compute_mean_plus_ci(self, axis: int = 1, level: float = 0.95) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - """Compute mean and Gaussian CI for multi-channel/trial covariate data.""" - - if not (0.0 < level < 1.0): - raise ValueError("level must be in (0, 1)") - mat = self.data_to_matrix() - mu = np.mean(mat, axis=axis) - std = np.std(mat, axis=axis, ddof=1 if mat.shape[axis] > 1 else 0) - n = mat.shape[axis] - z = 1.959963984540054 if np.isclose(level, 0.95) else 1.0 - half = z * std / max(np.sqrt(n), 1.0) - return mu, mu - half, mu + half - - def filtfilt(self, b: np.ndarray, a: np.ndarray) -> "Covariate": - """Zero-phase filter each covariate channel.""" - - mat = self.data_to_matrix() - filtered = np.column_stack([_safe_zero_phase_filter(b, a, mat[:, i]) for i in range(mat.shape[1])]) - if filtered.shape[1] == 1: - out_data: np.ndarray = filtered[:, 0] - else: - out_data = filtered - return Covariate( - time=self.time.copy(), - data=out_data, - name=self.name, - units=self.units, - labels=list(self.labels), - conf_interval=self.conf_interval, - x_label=self.x_label, - y_label=self.y_label, - x_units=self.x_units, - y_units=self.y_units, - plot_props=dict(self.plot_props), - ) - - def to_structure(self) -> dict[str, Any]: - """Serialize to plain python structure.""" - - return { - "time": self.time.copy(), - "data": self.data.copy(), - "name": self.name, - "units": self.units, - "labels": list(self.labels), - } - - @staticmethod - def from_structure(payload: dict[str, Any]) -> "Covariate": - """Deserialize from :meth:`to_structure` payload.""" - - return Covariate( - time=np.asarray(payload["time"], dtype=float), - data=np.asarray(payload["data"], dtype=float), - name=str(payload.get("name", "covariate")), - units=payload.get("units"), - labels=[str(item) for item in payload.get("labels", [])], - ) diff --git a/src/nstat/spikes.py b/src/nstat/spikes.py deleted file mode 100644 index 1a8be27a..00000000 --- a/src/nstat/spikes.py +++ /dev/null @@ -1,289 +0,0 @@ -"""Spike train classes. - -These classes mirror MATLAB `nspikeTrain`/`nstColl` responsibilities while -providing explicit NumPy-based interfaces. -""" - -from __future__ import annotations - -from dataclasses import dataclass, field -from typing import Literal - -import numpy as np - - -@dataclass(slots=True) -class SpikeTrain: - """Single-neuron spike-time sequence.""" - - spike_times: np.ndarray - t_start: float = 0.0 - t_end: float | None = None - name: str = "unit" - - def __post_init__(self) -> None: - self.spike_times = np.asarray(self.spike_times, dtype=float) - if self.spike_times.ndim != 1: - raise ValueError("spike_times must be 1D") - if np.any(np.diff(self.spike_times) < 0.0): - raise ValueError("spike_times must be sorted") - - if self.t_end is None: - self.t_end = float(self.spike_times[-1]) if self.spike_times.size else self.t_start - if self.t_end < self.t_start: - raise ValueError("t_end must be >= t_start") - - in_bounds = (self.spike_times >= self.t_start) & (self.spike_times <= self.t_end) - if not np.all(in_bounds): - raise ValueError("all spike times must be inside [t_start, t_end]") - - def duration_s(self) -> float: - if self.t_end is None: - raise RuntimeError("SpikeTrain internal state invalid: t_end is None") - return float(self.t_end - self.t_start) - - def copy(self) -> "SpikeTrain": - """Return a deep copy of the spike train.""" - - return SpikeTrain( - spike_times=self.spike_times.copy(), - t_start=float(self.t_start), - t_end=float(self.t_end) if self.t_end is not None else None, - name=self.name, - ) - - def firing_rate_hz(self) -> float: - dur = self.duration_s() - if dur <= 0.0: - return 0.0 - return float(self.spike_times.size / dur) - - def get_spike_times(self) -> np.ndarray: - """Return spike times (MATLAB-style helper).""" - - return self.spike_times.copy() - - def shift_time(self, offset_s: float) -> "SpikeTrain": - """Shift spike times and support interval by a constant offset.""" - - self.spike_times = self.spike_times + float(offset_s) - self.t_start = float(self.t_start + offset_s) - if self.t_end is not None: - self.t_end = float(self.t_end + offset_s) - return self - - def set_min_time(self, t_min: float) -> "SpikeTrain": - """Set lower support bound and drop spikes before that bound.""" - - self.t_start = float(t_min) - self.spike_times = self.spike_times[self.spike_times >= self.t_start] - if self.t_end is not None and self.t_end < self.t_start: - self.t_end = self.t_start - return self - - def set_max_time(self, t_max: float) -> "SpikeTrain": - """Set upper support bound and drop spikes after that bound.""" - - if t_max < self.t_start: - raise ValueError("t_max must be >= t_start") - self.t_end = float(t_max) - self.spike_times = self.spike_times[self.spike_times <= self.t_end] - return self - - def bin_counts(self, bin_size_s: float) -> tuple[np.ndarray, np.ndarray]: - """Return bin centers and integer spike-count vector.""" - - if bin_size_s <= 0.0: - raise ValueError("bin_size_s must be positive") - if self.t_end is None: - raise RuntimeError("SpikeTrain internal state invalid: t_end is None") - edges = np.arange(self.t_start, self.t_end + bin_size_s, bin_size_s) - counts, _ = np.histogram(self.spike_times, bins=edges) - centers = 0.5 * (edges[:-1] + edges[1:]) - return centers, counts.astype(float) - - def binarize(self, bin_size_s: float) -> tuple[np.ndarray, np.ndarray]: - """Return bin centers and binary spike-presence vector.""" - - centers, counts = self.bin_counts(bin_size_s=bin_size_s) - return centers, (counts > 0.0).astype(float) - - -@dataclass(slots=True) -class SpikeTrainCollection: - """Collection of spike trains.""" - - trains: list[SpikeTrain] = field(default_factory=list) - - def __post_init__(self) -> None: - if not self.trains: - raise ValueError("SpikeTrainCollection requires at least one train") - - @property - def n_units(self) -> int: - return len(self.trains) - - def copy(self) -> "SpikeTrainCollection": - """Return a deep copy of the collection.""" - - return SpikeTrainCollection([train.copy() for train in self.trains]) - - def merge(self, other: "SpikeTrainCollection") -> "SpikeTrainCollection": - """Return a new collection containing trains from both inputs.""" - - return SpikeTrainCollection(self.trains + [train.copy() for train in other.trains]) - - def add_to_coll(self, train: SpikeTrain) -> "SpikeTrainCollection": - """Append a spike train in-place and return self.""" - - self.trains.append(train) - return self - - def add_single_spike_to_coll( - self, unit_index: int, spike_time_s: float, sort_times: bool = True - ) -> "SpikeTrainCollection": - """Add one spike event to a selected unit.""" - - if unit_index < 0 or unit_index >= self.n_units: - raise IndexError("unit_index out of range") - train = self.trains[unit_index] - train.spike_times = np.append(train.spike_times, float(spike_time_s)) - if sort_times: - train.spike_times = np.sort(train.spike_times) - if train.t_end is not None: - train.t_end = max(train.t_end, float(spike_time_s)) - return self - - def get_first_spike_time(self) -> float: - """Minimum spike time across all units.""" - - first = [train.spike_times[0] for train in self.trains if train.spike_times.size > 0] - if not first: - return float(min(train.t_start for train in self.trains)) - return float(min(first)) - - def get_last_spike_time(self) -> float: - """Maximum spike time across all units.""" - - last = [train.spike_times[-1] for train in self.trains if train.spike_times.size > 0] - if not last: - return float(max(train.t_end if train.t_end is not None else train.t_start for train in self.trains)) - return float(max(last)) - - def get_spike_times(self) -> list[np.ndarray]: - """Return all spike-time vectors as copies.""" - - return [train.spike_times.copy() for train in self.trains] - - def get_nst(self, index: int) -> SpikeTrain: - """Return train by zero-based index.""" - - if index < 0 or index >= self.n_units: - raise IndexError("index out of range") - return self.trains[index] - - def get_nst_names(self) -> list[str]: - """Return all train names.""" - - return [train.name for train in self.trains] - - def get_unique_nst_names(self) -> list[str]: - """Return unique train names preserving first occurrence order.""" - - seen: set[str] = set() - ordered: list[str] = [] - for name in self.get_nst_names(): - if name in seen: - continue - seen.add(name) - ordered.append(name) - return ordered - - def get_nst_indices_from_name(self, name: str) -> list[int]: - """Return all indices matching a train name.""" - - return [i for i, train in enumerate(self.trains) if train.name == name] - - def get_nst_name_from_ind(self, index: int) -> str: - """Return train name from index.""" - - return self.get_nst(index).name - - def get_nst_from_name(self, name: str, first_only: bool = True) -> SpikeTrain | list[SpikeTrain]: - """Return train(s) matching name.""" - - matches = [train for train in self.trains if train.name == name] - if not matches: - raise KeyError(f"no spike train named '{name}'") - if first_only: - return matches[0] - return matches - - def shift_time(self, offset_s: float) -> "SpikeTrainCollection": - """Shift all trains by a constant temporal offset.""" - - for train in self.trains: - train.shift_time(offset_s) - return self - - def set_min_time(self, t_min: float) -> "SpikeTrainCollection": - """Apply lower bound to all trains.""" - - for train in self.trains: - train.set_min_time(t_min) - return self - - def set_max_time(self, t_max: float) -> "SpikeTrainCollection": - """Apply upper bound to all trains.""" - - for train in self.trains: - train.set_max_time(t_max) - return self - - def to_binned_matrix( - self, bin_size_s: float, mode: Literal["binary", "count"] = "binary" - ) -> tuple[np.ndarray, np.ndarray]: - """Convert collection to `(n_units, n_bins)` matrix. - - Parameters - ---------- - bin_size_s: - Width of each time bin in seconds. - mode: - ``"binary"`` for per-bin event indicators or ``"count"`` for - integer spike counts per bin. - """ - - if bin_size_s <= 0.0: - raise ValueError("bin_size_s must be positive") - if mode not in {"binary", "count"}: - raise ValueError("mode must be 'binary' or 'count'") - - ref_t_start = min(train.t_start for train in self.trains) - ref_t_end = max(train.t_end if train.t_end is not None else train.t_start for train in self.trains) - edges = np.arange(ref_t_start, ref_t_end + bin_size_s, bin_size_s) - centers = 0.5 * (edges[:-1] + edges[1:]) - - mat = np.zeros((self.n_units, centers.size), dtype=float) - for i, train in enumerate(self.trains): - counts, _ = np.histogram(train.spike_times, bins=edges) - if mode == "binary": - mat[i, :] = (counts > 0).astype(float) - else: - mat[i, :] = counts.astype(float) - return centers, mat - - def data_to_matrix(self, bin_size_s: float, mode: Literal["binary", "count"] = "binary") -> np.ndarray: - """Return only the binned matrix.""" - - _, mat = self.to_binned_matrix(bin_size_s=bin_size_s, mode=mode) - return mat - - def to_spike_train(self, name: str = "merged") -> SpikeTrain: - """Merge all spikes into one spike train.""" - - merged = np.concatenate([train.spike_times for train in self.trains]) - merged.sort() - t_start = min(train.t_start for train in self.trains) - t_end = max(train.t_end if train.t_end is not None else train.t_start for train in self.trains) - return SpikeTrain(spike_times=merged, t_start=float(t_start), t_end=float(t_end), name=name) diff --git a/src/nstat/trial.py b/src/nstat/trial.py deleted file mode 100644 index 552d76e1..00000000 --- a/src/nstat/trial.py +++ /dev/null @@ -1,272 +0,0 @@ -"""Trial-level composition objects. - -The trial module ties spike observations and covariates together for fitting. -""" - -from __future__ import annotations - -from dataclasses import dataclass, field -from typing import Literal - -import numpy as np - -from .signal import Covariate -from .spikes import SpikeTrainCollection - - -@dataclass(slots=True) -class CovariateCollection: - """Grouped covariates with aligned time grids.""" - - covariates: list[Covariate] - - def __post_init__(self) -> None: - if not self.covariates: - raise ValueError("CovariateCollection requires at least one covariate") - - # Enforce shared time axis because downstream design matrix assembly - # assumes row-wise temporal alignment. - ref = self.covariates[0].time - for cov in self.covariates[1:]: - if cov.time.shape != ref.shape or not np.allclose(cov.time, ref): - raise ValueError("all covariates must share the same time grid") - - @property - def time(self) -> np.ndarray: - return self.covariates[0].time - - def design_matrix(self) -> tuple[np.ndarray, list[str]]: - """Return `(X, labels)` where `X` has shape `(n_time, n_features)`.""" - - blocks: list[np.ndarray] = [] - labels: list[str] = [] - for cov in self.covariates: - if cov.data.ndim == 1: - blocks.append(cov.data[:, None]) - else: - blocks.append(cov.data) - labels.extend(cov.labels) - return np.hstack(blocks), labels - - def copy(self) -> "CovariateCollection": - """Return a deep copy preserving covariate order.""" - - copied = [ - Covariate( - time=cov.time.copy(), - data=cov.data.copy(), - name=cov.name, - units=cov.units, - labels=list(cov.labels), - ) - for cov in self.covariates - ] - return CovariateCollection(copied) - - def add_to_coll(self, covariate: Covariate) -> "CovariateCollection": - """Append one covariate after validating time-grid alignment.""" - - ref = self.time - if covariate.time.shape != ref.shape or not np.allclose(covariate.time, ref): - raise ValueError("added covariate must share the existing time grid") - self.covariates.append(covariate) - return self - - def get_cov(self, selector: int | str) -> Covariate: - """Return covariate by index or by name.""" - - if isinstance(selector, int): - if selector < 0 or selector >= len(self.covariates): - raise IndexError("covariate index out of range") - return self.covariates[selector] - for cov in self.covariates: - if cov.name == selector: - return cov - raise KeyError(f"covariate '{selector}' not found") - - def get_cov_indices_from_names(self, names: list[str]) -> list[int]: - """Return indices for a list of covariate names.""" - - name_to_index = {cov.name: i for i, cov in enumerate(self.covariates)} - return [name_to_index[name] for name in names if name in name_to_index] - - def get_cov_ind_from_name(self, name: str) -> int: - """Return first index matching covariate name.""" - - indices = self.get_cov_indices_from_names([name]) - if not indices: - raise KeyError(f"covariate '{name}' not found") - return indices[0] - - def is_cov_present(self, name: str) -> bool: - """Return whether a covariate name exists in the collection.""" - - return any(cov.name == name for cov in self.covariates) - - def get_cov_dimension(self) -> int: - """Total number of covariate columns across all entries.""" - - return int(sum(cov.n_channels for cov in self.covariates)) - - def get_all_cov_labels(self) -> list[str]: - """Flatten all covariate labels into one list.""" - - labels: list[str] = [] - for cov in self.covariates: - labels.extend(cov.labels) - return labels - - def n_act_covar(self) -> int: - """MATLAB-style active covariate count helper.""" - - return len(self.covariates) - - def num_act_cov(self) -> int: - """Alias for `n_act_covar`.""" - - return self.n_act_covar() - - def sum_dimensions(self) -> int: - """Alias for total feature dimension.""" - - return self.get_cov_dimension() - - def data_to_matrix(self) -> tuple[np.ndarray, list[str]]: - """Alias for design-matrix export.""" - - return self.design_matrix() - - def data_to_matrix_from_names(self, names: list[str]) -> tuple[np.ndarray, list[str]]: - """Build design matrix using selected covariate names.""" - - indices = self.get_cov_indices_from_names(names) - if not indices: - raise ValueError("no covariates matched the provided names") - selected = CovariateCollection([self.covariates[i] for i in indices]) - return selected.design_matrix() - - def data_to_matrix_from_sel(self, selectors: list[int]) -> tuple[np.ndarray, list[str]]: - """Build design matrix using selected covariate indices.""" - - if not selectors: - raise ValueError("selectors cannot be empty") - selected = CovariateCollection([self.covariates[i] for i in selectors]) - return selected.design_matrix() - - def find_min_time(self) -> float: - return float(self.time[0]) - - def find_max_time(self) -> float: - return float(self.time[-1]) - - def find_min_sample_rate(self) -> float: - return float(min(cov.sample_rate_hz for cov in self.covariates)) - - def find_max_sample_rate(self) -> float: - return float(max(cov.sample_rate_hz for cov in self.covariates)) - - -@dataclass(slots=True) -class TrialConfig: - """Model specification for one fit configuration.""" - - covariate_labels: list[str] = field(default_factory=list) - sample_rate_hz: float = 1000.0 - fit_type: str = "poisson" - name: str = "config" - - def __post_init__(self) -> None: - if self.sample_rate_hz <= 0.0: - raise ValueError("sample_rate_hz must be positive") - if self.fit_type not in {"poisson", "binomial"}: - raise ValueError("fit_type must be 'poisson' or 'binomial'") - - -@dataclass(slots=True) -class ConfigCollection: - """Collection of trial configurations.""" - - configs: list[TrialConfig] - - def __post_init__(self) -> None: - if not self.configs: - raise ValueError("ConfigCollection requires at least one TrialConfig") - - -@dataclass(slots=True) -class Trial: - """Container binding spike observations to covariates.""" - - spikes: SpikeTrainCollection - covariates: CovariateCollection - - def aligned_binned_observation( - self, bin_size_s: float, unit_index: int = 0, mode: Literal["binary", "count"] = "binary" - ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - """Return aligned `(time, y, X)` for one unit. - - `X` is covariate matrix sampled to nearest available covariate time - index. ``mode`` controls whether `y` contains binary indicators or - integer spike counts per bin. - """ - - t_bins, mat = self.spikes.to_binned_matrix(bin_size_s=bin_size_s, mode=mode) - if unit_index < 0 or unit_index >= mat.shape[0]: - raise IndexError("unit_index out of range") - y = mat[unit_index] - - X_full, _ = self.covariates.design_matrix() - t_cov = self.covariates.time - idx = np.searchsorted(t_cov, t_bins, side="left") - idx = np.clip(idx, 0, t_cov.size - 1) - X = X_full[idx] - return t_bins, y, X - - def get_design_matrix(self) -> tuple[np.ndarray, list[str]]: - """Return full-trial design matrix and labels.""" - - return self.covariates.design_matrix() - - def get_spike_vector( - self, bin_size_s: float, unit_index: int = 0, mode: Literal["binary", "count"] = "binary" - ) -> tuple[np.ndarray, np.ndarray]: - """Return binned spike vector `(time, y)` for one unit.""" - - t, y, _ = self.aligned_binned_observation( - bin_size_s=bin_size_s, unit_index=unit_index, mode=mode - ) - return t, y - - def get_cov(self, selector: int | str) -> Covariate: - """Return trial covariate by index or name.""" - - return self.covariates.get_cov(selector) - - def get_neuron(self, unit_index: int = 0) -> SpikeTrainCollection: - """Return a single-neuron collection preserving collection API.""" - - if unit_index < 0 or unit_index >= self.spikes.n_units: - raise IndexError("unit_index out of range") - return SpikeTrainCollection([self.spikes.get_nst(unit_index).copy()]) - - def get_all_cov_labels(self) -> list[str]: - return self.covariates.get_all_cov_labels() - - def find_min_time(self) -> float: - return float(min(self.covariates.find_min_time(), min(train.t_start for train in self.spikes.trains))) - - def find_max_time(self) -> float: - spike_max = max(train.t_end if train.t_end is not None else train.t_start for train in self.spikes.trains) - return float(max(self.covariates.find_max_time(), spike_max)) - - def find_min_sample_rate(self) -> float: - return self.covariates.find_min_sample_rate() - - def find_max_sample_rate(self) -> float: - return self.covariates.find_max_sample_rate() - - def is_sample_rate_consistent(self, rtol: float = 1.0e-6) -> bool: - """Check whether covariates share effectively identical sample rates.""" - - rates = np.array([cov.sample_rate_hz for cov in self.covariates.covariates], dtype=float) - return bool(np.allclose(rates, rates[0], rtol=rtol)) diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index eccd5f91..00000000 --- a/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Test utilities and regression suites for nSTAT-python.""" diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..30b590cf --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +import sys +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +SRC_ROOT = REPO_ROOT / "src" + +if str(SRC_ROOT) not in sys.path: + sys.path.insert(0, str(SRC_ROOT)) +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) diff --git a/tests/parity/class_behavior_specs.yml b/tests/parity/class_behavior_specs.yml deleted file mode 100644 index 781fbf7e..00000000 --- a/tests/parity/class_behavior_specs.yml +++ /dev/null @@ -1,302 +0,0 @@ -version: 1 -description: "Method-level input/output behavior contracts for all mapped MATLAB classes" - -classes: - - matlab_class: SignalObj - python_class: nstat.signal.Signal - scenario: signal_basic - contracts: - - member: n_samples - access: property - expect: - equals: 5 - - member: n_channels - access: property - expect: - equals: 1 - - member: sample_rate_hz - access: property - expect: - approx: 2.0 - abs_tol: 1.0e-12 - - member: duration_s - access: property - expect: - approx: 2.0 - abs_tol: 1.0e-12 - - member: copy - access: method - expect: - instance_of: nstat.signal.Signal - - - matlab_class: Covariate - python_class: nstat.signal.Covariate - scenario: covariate_basic - contracts: - - member: n_channels - access: property - expect: - equals: 2 - - member: labels - access: property - expect: - equals: - - stim1 - - stim2 - - - matlab_class: ConfidenceInterval - python_class: nstat.confidence.ConfidenceInterval - scenario: confidence_basic - contracts: - - member: width - access: method - expect: - shape: [5] - sum_approx: 2.5 - abs_tol: 1.0e-12 - - member: contains - access: method - args_key: contains_args - expect: - equals: - - true - - true - - true - - false - - false - - - matlab_class: Events - python_class: nstat.events.Events - scenario: events_basic - contracts: - - member: subset - access: method - args: [0.0, 0.5] - expect: - instance_of: nstat.events.Events - - member: subset - access: method - args: [0.0, 0.5] - extract: times - expect: - equals: - - 0.1 - - 0.4 - - - matlab_class: History - python_class: nstat.history.HistoryBasis - scenario: history_basic - contracts: - - member: n_bins - access: property - expect: - equals: 3 - - member: design_matrix - access: method - args_key: design_args - expect: - shape: [4, 3] - min: 0.0 - sum_approx: 5.0 - abs_tol: 1.0e-12 - - - matlab_class: nspikeTrain - python_class: nstat.spikes.SpikeTrain - scenario: spike_train_basic - contracts: - - member: firing_rate_hz - access: method - expect: - approx: 4.0 - abs_tol: 1.0e-12 - - member: bin_counts - access: method - args: [0.1] - select: 1 - expect: - shape: [10] - sum_approx: 4.0 - abs_tol: 1.0e-12 - - member: binarize - access: method - args: [0.1] - select: 1 - expect: - shape: [10] - min: 0.0 - max: 1.0 - - - matlab_class: nstColl - python_class: nstat.spikes.SpikeTrainCollection - scenario: spike_coll_basic - contracts: - - member: n_units - access: property - expect: - equals: 2 - - member: to_binned_matrix - access: method - kwargs: - bin_size_s: 0.1 - mode: count - select: 1 - expect: - shape: [2, 10] - sum_approx: 7.0 - abs_tol: 1.0e-12 - - - matlab_class: CovColl - python_class: nstat.trial.CovariateCollection - scenario: covcoll_basic - contracts: - - member: time - access: property - expect: - shape: [5] - - member: design_matrix - access: method - select: 0 - expect: - shape: [5, 3] - finite: true - - - matlab_class: TrialConfig - python_class: nstat.trial.TrialConfig - scenario: trial_config_basic - contracts: - - member: sample_rate_hz - access: property - expect: - approx: 1000.0 - abs_tol: 1.0e-12 - - member: fit_type - access: property - expect: - equals: poisson - - - matlab_class: ConfigColl - python_class: nstat.trial.ConfigCollection - scenario: config_coll_basic - contracts: - - member: configs - access: property - expect: - length: 2 - - - matlab_class: Trial - python_class: nstat.trial.Trial - scenario: trial_basic - contracts: - - member: aligned_binned_observation - access: method - kwargs: - bin_size_s: 0.1 - unit_index: 0 - mode: count - select: 1 - expect: - shape: [10] - sum_approx: 4.0 - abs_tol: 1.0e-12 - - member: aligned_binned_observation - access: method - kwargs: - bin_size_s: 0.1 - unit_index: 0 - mode: count - select: 2 - expect: - shape: [10, 3] - - - matlab_class: CIF - python_class: nstat.cif.CIFModel - scenario: cif_basic - contracts: - - member: evaluate - access: method - args_key: eval_args - expect: - shape: [5] - min: 0.0 - finite: true - - member: log_likelihood - access: method - args_key: ll_args - expect: - finite: true - - - matlab_class: Analysis - python_class: nstat.analysis.Analysis - scenario: analysis_basic - contracts: - - member: fit_glm - access: method - kwargs_key: fit_kwargs - expect: - instance_of: nstat.fit.FitResult - - member: fit_glm - access: method - kwargs_key: fit_kwargs - extract: coefficients.0 - expect: - approx_key: true_beta - abs_tol_key: binomial_glm.coefficient_abs_tol - - - matlab_class: FitResult - python_class: nstat.fit.FitResult - scenario: fit_result_basic - contracts: - - member: as_cif_model - access: method - expect: - instance_of: nstat.cif.CIFModel - - member: predict - access: method - args_key: predict_args - expect: - shape: [3] - finite: true - - member: aic - access: method - expect: - approx: 24.0 - abs_tol: 1.0e-12 - - - matlab_class: FitResSummary - python_class: nstat.fit.FitSummary - scenario: fit_summary_basic - contracts: - - member: best_by_aic - access: method - expect: - instance_of: nstat.fit.FitResult - - member: best_by_aic - access: method - extract: fit_type - expect: - equals: binomial - - - matlab_class: DecodingAlgorithms - python_class: nstat.decoding.DecodingAlgorithms - scenario: decoding_basic - contracts: - - member: compute_spike_rate_cis - access: method - args_key: ci_args - select: 0 - expect: - shape: [4] - finite: true - - member: compute_spike_rate_cis - access: method - args_key: ci_args - select: 2 - expect: - shape: [4, 4] - - member: decode_weighted_center - access: method - args_key: wc_args - expect: - shape: [6] - min: 0.0 - max: 2.0 diff --git a/tests/parity/compat_behavior_specs.yml b/tests/parity/compat_behavior_specs.yml deleted file mode 100644 index 6272aae3..00000000 --- a/tests/parity/compat_behavior_specs.yml +++ /dev/null @@ -1,2661 +0,0 @@ -version: 1 -description: "MATLAB-compat method behavior contracts for mapped nSTAT classes" - -classes: - - matlab_class: SignalObj - python_class: nstat.compat.matlab.SignalObj - scenario: compat_signal_basic - contracts: - - member: time - access: property - expect: - shape: [5] - - member: data - access: property - expect: - shape: [5] - - member: getValueAt - access: method - args: [1.0] - expect: - shape: [1] - sum_approx: 3.0 - abs_tol: 1.0e-12 - - member: derivative - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: integral - access: method - extract: 4 - expect: - approx: 4.0 - abs_tol: 1.0e-12 - - member: copySignal - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: resample - access: method - args: [4.0] - extract: n_samples - expect: - equals: 9 - - member: shift - access: method - args: [0.5] - extract: time - expect: - shape: [5] - - member: getOriginalData - access: method - expect: - shape: [5] - - member: getOrigDataSig - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setUnits - access: method - args: [spikes/sec] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setPlotProps - access: method - args_key: signal_plot_props_args - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setXUnits - access: method - args: [s] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setYUnits - access: method - args: [Hz] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setDataLabels - access: method - args_key: signal_labels_args - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: getIndexFromLabel - access: method - args_key: signal_index_arg - expect: - equals: 0 - - member: getIndicesFromLabels - access: method - args_key: signal_label_lookup_args - expect: - equals: - - 0 - - member: convertNamesToIndices - access: method - args_key: signal_label_lookup_args - expect: - equals: - - 0 - - member: plus - access: method - args: [1.0] - extract: data - expect: - shape: [5, 1] - min: 2.0 - - member: minus - access: method - args: [1.0] - extract: data - expect: - shape: [5, 1] - max: 2.0 - - member: times - access: method - args: [2.0] - extract: data - expect: - shape: [5, 1] - max: 6.0 - - member: mtimes - access: method - args: [2.0] - extract: data - expect: - shape: [5, 1] - max: 6.0 - - member: rdivide - access: method - args: [2.0] - extract: data - expect: - shape: [5, 1] - max: 1.5 - - member: ldivide - access: method - args: [2.0] - extract: data - expect: - shape: [5, 1] - min: 0.6666666 - - member: power - access: method - args: [2.0] - extract: data - expect: - shape: [5, 1] - max: 9.0 - - member: derivativeAt - access: method - args: [1.0] - expect: - shape: [1] - - member: findNearestTimeIndex - access: method - args: [1.0] - expect: - equals: 1 - - member: findNearestTimeIndices - access: method - args_key: signal_times_args - expect: - equals: - - 0 - - 1 - - 3 - - member: getSigInTimeWindow - access: method - args_key: signal_time_window_args - extract: n_samples - expect: - equals: 3 - - member: merge - access: method - args_key: signal_other_shifted_args - extract: n_channels - expect: - equals: 2 - - member: makeCompatible - access: method - args_key: signal_other_args - select: 0 - extract: n_samples - expect: - equals: 4 - - member: shiftMe - access: method - args: [0.25] - extract: time - expect: - shape: [5] - - member: setDataMask - access: method - args_key: signal_mask_args - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setMaskByInd - access: method - args_key: signal_mask_args - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setMaskByLabels - access: method - args_key: signal_names_args - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: getSubSignalFromNames - access: method - args_key: signal_names_args - extract: n_channels - expect: - equals: 1 - - member: filter - access: method - args_key: signal_filter_args - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: filtfilt - access: method - args_key: signal_filter_args - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: crosscorrelation - access: method - args_key: signal_crosscorr_args - select: 0 - expect: - equals: - - -1 - - 0 - - 1 - - member: getPlotProps - access: method - expect: - equals: - LineWidth: 2.0 - - member: plotPropsSet - access: method - expect: - equals: true - - member: areDataLabelsEmpty - access: method - expect: - equals: false - - member: isLabelPresent - access: method - args: [ch1] - expect: - equals: true - - member: dataToMatrix - access: method - expect: - shape: [5, 1] - sum_approx: 9.0 - abs_tol: 1.0e-12 - - member: getSubSignal - access: method - args: [0] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: getSubSignalFromInd - access: method - args: - - [0] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: alignToMax - access: method - extract: time - expect: - shape: [5] - min: -1.0 - max: 1.0 - - member: findGlobalPeak - access: method - select: 0 - expect: - approx: 3.0 - abs_tol: 1.0e-12 - - member: findGlobalPeak - access: method - select: 1 - expect: - approx: 0.0 - abs_tol: 1.0e-12 - - member: findGlobalPeak - access: method - select: 2 - expect: - equals: 2 - - member: findPeaks - access: method - select: 0 - expect: - shape: [1] - sum_approx: 0.0 - abs_tol: 1.0e-12 - - member: findPeaks - access: method - select: 1 - expect: - shape: [1] - sum_approx: 3.0 - abs_tol: 1.0e-12 - - member: findMinima - access: method - select: 0 - expect: - shape: [0] - - member: findMinima - access: method - select: 1 - expect: - shape: [0] - - member: setName - access: method - args: [sig_updated] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setXlabel - access: method - args: [time] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setYLabel - access: method - args: [value] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setSampleRate - access: method - args: [4.0] - extract: n_samples - expect: - equals: 9 - - member: setMinTime - access: method - args: [0.0] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setMaxTime - access: method - args: [2.0] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: setMask - access: method - args_key: signal_mask_args - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: isMaskSet - access: method - expect: - equals: false - - member: uplus - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: uminus - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: sqrt - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: ctranspose - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: transpose - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: abs - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: log - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: median - access: method - expect: - finite: true - - member: mode - access: method - expect: - finite: true - - member: mean - access: method - expect: - finite: true - - member: std - access: method - expect: - finite: true - - member: max - access: method - expect: - finite: true - - member: min - access: method - expect: - finite: true - - member: autocorrelation - access: method - expect: - length: 2 - - member: periodogram - access: method - expect: - length: 2 - - member: MTMspectrum - access: method - expect: - length: 2 - - member: spectrogram - access: method - expect: - length: 3 - - member: xcorr - access: method - expect: - length: 2 - - member: xcov - access: method - expect: - length: 2 - - member: resampleMe - access: method - args: [4.0] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: restoreToOriginal - access: method - extract: n_samples - expect: - equals: 5 - - member: resetMask - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: findIndFromDataMask - access: method - expect: - equals: - - 0 - - member: alignTime - access: method - args: [0.1] - extract: time - expect: - shape: [5] - - member: findMaxima - access: method - select: 0 - expect: - shape: [1] - - member: clearPlotProps - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: dataToStructure - access: method - expect: - length: 9 - - member: windowedSignal - access: method - args: [3] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: normWindowedSignal - access: method - args: [3] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: getSubSignalsWithinNStd - access: method - args: [1.0] - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: plot - access: method - expect: - length: 1 - - member: setupPlots - access: method - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: plotVariability - access: method - expect: - instance_of: matplotlib.collections.PolyCollection - - member: plotAllVariability - access: method - expect: - instance_of: matplotlib.collections.PolyCollection - - member: signalFromStruct - access: method - args_key: signal_from_structure_args - expect: - instance_of: nstat.compat.matlab.SignalObj - - member: convertSigStructureToStructure - access: method - args_key: signal_from_structure_args - expect: - length: 9 - - member: convertSimpleStructureToSigStructure - access: method - args_key: signal_from_structure_args - expect: - length: 9 - - member: getAvailableColor - access: method - expect: - equals: b - - member: cell2str - access: method - args_key: signal_cell2str_args - expect: - equals: a,b,c - - - matlab_class: Covariate - python_class: nstat.compat.matlab.Covariate - scenario: compat_covariate_basic - contracts: - - member: Covariate - access: method - args_key: cov_ctor_args - expect: - instance_of: nstat.compat.matlab.Covariate - - member: computeMeanPlusCI - access: method - select: 0 - expect: - shape: [5] - sum_approx: 2.1875 - abs_tol: 1.0e-12 - - member: getSubSignal - access: method - args: [1] - expect: - instance_of: nstat.compat.matlab.Covariate - - member: getSigRep - access: method - expect: - shape: [5, 2] - - member: isConfIntervalSet - access: method - expect: - equals: false - - member: copySignal - access: method - expect: - instance_of: nstat.compat.matlab.Covariate - - member: dataToStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: cov_from_structure_args - expect: - instance_of: nstat.compat.matlab.Covariate - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: plot - access: method - expect: {} - - member: setConfInterval - access: method - args_key: cov_set_ci_args - expect: - instance_of: nstat.compat.matlab.Covariate - - member: filtfilt - access: method - args_key: cov_filter_args - extract: data - expect: - shape: [5, 2] - - member: plus - access: method - args: [0.5] - extract: data - expect: - shape: [5, 2] - min: 0.5 - - member: minus - access: method - args: [0.5] - extract: data - expect: - shape: [5, 2] - max: 0.5 - - - matlab_class: ConfidenceInterval - python_class: nstat.compat.matlab.ConfidenceInterval - scenario: compat_confidence_basic - contracts: - - member: ConfidenceInterval - access: method - args_key: ci_ctor_args - expect: - instance_of: nstat.compat.matlab.ConfidenceInterval - - member: setColor - access: method - args_key: ci_set_color_args - expect: - instance_of: nstat.compat.matlab.ConfidenceInterval - - member: setValue - access: method - args_key: ci_set_value_args - expect: - instance_of: nstat.compat.matlab.ConfidenceInterval - - member: fromStructure - access: method - args_key: ci_from_structure_args - expect: - instance_of: nstat.compat.matlab.ConfidenceInterval - - member: plot - access: method - expect: {} - - - matlab_class: Events - python_class: nstat.compat.matlab.Events - scenario: compat_events_basic - contracts: - - member: Events - access: method - args_key: events_ctor_args - expect: - instance_of: nstat.compat.matlab.Events - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: events_from_structure_args - expect: - instance_of: nstat.compat.matlab.Events - - member: dsxy2figxy - access: method - args_key: events_dsxy_args - expect: - shape: [1, 2] - - member: plot - access: method - expect: {} - - - matlab_class: History - python_class: nstat.compat.matlab.History - scenario: compat_history_basic - contracts: - - member: History - access: method - args_key: history_ctor_args - expect: - instance_of: nstat.compat.matlab.History - - member: computeHistory - access: method - args_key: history_compute_args - expect: - shape: [4, 3] - sum_approx: 5.0 - abs_tol: 1.0e-12 - - member: computeNSTHistoryWindow - access: method - args_key: history_nst_window_args - expect: - shape: [4, 3] - - member: toFilter - access: method - expect: - shape: [3] - sum_approx: 1.0 - abs_tol: 1.0e-12 - - member: setWindow - access: method - args_key: history_set_window_args - extract: n_bins - expect: - equals: 3 - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: history_from_structure_args - expect: - instance_of: nstat.compat.matlab.History - - member: plot - access: method - expect: {} - - - matlab_class: nspikeTrain - python_class: nstat.compat.matlab.nspikeTrain - scenario: compat_spike_train_basic - contracts: - - member: nspikeTrain - access: method - args_key: spike_ctor_args - expect: - instance_of: nstat.compat.matlab.nspikeTrain - - member: computeRate - access: method - expect: - approx: 4.0 - abs_tol: 1.0e-12 - - member: spike_times - access: property - expect: - shape: [4] - - member: getISIs - access: method - expect: - shape: [3] - sum_approx: 0.8 - abs_tol: 1.0e-12 - - member: getMinISI - access: method - expect: - approx: 0.05 - abs_tol: 1.0e-12 - - member: getMaxBinSizeBinary - access: method - expect: - approx: 0.05 - abs_tol: 1.0e-12 - - member: getSigRep - access: method - args_key: spike_sigrep_args - expect: - shape: [10] - sum_approx: 4.0 - abs_tol: 1.0e-12 - - member: isSigRepBinary - access: method - args_key: spike_isbinary_args - expect: - equals: true - - member: nstCopy - access: method - expect: - instance_of: nstat.compat.matlab.nspikeTrain - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: spike_from_structure_args - expect: - instance_of: nstat.compat.matlab.nspikeTrain - - member: setSigRep - access: method - args_key: spike_set_sigrep_args - expect: - instance_of: nstat.compat.matlab.nspikeTrain - - member: getFieldVal - access: method - args_key: spike_get_field_name_args - expect: - equals: unit - - member: getLStatistic - access: method - expect: - approx: 1.0193441518937558 - abs_tol: 1.0e-12 - - member: setMER - access: method - args_key: spike_set_mer_args - extract: _mer - expect: - approx: 3.0 - abs_tol: 1.0e-12 - - member: setName - access: method - args_key: spike_set_name_args - extract: name - expect: - equals: unit - - member: computeStatistics - access: method - expect: - instance_of: builtins.dict - - member: setMinTime - access: method - args_key: spike_set_min_args - extract: t_start - expect: - approx: 0.05 - abs_tol: 1.0e-12 - - member: setMaxTime - access: method - args_key: spike_set_max_args - extract: t_end - expect: - approx: 0.95 - abs_tol: 1.0e-12 - - member: clearSigRep - access: method - extract: _sig_rep - expect: - equals: null - - member: resample - access: method - args_key: spike_resample_args - expect: - instance_of: nstat.compat.matlab.nspikeTrain - - member: plotISISpectrumFunction - access: method - expect: - length: 1 - - member: plotJointISIHistogram - access: method - expect: - instance_of: builtins.tuple - - member: plotISIHistogram - access: method - expect: - instance_of: builtins.tuple - - member: plotExponentialFit - access: method - expect: - length: 1 - - member: plotProbPlot - access: method - expect: - length: 1 - - member: partitionNST - access: method - args_key: spike_partition_args - expect: - length: 2 - - member: restoreToOriginal - access: method - extract: t_start - expect: - approx: 0.0 - abs_tol: 1.0e-12 - - member: plot - access: method - expect: - length: 1 - - - matlab_class: nstColl - python_class: nstat.compat.matlab.nstColl - scenario: compat_spike_coll_basic - contracts: - - member: nstColl - access: method - args_key: coll_ctor_args - expect: - instance_of: nstat.compat.matlab.nstColl - - member: copy - access: method - expect: - instance_of: nstat.spikes.SpikeTrainCollection - - member: getFirstSpikeTime - access: method - expect: - approx: 0.1 - abs_tol: 1.0e-12 - - member: getLastSpikeTime - access: method - expect: - approx: 0.9 - abs_tol: 1.0e-12 - - member: getNSTnames - access: method - expect: - equals: - - u1 - - u2 - - member: getNSTIndicesFromName - access: method - args_key: coll_name_args - expect: - equals: - - 0 - - member: getNSTnameFromInd - access: method - args_key: coll_ind_args - expect: - equals: u2 - - member: getNSTFromName - access: method - args_key: coll_name_args - expect: - instance_of: nstat.compat.matlab.nspikeTrain - - member: getNST - access: method - args_key: coll_ind_args - expect: - instance_of: nstat.compat.matlab.nspikeTrain - - member: dataToMatrix - access: method - args_key: coll_binned_args - expect: - shape: [2, 10] - sum_approx: 7.0 - abs_tol: 1.0e-12 - - member: to_binned_matrix - access: method - args: [0.1] - kwargs: - mode: count - select: 1 - expect: - shape: [2, 10] - sum_approx: 7.0 - abs_tol: 1.0e-12 - - member: getSpikeTimes - access: method - expect: - length: 2 - - member: getMinISIs - access: method - expect: - shape: [2] - min: 0.049 - - member: findMaxSampleRate - access: method - expect: - approx: 20.0 - abs_tol: 1.0e-9 - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: coll_from_structure_args - expect: - instance_of: nstat.compat.matlab.nstColl - - member: merge - access: method - args_key: coll_merge_args - extract: n_units - expect: - equals: 3 - - member: getFieldVal - access: method - args_key: coll_field_arg - expect: - length: 2 - - member: shiftTime - access: method - args_key: coll_shift_args - extract: trains.0.spike_times.0 - expect: - approx: 0.2 - abs_tol: 1.0e-12 - - member: setMask - access: method - args_key: coll_setmask_args - expect: - instance_of: nstat.compat.matlab.nstColl - - member: setNeuronMaskFromInd - access: method - args_key: coll_setneuronmask_ind_args - expect: - instance_of: nstat.compat.matlab.nstColl - - member: setNeuronMask - access: method - args_key: coll_setneuronmask_args - expect: - instance_of: nstat.compat.matlab.nstColl - - member: setNeighbors - access: method - args_key: coll_neighbors_args - expect: - instance_of: nstat.compat.matlab.nstColl - - member: areNeighborsSet - access: method - expect: - equals: true - - member: addToColl - access: method - args_key: coll_add_args - extract: n_units - expect: - equals: 3 - - member: addSingleSpikeToColl - access: method - args_key: coll_addspike_args - expect: - instance_of: nstat.compat.matlab.nstColl - - member: getNST - access: method - args_key: coll_ind0_args - extract: spike_times - expect: - shape: [5] - - member: addNeuronNamesToEnsCovColl - access: method - args_key: coll_addnames_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: generateUnitImpulseBasis - access: method - args_key: coll_basis_args - extract: data - expect: - shape: [11, 5] - - member: getMaxBinSizeBinary - access: method - expect: - approx: 0.05 - abs_tol: 1.0e-9 - - member: getNeighbors - access: method - expect: - shape: [2, 1] - - member: getIndFromMask - access: method - expect: - equals: - - 1 - - member: getIndFromMaskMinusOne - access: method - expect: - equals: - - 1 - - member: isNeuronMaskSet - access: method - expect: - equals: true - - member: getUniqueNSTnames - access: method - expect: - equals: - - u1 - - u2 - - u3 - - member: BinarySigRep - access: method - args: [0.1] - expect: - shape: [3, 12] - sum_approx: 9.0 - abs_tol: 1.0e-12 - - member: toSpikeTrain - access: method - args: [0] - extract: spike_times - expect: - shape: [10] - - member: psth - access: method - args: [0.1] - select: 0 - expect: - shape: [12] - - member: psthBars - access: method - args: [0.1] - select: 0 - expect: - shape: [12] - - member: ssglm - access: method - args: [0.1] - select: 1 - expect: - shape: [12] - - member: psthGLM - access: method - args: [0.1] - select: 1 - expect: - shape: [12] - - member: getISIs - access: method - select: 0 - expect: - shape: [4] - - member: plotISIHistogram - access: method - select: 0 - expect: - shape: [20] - - member: plotExponentialFit - access: method - expect: - length: 1 - - member: estimateVarianceAcrossTrials - access: method - args: [0.1] - expect: - shape: [12] - sum_approx: 1.7777777777777777 - abs_tol: 1.0e-12 - - member: ensureConsistancy - access: method - expect: - equals: true - - member: setMinTime - access: method - args: [0.05] - extract: trains.0.t_start - expect: - approx: 0.05 - abs_tol: 1.0e-12 - - member: setMaxTime - access: method - args: [0.95] - extract: trains.0.t_end - expect: - approx: 0.95 - abs_tol: 1.0e-12 - - member: resample - access: method - args: [5.0] - expect: - instance_of: nstat.compat.matlab.nstColl - - member: enforceSampleRate - access: method - args: [10.0] - expect: - instance_of: nstat.compat.matlab.nstColl - - member: restoreToOriginal - access: method - expect: - instance_of: nstat.compat.matlab.nstColl - - member: resetMask - access: method - expect: - instance_of: nstat.compat.matlab.nstColl - - member: updateTimes - access: method - expect: - instance_of: nstat.compat.matlab.nstColl - - member: nstColl - access: method - args_key: coll_ctor_args - expect: - instance_of: nstat.compat.matlab.nstColl - - member: isSigRepBinary - access: method - args: [0.1] - expect: - equals: false - - member: getEnsembleNeuronCovariates - access: method - args: [0.1] - expect: - instance_of: nstat.compat.matlab.CovColl - - member: plot - access: method - expect: - instance_of: matplotlib.axes._axes.Axes - - - matlab_class: CovColl - python_class: nstat.compat.matlab.CovColl - scenario: compat_covcoll_basic - contracts: - - member: getCovDimension - access: method - expect: - equals: 3 - - member: getAllCovLabels - access: method - expect: - equals: - - sine - - t - - t2 - - member: dataToMatrix - access: method - select: 0 - expect: - shape: [5, 3] - - member: dataToMatrixFromNames - access: method - args_key: covcoll_names_args - select: 0 - expect: - shape: [5, 3] - - member: dataToMatrixFromSel - access: method - args_key: covcoll_sel_args - select: 0 - expect: - shape: [5, 2] - - member: getCovIndFromName - access: method - args_key: covcoll_name_arg - expect: - equals: 1 - - member: getCovIndicesFromNames - access: method - args_key: covcoll_names_lookup_args - expect: - equals: - - 0 - - 1 - - member: isCovPresent - access: method - args_key: covcoll_present_args - expect: - equals: true - - member: numActCov - access: method - expect: - equals: 2 - - member: sumDimensions - access: method - expect: - equals: 3 - - member: findMinTime - access: method - expect: - approx: 0.0 - abs_tol: 1.0e-12 - - member: findMaxTime - access: method - expect: - approx: 1.0 - abs_tol: 1.0e-12 - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: covcoll_from_structure_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: containsChars - access: method - args_key: covcoll_contains_args - expect: - equals: true - - member: parseDataSelectorArray - access: method - args_key: covcoll_parse_args - expect: - equals: - - 0 - - member: covIndFromSelector - access: method - args_key: covcoll_from_selector_args - expect: - equals: - - 0 - - member: generateRemainingIndex - access: method - args_key: covcoll_remaining_args - expect: - equals: - - 1 - - member: flattenCovMask - access: method - args_key: covcoll_flat_mask_args - expect: - equals: - - 0 - - 1 - - member: generateSelectorCell - access: method - args_key: covcoll_selector_mask_args - expect: - equals: - - sine - - poly - - member: getSelectorFromMasks - access: method - args_key: covcoll_selector_mask_args - expect: - equals: - - sine - - poly - - member: setMask - access: method - args_key: covcoll_mask_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: setMasksFromSelector - access: method - args_key: covcoll_masks_selector_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: addSingleCovToColl - access: method - args_key: covcoll_add_single_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: numActCov - access: method - expect: - equals: 3 - - member: addToColl - access: method - args_key: covcoll_add_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: numActCov - access: method - expect: - equals: 4 - - member: addCovCellToColl - access: method - args_key: covcoll_add_cell_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: numActCov - access: method - expect: - equals: 5 - - member: addCovCollection - access: method - args_key: covcoll_add_collection_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: numActCov - access: method - expect: - equals: 6 - - member: removeFromCollByIndices - access: method - args_key: covcoll_remove_indices_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: numActCov - access: method - expect: - equals: 5 - - member: copy - access: method - expect: - instance_of: nstat.compat.matlab.CovColl - - member: getCov - access: method - args_key: covcoll_get_cov_args - expect: - instance_of: nstat.compat.matlab.Covariate - - member: getCovMaskFromSelector - access: method - args_key: covcoll_mask_args - expect: - equals: - - 0 - - member: isaSelectorCell - access: method - args_key: covcoll_selector_cell_args - expect: - equals: true - - member: setMinTime - access: method - args_key: covcoll_set_min_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: setMaxTime - access: method - args_key: covcoll_set_max_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: restrictToTimeWindow - access: method - args_key: covcoll_restrict_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: setSampleRate - access: method - args_key: covcoll_sample_rate_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: resample - access: method - args_key: covcoll_sample_rate_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: enforceSampleRate - access: method - args_key: covcoll_sample_rate_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: updateTimes - access: method - expect: - instance_of: nstat.compat.matlab.CovColl - - member: setCovShift - access: method - args_key: covcoll_shift_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: resetCovShift - access: method - expect: - instance_of: nstat.compat.matlab.CovColl - - member: dataToStructure - access: method - expect: - instance_of: builtins.dict - - member: resetMask - access: method - expect: - instance_of: nstat.compat.matlab.CovColl - - member: isCovMaskSet - access: method - expect: - equals: true - - member: getCovDataMask - access: method - expect: - length: 5 - - member: getCovLabelsFromMask - access: method - expect: - length: 5 - - member: nActCovar - access: method - expect: - equals: 5 - - member: maskAwayCov - access: method - args_key: covcoll_mask_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: maskAwayOnlyCov - access: method - args_key: covcoll_mask_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: maskAwayAllExcept - access: method - args_key: covcoll_mask_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: plot - access: method - expect: - instance_of: builtins.list - - member: removeCovariate - access: method - args_key: covcoll_remove_name_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: removeFromColl - access: method - args_key: covcoll_remove_from_coll_args - expect: - instance_of: nstat.compat.matlab.CovColl - - member: numActCov - access: method - expect: - equals: 3 - - member: restoreToOriginal - access: method - expect: - instance_of: nstat.compat.matlab.CovColl - - member: numActCov - access: method - expect: - equals: 2 - - - matlab_class: TrialConfig - python_class: nstat.compat.matlab.TrialConfig - scenario: compat_trial_config_basic - contracts: - - member: getName - access: method - expect: - equals: cfg - - member: getFitType - access: method - expect: - equals: poisson - - member: getSampleRate - access: method - expect: - approx: 1000.0 - abs_tol: 1.0e-12 - - member: getCovariateLabels - access: method - expect: - equals: - - stim - - member: setName - access: method - args_key: trial_cfg_set_name_args - extract: name - expect: - equals: cfg2 - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: trial_cfg_from_structure_args - expect: - instance_of: nstat.compat.matlab.TrialConfig - - member: setConfig - access: method - args_key: trial_cfg_set_config_args - expect: - instance_of: nstat.compat.matlab.TrialConfig - - - matlab_class: ConfigColl - python_class: nstat.compat.matlab.ConfigColl - scenario: compat_config_coll_basic - contracts: - - member: ConfigColl - access: method - args_key: config_ctor_args - expect: - instance_of: nstat.compat.matlab.ConfigColl - - member: getConfigNames - access: method - expect: - equals: - - cfg - - member: getConfigs - access: method - expect: - length: 1 - - member: getConfig - access: method - args_key: config_get_args - expect: - instance_of: nstat.compat.matlab.TrialConfig - - member: getSubsetConfigs - access: method - args_key: config_subset_args - expect: - instance_of: nstat.compat.matlab.ConfigColl - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: config_from_structure_args - expect: - instance_of: nstat.compat.matlab.ConfigColl - - member: addConfig - access: method - args_key: config_add_args - expect: - instance_of: nstat.compat.matlab.ConfigColl - - member: setConfig - access: method - args_key: config_set_args - expect: - instance_of: nstat.compat.matlab.ConfigColl - - member: setConfigNames - access: method - args_key: config_set_names_args - expect: - instance_of: nstat.compat.matlab.ConfigColl - - - matlab_class: Trial - python_class: nstat.compat.matlab.Trial - scenario: compat_trial_basic - contracts: - - member: getDesignMatrix - access: method - select: 0 - expect: - shape: [11, 3] - - member: getSpikeVector - access: method - args_key: trial_spike_vector_args - select: 1 - expect: - shape: [10] - sum_approx: 4.0 - abs_tol: 1.0e-12 - - member: getAllCovLabels - access: method - expect: - equals: - - sine - - t - - t2 - - member: getCov - access: method - args_key: trial_cov_args - expect: - instance_of: nstat.compat.matlab.Covariate - - member: getNeuron - access: method - args_key: trial_neuron_args - expect: - instance_of: nstat.compat.matlab.nstColl - - member: getNeuronNames - access: method - expect: - equals: - - u1 - - u2 - - member: getNumUniqueNeurons - access: method - expect: - equals: 2 - - member: getUniqueNeuronNames - access: method - expect: - equals: - - u1 - - u2 - - member: getAllLabels - access: method - args_key: trial_all_labels_args - expect: - length: 5 - - member: getAlignedBinnedObservation - access: method - args_key: trial_aligned_args - select: 1 - expect: - shape: [10] - sum_approx: 4.0 - abs_tol: 1.0e-12 - - member: isSampleRateConsistent - access: method - expect: - equals: true - - member: findMinTime - access: method - expect: - approx: 0.0 - abs_tol: 1.0e-12 - - member: findMaxTime - access: method - expect: - approx: 1.0 - abs_tol: 1.0e-12 - - member: findMinSampleRate - access: method - expect: - approx: 10.0 - abs_tol: 1.0e-9 - - member: findMaxSampleRate - access: method - expect: - approx: 10.0 - abs_tol: 1.0e-9 - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: trial_from_structure_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setTrialEvents - access: method - args_key: trial_events_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setTrialPartition - access: method - args_key: trial_partition_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: getTrialPartition - access: method - expect: - length: 1 - - member: setTrialTimesFor - access: method - args_key: trial_times_for_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: updateTimePartitions - access: method - expect: - instance_of: nstat.compat.matlab.Trial - - member: setEnsCovMask - access: method - args_key: trial_ens_cov_mask_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setCovMask - access: method - args_key: trial_cov_mask_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setNeuronMask - access: method - args_key: trial_neuron_mask_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setNeighbors - access: method - args_key: trial_neighbors_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setHistory - access: method - args_key: trial_history_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setEnsCovHist - access: method - args_key: trial_ens_hist_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: getHistForNeurons - access: method - args_key: trial_hist_for_neurons_args - expect: - length: 1 - - member: flattenCovMask - access: method - args_key: trial_flat_mask_args - expect: - equals: - - 0 - - 1 - - member: flattenMask - access: method - args_key: trial_flat_mask_args - expect: - equals: - - 0 - - 1 - - member: addCov - access: method - args_key: trial_add_cov_args - extract: covariates.covariates - expect: - length: 3 - - member: removeCov - access: method - args_key: trial_remove_cov_args - extract: covariates.covariates - expect: - length: 2 - - member: shiftCovariates - access: method - args_key: trial_shift_cov_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: makeConsistentSampleRate - access: method - args_key: trial_consistent_sr_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: makeConsistentTime - access: method - expect: - instance_of: nstat.compat.matlab.Trial - - member: plotCovariates - access: method - expect: - length: 3 - - member: restoreToOriginal - access: method - expect: - instance_of: nstat.compat.matlab.Trial - - member: setEnsCovMask - access: method - args_key: trial_ens_cov_mask_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setCovMask - access: method - args_key: trial_cov_mask_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setNeuronMask - access: method - args_key: trial_neuron_mask_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setHistory - access: method - args_key: trial_history_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setEnsCovHist - access: method - args_key: trial_ens_hist_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: setTrialEvents - access: method - args_key: trial_events_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: isNeuronMaskSet - access: method - expect: - equals: true - - member: isCovMaskSet - access: method - expect: - equals: true - - member: isMaskSet - access: method - expect: - equals: true - - member: isHistSet - access: method - expect: - equals: true - - member: isEnsCovHistSet - access: method - expect: - equals: true - - member: getEnsCovMatrix - access: method - select: 0 - expect: - shape: [1000, 1] - - member: getEnsCovMatrix - access: method - select: 1 - expect: - equals: - - u1 - - member: getHistMatrices - access: method - select: 0 - expect: - shape: [1000, 2] - - member: getHistMatrices - access: method - select: 1 - expect: - shape: [1000, 2] - - member: getEnsembleNeuronCovariates - access: method - args: [0.1] - expect: - instance_of: nstat.compat.matlab.CovColl - - member: getNeuronIndFromMask - access: method - expect: - equals: - - 0 - - member: getNeuronIndFromName - access: method - args: [u1] - expect: - equals: - - 0 - - member: getCovSelectorFromMask - access: method - expect: - equals: - - sine - - member: getEvents - access: method - expect: - instance_of: nstat.compat.matlab.Events - - member: getNumHist - access: method - expect: - equals: 1 - - member: getCovLabelsFromMask - access: method - expect: - equals: - - sine - - member: getHistLabels - access: method - expect: - equals: - - hist_1 - - member: getEnsCovLabels - access: method - expect: - equals: - - u1 - - u2 - - member: getEnsCovLabelsFromMask - access: method - expect: - equals: - - u1 - - member: getLabelsFromMask - access: method - expect: - equals: - - sine - - member: resetEnsCovMask - access: method - expect: - instance_of: nstat.compat.matlab.Trial - - member: resetCovMask - access: method - expect: - instance_of: nstat.compat.matlab.Trial - - member: resetNeuronMask - access: method - expect: - instance_of: nstat.compat.matlab.Trial - - member: resetHistory - access: method - expect: - instance_of: nstat.compat.matlab.Trial - - member: resample - access: method - args: [5.0] - extract: covariates.covariates.0.time - expect: - shape: [6] - - member: resampleEnsColl - access: method - args: [5.0] - extract: covariates.0.time - expect: - shape: [6] - - member: setNeighbors - access: method - args_key: trial_neighbors_args - expect: - instance_of: nstat.compat.matlab.Trial - - member: getNeuronNeighbors - access: method - expect: - shape: [2, 1] - - member: setMinTime - access: method - args: [0.1] - extract: spikes.trains.0.t_start - expect: - approx: 0.1 - abs_tol: 1.0e-12 - - member: setMaxTime - access: method - args: [0.9] - extract: spikes.trains.0.t_end - expect: - approx: 0.9 - abs_tol: 1.0e-12 - - member: setSampleRate - access: method - args: [5.0] - expect: - instance_of: nstat.compat.matlab.Trial - - member: plotRaster - access: method - expect: - instance_of: matplotlib.axes._axes.Axes - - member: plot - access: method - expect: - instance_of: matplotlib.axes._axes.Axes - - - matlab_class: CIF - python_class: nstat.compat.matlab.CIF - scenario: compat_cif_basic - contracts: - - member: CIF - access: method - args_key: cif_from_structure_args - expect: - instance_of: nstat.compat.matlab.CIF - - member: CIFCopy - access: method - expect: - instance_of: nstat.compat.matlab.CIF - - member: evalLambdaDelta - access: method - args_key: cif_eval_args - expect: - shape: [5] - min: 0.0 - finite: true - - member: evalGradient - access: method - args_key: cif_grad_args - expect: - shape: [5, 3] - finite: true - - member: evalGradientLog - access: method - args_key: cif_grad_args - expect: - shape: [5, 3] - finite: true - - member: evalJacobian - access: method - args_key: cif_grad_args - expect: - shape: [5, 3] - finite: true - - member: evalJacobianLog - access: method - args_key: cif_grad_args - expect: - shape: [5, 3] - finite: true - - member: evalLDGamma - access: method - args_key: cif_grad_args - expect: - shape: [5] - finite: true - - member: evalLogLDGamma - access: method - args_key: cif_grad_args - expect: - shape: [5] - finite: true - - member: evalGradientLDGamma - access: method - args_key: cif_grad_args - expect: - shape: [5, 3] - finite: true - - member: evalGradientLogLDGamma - access: method - args_key: cif_grad_args - expect: - shape: [5, 3] - finite: true - - member: evalJacobianLogLDGamma - access: method - args_key: cif_grad_args - expect: - shape: [5, 3] - finite: true - - member: evalJacobianLDGamma - access: method - args_key: cif_grad_args - expect: - shape: [5, 3] - finite: true - - member: isSymBeta - access: method - expect: - equals: false - - member: evalFunctionWithVectorArgs - access: method - args_key: cif_fn_args - expect: - shape: [5] - finite: true - - member: resolveSimulinkModelName - access: method - expect: - equals: nstat_python_cif_model - - member: setSpikeTrain - access: method - args_key: cif_set_spike_args - expect: - instance_of: nstat.compat.matlab.CIF - - member: setHistory - access: method - args_key: cif_set_history_args - expect: - instance_of: nstat.compat.matlab.CIF - - member: simulateCIF - access: method - args_key: cif_sim_args - expect: {} - - member: simulateCIFByThinning - access: method - args_key: cif_sim_args - expect: {} - - member: simulateCIFByThinningFromLambda - access: method - args_key: cif_lambda_sim_args - expect: - instance_of: nstat.compat.matlab.nstColl - - - matlab_class: Analysis - python_class: nstat.compat.matlab.Analysis - scenario: compat_analysis_basic - contracts: - - member: GLMFit - access: method - args_key: glm_args - expect: - instance_of: nstat.fit.FitResult - - member: computeFitResidual - access: method - args_key: residual_args - expect: - shape: [400] - finite: true - - member: computeInvGausTrans - access: method - args_key: inv_args - expect: - shape: [125] - finite: true - - member: computeKSStats - access: method - args_key: ks_args - expect: - instance_of: builtins.dict - - member: fdr_bh - access: method - args_key: fdr_args - expect: - equals: - - true - - true - - false - - false - - member: computeHistLag - access: method - args_key: hist_lag_args - select: 0 - expect: - shape: [3] - finite: true - - member: computeNeighbors - access: method - args_key: neighbors_args - expect: - shape: [3, 1] - - member: spikeTrigAvg - access: method - args_key: sta_args - select: 0 - expect: - shape: [9] - - member: RunAnalysisForNeuron - access: method - args_key: analysis_run_neuron_args - expect: - instance_of: nstat.fit.FitResult - - member: RunAnalysisForAllNeurons - access: method - args_key: analysis_run_all_args - expect: - length: 2 - - member: plotSeqCorr - access: method - args_key: analysis_plot_seq_args - expect: - length: 1 - - member: plotFitResidual - access: method - args_key: residual_args - expect: {} - - member: plotInvGausTrans - access: method - args_key: inv_args - expect: {} - - member: KSPlot - access: method - args_key: analysis_ksplot_args - expect: {} - - member: plotCoeffs - access: method - args_key: analysis_plot_coeffs_args - expect: {} - - member: compHistEnsCoeff - access: method - args_key: analysis_comp_hist_args - expect: - finite: true - - member: computeHistLagForAll - access: method - args_key: analysis_hist_lag_all_args - expect: - instance_of: builtins.tuple - - member: bnlrCG - access: method - args_key: analysis_bnlrcg_args - expect: - instance_of: nstat.fit.FitResult - - member: compHistEnsCoeffForAll - access: method - args_key: analysis_comp_hist_all_args - expect: - length: 2 - - member: computeGrangerCausalityMatrix - access: method - args_key: analysis_granger_args - expect: - shape: [3, 3] - finite: true - - member: flatMaskCellToMat - access: method - args_key: analysis_flat_mask_args - expect: - shape: [2, 3] - - member: ksdiscrete - access: method - args_key: analysis_ksdisc_args - expect: - instance_of: builtins.dict - - - matlab_class: FitResult - python_class: nstat.compat.matlab.FitResult - scenario: compat_fit_result_basic - contracts: - - member: getCoeffs - access: method - expect: - shape: [2] - - member: getCoeffIndex - access: method - args_key: fit_coeff_index_args - expect: - equals: 0 - - member: getParam - access: method - args_key: fit_param_args - expect: - equals: binomial - - member: predict - access: method - args_key: fit_eval_args - expect: - shape: [3] - finite: true - - member: computeValLambda - access: method - args_key: fit_eval_args - expect: - shape: [3] - finite: true - - member: computePlotParams - access: method - expect: - instance_of: builtins.dict - - member: getPlotParams - access: method - expect: - instance_of: builtins.dict - - member: isValDataPresent - access: method - expect: - equals: false - - member: getUniqueLabels - access: method - expect: - equals: - - stim - - hist - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: fromStructure - access: method - args_key: fit_from_structure_args - expect: - instance_of: nstat.compat.matlab.FitResult - - member: setKSStats - access: method - args_key: fit_set_ks_args - expect: - instance_of: nstat.compat.matlab.FitResult - - member: setFitResidual - access: method - args_key: fit_set_resid_args - expect: - instance_of: nstat.compat.matlab.FitResult - - member: setInvGausStats - access: method - args_key: fit_set_inv_args - expect: - instance_of: nstat.compat.matlab.FitResult - - member: xticklabel_rotate - access: method - args_key: fit_xtick_rotate_args - expect: - instance_of: builtins.list - - member: CellArrayToStructure - access: method - args_key: fit_cell_array_args - expect: - instance_of: builtins.list - - member: getSubsetFitResult - access: method - args_key: fit_subset_args - expect: - instance_of: nstat.compat.matlab.FitResult - - member: FitResult - access: method - args_key: fit_ctor_args - expect: - instance_of: nstat.compat.matlab.FitResult - - member: setNeuronName - access: method - args_key: fit_set_name_args - extract: neuron_name - expect: - equals: n1 - - member: mergeResults - access: method - args_key: fit_merge_args - expect: - instance_of: nstat.compat.matlab.FitResSummary - - member: addParamsToFit - access: method - args_key: fit_add_params_args - extract: neuron_name - expect: - equals: n2 - - member: mapCovLabelsToUniqueLabels - access: method - expect: - equals: - - stim - - hist - - member: getHistIndex - access: method - select: 2 - expect: - equals: 1 - - member: getHistCoeffs - access: method - select: 0 - expect: - shape: [0, 1] - - member: plotHistCoeffs - access: method - expect: - length: 1 - - member: plotCoeffs - access: method - expect: - instance_of: matplotlib.container.BarContainer - - member: plotCoeffsWithoutHistory - access: method - expect: - instance_of: matplotlib.container.BarContainer - - member: plotResults - access: method - expect: - instance_of: matplotlib.axes._axes.Axes - - member: KSPlot - access: method - expect: - length: 1 - - member: plotSeqCorr - access: method - expect: - length: 1 - - member: plotInvGausTrans - access: method - expect: - length: 1 - - member: plotResidual - access: method - expect: - length: 1 - - member: plotValidation - access: method - expect: - length: 1 - - - matlab_class: FitResSummary - python_class: nstat.compat.matlab.FitResSummary - scenario: compat_fit_summary_basic - contracts: - - member: FitResSummary - access: method - args_key: summary_ctor_args - expect: - instance_of: nstat.compat.matlab.FitResSummary - - member: mapCovLabelsToUniqueLabels - access: method - expect: - equals: - - stim - - hist - - member: getDiffAIC - access: method - expect: - shape: [2] - sum_approx: 20.0 - abs_tol: 1.0e-12 - - member: getDiffBIC - access: method - expect: - shape: [2] - sum_approx: 20.0 - abs_tol: 1.0e-12 - - member: getDifflogLL - access: method - expect: - shape: [2] - sum_approx: 10.0 - abs_tol: 1.0e-12 - - member: binCoeffs - access: method - args_key: summary_bin_coeffs_args - select: 0 - expect: - shape: [10] - - member: getSigCoeffs - access: method - select: 0 - expect: - shape: [2, 2] - - member: toStructure - access: method - expect: - instance_of: builtins.dict - - member: getCoeffIndex - access: method - select: 2 - expect: - equals: 1 - - member: getCoeffs - access: method - select: 0 - expect: - shape: [2, 2] - - member: getHistCoeffs - access: method - select: 0 - expect: - shape: [1, 2] - - member: fromStructure - access: method - args_key: summary_from_structure_args - expect: - instance_of: nstat.compat.matlab.FitResSummary - - member: setCoeffRange - access: method - args_key: summary_set_coeff_range_args - expect: - instance_of: nstat.compat.matlab.FitResSummary - - member: xticklabel_rotate - access: method - args_key: summary_xtick_rotate_args - expect: - instance_of: builtins.list - - member: computeDiffMat - access: method - args_key: summary_diff_metric_args - expect: - shape: [2, 2] - - member: getUniqueLabels - access: method - expect: - equals: - - stim - - hist - - member: plotIC - access: method - expect: {} - - member: plotAllCoeffs - access: method - expect: {} - - member: plot3dCoeffSummary - access: method - expect: {} - - member: plot2dCoeffSummary - access: method - expect: {} - - member: plotKSSummary - access: method - expect: {} - - member: plotAIC - access: method - expect: {} - - member: plotBIC - access: method - expect: {} - - member: plotlogLL - access: method - expect: {} - - member: plotResidualSummary - access: method - expect: {} - - member: plotSummary - access: method - expect: {} - - member: boxPlot - access: method - expect: - instance_of: builtins.dict - - member: plotCoeffsWithoutHistory - access: method - expect: {} - - member: getHistIndex - access: method - expect: - instance_of: builtins.tuple - - member: plotHistCoeffs - access: method - expect: {} - - - matlab_class: DecodingAlgorithms - python_class: nstat.compat.matlab.DecodingAlgorithms - scenario: compat_decoding_basic - contracts: - - member: getPoolSizeCompat - access: method - expect: - equals: 0 - - member: computeSpikeRateDiffCIs - access: method - args_key: diff_args - select: 0 - expect: - shape: [4] - sum_approx: 0.0 - abs_tol: 1.0e-12 - - member: PPDecodeFilter - access: method - args_key: posterior_args - select: 0 - expect: - shape: [6] - min: 0.0 - max: 2.0 - - member: PPDecodeFilterLinear - access: method - args_key: posterior_args - select: 0 - expect: - shape: [6] - min: 0.0 - max: 2.0 - - member: PPHybridFilter - access: method - args_key: posterior_args - select: 0 - expect: - shape: [6] - min: 0.0 - max: 2.0 - - member: PPHybridFilterLinear - access: method - args_key: posterior_args - select: 0 - expect: - shape: [6] - min: 0.0 - max: 2.0 - - member: mPPCODecodeLinear - access: method - args_key: posterior_args - select: 0 - expect: - shape: [6] - min: 0.0 - max: 2.0 - - member: ComputeStimulusCIs - access: method - args_key: stim_ci_args - select: 0 - expect: - shape: [6] - min: 0.0 - max: 2.0 - - member: ukf_sigmas - access: method - args_key: ukf_sigmas_args - expect: - shape: [2, 5] - - member: ukf_ut - access: method - args_key: ukf_ut_args - select: 0 - expect: - shape: [2] - finite: true - - member: ukf - access: method - args_key: kalman_predict_args - select: 0 - expect: - shape: [2] - finite: true - - member: kalman_predict - access: method - args_key: kalman_predict_args - select: 0 - expect: - shape: [2] - finite: true - - member: kalman_update - access: method - args_key: kalman_update_args - select: 0 - expect: - shape: [2] - finite: true - - member: kalman_filter - access: method - args_key: kalman_filter_args - select: 0 - expect: - shape: [4, 2] - finite: true - - member: kalman_fixedIntervalSmoother - access: method - args_key: kalman_smoother_args - select: 0 - expect: - shape: [4, 2] - finite: true - - member: kalman_smoother - access: method - args_key: kalman_smoother_args - select: 0 - expect: - shape: [4, 2] - finite: true - - member: kalman_smootherFromFiltered - access: method - args_key: kalman_from_filtered_args - select: 0 - expect: - shape: [4, 2] - finite: true - - member: PPDecode_predict - access: method - args_key: kalman_predict_args - select: 0 - expect: - shape: [2] - finite: true - - member: PPDecode_update - access: method - args_key: kalman_update_args - select: 0 - expect: - shape: [2] - finite: true - - member: PPDecode_updateLinear - access: method - args_key: kalman_update_args - select: 0 - expect: - shape: [2] - finite: true - - member: PP_fixedIntervalSmoother - access: method - args_key: kalman_smoother_args - select: 0 - expect: - shape: [4, 2] - finite: true - - member: mPPCODecode_predict - access: method - args_key: kalman_predict_args - select: 0 - expect: - shape: [2] - finite: true - - member: mPPCODecode_update - access: method - args_key: kalman_update_args - select: 0 - expect: - shape: [2] - finite: true - - member: mPPCO_fixedIntervalSmoother - access: method - args_key: kalman_smoother_args - select: 0 - expect: - shape: [4, 2] - finite: true diff --git a/tests/parity/fixtures/analysis_poisson_glm.npz b/tests/parity/fixtures/analysis_poisson_glm.npz deleted file mode 100644 index 63def70f..00000000 Binary files a/tests/parity/fixtures/analysis_poisson_glm.npz and /dev/null differ diff --git a/tests/parity/fixtures/confidence_interval_compat.npz b/tests/parity/fixtures/confidence_interval_compat.npz deleted file mode 100644 index 4d12a55e..00000000 Binary files a/tests/parity/fixtures/confidence_interval_compat.npz and /dev/null differ diff --git a/tests/parity/fixtures/decoding_state_posterior.npz b/tests/parity/fixtures/decoding_state_posterior.npz deleted file mode 100644 index 3c63631d..00000000 Binary files a/tests/parity/fixtures/decoding_state_posterior.npz and /dev/null differ diff --git a/tests/parity/fixtures/fit_result_roundtrip.npz b/tests/parity/fixtures/fit_result_roundtrip.npz deleted file mode 100644 index a0b0a334..00000000 Binary files a/tests/parity/fixtures/fit_result_roundtrip.npz and /dev/null differ diff --git a/tests/parity/fixtures/fit_summary_structure.npz b/tests/parity/fixtures/fit_summary_structure.npz deleted file mode 100644 index e0c77e43..00000000 Binary files a/tests/parity/fixtures/fit_summary_structure.npz and /dev/null differ diff --git a/tests/parity/fixtures/manifest.yml b/tests/parity/fixtures/manifest.yml deleted file mode 100644 index 70f28c88..00000000 --- a/tests/parity/fixtures/manifest.yml +++ /dev/null @@ -1,29 +0,0 @@ -version: 1 -policy: - purpose: regression_guard - matlab_reference_upgrade_expected: true -fixtures: -- path: tests/parity/fixtures/analysis_poisson_glm.npz - sha256: 556257628fff2df24e6471a0e5fb76a29754762cdaeffe009c3e3cce0e6b58bb - name: analysis_poisson_glm - source: python_seeded_reference -- path: tests/parity/fixtures/decoding_state_posterior.npz - sha256: e01cd0b6911332db18790dfd6a43e6fe3e8784471c5b59ff7eeef67d78ba4ecf - name: decoding_state_posterior - source: python_seeded_reference -- path: tests/parity/fixtures/trial_alignment.npz - sha256: fcfd4eb5d871f3395ee4b3c77afec873a3a226ff24410f3dde4e80f22f90b343 - name: trial_alignment - source: python_seeded_reference -- path: tests/parity/fixtures/fit_summary_structure.npz - sha256: 6471af684b4acd0dad0092435e13c8afd0c8b0115577396893bb822a96131834 - name: fit_summary_structure - source: python_seeded_reference -- path: tests/parity/fixtures/fit_result_roundtrip.npz - sha256: 1f86bc65628abfd544b9587c4b1b1594fd2395e442aaa4b5dae3ab9bf34b493e - name: fit_result_roundtrip - source: python_seeded_reference -- path: tests/parity/fixtures/confidence_interval_compat.npz - sha256: a0628ae325371bc30a8e1c4ea0f1f760ca33a4c13f28c28051adb88f9fbeeb95 - name: confidence_interval_compat - source: python_seeded_reference diff --git a/tests/parity/fixtures/matlab_gold/AnalysisExamples2_audit_gold.json b/tests/parity/fixtures/matlab_gold/AnalysisExamples2_audit_gold.json deleted file mode 100644 index 21f15652..00000000 --- a/tests/parity/fixtures/matlab_gold/AnalysisExamples2_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "AnalysisExamples2", - "alignment_status": "validated", - "matlab_code_lines": 61, - "matlab_reference_image_count": 6, - "min_assertion_count": 2, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/AnalysisExamples_gold.mat b/tests/parity/fixtures/matlab_gold/AnalysisExamples_gold.mat deleted file mode 100644 index 7ae2121f..00000000 Binary files a/tests/parity/fixtures/matlab_gold/AnalysisExamples_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/ConfigCollExamples_audit_gold.json b/tests/parity/fixtures/matlab_gold/ConfigCollExamples_audit_gold.json deleted file mode 100644 index 27ef1f30..00000000 --- a/tests/parity/fixtures/matlab_gold/ConfigCollExamples_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "ConfigCollExamples", - "alignment_status": "validated", - "matlab_code_lines": 3, - "matlab_reference_image_count": 0, - "min_assertion_count": 4, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat b/tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat deleted file mode 100644 index 679c686b..00000000 Binary files a/tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/CovariateExamples_audit_gold.json b/tests/parity/fixtures/matlab_gold/CovariateExamples_audit_gold.json deleted file mode 100644 index 10a14f54..00000000 --- a/tests/parity/fixtures/matlab_gold/CovariateExamples_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "CovariateExamples", - "alignment_status": "validated", - "matlab_code_lines": 19, - "matlab_reference_image_count": 3, - "min_assertion_count": 4, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 2, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/DecodingExampleWithHist_gold.mat b/tests/parity/fixtures/matlab_gold/DecodingExampleWithHist_gold.mat deleted file mode 100644 index 365ec32b..00000000 Binary files a/tests/parity/fixtures/matlab_gold/DecodingExampleWithHist_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/DecodingExample_gold.mat b/tests/parity/fixtures/matlab_gold/DecodingExample_gold.mat deleted file mode 100644 index 6e152f4d..00000000 Binary files a/tests/parity/fixtures/matlab_gold/DecodingExample_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/DocumentationSetup2025b_audit_gold.json b/tests/parity/fixtures/matlab_gold/DocumentationSetup2025b_audit_gold.json deleted file mode 100644 index 1f16814f..00000000 --- a/tests/parity/fixtures/matlab_gold/DocumentationSetup2025b_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "DocumentationSetup2025b", - "alignment_status": "matlab_doc_only", - "matlab_code_lines": 0, - "matlab_reference_image_count": 0, - "min_assertion_count": 3, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/EventsExamples_gold.mat b/tests/parity/fixtures/matlab_gold/EventsExamples_gold.mat deleted file mode 100644 index d3b8d1d7..00000000 Binary files a/tests/parity/fixtures/matlab_gold/EventsExamples_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/ExplicitStimulusWhiskerData_gold.mat b/tests/parity/fixtures/matlab_gold/ExplicitStimulusWhiskerData_gold.mat deleted file mode 100644 index 9b992568..00000000 Binary files a/tests/parity/fixtures/matlab_gold/ExplicitStimulusWhiskerData_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/FitResSummaryExamples_audit_gold.json b/tests/parity/fixtures/matlab_gold/FitResSummaryExamples_audit_gold.json deleted file mode 100644 index 2d09adef..00000000 --- a/tests/parity/fixtures/matlab_gold/FitResSummaryExamples_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "FitResSummaryExamples", - "alignment_status": "matlab_doc_only", - "matlab_code_lines": 0, - "matlab_reference_image_count": 0, - "min_assertion_count": 3, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/FitResultExamples_audit_gold.json b/tests/parity/fixtures/matlab_gold/FitResultExamples_audit_gold.json deleted file mode 100644 index 3f03e4c5..00000000 --- a/tests/parity/fixtures/matlab_gold/FitResultExamples_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "FitResultExamples", - "alignment_status": "matlab_doc_only", - "matlab_code_lines": 0, - "matlab_reference_image_count": 0, - "min_assertion_count": 3, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/FitResultReference_audit_gold.json b/tests/parity/fixtures/matlab_gold/FitResultReference_audit_gold.json deleted file mode 100644 index f3b2f88b..00000000 --- a/tests/parity/fixtures/matlab_gold/FitResultReference_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "FitResultReference", - "alignment_status": "matlab_doc_only", - "matlab_code_lines": 0, - "matlab_reference_image_count": 0, - "min_assertion_count": 3, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/HippocampalPlaceCellExample_gold.mat b/tests/parity/fixtures/matlab_gold/HippocampalPlaceCellExample_gold.mat deleted file mode 100644 index 154fb591..00000000 Binary files a/tests/parity/fixtures/matlab_gold/HippocampalPlaceCellExample_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/HistoryExamples_audit_gold.json b/tests/parity/fixtures/matlab_gold/HistoryExamples_audit_gold.json deleted file mode 100644 index 102bc606..00000000 --- a/tests/parity/fixtures/matlab_gold/HistoryExamples_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "HistoryExamples", - "alignment_status": "validated", - "matlab_code_lines": 18, - "matlab_reference_image_count": 5, - "min_assertion_count": 3, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat b/tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat deleted file mode 100644 index 280a1b45..00000000 Binary files a/tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/HybridFilterExample_audit_gold.json b/tests/parity/fixtures/matlab_gold/HybridFilterExample_audit_gold.json deleted file mode 100644 index c70a879d..00000000 --- a/tests/parity/fixtures/matlab_gold/HybridFilterExample_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "HybridFilterExample", - "alignment_status": "validated", - "matlab_code_lines": 288, - "matlab_reference_image_count": 3, - "min_assertion_count": 2, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 2, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/HybridFilterExample_gold.mat b/tests/parity/fixtures/matlab_gold/HybridFilterExample_gold.mat deleted file mode 100644 index 1db919eb..00000000 Binary files a/tests/parity/fixtures/matlab_gold/HybridFilterExample_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/NetworkTutorial_audit_gold.json b/tests/parity/fixtures/matlab_gold/NetworkTutorial_audit_gold.json deleted file mode 100644 index bd24323d..00000000 --- a/tests/parity/fixtures/matlab_gold/NetworkTutorial_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "NetworkTutorial", - "alignment_status": "validated", - "matlab_code_lines": 88, - "matlab_reference_image_count": 8, - "min_assertion_count": 2, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 5, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/NetworkTutorial_gold.mat b/tests/parity/fixtures/matlab_gold/NetworkTutorial_gold.mat deleted file mode 100644 index a4da7c55..00000000 Binary files a/tests/parity/fixtures/matlab_gold/NetworkTutorial_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/PPSimExample_gold.mat b/tests/parity/fixtures/matlab_gold/PPSimExample_gold.mat deleted file mode 100644 index c96cd49f..00000000 Binary files a/tests/parity/fixtures/matlab_gold/PPSimExample_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/PPThinning_audit_gold.json b/tests/parity/fixtures/matlab_gold/PPThinning_audit_gold.json deleted file mode 100644 index 08f6abc6..00000000 --- a/tests/parity/fixtures/matlab_gold/PPThinning_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "PPThinning", - "alignment_status": "validated", - "matlab_code_lines": 40, - "matlab_reference_image_count": 5, - "min_assertion_count": 3, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 4, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/PPThinning_gold.mat b/tests/parity/fixtures/matlab_gold/PPThinning_gold.mat deleted file mode 100644 index 681ea9e0..00000000 Binary files a/tests/parity/fixtures/matlab_gold/PPThinning_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/PSTHEstimation_gold.mat b/tests/parity/fixtures/matlab_gold/PSTHEstimation_gold.mat deleted file mode 100644 index b0de27cc..00000000 Binary files a/tests/parity/fixtures/matlab_gold/PSTHEstimation_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/SignalObjExamples_audit_gold.json b/tests/parity/fixtures/matlab_gold/SignalObjExamples_audit_gold.json deleted file mode 100644 index 7816aabb..00000000 --- a/tests/parity/fixtures/matlab_gold/SignalObjExamples_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "SignalObjExamples", - "alignment_status": "validated", - "matlab_code_lines": 81, - "matlab_reference_image_count": 21, - "min_assertion_count": 4, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 6, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat b/tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat deleted file mode 100644 index 15f52a54..00000000 Binary files a/tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/SpikeRateDiffCIs_gold.mat b/tests/parity/fixtures/matlab_gold/SpikeRateDiffCIs_gold.mat deleted file mode 100644 index 0fb5d8ef..00000000 Binary files a/tests/parity/fixtures/matlab_gold/SpikeRateDiffCIs_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/StimulusDecode2D_audit_gold.json b/tests/parity/fixtures/matlab_gold/StimulusDecode2D_audit_gold.json deleted file mode 100644 index a3caf7fa..00000000 --- a/tests/parity/fixtures/matlab_gold/StimulusDecode2D_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "StimulusDecode2D", - "alignment_status": "validated", - "matlab_code_lines": 92, - "matlab_reference_image_count": 7, - "min_assertion_count": 2, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/StimulusDecode2D_gold.mat b/tests/parity/fixtures/matlab_gold/StimulusDecode2D_gold.mat deleted file mode 100644 index f2b85b88..00000000 Binary files a/tests/parity/fixtures/matlab_gold/StimulusDecode2D_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/TrialConfigExamples_audit_gold.json b/tests/parity/fixtures/matlab_gold/TrialConfigExamples_audit_gold.json deleted file mode 100644 index 2138adca..00000000 --- a/tests/parity/fixtures/matlab_gold/TrialConfigExamples_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "TrialConfigExamples", - "alignment_status": "validated", - "matlab_code_lines": 3, - "matlab_reference_image_count": 0, - "min_assertion_count": 4, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/TrialExamples_gold.mat b/tests/parity/fixtures/matlab_gold/TrialExamples_gold.mat deleted file mode 100644 index 1c9a570f..00000000 Binary files a/tests/parity/fixtures/matlab_gold/TrialExamples_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/ValidationDataSet_audit_gold.json b/tests/parity/fixtures/matlab_gold/ValidationDataSet_audit_gold.json deleted file mode 100644 index 3b43b84d..00000000 --- a/tests/parity/fixtures/matlab_gold/ValidationDataSet_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "ValidationDataSet", - "alignment_status": "validated", - "matlab_code_lines": 77, - "matlab_reference_image_count": 13, - "min_assertion_count": 3, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/ValidationDataSet_gold.mat b/tests/parity/fixtures/matlab_gold/ValidationDataSet_gold.mat deleted file mode 100644 index 8262ccd2..00000000 Binary files a/tests/parity/fixtures/matlab_gold/ValidationDataSet_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/classes/CIF/basic.mat b/tests/parity/fixtures/matlab_gold/classes/CIF/basic.mat deleted file mode 100644 index 81e02193..00000000 Binary files a/tests/parity/fixtures/matlab_gold/classes/CIF/basic.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/classes/ConfidenceInterval/basic.mat b/tests/parity/fixtures/matlab_gold/classes/ConfidenceInterval/basic.mat deleted file mode 100644 index 7fd7deba..00000000 Binary files a/tests/parity/fixtures/matlab_gold/classes/ConfidenceInterval/basic.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/classes/ConfigColl/basic.mat b/tests/parity/fixtures/matlab_gold/classes/ConfigColl/basic.mat deleted file mode 100644 index 2a38fb8c..00000000 Binary files a/tests/parity/fixtures/matlab_gold/classes/ConfigColl/basic.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/classes/FitResSummary/basic.mat b/tests/parity/fixtures/matlab_gold/classes/FitResSummary/basic.mat deleted file mode 100644 index 3ba797be..00000000 Binary files a/tests/parity/fixtures/matlab_gold/classes/FitResSummary/basic.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/classes/FitResult/basic.mat b/tests/parity/fixtures/matlab_gold/classes/FitResult/basic.mat deleted file mode 100644 index 5475e62c..00000000 Binary files a/tests/parity/fixtures/matlab_gold/classes/FitResult/basic.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/classes/TrialConfig/basic.mat b/tests/parity/fixtures/matlab_gold/classes/TrialConfig/basic.mat deleted file mode 100644 index 24c0e876..00000000 Binary files a/tests/parity/fixtures/matlab_gold/classes/TrialConfig/basic.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/mEPSCAnalysis_gold.mat b/tests/parity/fixtures/matlab_gold/mEPSCAnalysis_gold.mat deleted file mode 100644 index 54557b59..00000000 Binary files a/tests/parity/fixtures/matlab_gold/mEPSCAnalysis_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/manifest.yml b/tests/parity/fixtures/matlab_gold/manifest.yml deleted file mode 100644 index 58441038..00000000 --- a/tests/parity/fixtures/matlab_gold/manifest.yml +++ /dev/null @@ -1,157 +0,0 @@ -version: 1 -fixtures: -- name: PPSimExample - path: tests/parity/fixtures/matlab_gold/PPSimExample_gold.mat - sha256: d2073978069438c499aa972562d46bb0d69737eb0333885a2d3456d5a298a765 - source: matlab_batch_export - fixture_type: numeric -- name: DecodingExampleWithHist - path: tests/parity/fixtures/matlab_gold/DecodingExampleWithHist_gold.mat - sha256: 475f2420263e04414f5d71e387f4541278e000785f4b75f1e905b37dc8191578 - source: matlab_batch_export - fixture_type: numeric -- name: HippocampalPlaceCellExample - path: tests/parity/fixtures/matlab_gold/HippocampalPlaceCellExample_gold.mat - sha256: 32eda491374c0219e35afef8e715056c8d751077204a3f103077bd879d8f65c3 - source: matlab_batch_export - fixture_type: numeric -- name: SpikeRateDiffCIs - path: tests/parity/fixtures/matlab_gold/SpikeRateDiffCIs_gold.mat - sha256: dbd2eb12dcc0c5113b6ad2c5eebfa0fbd77d0f1f5fe31e32bee43a20a37da634 - source: matlab_batch_export - fixture_type: numeric -- name: PSTHEstimation - path: tests/parity/fixtures/matlab_gold/PSTHEstimation_gold.mat - sha256: 568a9ae7a80e39be0b8ea566472dcc501f1e1406a1a512e3443cedecfbb53254 - source: matlab_batch_export - fixture_type: numeric -- name: nstCollExamples - path: tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat - sha256: 0f7bc66aadc931b6847a3004d67ab0532d43d9a5aa70a6eadc7558e81ca69c95 - source: matlab_batch_export - fixture_type: numeric -- name: TrialExamples - path: tests/parity/fixtures/matlab_gold/TrialExamples_gold.mat - sha256: bbdf2d0c1fff4bf43fd9af83f6af332c4665b608ddada556bc913a9b78def456 - source: matlab_batch_export - fixture_type: numeric -- name: CovCollExamples - path: tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat - sha256: d6d253776f47efc5c63ba9eb61638682158887f978fc09b12b619ef22fb242dd - source: matlab_batch_export - fixture_type: numeric -- name: EventsExamples - path: tests/parity/fixtures/matlab_gold/EventsExamples_gold.mat - sha256: de40ebb042f65eaa0bbd418fe054df880a45f46bb23ae99f3b44f5a47b237495 - source: matlab_batch_export - fixture_type: numeric -- name: AnalysisExamples - path: tests/parity/fixtures/matlab_gold/AnalysisExamples_gold.mat - sha256: 5b8abe3559bcfd76dcddbe535e3ccf8f848f8adca1021be0b38d2170314105cc - source: matlab_batch_export - fixture_type: numeric -- name: DecodingExample - path: tests/parity/fixtures/matlab_gold/DecodingExample_gold.mat - sha256: e88f7b5375b276419956272ffdb8b9d94392f6a647bb35b2aaf6235fd7260756 - source: matlab_batch_export - fixture_type: numeric -- name: ExplicitStimulusWhiskerData - path: tests/parity/fixtures/matlab_gold/ExplicitStimulusWhiskerData_gold.mat - sha256: 10767bf1b29c9953fb9aa560601d2fb3ba5a69298381f2982436f0460a3b20c7 - source: matlab_batch_export - fixture_type: numeric -- name: mEPSCAnalysis - path: tests/parity/fixtures/matlab_gold/mEPSCAnalysis_gold.mat - sha256: 67d5a9dcffe0b43089dcb6439c59167afeebbc698e90b4d4c56e868930fee5e1 - source: matlab_batch_export - fixture_type: numeric -- name: HybridFilterExample - path: tests/parity/fixtures/matlab_gold/HybridFilterExample_gold.mat - sha256: d89eb15adcfaa1b68a59831901a7711c731a7ceae383bbb6c0559ba35203bc1f - source: matlab_batch_export - fixture_type: numeric -- name: ValidationDataSet - path: tests/parity/fixtures/matlab_gold/ValidationDataSet_gold.mat - sha256: 04697d36296a8ccf0c8c6d14b63bf5c4d04b75e2f3908363265406e51aa30cd4 - source: matlab_batch_export - fixture_type: numeric -- name: StimulusDecode2D - path: tests/parity/fixtures/matlab_gold/StimulusDecode2D_gold.mat - sha256: 620e0f99897fba7752277817ce93a40b39a495ddc08b51ccd30ef136e7e6f6d4 - source: matlab_batch_export - fixture_type: numeric -- name: SignalObjExamples - path: tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat - sha256: 2cabfaa7d3a4913952bfa1f9989203da981adf0c0e003b32bad4f88eb5bb50dd - source: matlab_batch_export - fixture_type: numeric -- name: HistoryExamples - path: tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat - sha256: a38ac480f26c8840320b5c6318bba8f4e2bb6226a7408a7752e401c455362908 - source: matlab_batch_export - fixture_type: numeric -- name: PPThinning - path: tests/parity/fixtures/matlab_gold/PPThinning_gold.mat - sha256: fc7b6f1e31a35b0ba52bafd617ddd09ddcb41f21a891c493a25d552800977c75 - source: matlab_batch_export - fixture_type: numeric -- name: NetworkTutorial - path: tests/parity/fixtures/matlab_gold/NetworkTutorial_gold.mat - sha256: 0a2a56c8364ceac9e4d883cd603a591d3fbb721ce9fab17b618bbdcb108112ac - source: matlab_batch_export - fixture_type: numeric -- name: AnalysisExamples2 - path: tests/parity/fixtures/matlab_gold/AnalysisExamples2_audit_gold.json - sha256: dda68f120bffeb4027000ed28a1c9656cad4acf2a3346bc898a945bee25486c6 - source: equivalence_audit_export - fixture_type: topic_audit -- name: ConfigCollExamples - path: tests/parity/fixtures/matlab_gold/ConfigCollExamples_audit_gold.json - sha256: f22515244492366248c3ae5f23d440f54e9a272255e8c74184c60c97a14924df - source: equivalence_audit_export - fixture_type: topic_audit -- name: CovariateExamples - path: tests/parity/fixtures/matlab_gold/CovariateExamples_audit_gold.json - sha256: 9d3a359d13235aac6dda92ff5913db158be6684dbbf26242cdc4cfab9cd5b91e - source: equivalence_audit_export - fixture_type: topic_audit -- name: DocumentationSetup2025b - path: tests/parity/fixtures/matlab_gold/DocumentationSetup2025b_audit_gold.json - sha256: 05a73d2e5204a0cf28e1f19687b898b083447df6b9efe92a8d58a7713b059bef - source: equivalence_audit_export - fixture_type: topic_audit -- name: FitResSummaryExamples - path: tests/parity/fixtures/matlab_gold/FitResSummaryExamples_audit_gold.json - sha256: e8268c66a4751f100f1fc884e6a13224d2d5fce2f5a2b8f109f22679a874b643 - source: equivalence_audit_export - fixture_type: topic_audit -- name: FitResultExamples - path: tests/parity/fixtures/matlab_gold/FitResultExamples_audit_gold.json - sha256: d82037f30b9fa211fa094dada9f6b26787bddabf256a909db0355a893ad0852c - source: equivalence_audit_export - fixture_type: topic_audit -- name: FitResultReference - path: tests/parity/fixtures/matlab_gold/FitResultReference_audit_gold.json - sha256: 4cf27f92324db28f5bce69d8d9cfadfe4caa62282a18abcc0b9c4a4faab0fa0a - source: equivalence_audit_export - fixture_type: topic_audit -- name: TrialConfigExamples - path: tests/parity/fixtures/matlab_gold/TrialConfigExamples_audit_gold.json - sha256: 759be3e852251f6bc2a9f8ab524110eafe0603dac356ad3d923b8d3a1c1c5b01 - source: equivalence_audit_export - fixture_type: topic_audit -- name: nSTATPaperExamples - path: tests/parity/fixtures/matlab_gold/nSTATPaperExamples_audit_gold.json - sha256: 7bf58953de236c90e4b3cf6b796a4512bb0f15c50a46de9968e881f6c2c1c215 - source: equivalence_audit_export - fixture_type: topic_audit -- name: nSpikeTrainExamples - path: tests/parity/fixtures/matlab_gold/nSpikeTrainExamples_audit_gold.json - sha256: 4db9ab45939e21b1e04365bb47cc3004bb763c1f6c270b1959ade867be123620 - source: equivalence_audit_export - fixture_type: topic_audit -- name: publish_all_helpfiles - path: tests/parity/fixtures/matlab_gold/publish_all_helpfiles_audit_gold.json - sha256: efee9081567a606468929d222fb1371c6f17db18912d888b8c4dffd52f5457b3 - source: equivalence_audit_export - fixture_type: topic_audit diff --git a/tests/parity/fixtures/matlab_gold/nSTATPaperExamples_audit_gold.json b/tests/parity/fixtures/matlab_gold/nSTATPaperExamples_audit_gold.json deleted file mode 100644 index 4e11d677..00000000 --- a/tests/parity/fixtures/matlab_gold/nSTATPaperExamples_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "nSTATPaperExamples", - "alignment_status": "validated", - "matlab_code_lines": 1576, - "matlab_reference_image_count": 26, - "min_assertion_count": 15, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/nSTATPaperExamples_plot_gold.mat b/tests/parity/fixtures/matlab_gold/nSTATPaperExamples_plot_gold.mat deleted file mode 100644 index 95968377..00000000 Binary files a/tests/parity/fixtures/matlab_gold/nSTATPaperExamples_plot_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/nSpikeTrainExamples_audit_gold.json b/tests/parity/fixtures/matlab_gold/nSpikeTrainExamples_audit_gold.json deleted file mode 100644 index 54030d50..00000000 --- a/tests/parity/fixtures/matlab_gold/nSpikeTrainExamples_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "nSpikeTrainExamples", - "alignment_status": "validated", - "matlab_code_lines": 10, - "matlab_reference_image_count": 6, - "min_assertion_count": 4, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat b/tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat deleted file mode 100644 index 8db216ca..00000000 Binary files a/tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat and /dev/null differ diff --git a/tests/parity/fixtures/matlab_gold/publish_all_helpfiles_audit_gold.json b/tests/parity/fixtures/matlab_gold/publish_all_helpfiles_audit_gold.json deleted file mode 100644 index 4fedfe5f..00000000 --- a/tests/parity/fixtures/matlab_gold/publish_all_helpfiles_audit_gold.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": 1, - "topic": "publish_all_helpfiles", - "alignment_status": "validated", - "matlab_code_lines": 126, - "matlab_reference_image_count": 0, - "min_assertion_count": 14, - "require_topic_checkpoint": true, - "min_python_validation_image_count": 1, - "require_plot_call": true, - "source": "equivalence_audit_report", - "equivalence_report": "parity/function_example_alignment_report.json" -} diff --git a/tests/parity/fixtures/trial_alignment.npz b/tests/parity/fixtures/trial_alignment.npz deleted file mode 100644 index 3118e493..00000000 Binary files a/tests/parity/fixtures/trial_alignment.npz and /dev/null differ diff --git a/tests/parity/tolerances.yml b/tests/parity/tolerances.yml deleted file mode 100644 index 3809c234..00000000 --- a/tests/parity/tolerances.yml +++ /dev/null @@ -1,14 +0,0 @@ -poisson_glm: - coefficient_abs_tol: 0.25 - rate_rel_tol: 0.20 - -binomial_glm: - coefficient_abs_tol: 0.30 - probability_abs_tol: 0.10 - -decoding: - normalized_rmse_tol: 0.20 - ci_coverage_tol: 0.10 - -place_decoding: - normalized_rmse_tol: 0.30 diff --git a/tests/parity_utils.py b/tests/parity_utils.py deleted file mode 100644 index ff8cf9ec..00000000 --- a/tests/parity_utils.py +++ /dev/null @@ -1,159 +0,0 @@ -from __future__ import annotations - -import random -from pathlib import Path -from typing import Any - -import numpy as np -import scipy.io - - -def set_deterministic_seeds(seed: int) -> np.random.Generator: - """Set deterministic Python + NumPy RNG state and return a Generator.""" - random.seed(int(seed)) - np.random.seed(int(seed)) - return np.random.default_rng(int(seed)) - - -def matlab_rng_command(seed: int, generator: str = "twister") -> str: - """Return the MATLAB RNG statement used for fixture generation scripts.""" - return f"rng({int(seed)}, '{generator}');" - - -def _convert_matlab_value(value: Any) -> Any: - if isinstance(value, np.ndarray) and value.dtype == object: - if value.size == 1: - return _convert_matlab_value(value.reshape(-1)[0]) - if value.ndim == 0: - return _convert_matlab_value(value.item()) - if value.ndim == 1: - return [_convert_matlab_value(x) for x in value.tolist()] - if value.ndim == 2: - return [[_convert_matlab_value(x) for x in row] for row in value.tolist()] - return [_convert_matlab_value(x) for x in value.reshape(-1).tolist()] - if isinstance(value, np.ndarray): - return value - if hasattr(value, "_fieldnames"): - out: dict[str, Any] = {} - for name in getattr(value, "_fieldnames", []): - out[str(name)] = _convert_matlab_value(getattr(value, name)) - return out - return value - - -def loadmat_normalized( - path: str | Path, - *, - squeeze_me: bool = False, - keep_metadata: bool = False, -) -> dict[str, Any]: - """Load a MATLAB .mat file and normalize structs/cells into Python types.""" - payload = scipy.io.loadmat( - str(path), - squeeze_me=squeeze_me, - struct_as_record=False, - ) - out: dict[str, Any] = {} - for key, value in payload.items(): - if not keep_metadata and key.startswith("__"): - continue - out[key] = _convert_matlab_value(value) - return out - - -def canonicalize_numeric(value: Any, *, vector_shape: str = "preserve") -> np.ndarray: - """Canonicalize numeric values for parity comparisons (dtype + vector orientation).""" - arr = np.asarray(value) - if np.issubdtype(arr.dtype, np.number): - arr = arr.astype(np.float64, copy=False) - if arr.ndim == 1: - if vector_shape == "column": - arr = arr[:, None] - elif vector_shape == "row": - arr = arr[None, :] - return arr - - -def assert_same_shape(actual: Any, expected: Any) -> None: - a = np.asarray(actual) - b = np.asarray(expected) - if a.shape != b.shape: - raise AssertionError(f"shape mismatch: actual={a.shape} expected={b.shape}") - - -def assert_matching_nan_inf_locations(actual: Any, expected: Any) -> None: - a = canonicalize_numeric(actual) - b = canonicalize_numeric(expected) - assert_same_shape(a, b) - - a_nan = np.isnan(a) - b_nan = np.isnan(b) - if not np.array_equal(a_nan, b_nan): - raise AssertionError("NaN locations do not match") - - a_pos_inf = np.isposinf(a) - b_pos_inf = np.isposinf(b) - if not np.array_equal(a_pos_inf, b_pos_inf): - raise AssertionError("+Inf locations do not match") - - a_neg_inf = np.isneginf(a) - b_neg_inf = np.isneginf(b) - if not np.array_equal(a_neg_inf, b_neg_inf): - raise AssertionError("-Inf locations do not match") - - -def _scale_from_expected(expected: np.ndarray, mode: str) -> float: - finite = np.isfinite(expected) - if not np.any(finite): - return 1.0 - vals = np.abs(expected[finite]) - if mode == "maxabs": - return float(max(np.max(vals), 1.0)) - if mode == "rms": - return float(max(np.sqrt(np.mean(expected[finite] ** 2)), 1.0)) - if mode == "range": - rng = float(np.max(expected[finite]) - np.min(expected[finite])) - return max(rng, 1.0) - raise ValueError(f"unsupported scale mode: {mode}") - - -def assert_allclose_scaled( - actual: Any, - expected: Any, - *, - rtol: float, - atol: float, - scale: str = "maxabs", -) -> None: - a = canonicalize_numeric(actual) - b = canonicalize_numeric(expected) - assert_same_shape(a, b) - assert_matching_nan_inf_locations(a, b) - - finite = np.isfinite(a) & np.isfinite(b) - if not np.any(finite): - return - - scale_val = _scale_from_expected(b, scale) - np.testing.assert_allclose( - a[finite], - b[finite], - rtol=float(rtol), - atol=float(atol) * scale_val, - ) - - -def assert_event_times_close( - actual: Any, - expected: Any, - *, - atol: float = 1.0e-9, - sort_values: bool = True, -) -> None: - a = np.asarray(actual, dtype=np.float64).reshape(-1) - b = np.asarray(expected, dtype=np.float64).reshape(-1) - if sort_values: - a = np.sort(a) - b = np.sort(b) - assert_same_shape(a, b) - np.testing.assert_allclose(a, b, rtol=0.0, atol=float(atol)) diff --git a/tests/performance/fixtures/matlab/performance_baseline_470fde8.csv b/tests/performance/fixtures/matlab/performance_baseline_470fde8.csv deleted file mode 100644 index f4340690..00000000 --- a/tests/performance/fixtures/matlab/performance_baseline_470fde8.csv +++ /dev/null @@ -1,16 +0,0 @@ -case,tier,repeats,median_runtime_ms,mean_runtime_ms,std_runtime_ms,median_peak_memory_mb,summary -unit_impulse_basis,S,7,4.297083333,3.773136905,2.034040669,0.191116333,"{""rows"":501,""cols"":50,""total_mass"":501,""memory_proxy_mb"":0.1911163330078125}" -unit_impulse_basis,M,7,2.735708333,2.732898810,0.126777277,1.526641846,"{""rows"":2001,""cols"":100,""total_mass"":2001,""memory_proxy_mb"":1.526641845703125}" -unit_impulse_basis,L,7,6.359083333,6.330571429,0.332416673,9.156799316,"{""rows"":6001,""cols"":200,""total_mass"":6001,""memory_proxy_mb"":9.15679931640625}" -covariate_resample,S,7,2.632916667,2.811726190,0.653497244,0.007637024,"{""rows"":1001,""cols"":1,""signal_energy"":0.51952047952047953,""memory_proxy_mb"":0.00763702392578125}" -covariate_resample,M,7,2.875166667,3.222666667,0.757170547,0.022895813,"{""rows"":3001,""cols"":1,""signal_energy"":0.51984005257749533,""memory_proxy_mb"":0.02289581298828125}" -covariate_resample,L,7,1.947208333,1.888410714,0.315633896,0.045783997,"{""rows"":6001,""cols"":1,""signal_energy"":0.519920013331112,""memory_proxy_mb"":0.04578399658203125}" -history_design_matrix,S,7,15.547416667,15.334202381,2.620143725,0.061065674,"{""rows"":2001,""cols"":4,""total_count"":19479,""memory_proxy_mb"":0.061065673828125}" -history_design_matrix,M,7,12.951875000,12.782089286,1.140924257,0.061065674,"{""rows"":2001,""cols"":4,""total_count"":97507,""memory_proxy_mb"":0.061065673828125}" -history_design_matrix,L,7,13.820333333,13.938613095,0.434794481,0.061065674,"{""rows"":2001,""cols"":4,""total_count"":292495,""memory_proxy_mb"":0.061065673828125}" -simulate_cif_thinning,S,7,18.633500000,22.285202381,10.204807908,0.007637024,"{""num_units"":5,""total_spikes"":53,""mean_spikes_per_unit"":10.6,""memory_proxy_mb"":0.00763702392578125}" -simulate_cif_thinning,M,7,10.393083333,11.535672619,6.034641619,0.015266418,"{""num_units"":10,""total_spikes"":227,""mean_spikes_per_unit"":22.7,""memory_proxy_mb"":0.01526641845703125}" -simulate_cif_thinning,L,7,11.125333333,11.006880952,1.380233877,0.022895813,"{""num_units"":20,""total_spikes"":697,""mean_spikes_per_unit"":34.85,""memory_proxy_mb"":0.02289581298828125}" -decoding_spike_rate_cis,S,7,17.276083333,20.075815476,8.011035032,0.000274658,"{""num_trials"":6,""prob_mean"":0.17222222222222225,""sig_count"":0,""rate_mean"":50.340528015525138,""memory_proxy_mb"":0.000274658203125}" -decoding_spike_rate_cis,M,7,15.002750000,15.106750000,2.117378368,0.000488281,"{""num_trials"":8,""prob_mean"":0.188125,""sig_count"":0,""rate_mean"":50.22232623024469,""memory_proxy_mb"":0.00048828125}" -decoding_spike_rate_cis,L,7,26.472458333,25.936833333,1.395156968,0.001098633,"{""num_trials"":12,""prob_mean"":0.20998263888888888,""sig_count"":0,""rate_mean"":50.1178888198292,""memory_proxy_mb"":0.0010986328125}" diff --git a/tests/performance/fixtures/matlab/performance_baseline_470fde8.json b/tests/performance/fixtures/matlab/performance_baseline_470fde8.json deleted file mode 100644 index ca8e6236..00000000 --- a/tests/performance/fixtures/matlab/performance_baseline_470fde8.json +++ /dev/null @@ -1,536 +0,0 @@ -{ - "schema_version": 1, - "generated_at_utc": "2026-03-04T04:09:43Z", - "implementation": "matlab", - "nstat_root": "/Users/iahncajigas/Library/CloudStorage/Dropbox/Research/Matlab/nSTAT_currentRelease_Local", - "reference_sha": "0afc8390b5958bb9af255344d7e4a33fedb172ca", - "tiers": [ - "S", - "M", - "L" - ], - "cases": [ - { - "case": "unit_impulse_basis", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 4.2970833333333331, - "mean_runtime_ms": 3.773136904761905, - "std_runtime_ms": 2.0340406685672687, - "median_peak_memory_mb": 0.1911163330078125, - "summary": { - "rows": 501, - "cols": 50, - "total_mass": 501, - "memory_proxy_mb": 0.1911163330078125 - }, - "samples_runtime_ms": [ - 7.0744583333333333, - 5.0766666666666671, - 4.3886666666666665, - 4.2970833333333331, - 2.3883333333333336, - 1.86925, - 1.3175000000000001 - ], - "samples_peak_memory_mb": [ - 0.1911163330078125, - 0.1911163330078125, - 0.1911163330078125, - 0.1911163330078125, - 0.1911163330078125, - 0.1911163330078125, - 0.1911163330078125 - ] - }, - { - "case": "unit_impulse_basis", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 2.7357083333333336, - "mean_runtime_ms": 2.73289880952381, - "std_runtime_ms": 0.12677727685428219, - "median_peak_memory_mb": 1.526641845703125, - "summary": { - "rows": 2001, - "cols": 100, - "total_mass": 2001, - "memory_proxy_mb": 1.526641845703125 - }, - "samples_runtime_ms": [ - 2.6884583333333336, - 2.5345, - 2.9364583333333334, - 2.8283750000000003, - 2.7407916666666665, - 2.7357083333333336, - 2.666 - ], - "samples_peak_memory_mb": [ - 1.526641845703125, - 1.526641845703125, - 1.526641845703125, - 1.526641845703125, - 1.526641845703125, - 1.526641845703125, - 1.526641845703125 - ] - }, - { - "case": "unit_impulse_basis", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 6.3590833333333325, - "mean_runtime_ms": 6.330571428571429, - "std_runtime_ms": 0.33241667251111179, - "median_peak_memory_mb": 9.15679931640625, - "summary": { - "rows": 6001, - "cols": 200, - "total_mass": 6001, - "memory_proxy_mb": 9.15679931640625 - }, - "samples_runtime_ms": [ - 6.29275, - 6.87575, - 6.2596666666666669, - 6.3685833333333335, - 6.3590833333333325, - 6.418625, - 5.7395416666666668 - ], - "samples_peak_memory_mb": [ - 9.15679931640625, - 9.15679931640625, - 9.15679931640625, - 9.15679931640625, - 9.15679931640625, - 9.15679931640625, - 9.15679931640625 - ] - }, - { - "case": "covariate_resample", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 2.6329166666666666, - "mean_runtime_ms": 2.81172619047619, - "std_runtime_ms": 0.65349724411467558, - "median_peak_memory_mb": 0.00763702392578125, - "summary": { - "rows": 1001, - "cols": 1, - "signal_energy": 0.51952047952047953, - "memory_proxy_mb": 0.00763702392578125 - }, - "samples_runtime_ms": [ - 2.8413333333333335, - 2.6329166666666666, - 3.9391666666666665, - 2.50025, - 3.3961249999999996, - 2.3224166666666668, - 2.049875 - ], - "samples_peak_memory_mb": [ - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125 - ] - }, - { - "case": "covariate_resample", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 2.8751666666666664, - "mean_runtime_ms": 3.2226666666666666, - "std_runtime_ms": 0.75717054663385741, - "median_peak_memory_mb": 0.02289581298828125, - "summary": { - "rows": 3001, - "cols": 1, - "signal_energy": 0.51984005257749533, - "memory_proxy_mb": 0.02289581298828125 - }, - "samples_runtime_ms": [ - 4.409, - 3.195, - 2.7273750000000003, - 2.67125, - 4.1570833333333326, - 2.5237916666666669, - 2.8751666666666664 - ], - "samples_peak_memory_mb": [ - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125 - ] - }, - { - "case": "covariate_resample", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 1.9472083333333334, - "mean_runtime_ms": 1.8884107142857143, - "std_runtime_ms": 0.31563389649046991, - "median_peak_memory_mb": 0.04578399658203125, - "summary": { - "rows": 6001, - "cols": 1, - "signal_energy": 0.519920013331112, - "memory_proxy_mb": 0.04578399658203125 - }, - "samples_runtime_ms": [ - 1.95875, - 1.526, - 2.4904166666666669, - 1.9485416666666666, - 1.6713749999999998, - 1.6765833333333333, - 1.9472083333333334 - ], - "samples_peak_memory_mb": [ - 0.04578399658203125, - 0.04578399658203125, - 0.04578399658203125, - 0.04578399658203125, - 0.04578399658203125, - 0.04578399658203125, - 0.04578399658203125 - ] - }, - { - "case": "history_design_matrix", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 15.547416666666665, - "mean_runtime_ms": 15.33420238095238, - "std_runtime_ms": 2.6201437253425088, - "median_peak_memory_mb": 0.061065673828125, - "summary": { - "rows": 2001, - "cols": 4, - "total_count": 19479, - "memory_proxy_mb": 0.061065673828125 - }, - "samples_runtime_ms": [ - 19.652708333333333, - 16.800625, - 15.547416666666665, - 15.985833333333334, - 14.421083333333332, - 13.613166666666668, - 11.318583333333333 - ], - "samples_peak_memory_mb": [ - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125 - ] - }, - { - "case": "history_design_matrix", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 12.951875, - "mean_runtime_ms": 12.782089285714287, - "std_runtime_ms": 1.1409242568944873, - "median_peak_memory_mb": 0.061065673828125, - "summary": { - "rows": 2001, - "cols": 4, - "total_count": 97507, - "memory_proxy_mb": 0.061065673828125 - }, - "samples_runtime_ms": [ - 13.366875, - 14.438875, - 11.997499999999999, - 12.951875, - 12.24975, - 13.499125000000001, - 10.970625 - ], - "samples_peak_memory_mb": [ - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125 - ] - }, - { - "case": "history_design_matrix", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 13.820333333333334, - "mean_runtime_ms": 13.938613095238097, - "std_runtime_ms": 0.43479448084744254, - "median_peak_memory_mb": 0.061065673828125, - "summary": { - "rows": 2001, - "cols": 4, - "total_count": 292495, - "memory_proxy_mb": 0.061065673828125 - }, - "samples_runtime_ms": [ - 14.813, - 14.0275, - 13.763958333333333, - 13.514791666666666, - 14.047, - 13.820333333333334, - 13.583708333333334 - ], - "samples_peak_memory_mb": [ - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125, - 0.061065673828125 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 18.6335, - "mean_runtime_ms": 22.285202380952381, - "std_runtime_ms": 10.204807907674679, - "median_peak_memory_mb": 0.00763702392578125, - "summary": { - "num_units": 5, - "total_spikes": 53, - "mean_spikes_per_unit": 10.6, - "memory_proxy_mb": 0.00763702392578125 - }, - "samples_runtime_ms": [ - 38.645125, - 33.8315, - 21.978791666666666, - 17.852333333333334, - 18.6335, - 12.101458333333333, - 12.953708333333333 - ], - "samples_peak_memory_mb": [ - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125, - 0.00763702392578125 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 10.393083333333333, - "mean_runtime_ms": 11.535672619047618, - "std_runtime_ms": 6.0346416186965479, - "median_peak_memory_mb": 0.01526641845703125, - "summary": { - "num_units": 10, - "total_spikes": 227, - "mean_spikes_per_unit": 22.7, - "memory_proxy_mb": 0.01526641845703125 - }, - "samples_runtime_ms": [ - 18.474083333333333, - 16.471166666666665, - 18.113541666666666, - 10.393083333333333, - 6.7640416666666665, - 5.4447916666666663, - 5.0889999999999995 - ], - "samples_peak_memory_mb": [ - 0.01526641845703125, - 0.01526641845703125, - 0.01526641845703125, - 0.01526641845703125, - 0.01526641845703125, - 0.01526641845703125, - 0.01526641845703125 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 11.125333333333332, - "mean_runtime_ms": 11.006880952380952, - "std_runtime_ms": 1.3802338767926841, - "median_peak_memory_mb": 0.02289581298828125, - "summary": { - "num_units": 20, - "total_spikes": 697, - "mean_spikes_per_unit": 34.85, - "memory_proxy_mb": 0.02289581298828125 - }, - "samples_runtime_ms": [ - 11.999833333333333, - 13.285416666666666, - 11.125333333333332, - 11.472166666666666, - 9.8583333333333343, - 9.512375, - 9.7947083333333342 - ], - "samples_peak_memory_mb": [ - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125, - 0.02289581298828125 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 17.276083333333336, - "mean_runtime_ms": 20.075815476190478, - "std_runtime_ms": 8.01103503153854, - "median_peak_memory_mb": 0.000274658203125, - "summary": { - "num_trials": 6, - "prob_mean": 0.17222222222222225, - "sig_count": 0, - "rate_mean": 50.340528015525138, - "memory_proxy_mb": 0.000274658203125 - }, - "samples_runtime_ms": [ - 35.707833333333333, - 25.233916666666669, - 17.276083333333336, - 16.183166666666665, - 13.461833333333333, - 13.223083333333333, - 19.444791666666667 - ], - "samples_peak_memory_mb": [ - 0.000274658203125, - 0.000274658203125, - 0.000274658203125, - 0.000274658203125, - 0.000274658203125, - 0.000274658203125, - 0.000274658203125 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 15.00275, - "mean_runtime_ms": 15.106750000000002, - "std_runtime_ms": 2.1173783681560523, - "median_peak_memory_mb": 0.00048828125, - "summary": { - "num_trials": 8, - "prob_mean": 0.188125, - "sig_count": 0, - "rate_mean": 50.22232623024469, - "memory_proxy_mb": 0.00048828125 - }, - "samples_runtime_ms": [ - 18.718333333333334, - 16.751625, - 15.287875, - 13.339791666666667, - 14.224666666666666, - 12.422208333333334, - 15.00275 - ], - "samples_peak_memory_mb": [ - 0.00048828125, - 0.00048828125, - 0.00048828125, - 0.00048828125, - 0.00048828125, - 0.00048828125, - 0.00048828125 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 26.472458333333336, - "mean_runtime_ms": 25.936833333333336, - "std_runtime_ms": 1.395156967556114, - "median_peak_memory_mb": 0.0010986328125, - "summary": { - "num_trials": 12, - "prob_mean": 0.20998263888888888, - "sig_count": 0, - "rate_mean": 50.1178888198292, - "memory_proxy_mb": 0.0010986328125 - }, - "samples_runtime_ms": [ - 26.474541666666667, - 25.155833333333334, - 27.055541666666667, - 24.789291666666667, - 27.79125, - 26.472458333333336, - 23.818916666666667 - ], - "samples_peak_memory_mb": [ - 0.0010986328125, - 0.0010986328125, - 0.0010986328125, - 0.0010986328125, - 0.0010986328125, - 0.0010986328125, - 0.0010986328125 - ] - } - ], - "environment": { - "matlab_version": "25.2.0.3123386 (R2025b) Update 3", - "matlab_release": "2025b", - "os": "MACA64", - "blas": "Apple Accelerate BLAS (ILP64)", - "omp_num_threads": "", - "mkl_num_threads": "", - "openblas_num_threads": "" - } -} \ No newline at end of file diff --git a/tests/performance/fixtures/python/performance_baseline_20260303.csv b/tests/performance/fixtures/python/performance_baseline_20260303.csv deleted file mode 100644 index 0103fa42..00000000 --- a/tests/performance/fixtures/python/performance_baseline_20260303.csv +++ /dev/null @@ -1,16 +0,0 @@ -case,tier,repeats,median_runtime_ms,mean_runtime_ms,std_runtime_ms,median_peak_memory_mb,summary -unit_impulse_basis,S,7,1.7683329933788627,1.7861547135648184,0.158024180816925,0.4534463882446289,"{""cols"": 50.0, ""rows"": 501.0, ""total_mass"": 500.0}" -unit_impulse_basis,M,7,4.475333000300452,4.500089290169334,0.9284738746088693,3.1384315490722656,"{""cols"": 100.0, ""rows"": 2001.0, ""total_mass"": 2000.0}" -unit_impulse_basis,L,7,9.582500002579764,9.65004785601715,0.5994475223217789,18.434642791748047,"{""cols"": 200.0, ""rows"": 6001.0, ""total_mass"": 6000.0}" -covariate_resample,S,7,0.37954199069645256,0.5145418565786842,0.342992624379633,0.061981201171875,"{""cols"": 1.0, ""rows"": 1001.0, ""signal_energy"": 0.5195204795204795}" -covariate_resample,M,7,0.8639160078018904,0.9734344265390453,0.36931540455016815,0.1353321075439453,"{""cols"": 1.0, ""rows"": 3001.0, ""signal_energy"": 0.5198042747802832}" -covariate_resample,L,7,0.9690420120023191,0.9464108568084028,0.48446691060044744,0.23737525939941406,"{""cols"": 1.0, ""rows"": 6001.0, ""signal_energy"": 0.5199200133311115}" -history_design_matrix,S,7,0.7950409926706925,1.645898716690551,1.8429881668958228,0.08904266357421875,"{""cols"": 4.0, ""rows"": 1000.0, ""total_count"": 9737.0}" -history_design_matrix,M,7,5.126874995767139,4.977494141452813,0.5063190759208223,0.436859130859375,"{""cols"": 4.0, ""rows"": 5000.0, ""total_count"": 243740.0}" -history_design_matrix,L,7,16.20729199203197,14.745523999278833,3.320744565978393,0.8869171142578125,"{""cols"": 4.0, ""rows"": 10000.0, ""total_count"": 1462420.0}" -simulate_cif_thinning,S,7,11.668874998576939,13.197898854351868,4.439189648217996,0.07119369506835938,"{""mean_spikes_per_unit"": 11.8, ""num_units"": 5.0, ""total_spikes"": 59.0}" -simulate_cif_thinning,M,7,35.64529199502431,39.50604771463467,10.14234695828477,0.13432693481445312,"{""mean_spikes_per_unit"": 23.6, ""num_units"": 10.0, ""total_spikes"": 236.0}" -simulate_cif_thinning,L,7,95.53704199788626,101.42410728648039,15.004523282406359,0.20084762573242188,"{""mean_spikes_per_unit"": 36.5, ""num_units"": 20.0, ""total_spikes"": 730.0}" -decoding_spike_rate_cis,S,7,20.557166004437022,20.735029426370083,0.32869912750478875,0.23363685607910156,"{""num_trials"": 6.0, ""prob_mean"": 0.1509259259259259, ""rate_mean"": 50.4457886636761, ""sig_count"": 0.0}" -decoding_spike_rate_cis,M,7,45.79670800012536,55.404220285709016,17.298491800109527,0.7647151947021484,"{""num_trials"": 8.0, ""prob_mean"": 0.18562499999999998, ""rate_mean"": 50.12398439148756, ""sig_count"": 0.0}" -decoding_spike_rate_cis,L,7,99.45741599949542,100.12100585819488,2.1007428451842776,2.7344188690185547,"{""num_trials"": 12.0, ""prob_mean"": 0.21328124999999998, ""rate_mean"": 50.073736692667104, ""sig_count"": 0.0}" diff --git a/tests/performance/fixtures/python/performance_baseline_20260303.json b/tests/performance/fixtures/python/performance_baseline_20260303.json deleted file mode 100644 index dcb456e8..00000000 --- a/tests/performance/fixtures/python/performance_baseline_20260303.json +++ /dev/null @@ -1,523 +0,0 @@ -{ - "schema_version": 1, - "generated_at_utc": "2026-03-04T04:20:29Z", - "implementation": "python", - "repo_root": "/private/tmp/nstat_python_exec_next", - "git_sha": "540519f52cb6799fa4886ddbe8cdd3b5fd1c9c3b", - "tiers": [ - "S", - "M", - "L" - ], - "cases": [ - { - "case": "unit_impulse_basis", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 1.7683329933788627, - "mean_runtime_ms": 1.7861547135648184, - "std_runtime_ms": 0.158024180816925, - "median_peak_memory_mb": 0.4534463882446289, - "summary": { - "rows": 501.0, - "cols": 50.0, - "total_mass": 500.0 - }, - "samples_runtime_ms": [ - 1.694457998382859, - 1.5242920053424314, - 1.7683329933788627, - 1.9450409890851006, - 1.9406670035095885, - 1.9679590041050687, - 1.6623330011498183 - ], - "samples_peak_memory_mb": [ - 0.4534463882446289, - 0.45345401763916016, - 0.4534616470336914, - 0.4534463882446289, - 0.4534311294555664, - 0.4534006118774414, - 0.4533853530883789 - ] - }, - { - "case": "unit_impulse_basis", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 4.475333000300452, - "mean_runtime_ms": 4.500089290169334, - "std_runtime_ms": 0.9284738746088693, - "median_peak_memory_mb": 3.1384315490722656, - "summary": { - "rows": 2001.0, - "cols": 100.0, - "total_mass": 2000.0 - }, - "samples_runtime_ms": [ - 4.051500000059605, - 5.044250006903894, - 5.633542008581571, - 5.681417009327561, - 3.234125004382804, - 4.475333000300452, - 3.3804580016294494 - ], - "samples_peak_memory_mb": [ - 3.1385536193847656, - 3.138561248779297, - 3.138446807861328, - 3.1384315490722656, - 3.138416290283203, - 3.138408660888672, - 3.1384010314941406 - ] - }, - { - "case": "unit_impulse_basis", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 9.582500002579764, - "mean_runtime_ms": 9.65004785601715, - "std_runtime_ms": 0.5994475223217789, - "median_peak_memory_mb": 18.434642791748047, - "summary": { - "rows": 6001.0, - "cols": 200.0, - "total_mass": 6000.0 - }, - "samples_runtime_ms": [ - 9.086833990295418, - 8.696708013303578, - 9.401916991919279, - 9.582500002579764, - 10.047749994555488, - 10.233041990431957, - 10.50158400903456 - ], - "samples_peak_memory_mb": [ - 18.434635162353516, - 18.434650421142578, - 18.43466567993164, - 18.434650421142578, - 18.434642791748047, - 18.434635162353516, - 18.434627532958984 - ] - }, - { - "case": "covariate_resample", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.37954199069645256, - "mean_runtime_ms": 0.5145418565786842, - "std_runtime_ms": 0.342992624379633, - "median_peak_memory_mb": 0.061981201171875, - "summary": { - "rows": 1001.0, - "cols": 1.0, - "signal_energy": 0.5195204795204795 - }, - "samples_runtime_ms": [ - 0.19366700144018978, - 0.17533400387037545, - 0.37954199069645256, - 0.3596659953473136, - 0.48983399756252766, - 1.2112499971408397, - 0.7925000099930912 - ], - "samples_peak_memory_mb": [ - 0.061981201171875, - 0.061981201171875, - 0.061981201171875, - 0.061981201171875, - 0.061981201171875, - 0.061981201171875, - 0.061981201171875 - ] - }, - { - "case": "covariate_resample", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.8639160078018904, - "mean_runtime_ms": 0.9734344265390453, - "std_runtime_ms": 0.36931540455016815, - "median_peak_memory_mb": 0.1353321075439453, - "summary": { - "rows": 3001.0, - "cols": 1.0, - "signal_energy": 0.5198042747802832 - }, - "samples_runtime_ms": [ - 1.240666999365203, - 1.4605409960495308, - 0.6025000038789585, - 1.4403749955818057, - 0.6479579897131771, - 0.8639160078018904, - 0.5580839933827519 - ], - "samples_peak_memory_mb": [ - 0.13530921936035156, - 0.13530921936035156, - 0.1353321075439453, - 0.1353321075439453, - 0.1353321075439453, - 0.1353321075439453, - 0.1353321075439453 - ] - }, - { - "case": "covariate_resample", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.9690420120023191, - "mean_runtime_ms": 0.9464108568084028, - "std_runtime_ms": 0.48446691060044744, - "median_peak_memory_mb": 0.23737525939941406, - "summary": { - "rows": 6001.0, - "cols": 1.0, - "signal_energy": 0.5199200133311115 - }, - "samples_runtime_ms": [ - 1.9614159973571077, - 0.9757090010680258, - 0.7324170001083985, - 1.1260829924140126, - 0.9690420120023191, - 0.4219999973429367, - 0.4382089973660186 - ], - "samples_peak_memory_mb": [ - 0.2373523712158203, - 0.2373523712158203, - 0.23737525939941406, - 0.23737525939941406, - 0.23737525939941406, - 0.23737525939941406, - 0.23737525939941406 - ] - }, - { - "case": "history_design_matrix", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.7950409926706925, - "mean_runtime_ms": 1.645898716690551, - "std_runtime_ms": 1.8429881668958228, - "median_peak_memory_mb": 0.08904266357421875, - "summary": { - "rows": 1000.0, - "cols": 4.0, - "total_count": 9737.0 - }, - "samples_runtime_ms": [ - 0.7901250064605847, - 0.9010420035338029, - 1.5587500092806295, - 0.7950409926706925, - 6.106041997554712, - 0.7814580021658912, - 0.5888330051675439 - ], - "samples_peak_memory_mb": [ - 0.08902740478515625, - 0.08904266357421875, - 0.08905792236328125, - 0.08905029296875, - 0.08904266357421875, - 0.08902740478515625, - 0.089019775390625 - ] - }, - { - "case": "history_design_matrix", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 5.126874995767139, - "mean_runtime_ms": 4.977494141452813, - "std_runtime_ms": 0.5063190759208223, - "median_peak_memory_mb": 0.436859130859375, - "summary": { - "rows": 5000.0, - "cols": 4.0, - "total_count": 243740.0 - }, - "samples_runtime_ms": [ - 5.498124999576248, - 4.521750001003966, - 4.666374996304512, - 5.706082985852845, - 5.126874995767139, - 4.17879200540483, - 5.144459006260149 - ], - "samples_peak_memory_mb": [ - 0.43685150146484375, - 0.43686676025390625, - 0.43688201904296875, - 0.4368743896484375, - 0.436859130859375, - 0.43685150146484375, - 0.4368438720703125 - ] - }, - { - "case": "history_design_matrix", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 16.20729199203197, - "mean_runtime_ms": 14.745523999278833, - "std_runtime_ms": 3.320744565978393, - "median_peak_memory_mb": 0.8869171142578125, - "summary": { - "rows": 10000.0, - "cols": 4.0, - "total_count": 1462420.0 - }, - "samples_runtime_ms": [ - 10.213750007096678, - 12.098499995772727, - 16.20729199203197, - 17.953916991245933, - 18.11012500547804, - 17.890375005663373, - 10.74470899766311 - ], - "samples_peak_memory_mb": [ - 0.8869094848632812, - 0.8869247436523438, - 0.8869400024414062, - 0.8869247436523438, - 0.8869171142578125, - 0.8869094848632812, - 0.88690185546875 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 11.668874998576939, - "mean_runtime_ms": 13.197898854351868, - "std_runtime_ms": 4.439189648217996, - "median_peak_memory_mb": 0.07119369506835938, - "summary": { - "num_units": 5.0, - "total_spikes": 59.0, - "mean_spikes_per_unit": 11.8 - }, - "samples_runtime_ms": [ - 15.166458004387096, - 23.260666988790035, - 9.778041989193298, - 11.668874998576939, - 11.702959003741853, - 9.72149999870453, - 11.086790997069329 - ], - "samples_peak_memory_mb": [ - 0.07107925415039062, - 0.07112503051757812, - 0.07119369506835938, - 0.07131576538085938, - 0.07126998901367188, - 0.07120132446289062, - 0.07112503051757812 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 35.64529199502431, - "mean_runtime_ms": 39.50604771463467, - "std_runtime_ms": 10.14234695828477, - "median_peak_memory_mb": 0.13432693481445312, - "summary": { - "num_units": 10.0, - "total_spikes": 236.0, - "mean_spikes_per_unit": 23.6 - }, - "samples_runtime_ms": [ - 63.98295899271034, - 35.64529199502431, - 38.63129101227969, - 33.676250008284114, - 36.9453750026878, - 34.22758399392478, - 33.43358299753163 - ], - "samples_peak_memory_mb": [ - 0.13429641723632812, - 0.13458633422851562, - 0.13427352905273438, - 0.13451004028320312, - 0.13428878784179688, - 0.13432693481445312, - 0.13438034057617188 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 95.53704199788626, - "mean_runtime_ms": 101.42410728648039, - "std_runtime_ms": 15.004523282406359, - "median_peak_memory_mb": 0.20084762573242188, - "summary": { - "num_units": 20.0, - "total_spikes": 730.0, - "mean_spikes_per_unit": 36.5 - }, - "samples_runtime_ms": [ - 95.53704199788626, - 138.14341700344812, - 96.45345799799543, - 95.80341700348072, - 94.85275000042748, - 94.7820420115022, - 94.39662499062251 - ], - "samples_peak_memory_mb": [ - 0.20105361938476562, - 0.20028305053710938, - 0.20032119750976562, - 0.20097732543945312, - 0.20128250122070312, - 0.20084762573242188, - 0.20074081420898438 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 20.557166004437022, - "mean_runtime_ms": 20.735029426370083, - "std_runtime_ms": 0.32869912750478875, - "median_peak_memory_mb": 0.23363685607910156, - "summary": { - "num_trials": 6.0, - "prob_mean": 0.1509259259259259, - "sig_count": 0.0, - "rate_mean": 50.4457886636761 - }, - "samples_runtime_ms": [ - 20.557166004437022, - 20.73420799570158, - 20.454083001823165, - 21.412290996522643, - 20.491249990300275, - 21.00037499621976, - 20.495832999586128 - ], - "samples_peak_memory_mb": [ - 0.23363685607910156, - 0.23363685607910156, - 0.23363685607910156, - 0.23363685607910156, - 0.23363685607910156, - 0.2334461212158203, - 0.23340415954589844 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 45.79670800012536, - "mean_runtime_ms": 55.404220285709016, - "std_runtime_ms": 17.298491800109527, - "median_peak_memory_mb": 0.7647151947021484, - "summary": { - "num_trials": 8.0, - "prob_mean": 0.18562499999999998, - "sig_count": 0.0, - "rate_mean": 50.12398439148756 - }, - "samples_runtime_ms": [ - 92.78645800077356, - 68.6920409934828, - 44.14379199442919, - 43.69733401108533, - 45.79670800012536, - 46.98724999616388, - 45.72595900390297 - ], - "samples_peak_memory_mb": [ - 0.7647151947021484, - 0.7647151947021484, - 0.7647151947021484, - 0.7647151947021484, - 0.7647151947021484, - 0.7647151947021484, - 0.7647151947021484 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 99.45741599949542, - "mean_runtime_ms": 100.12100585819488, - "std_runtime_ms": 2.1007428451842776, - "median_peak_memory_mb": 2.7344188690185547, - "summary": { - "num_trials": 12.0, - "prob_mean": 0.21328124999999998, - "sig_count": 0.0, - "rate_mean": 50.073736692667104 - }, - "samples_runtime_ms": [ - 97.61908301152289, - 98.89920899877325, - 98.79516600631177, - 99.45741599949542, - 104.42429198883474, - 99.98062500380911, - 101.67124999861699 - ], - "samples_peak_memory_mb": [ - 2.734373092651367, - 2.734395980834961, - 2.7344188690185547, - 2.7344188690185547, - 2.7344188690185547, - 2.7344188690185547, - 2.7344188690185547 - ] - } - ], - "environment": { - "python": "3.12.4", - "platform": "macOS-26.3-arm64-arm-64bit", - "numpy": "1.26.4", - "scipy": "1.13.1", - "matplotlib": "3.8.4", - "omp_num_threads": "", - "mkl_num_threads": "", - "openblas_num_threads": "", - "veclib_maximum_threads": "" - } -} \ No newline at end of file diff --git a/tests/performance/fixtures/python/performance_baseline_linux_20260304.csv b/tests/performance/fixtures/python/performance_baseline_linux_20260304.csv deleted file mode 100644 index cfa04b5f..00000000 --- a/tests/performance/fixtures/python/performance_baseline_linux_20260304.csv +++ /dev/null @@ -1,22 +0,0 @@ -case,tier,repeats,median_runtime_ms,mean_runtime_ms,std_runtime_ms,median_peak_memory_mb,summary -unit_impulse_basis,S,7,1.7951030000062929,1.800190142854977,0.030044572115161792,0.39142704010009766,"{""cols"": 50.0, ""rows"": 501.0, ""total_mass"": 500.0}" -unit_impulse_basis,M,7,6.6628950000051645,6.653057285713463,1.4829550166016998,3.076824188232422,"{""cols"": 100.0, ""rows"": 2001.0, ""total_mass"": 2000.0}" -unit_impulse_basis,L,7,16.024357000020473,16.10430300001196,0.23143857554091385,18.37380599975586,"{""cols"": 200.0, ""rows"": 6001.0, ""total_mass"": 6000.0}" -covariate_resample,S,7,0.29961199999206656,0.29913757142756886,0.009541632013909111,0.06201934814453125,"{""cols"": 1.0, ""rows"": 1001.0, ""signal_energy"": 0.5195204795204795}" -covariate_resample,M,7,0.3440330000046288,0.34703042856725524,0.01738929698449399,0.1356220245361328,"{""cols"": 1.0, ""rows"": 3001.0, ""signal_energy"": 0.5198042747802833}" -covariate_resample,L,7,0.4108699999960663,0.4196135714299284,0.017089334564883416,0.2376880645751953,"{""cols"": 1.0, ""rows"": 6001.0, ""signal_energy"": 0.5199200133311115}" -history_design_matrix,S,7,0.3993699999966793,0.4031285714266427,0.013794363505286652,0.0890960693359375,"{""cols"": 4.0, ""rows"": 1000.0, ""total_count"": 9737.0}" -history_design_matrix,M,7,0.9118490000048496,0.9101645714265162,0.05885667560476089,0.43691253662109375,"{""cols"": 4.0, ""rows"": 5000.0, ""total_count"": 243740.0}" -history_design_matrix,L,7,1.8411630000230161,1.8406257142860991,0.014739662895922209,0.8869705200195312,"{""cols"": 4.0, ""rows"": 10000.0, ""total_count"": 1462420.0}" -simulate_cif_thinning,S,7,12.83120299999041,12.864690857132441,0.17008704628575258,0.07111740112304688,"{""mean_spikes_per_unit"": 12.6, ""num_units"": 5.0, ""total_spikes"": 63.0}" -simulate_cif_thinning,M,7,49.6265170000072,49.62809900000106,0.2452487903460643,0.13447189331054688,"{""mean_spikes_per_unit"": 23.9, ""num_units"": 10.0, ""total_spikes"": 239.0}" -simulate_cif_thinning,L,7,148.1780189999995,147.96911385714193,0.8086479240372416,0.20068740844726562,"{""mean_spikes_per_unit"": 35.2, ""num_units"": 20.0, ""total_spikes"": 704.0}" -decoding_spike_rate_cis,S,7,9.922279000022627,9.8990294285792,0.09977266978679186,0.08637428283691406,"{""num_trials"": 6.0, ""prob_mean"": 0.1509259259259259, ""rate_mean"": 50.4457886636761, ""sig_count"": 0.0}" -decoding_spike_rate_cis,M,7,15.846046000007163,15.825482000000843,0.11100674963412104,0.19997024536132812,"{""num_trials"": 8.0, ""prob_mean"": 0.18562499999999998, ""rate_mean"": 50.12398439148756, ""sig_count"": 0.0}" -decoding_spike_rate_cis,L,7,29.582787000009603,29.530547285718608,0.2645464377729889,0.5168647766113281,"{""num_trials"": 12.0, ""prob_mean"": 0.21328124999999998, ""rate_mean"": 50.073736692667104, ""sig_count"": 0.0}" -nspiketrain_get_sigrep,S,7,0.45410599997808276,0.45695271428160467,0.02263874211807069,0.05826568603515625,"{""binary_sum"": 746.0, ""count_sum"": 800.0, ""n_bins"": 1000.0}" -nspiketrain_get_sigrep,M,7,0.5966520000129094,0.6046927142863622,0.017903597884198864,0.18491363525390625,"{""binary_sum"": 2577.0, ""count_sum"": 3000.0, ""n_bins"": 3000.0}" -nspiketrain_get_sigrep,L,7,0.9368639999820516,0.9338544285648303,0.016064032275827016,0.39853668212890625,"{""binary_sum"": 5000.0, ""count_sum"": 9000.0, ""n_bins"": 5000.0}" -analysis_fit_glm_pipeline,S,7,5.966330000006792,6.041203285718666,0.12616461532934142,0.10829353332519531,"{""coeff_norm"": 8.000957080893618e-16, ""intercept"": -12.01100351405273, ""log_likelihood"": -5.469277525370689e-06, ""pred_mean"": 6.076975028189657e-06}" -analysis_fit_glm_pipeline,M,7,7.278939000002538,7.281217000001204,0.1861142338621149,0.22568511962890625,"{""coeff_norm"": 9.782140347964175e-16, ""intercept"": -12.704150666835071, ""log_likelihood"": -5.46927767729412e-06, ""pred_mean"": 3.038487598496732e-06}" -analysis_fit_glm_pipeline,L,7,9.020953999993253,9.130242857143653,0.1717714863551795,0.4345836639404297,"{""coeff_norm"": 8.223875012950201e-16, ""intercept"": -12.704150666835066, ""log_likelihood"": -9.723160315189595e-06, ""pred_mean"": 3.0384875984967483e-06}" diff --git a/tests/performance/fixtures/python/performance_baseline_linux_20260304.json b/tests/performance/fixtures/python/performance_baseline_linux_20260304.json deleted file mode 100644 index 3a34741d..00000000 --- a/tests/performance/fixtures/python/performance_baseline_linux_20260304.json +++ /dev/null @@ -1,724 +0,0 @@ -{ - "schema_version": 1, - "generated_at_utc": "2026-03-04T06:13:09Z", - "implementation": "python", - "repo_root": "/home/runner/work/nSTAT-python/nSTAT-python", - "git_sha": "08ac1adde9a2d9b74a819c22e1fc19b0c2d758b3", - "tiers": [ - "S", - "M", - "L" - ], - "cases": [ - { - "case": "unit_impulse_basis", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 1.7951030000062929, - "mean_runtime_ms": 1.800190142854977, - "std_runtime_ms": 0.030044572115161792, - "median_peak_memory_mb": 0.39142704010009766, - "summary": { - "rows": 501.0, - "cols": 50.0, - "total_mass": 500.0 - }, - "samples_runtime_ms": [ - 1.864554999997381, - 1.7951030000062929, - 1.8160890000160634, - 1.7815100000007078, - 1.778256999983796, - 1.7982370000027004, - 1.7675799999778974 - ], - "samples_peak_memory_mb": [ - 0.39147281646728516, - 0.39145755767822266, - 0.39144229888916016, - 0.39142704010009766, - 0.39141178131103516, - 0.39138126373291016, - 0.39136600494384766 - ] - }, - { - "case": "unit_impulse_basis", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 6.6628950000051645, - "mean_runtime_ms": 6.653057285713463, - "std_runtime_ms": 1.4829550166016998, - "median_peak_memory_mb": 3.076824188232422, - "summary": { - "rows": 2001.0, - "cols": 100.0, - "total_mass": 2000.0 - }, - "samples_runtime_ms": [ - 5.253328000009105, - 5.174608000004355, - 5.262399000002915, - 9.362254999984998, - 8.050177000001213, - 6.805738999986488, - 6.6628950000051645 - ], - "samples_peak_memory_mb": [ - 3.0769691467285156, - 3.0769615173339844, - 3.076953887939453, - 3.076824188232422, - 3.0768089294433594, - 3.076801300048828, - 3.076793670654297 - ] - }, - { - "case": "unit_impulse_basis", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 16.024357000020473, - "mean_runtime_ms": 16.10430300001196, - "std_runtime_ms": 0.23143857554091385, - "median_peak_memory_mb": 18.37380599975586, - "summary": { - "rows": 6001.0, - "cols": 200.0, - "total_mass": 6000.0 - }, - "samples_runtime_ms": [ - 16.00895999999352, - 16.42452300001196, - 15.90741600000456, - 16.075996000012083, - 15.817221000020254, - 16.024357000020473, - 16.471648000020878 - ], - "samples_peak_memory_mb": [ - 18.373836517333984, - 18.373828887939453, - 18.373821258544922, - 18.37380599975586, - 18.373798370361328, - 18.373790740966797, - 18.373783111572266 - ] - }, - { - "case": "covariate_resample", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.29961199999206656, - "mean_runtime_ms": 0.29913757142756886, - "std_runtime_ms": 0.009541632013909111, - "median_peak_memory_mb": 0.06201934814453125, - "summary": { - "rows": 1001.0, - "cols": 1.0, - "signal_energy": 0.5195204795204795 - }, - "samples_runtime_ms": [ - 0.31718400001068403, - 0.29961199999206656, - 0.2958649999982299, - 0.30228200000692595, - 0.28286899998875015, - 0.29462000000535227, - 0.3015309999909732 - ], - "samples_peak_memory_mb": [ - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125 - ] - }, - { - "case": "covariate_resample", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.3440330000046288, - "mean_runtime_ms": 0.34703042856725524, - "std_runtime_ms": 0.01738929698449399, - "median_peak_memory_mb": 0.1356220245361328, - "summary": { - "rows": 3001.0, - "cols": 1.0, - "signal_energy": 0.5198042747802833 - }, - "samples_runtime_ms": [ - 0.3440330000046288, - 0.3872629999932542, - 0.3394640000067284, - 0.34691299998712566, - 0.3345760000001974, - 0.3304029999924296, - 0.34656099998642276 - ], - "samples_peak_memory_mb": [ - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328 - ] - }, - { - "case": "covariate_resample", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.4108699999960663, - "mean_runtime_ms": 0.4196135714299284, - "std_runtime_ms": 0.017089334564883416, - "median_peak_memory_mb": 0.2376880645751953, - "summary": { - "rows": 6001.0, - "cols": 1.0, - "signal_energy": 0.5199200133311115 - }, - "samples_runtime_ms": [ - 0.42476900000565365, - 0.4108699999960663, - 0.4027309999798945, - 0.4545680000092034, - 0.4038190000130726, - 0.41067399999406007, - 0.42986400001154834 - ], - "samples_peak_memory_mb": [ - 0.23766517639160156, - 0.23766517639160156, - 0.2376880645751953, - 0.2376880645751953, - 0.2376880645751953, - 0.2376880645751953, - 0.2376880645751953 - ] - }, - { - "case": "history_design_matrix", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.3993699999966793, - "mean_runtime_ms": 0.4031285714266427, - "std_runtime_ms": 0.013794363505286652, - "median_peak_memory_mb": 0.0890960693359375, - "summary": { - "rows": 1000.0, - "cols": 4.0, - "total_count": 9737.0 - }, - "samples_runtime_ms": [ - 0.4107149999867943, - 0.3993699999966793, - 0.4110679999769218, - 0.38829799999007264, - 0.4294660000141448, - 0.3940240000019912, - 0.38895900001989503 - ], - "samples_peak_memory_mb": [ - 0.089080810546875, - 0.0890960693359375, - 0.089111328125, - 0.08910369873046875, - 0.0890960693359375, - 0.089080810546875, - 0.08907318115234375 - ] - }, - { - "case": "history_design_matrix", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.9118490000048496, - "mean_runtime_ms": 0.9101645714265162, - "std_runtime_ms": 0.05885667560476089, - "median_peak_memory_mb": 0.43691253662109375, - "summary": { - "rows": 5000.0, - "cols": 4.0, - "total_count": 243740.0 - }, - "samples_runtime_ms": [ - 0.9850819999996929, - 0.9938119999901573, - 0.9118490000048496, - 0.8551290000013978, - 0.8512590000009368, - 0.8419250000031298, - 0.9320959999854495 - ], - "samples_peak_memory_mb": [ - 0.4369049072265625, - 0.436920166015625, - 0.4369354248046875, - 0.43692779541015625, - 0.43691253662109375, - 0.4369049072265625, - 0.43689727783203125 - ] - }, - { - "case": "history_design_matrix", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 1.8411630000230161, - "mean_runtime_ms": 1.8406257142860991, - "std_runtime_ms": 0.014739662895922209, - "median_peak_memory_mb": 0.8869705200195312, - "summary": { - "rows": 10000.0, - "cols": 4.0, - "total_count": 1462420.0 - }, - "samples_runtime_ms": [ - 1.8261639999934687, - 1.8664680000028966, - 1.843834999988303, - 1.8197750000013002, - 1.8411630000230161, - 1.833944999987125, - 1.8530300000065836 - ], - "samples_peak_memory_mb": [ - 0.886962890625, - 0.8869781494140625, - 0.886993408203125, - 0.8869781494140625, - 0.8869705200195312, - 0.886962890625, - 0.8869552612304688 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 12.83120299999041, - "mean_runtime_ms": 12.864690857132441, - "std_runtime_ms": 0.17008704628575258, - "median_peak_memory_mb": 0.07111740112304688, - "summary": { - "num_units": 5.0, - "total_spikes": 63.0, - "mean_spikes_per_unit": 12.6 - }, - "samples_runtime_ms": [ - 13.047533999980487, - 13.09318899998857, - 13.005707999980132, - 12.636868999976514, - 12.747445999991669, - 12.690887000019302, - 12.83120299999041 - ], - "samples_peak_memory_mb": [ - 0.07109451293945312, - 0.07122421264648438, - 0.07120132446289062, - 0.07110214233398438, - 0.07108688354492188, - 0.07111740112304688, - 0.07133102416992188 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 49.6265170000072, - "mean_runtime_ms": 49.62809900000106, - "std_runtime_ms": 0.2452487903460643, - "median_peak_memory_mb": 0.13447189331054688, - "summary": { - "num_units": 10.0, - "total_spikes": 239.0, - "mean_spikes_per_unit": 23.9 - }, - "samples_runtime_ms": [ - 49.933012999986204, - 49.47553599998855, - 49.15841700000101, - 49.6265170000072, - 49.57282899999882, - 49.74063900002079, - 49.889742000004844 - ], - "samples_peak_memory_mb": [ - 0.13447952270507812, - 0.13440322875976562, - 0.13442611694335938, - 0.13442611694335938, - 0.13451004028320312, - 0.13466262817382812, - 0.13447189331054688 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 148.1780189999995, - "mean_runtime_ms": 147.96911385714193, - "std_runtime_ms": 0.8086479240372416, - "median_peak_memory_mb": 0.20068740844726562, - "summary": { - "num_units": 20.0, - "total_spikes": 704.0, - "mean_spikes_per_unit": 35.2 - }, - "samples_runtime_ms": [ - 148.17126599999142, - 149.08999700000436, - 148.1780189999995, - 148.30773799999974, - 147.23606999999106, - 146.41610300000707, - 148.3846040000003 - ], - "samples_peak_memory_mb": [ - 0.20109176635742188, - 0.20068740844726562, - 0.20077896118164062, - 0.20093154907226562, - 0.20005416870117188, - 0.20032882690429688, - 0.20064163208007812 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 9.922279000022627, - "mean_runtime_ms": 9.8990294285792, - "std_runtime_ms": 0.09977266978679186, - "median_peak_memory_mb": 0.08637428283691406, - "summary": { - "num_trials": 6.0, - "prob_mean": 0.1509259259259259, - "sig_count": 0.0, - "rate_mean": 50.4457886636761 - }, - "samples_runtime_ms": [ - 10.008196000001135, - 9.922279000022627, - 9.995544000020118, - 9.960062000004655, - 9.712960000001658, - 9.801446000011538, - 9.892718999992667 - ], - "samples_peak_memory_mb": [ - 0.08637428283691406, - 0.08667182922363281, - 0.08637428283691406, - 0.08632469177246094, - 0.08632469177246094, - 0.08667182922363281, - 0.08662223815917969 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 15.846046000007163, - "mean_runtime_ms": 15.825482000000843, - "std_runtime_ms": 0.11100674963412104, - "median_peak_memory_mb": 0.19997024536132812, - "summary": { - "num_trials": 8.0, - "prob_mean": 0.18562499999999998, - "sig_count": 0.0, - "rate_mean": 50.12398439148756 - }, - "samples_runtime_ms": [ - 15.777557000006937, - 15.72368399999391, - 15.935339000009208, - 15.636774000000742, - 15.846046000007163, - 15.8855459999927, - 15.973427999995238 - ], - "samples_peak_memory_mb": [ - 0.1999664306640625, - 0.2000579833984375, - 0.199951171875, - 0.19994354248046875, - 0.20047378540039062, - 0.19997024536132812, - 0.200408935546875 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 29.582787000009603, - "mean_runtime_ms": 29.530547285718608, - "std_runtime_ms": 0.2645464377729889, - "median_peak_memory_mb": 0.5168647766113281, - "summary": { - "num_trials": 12.0, - "prob_mean": 0.21328124999999998, - "sig_count": 0.0, - "rate_mean": 50.073736692667104 - }, - "samples_runtime_ms": [ - 29.582787000009603, - 29.906474999989996, - 29.30477500001416, - 29.572859000012386, - 29.619026999995413, - 29.702882000009367, - 29.025025999999343 - ], - "samples_peak_memory_mb": [ - 0.5170211791992188, - 0.5168380737304688, - 0.5168533325195312, - 0.5168380737304688, - 0.51702880859375, - 0.5169715881347656, - 0.5168647766113281 - ] - }, - { - "case": "nspiketrain_get_sigrep", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.45410599997808276, - "mean_runtime_ms": 0.45695271428160467, - "std_runtime_ms": 0.02263874211807069, - "median_peak_memory_mb": 0.05826568603515625, - "summary": { - "n_bins": 1000.0, - "binary_sum": 746.0, - "count_sum": 800.0 - }, - "samples_runtime_ms": [ - 0.4896680000001652, - 0.4847839999797543, - 0.4665940000165847, - 0.45410599997808276, - 0.4348740000068574, - 0.4423789999918881, - 0.4262639999979001 - ], - "samples_peak_memory_mb": [ - 0.05821990966796875, - 0.0582427978515625, - 0.05826568603515625, - 0.05826568603515625, - 0.05826568603515625, - 0.05826568603515625, - 0.05826568603515625 - ] - }, - { - "case": "nspiketrain_get_sigrep", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.5966520000129094, - "mean_runtime_ms": 0.6046927142863622, - "std_runtime_ms": 0.017903597884198864, - "median_peak_memory_mb": 0.18491363525390625, - "summary": { - "n_bins": 3000.0, - "binary_sum": 2577.0, - "count_sum": 3000.0 - }, - "samples_runtime_ms": [ - 0.5925520000005235, - 0.6113869999921917, - 0.6010390000028565, - 0.5898320000028434, - 0.6456000000127915, - 0.5957869999804188, - 0.5966520000129094 - ], - "samples_peak_memory_mb": [ - 0.18486785888671875, - 0.1848907470703125, - 0.18491363525390625, - 0.18491363525390625, - 0.18491363525390625, - 0.18491363525390625, - 0.18491363525390625 - ] - }, - { - "case": "nspiketrain_get_sigrep", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.9368639999820516, - "mean_runtime_ms": 0.9338544285648303, - "std_runtime_ms": 0.016064032275827016, - "median_peak_memory_mb": 0.39853668212890625, - "summary": { - "n_bins": 5000.0, - "binary_sum": 5000.0, - "count_sum": 9000.0 - }, - "samples_runtime_ms": [ - 0.9550629999921512, - 0.9480619999919782, - 0.9367819999965832, - 0.9368639999820516, - 0.9381259999940994, - 0.9172879999823635, - 0.9047960000145849 - ], - "samples_peak_memory_mb": [ - 0.39849090576171875, - 0.3985137939453125, - 0.39853668212890625, - 0.39853668212890625, - 0.39853668212890625, - 0.39853668212890625, - 0.39853668212890625 - ] - }, - { - "case": "analysis_fit_glm_pipeline", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 5.966330000006792, - "mean_runtime_ms": 6.041203285718666, - "std_runtime_ms": 0.12616461532934142, - "median_peak_memory_mb": 0.10829353332519531, - "summary": { - "coeff_norm": 8.000957080893618e-16, - "intercept": -12.01100351405273, - "log_likelihood": -5.469277525370689e-06, - "pred_mean": 6.076975028189657e-06 - }, - "samples_runtime_ms": [ - 6.125865999990765, - 5.9515330000010636, - 5.966330000006792, - 6.293014000021913, - 6.0914080000031845, - 5.932005999994772, - 5.928266000012172 - ], - "samples_peak_memory_mb": [ - 0.10882186889648438, - 0.10835075378417969, - 0.10818862915039062, - 0.10810661315917969, - 0.10807609558105469, - 0.10838031768798828, - 0.10829353332519531 - ] - }, - { - "case": "analysis_fit_glm_pipeline", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 7.278939000002538, - "mean_runtime_ms": 7.281217000001204, - "std_runtime_ms": 0.1861142338621149, - "median_peak_memory_mb": 0.22568511962890625, - "summary": { - "coeff_norm": 9.782140347964175e-16, - "intercept": -12.704150666835071, - "log_likelihood": -5.46927767729412e-06, - "pred_mean": 3.038487598496732e-06 - }, - "samples_runtime_ms": [ - 7.373918000013191, - 7.072136999994427, - 7.63983100000587, - 7.278939000002538, - 7.033398000004354, - 7.2778239999991, - 7.292471999988948 - ], - "samples_peak_memory_mb": [ - 0.22541141510009766, - 0.22597312927246094, - 0.22608566284179688, - 0.22600650787353516, - 0.22519302368164062, - 0.22568511962890625, - 0.22504425048828125 - ] - }, - { - "case": "analysis_fit_glm_pipeline", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 9.020953999993253, - "mean_runtime_ms": 9.130242857143653, - "std_runtime_ms": 0.1717714863551795, - "median_peak_memory_mb": 0.4345836639404297, - "summary": { - "coeff_norm": 8.223875012950201e-16, - "intercept": -12.704150666835066, - "log_likelihood": -9.723160315189595e-06, - "pred_mean": 3.0384875984967483e-06 - }, - "samples_runtime_ms": [ - 9.016440000010562, - 9.243217999994613, - 9.486309000010351, - 8.973138000015979, - 9.167880999996214, - 9.020953999993253, - 9.003759999984595 - ], - "samples_peak_memory_mb": [ - 0.43473052978515625, - 0.4345836639404297, - 0.43505001068115234, - 0.43523597717285156, - 0.4340991973876953, - 0.43387603759765625, - 0.4338197708129883 - ] - } - ], - "environment": { - "python": "3.11.14", - "platform": "Linux-6.14.0-1017-azure-x86_64-with-glibc2.39", - "numpy": "2.4.2", - "scipy": "1.17.1", - "matplotlib": "3.10.8", - "omp_num_threads": "1", - "mkl_num_threads": "1", - "openblas_num_threads": "1", - "veclib_maximum_threads": "1" - } -} \ No newline at end of file diff --git a/tests/performance/fixtures/python/performance_baseline_linux_latest.csv b/tests/performance/fixtures/python/performance_baseline_linux_latest.csv deleted file mode 100644 index cfa04b5f..00000000 --- a/tests/performance/fixtures/python/performance_baseline_linux_latest.csv +++ /dev/null @@ -1,22 +0,0 @@ -case,tier,repeats,median_runtime_ms,mean_runtime_ms,std_runtime_ms,median_peak_memory_mb,summary -unit_impulse_basis,S,7,1.7951030000062929,1.800190142854977,0.030044572115161792,0.39142704010009766,"{""cols"": 50.0, ""rows"": 501.0, ""total_mass"": 500.0}" -unit_impulse_basis,M,7,6.6628950000051645,6.653057285713463,1.4829550166016998,3.076824188232422,"{""cols"": 100.0, ""rows"": 2001.0, ""total_mass"": 2000.0}" -unit_impulse_basis,L,7,16.024357000020473,16.10430300001196,0.23143857554091385,18.37380599975586,"{""cols"": 200.0, ""rows"": 6001.0, ""total_mass"": 6000.0}" -covariate_resample,S,7,0.29961199999206656,0.29913757142756886,0.009541632013909111,0.06201934814453125,"{""cols"": 1.0, ""rows"": 1001.0, ""signal_energy"": 0.5195204795204795}" -covariate_resample,M,7,0.3440330000046288,0.34703042856725524,0.01738929698449399,0.1356220245361328,"{""cols"": 1.0, ""rows"": 3001.0, ""signal_energy"": 0.5198042747802833}" -covariate_resample,L,7,0.4108699999960663,0.4196135714299284,0.017089334564883416,0.2376880645751953,"{""cols"": 1.0, ""rows"": 6001.0, ""signal_energy"": 0.5199200133311115}" -history_design_matrix,S,7,0.3993699999966793,0.4031285714266427,0.013794363505286652,0.0890960693359375,"{""cols"": 4.0, ""rows"": 1000.0, ""total_count"": 9737.0}" -history_design_matrix,M,7,0.9118490000048496,0.9101645714265162,0.05885667560476089,0.43691253662109375,"{""cols"": 4.0, ""rows"": 5000.0, ""total_count"": 243740.0}" -history_design_matrix,L,7,1.8411630000230161,1.8406257142860991,0.014739662895922209,0.8869705200195312,"{""cols"": 4.0, ""rows"": 10000.0, ""total_count"": 1462420.0}" -simulate_cif_thinning,S,7,12.83120299999041,12.864690857132441,0.17008704628575258,0.07111740112304688,"{""mean_spikes_per_unit"": 12.6, ""num_units"": 5.0, ""total_spikes"": 63.0}" -simulate_cif_thinning,M,7,49.6265170000072,49.62809900000106,0.2452487903460643,0.13447189331054688,"{""mean_spikes_per_unit"": 23.9, ""num_units"": 10.0, ""total_spikes"": 239.0}" -simulate_cif_thinning,L,7,148.1780189999995,147.96911385714193,0.8086479240372416,0.20068740844726562,"{""mean_spikes_per_unit"": 35.2, ""num_units"": 20.0, ""total_spikes"": 704.0}" -decoding_spike_rate_cis,S,7,9.922279000022627,9.8990294285792,0.09977266978679186,0.08637428283691406,"{""num_trials"": 6.0, ""prob_mean"": 0.1509259259259259, ""rate_mean"": 50.4457886636761, ""sig_count"": 0.0}" -decoding_spike_rate_cis,M,7,15.846046000007163,15.825482000000843,0.11100674963412104,0.19997024536132812,"{""num_trials"": 8.0, ""prob_mean"": 0.18562499999999998, ""rate_mean"": 50.12398439148756, ""sig_count"": 0.0}" -decoding_spike_rate_cis,L,7,29.582787000009603,29.530547285718608,0.2645464377729889,0.5168647766113281,"{""num_trials"": 12.0, ""prob_mean"": 0.21328124999999998, ""rate_mean"": 50.073736692667104, ""sig_count"": 0.0}" -nspiketrain_get_sigrep,S,7,0.45410599997808276,0.45695271428160467,0.02263874211807069,0.05826568603515625,"{""binary_sum"": 746.0, ""count_sum"": 800.0, ""n_bins"": 1000.0}" -nspiketrain_get_sigrep,M,7,0.5966520000129094,0.6046927142863622,0.017903597884198864,0.18491363525390625,"{""binary_sum"": 2577.0, ""count_sum"": 3000.0, ""n_bins"": 3000.0}" -nspiketrain_get_sigrep,L,7,0.9368639999820516,0.9338544285648303,0.016064032275827016,0.39853668212890625,"{""binary_sum"": 5000.0, ""count_sum"": 9000.0, ""n_bins"": 5000.0}" -analysis_fit_glm_pipeline,S,7,5.966330000006792,6.041203285718666,0.12616461532934142,0.10829353332519531,"{""coeff_norm"": 8.000957080893618e-16, ""intercept"": -12.01100351405273, ""log_likelihood"": -5.469277525370689e-06, ""pred_mean"": 6.076975028189657e-06}" -analysis_fit_glm_pipeline,M,7,7.278939000002538,7.281217000001204,0.1861142338621149,0.22568511962890625,"{""coeff_norm"": 9.782140347964175e-16, ""intercept"": -12.704150666835071, ""log_likelihood"": -5.46927767729412e-06, ""pred_mean"": 3.038487598496732e-06}" -analysis_fit_glm_pipeline,L,7,9.020953999993253,9.130242857143653,0.1717714863551795,0.4345836639404297,"{""coeff_norm"": 8.223875012950201e-16, ""intercept"": -12.704150666835066, ""log_likelihood"": -9.723160315189595e-06, ""pred_mean"": 3.0384875984967483e-06}" diff --git a/tests/performance/fixtures/python/performance_baseline_linux_latest.json b/tests/performance/fixtures/python/performance_baseline_linux_latest.json deleted file mode 100644 index 3a34741d..00000000 --- a/tests/performance/fixtures/python/performance_baseline_linux_latest.json +++ /dev/null @@ -1,724 +0,0 @@ -{ - "schema_version": 1, - "generated_at_utc": "2026-03-04T06:13:09Z", - "implementation": "python", - "repo_root": "/home/runner/work/nSTAT-python/nSTAT-python", - "git_sha": "08ac1adde9a2d9b74a819c22e1fc19b0c2d758b3", - "tiers": [ - "S", - "M", - "L" - ], - "cases": [ - { - "case": "unit_impulse_basis", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 1.7951030000062929, - "mean_runtime_ms": 1.800190142854977, - "std_runtime_ms": 0.030044572115161792, - "median_peak_memory_mb": 0.39142704010009766, - "summary": { - "rows": 501.0, - "cols": 50.0, - "total_mass": 500.0 - }, - "samples_runtime_ms": [ - 1.864554999997381, - 1.7951030000062929, - 1.8160890000160634, - 1.7815100000007078, - 1.778256999983796, - 1.7982370000027004, - 1.7675799999778974 - ], - "samples_peak_memory_mb": [ - 0.39147281646728516, - 0.39145755767822266, - 0.39144229888916016, - 0.39142704010009766, - 0.39141178131103516, - 0.39138126373291016, - 0.39136600494384766 - ] - }, - { - "case": "unit_impulse_basis", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 6.6628950000051645, - "mean_runtime_ms": 6.653057285713463, - "std_runtime_ms": 1.4829550166016998, - "median_peak_memory_mb": 3.076824188232422, - "summary": { - "rows": 2001.0, - "cols": 100.0, - "total_mass": 2000.0 - }, - "samples_runtime_ms": [ - 5.253328000009105, - 5.174608000004355, - 5.262399000002915, - 9.362254999984998, - 8.050177000001213, - 6.805738999986488, - 6.6628950000051645 - ], - "samples_peak_memory_mb": [ - 3.0769691467285156, - 3.0769615173339844, - 3.076953887939453, - 3.076824188232422, - 3.0768089294433594, - 3.076801300048828, - 3.076793670654297 - ] - }, - { - "case": "unit_impulse_basis", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 16.024357000020473, - "mean_runtime_ms": 16.10430300001196, - "std_runtime_ms": 0.23143857554091385, - "median_peak_memory_mb": 18.37380599975586, - "summary": { - "rows": 6001.0, - "cols": 200.0, - "total_mass": 6000.0 - }, - "samples_runtime_ms": [ - 16.00895999999352, - 16.42452300001196, - 15.90741600000456, - 16.075996000012083, - 15.817221000020254, - 16.024357000020473, - 16.471648000020878 - ], - "samples_peak_memory_mb": [ - 18.373836517333984, - 18.373828887939453, - 18.373821258544922, - 18.37380599975586, - 18.373798370361328, - 18.373790740966797, - 18.373783111572266 - ] - }, - { - "case": "covariate_resample", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.29961199999206656, - "mean_runtime_ms": 0.29913757142756886, - "std_runtime_ms": 0.009541632013909111, - "median_peak_memory_mb": 0.06201934814453125, - "summary": { - "rows": 1001.0, - "cols": 1.0, - "signal_energy": 0.5195204795204795 - }, - "samples_runtime_ms": [ - 0.31718400001068403, - 0.29961199999206656, - 0.2958649999982299, - 0.30228200000692595, - 0.28286899998875015, - 0.29462000000535227, - 0.3015309999909732 - ], - "samples_peak_memory_mb": [ - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125, - 0.06201934814453125 - ] - }, - { - "case": "covariate_resample", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.3440330000046288, - "mean_runtime_ms": 0.34703042856725524, - "std_runtime_ms": 0.01738929698449399, - "median_peak_memory_mb": 0.1356220245361328, - "summary": { - "rows": 3001.0, - "cols": 1.0, - "signal_energy": 0.5198042747802833 - }, - "samples_runtime_ms": [ - 0.3440330000046288, - 0.3872629999932542, - 0.3394640000067284, - 0.34691299998712566, - 0.3345760000001974, - 0.3304029999924296, - 0.34656099998642276 - ], - "samples_peak_memory_mb": [ - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328, - 0.1356220245361328 - ] - }, - { - "case": "covariate_resample", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.4108699999960663, - "mean_runtime_ms": 0.4196135714299284, - "std_runtime_ms": 0.017089334564883416, - "median_peak_memory_mb": 0.2376880645751953, - "summary": { - "rows": 6001.0, - "cols": 1.0, - "signal_energy": 0.5199200133311115 - }, - "samples_runtime_ms": [ - 0.42476900000565365, - 0.4108699999960663, - 0.4027309999798945, - 0.4545680000092034, - 0.4038190000130726, - 0.41067399999406007, - 0.42986400001154834 - ], - "samples_peak_memory_mb": [ - 0.23766517639160156, - 0.23766517639160156, - 0.2376880645751953, - 0.2376880645751953, - 0.2376880645751953, - 0.2376880645751953, - 0.2376880645751953 - ] - }, - { - "case": "history_design_matrix", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.3993699999966793, - "mean_runtime_ms": 0.4031285714266427, - "std_runtime_ms": 0.013794363505286652, - "median_peak_memory_mb": 0.0890960693359375, - "summary": { - "rows": 1000.0, - "cols": 4.0, - "total_count": 9737.0 - }, - "samples_runtime_ms": [ - 0.4107149999867943, - 0.3993699999966793, - 0.4110679999769218, - 0.38829799999007264, - 0.4294660000141448, - 0.3940240000019912, - 0.38895900001989503 - ], - "samples_peak_memory_mb": [ - 0.089080810546875, - 0.0890960693359375, - 0.089111328125, - 0.08910369873046875, - 0.0890960693359375, - 0.089080810546875, - 0.08907318115234375 - ] - }, - { - "case": "history_design_matrix", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.9118490000048496, - "mean_runtime_ms": 0.9101645714265162, - "std_runtime_ms": 0.05885667560476089, - "median_peak_memory_mb": 0.43691253662109375, - "summary": { - "rows": 5000.0, - "cols": 4.0, - "total_count": 243740.0 - }, - "samples_runtime_ms": [ - 0.9850819999996929, - 0.9938119999901573, - 0.9118490000048496, - 0.8551290000013978, - 0.8512590000009368, - 0.8419250000031298, - 0.9320959999854495 - ], - "samples_peak_memory_mb": [ - 0.4369049072265625, - 0.436920166015625, - 0.4369354248046875, - 0.43692779541015625, - 0.43691253662109375, - 0.4369049072265625, - 0.43689727783203125 - ] - }, - { - "case": "history_design_matrix", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 1.8411630000230161, - "mean_runtime_ms": 1.8406257142860991, - "std_runtime_ms": 0.014739662895922209, - "median_peak_memory_mb": 0.8869705200195312, - "summary": { - "rows": 10000.0, - "cols": 4.0, - "total_count": 1462420.0 - }, - "samples_runtime_ms": [ - 1.8261639999934687, - 1.8664680000028966, - 1.843834999988303, - 1.8197750000013002, - 1.8411630000230161, - 1.833944999987125, - 1.8530300000065836 - ], - "samples_peak_memory_mb": [ - 0.886962890625, - 0.8869781494140625, - 0.886993408203125, - 0.8869781494140625, - 0.8869705200195312, - 0.886962890625, - 0.8869552612304688 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 12.83120299999041, - "mean_runtime_ms": 12.864690857132441, - "std_runtime_ms": 0.17008704628575258, - "median_peak_memory_mb": 0.07111740112304688, - "summary": { - "num_units": 5.0, - "total_spikes": 63.0, - "mean_spikes_per_unit": 12.6 - }, - "samples_runtime_ms": [ - 13.047533999980487, - 13.09318899998857, - 13.005707999980132, - 12.636868999976514, - 12.747445999991669, - 12.690887000019302, - 12.83120299999041 - ], - "samples_peak_memory_mb": [ - 0.07109451293945312, - 0.07122421264648438, - 0.07120132446289062, - 0.07110214233398438, - 0.07108688354492188, - 0.07111740112304688, - 0.07133102416992188 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 49.6265170000072, - "mean_runtime_ms": 49.62809900000106, - "std_runtime_ms": 0.2452487903460643, - "median_peak_memory_mb": 0.13447189331054688, - "summary": { - "num_units": 10.0, - "total_spikes": 239.0, - "mean_spikes_per_unit": 23.9 - }, - "samples_runtime_ms": [ - 49.933012999986204, - 49.47553599998855, - 49.15841700000101, - 49.6265170000072, - 49.57282899999882, - 49.74063900002079, - 49.889742000004844 - ], - "samples_peak_memory_mb": [ - 0.13447952270507812, - 0.13440322875976562, - 0.13442611694335938, - 0.13442611694335938, - 0.13451004028320312, - 0.13466262817382812, - 0.13447189331054688 - ] - }, - { - "case": "simulate_cif_thinning", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 148.1780189999995, - "mean_runtime_ms": 147.96911385714193, - "std_runtime_ms": 0.8086479240372416, - "median_peak_memory_mb": 0.20068740844726562, - "summary": { - "num_units": 20.0, - "total_spikes": 704.0, - "mean_spikes_per_unit": 35.2 - }, - "samples_runtime_ms": [ - 148.17126599999142, - 149.08999700000436, - 148.1780189999995, - 148.30773799999974, - 147.23606999999106, - 146.41610300000707, - 148.3846040000003 - ], - "samples_peak_memory_mb": [ - 0.20109176635742188, - 0.20068740844726562, - 0.20077896118164062, - 0.20093154907226562, - 0.20005416870117188, - 0.20032882690429688, - 0.20064163208007812 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 9.922279000022627, - "mean_runtime_ms": 9.8990294285792, - "std_runtime_ms": 0.09977266978679186, - "median_peak_memory_mb": 0.08637428283691406, - "summary": { - "num_trials": 6.0, - "prob_mean": 0.1509259259259259, - "sig_count": 0.0, - "rate_mean": 50.4457886636761 - }, - "samples_runtime_ms": [ - 10.008196000001135, - 9.922279000022627, - 9.995544000020118, - 9.960062000004655, - 9.712960000001658, - 9.801446000011538, - 9.892718999992667 - ], - "samples_peak_memory_mb": [ - 0.08637428283691406, - 0.08667182922363281, - 0.08637428283691406, - 0.08632469177246094, - 0.08632469177246094, - 0.08667182922363281, - 0.08662223815917969 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 15.846046000007163, - "mean_runtime_ms": 15.825482000000843, - "std_runtime_ms": 0.11100674963412104, - "median_peak_memory_mb": 0.19997024536132812, - "summary": { - "num_trials": 8.0, - "prob_mean": 0.18562499999999998, - "sig_count": 0.0, - "rate_mean": 50.12398439148756 - }, - "samples_runtime_ms": [ - 15.777557000006937, - 15.72368399999391, - 15.935339000009208, - 15.636774000000742, - 15.846046000007163, - 15.8855459999927, - 15.973427999995238 - ], - "samples_peak_memory_mb": [ - 0.1999664306640625, - 0.2000579833984375, - 0.199951171875, - 0.19994354248046875, - 0.20047378540039062, - 0.19997024536132812, - 0.200408935546875 - ] - }, - { - "case": "decoding_spike_rate_cis", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 29.582787000009603, - "mean_runtime_ms": 29.530547285718608, - "std_runtime_ms": 0.2645464377729889, - "median_peak_memory_mb": 0.5168647766113281, - "summary": { - "num_trials": 12.0, - "prob_mean": 0.21328124999999998, - "sig_count": 0.0, - "rate_mean": 50.073736692667104 - }, - "samples_runtime_ms": [ - 29.582787000009603, - 29.906474999989996, - 29.30477500001416, - 29.572859000012386, - 29.619026999995413, - 29.702882000009367, - 29.025025999999343 - ], - "samples_peak_memory_mb": [ - 0.5170211791992188, - 0.5168380737304688, - 0.5168533325195312, - 0.5168380737304688, - 0.51702880859375, - 0.5169715881347656, - 0.5168647766113281 - ] - }, - { - "case": "nspiketrain_get_sigrep", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.45410599997808276, - "mean_runtime_ms": 0.45695271428160467, - "std_runtime_ms": 0.02263874211807069, - "median_peak_memory_mb": 0.05826568603515625, - "summary": { - "n_bins": 1000.0, - "binary_sum": 746.0, - "count_sum": 800.0 - }, - "samples_runtime_ms": [ - 0.4896680000001652, - 0.4847839999797543, - 0.4665940000165847, - 0.45410599997808276, - 0.4348740000068574, - 0.4423789999918881, - 0.4262639999979001 - ], - "samples_peak_memory_mb": [ - 0.05821990966796875, - 0.0582427978515625, - 0.05826568603515625, - 0.05826568603515625, - 0.05826568603515625, - 0.05826568603515625, - 0.05826568603515625 - ] - }, - { - "case": "nspiketrain_get_sigrep", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.5966520000129094, - "mean_runtime_ms": 0.6046927142863622, - "std_runtime_ms": 0.017903597884198864, - "median_peak_memory_mb": 0.18491363525390625, - "summary": { - "n_bins": 3000.0, - "binary_sum": 2577.0, - "count_sum": 3000.0 - }, - "samples_runtime_ms": [ - 0.5925520000005235, - 0.6113869999921917, - 0.6010390000028565, - 0.5898320000028434, - 0.6456000000127915, - 0.5957869999804188, - 0.5966520000129094 - ], - "samples_peak_memory_mb": [ - 0.18486785888671875, - 0.1848907470703125, - 0.18491363525390625, - 0.18491363525390625, - 0.18491363525390625, - 0.18491363525390625, - 0.18491363525390625 - ] - }, - { - "case": "nspiketrain_get_sigrep", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 0.9368639999820516, - "mean_runtime_ms": 0.9338544285648303, - "std_runtime_ms": 0.016064032275827016, - "median_peak_memory_mb": 0.39853668212890625, - "summary": { - "n_bins": 5000.0, - "binary_sum": 5000.0, - "count_sum": 9000.0 - }, - "samples_runtime_ms": [ - 0.9550629999921512, - 0.9480619999919782, - 0.9367819999965832, - 0.9368639999820516, - 0.9381259999940994, - 0.9172879999823635, - 0.9047960000145849 - ], - "samples_peak_memory_mb": [ - 0.39849090576171875, - 0.3985137939453125, - 0.39853668212890625, - 0.39853668212890625, - 0.39853668212890625, - 0.39853668212890625, - 0.39853668212890625 - ] - }, - { - "case": "analysis_fit_glm_pipeline", - "tier": "S", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 5.966330000006792, - "mean_runtime_ms": 6.041203285718666, - "std_runtime_ms": 0.12616461532934142, - "median_peak_memory_mb": 0.10829353332519531, - "summary": { - "coeff_norm": 8.000957080893618e-16, - "intercept": -12.01100351405273, - "log_likelihood": -5.469277525370689e-06, - "pred_mean": 6.076975028189657e-06 - }, - "samples_runtime_ms": [ - 6.125865999990765, - 5.9515330000010636, - 5.966330000006792, - 6.293014000021913, - 6.0914080000031845, - 5.932005999994772, - 5.928266000012172 - ], - "samples_peak_memory_mb": [ - 0.10882186889648438, - 0.10835075378417969, - 0.10818862915039062, - 0.10810661315917969, - 0.10807609558105469, - 0.10838031768798828, - 0.10829353332519531 - ] - }, - { - "case": "analysis_fit_glm_pipeline", - "tier": "M", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 7.278939000002538, - "mean_runtime_ms": 7.281217000001204, - "std_runtime_ms": 0.1861142338621149, - "median_peak_memory_mb": 0.22568511962890625, - "summary": { - "coeff_norm": 9.782140347964175e-16, - "intercept": -12.704150666835071, - "log_likelihood": -5.46927767729412e-06, - "pred_mean": 3.038487598496732e-06 - }, - "samples_runtime_ms": [ - 7.373918000013191, - 7.072136999994427, - 7.63983100000587, - 7.278939000002538, - 7.033398000004354, - 7.2778239999991, - 7.292471999988948 - ], - "samples_peak_memory_mb": [ - 0.22541141510009766, - 0.22597312927246094, - 0.22608566284179688, - 0.22600650787353516, - 0.22519302368164062, - 0.22568511962890625, - 0.22504425048828125 - ] - }, - { - "case": "analysis_fit_glm_pipeline", - "tier": "L", - "repeats": 7, - "warmup": 2, - "median_runtime_ms": 9.020953999993253, - "mean_runtime_ms": 9.130242857143653, - "std_runtime_ms": 0.1717714863551795, - "median_peak_memory_mb": 0.4345836639404297, - "summary": { - "coeff_norm": 8.223875012950201e-16, - "intercept": -12.704150666835066, - "log_likelihood": -9.723160315189595e-06, - "pred_mean": 3.0384875984967483e-06 - }, - "samples_runtime_ms": [ - 9.016440000010562, - 9.243217999994613, - 9.486309000010351, - 8.973138000015979, - 9.167880999996214, - 9.020953999993253, - 9.003759999984595 - ], - "samples_peak_memory_mb": [ - 0.43473052978515625, - 0.4345836639404297, - 0.43505001068115234, - 0.43523597717285156, - 0.4340991973876953, - 0.43387603759765625, - 0.4338197708129883 - ] - } - ], - "environment": { - "python": "3.11.14", - "platform": "Linux-6.14.0-1017-azure-x86_64-with-glibc2.39", - "numpy": "2.4.2", - "scipy": "1.17.1", - "matplotlib": "3.10.8", - "omp_num_threads": "1", - "mkl_num_threads": "1", - "openblas_num_threads": "1", - "veclib_maximum_threads": "1" - } -} \ No newline at end of file diff --git a/tests/performance/test_pytest_benchmarks.py b/tests/performance/test_pytest_benchmarks.py deleted file mode 100644 index 2407abfb..00000000 --- a/tests/performance/test_pytest_benchmarks.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import annotations - -import os - -import pytest - -from nstat.performance_workloads import CASE_ORDER, run_python_workload - -pytestmark = pytest.mark.skipif( - os.getenv("NSTAT_RUN_PERF_BENCHMARKS", "0") != "1", - reason="Performance benchmarks run only in dedicated CI jobs", -) - - -@pytest.mark.performance -@pytest.mark.parametrize("case", CASE_ORDER) -def test_benchmark_tier_s(benchmark: pytest.BenchmarkFixture, case: str) -> None: # type: ignore[name-defined] - summary = benchmark(run_python_workload, case, "S", 20260303) - assert summary - assert all(value == value for value in summary.values()) diff --git a/tests/performance/test_workload_outputs.py b/tests/performance/test_workload_outputs.py deleted file mode 100644 index d466a035..00000000 --- a/tests/performance/test_workload_outputs.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -from nstat.performance_workloads import CASE_ORDER, TIER_ORDER, run_python_workload - - -def test_workloads_return_finite_metrics() -> None: - for case in CASE_ORDER: - for tier in TIER_ORDER: - metrics = run_python_workload(case=case, tier=tier, seed=20260303) - assert metrics, f"{case}/{tier} returned no metrics" - for name, value in metrics.items(): - assert isinstance(value, float), f"{case}/{tier}:{name} must be float" - assert value == value, f"{case}/{tier}:{name} is NaN" - assert value != float("inf"), f"{case}/{tier}:{name} is inf" diff --git a/tests/test_analysis_fit_decode.py b/tests/test_analysis_fit_decode.py deleted file mode 100644 index bf4287e9..00000000 --- a/tests/test_analysis_fit_decode.py +++ /dev/null @@ -1,38 +0,0 @@ -import numpy as np - -from nstat.analysis import Analysis -from nstat.decoding import DecodingAlgorithms -from nstat.signal import Covariate -from nstat.spikes import SpikeTrain, SpikeTrainCollection -from nstat.trial import CovariateCollection, Trial, TrialConfig - - -def _trial() -> Trial: - t = np.linspace(0.0, 1.0, 1001) - stim = np.sin(2 * np.pi * 5 * t) - cov = Covariate(time=t, data=stim, name="stim") - - spikes = np.array([0.12, 0.26, 0.41, 0.6, 0.77, 0.91]) - st = SpikeTrain(spike_times=spikes, t_start=0.0, t_end=1.0) - - return Trial( - spikes=SpikeTrainCollection([st]), - covariates=CovariateCollection([cov]), - ) - - -def test_fit_trial_poisson() -> None: - trial = _trial() - cfg = TrialConfig(covariate_labels=["stim"], sample_rate_hz=1000.0, fit_type="poisson") - res = Analysis.fit_trial(trial, cfg) - assert res.n_parameters >= 1 - assert np.isfinite(res.aic()) - - -def test_decode_algorithms() -> None: - rng = np.random.default_rng(0) - mat = rng.binomial(1, 0.1, size=(8, 200)).astype(float) - rates, prob, sig = DecodingAlgorithms.compute_spike_rate_cis(mat) - assert rates.shape == (8,) - assert prob.shape == (8, 8) - assert sig.shape == (8, 8) diff --git a/tests/test_analysis_pipeline.py b/tests/test_analysis_pipeline.py new file mode 100644 index 00000000..1da1fb7f --- /dev/null +++ b/tests/test_analysis_pipeline.py @@ -0,0 +1,25 @@ +from __future__ import annotations + +import numpy as np + +from nstat import Analysis, CIFModel, ConfigCollection, Covariate, CovariateCollection, FitSummary, Trial, TrialConfig + + +def test_trial_analysis_pipeline() -> None: + t = np.arange(0.0, 1.0, 0.001) + stim = np.sin(2 * np.pi * 2 * t) + cov = Covariate(t, stim, "stim", "time", "s", "a.u.", ["stim"]) + + model = CIFModel(t, 10.0 + 5.0 * np.maximum(stim, 0.0), name="lambda") + spikes = model.simulate(num_realizations=3, seed=2) + + trial = Trial(spike_collection=spikes, covariate_collection=CovariateCollection([cov])) + cfgs = ConfigCollection([TrialConfig(covMask=["stim"], sampleRate=1000.0, name="stim_model")]) + + fits = Analysis.run_analysis_for_all_neurons(trial, cfgs) + assert len(fits) == 3 + assert fits[0].AIC.shape == (1,) + + summary = FitSummary(fits) + assert summary.numNeurons == 3 + assert summary.AIC.shape == (1,) diff --git a/tests/test_api_surface.py b/tests/test_api_surface.py new file mode 100644 index 00000000..1aef5dc4 --- /dev/null +++ b/tests/test_api_surface.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +import warnings + +import nstat + + +def test_canonical_api_imports() -> None: + assert nstat.Signal is not None + assert nstat.SpikeTrain is not None + assert nstat.SpikeTrainCollection is not None + assert nstat.Trial is not None + assert nstat.Analysis is not None + assert nstat.FitResult is not None + assert nstat.FitSummary is not None + assert nstat.CIFModel is not None + assert nstat.DecoderSuite is not None + + +def test_compatibility_adapters_emit_deprecation() -> None: + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + from nstat.SignalObj import SignalObj + + _ = SignalObj([0.0, 1.0], [1.0, 2.0]) + assert any("deprecated" in str(item.message).lower() for item in w) diff --git a/tests/test_behavior_contracts.py b/tests/test_behavior_contracts.py deleted file mode 100644 index 1ebefa9c..00000000 --- a/tests/test_behavior_contracts.py +++ /dev/null @@ -1,325 +0,0 @@ -from __future__ import annotations - -import importlib -from pathlib import Path -from typing import Any - -import numpy as np -import yaml - -from nstat.analysis import Analysis -from nstat.cif import CIFModel -from nstat.confidence import ConfidenceInterval -from nstat.decoding import DecodingAlgorithms -from nstat.events import Events -from nstat.fit import FitResult, FitSummary -from nstat.history import HistoryBasis -from nstat.signal import Covariate, Signal -from nstat.spikes import SpikeTrain, SpikeTrainCollection -from nstat.trial import ConfigCollection, CovariateCollection, Trial, TrialConfig - - -REQUIRED_MATLAB_CLASSES = { - "SignalObj", - "Covariate", - "ConfidenceInterval", - "Events", - "History", - "nspikeTrain", - "nstColl", - "CovColl", - "TrialConfig", - "ConfigColl", - "Trial", - "CIF", - "Analysis", - "FitResult", - "FitResSummary", - "DecodingAlgorithms", -} - - -def _load_yaml(path: str) -> dict[str, Any]: - return yaml.safe_load(Path(path).read_text(encoding="utf-8")) - - -def _resolve_obj(path: str) -> Any: - module_name, attr_name = path.rsplit(".", 1) - module = importlib.import_module(module_name) - return getattr(module, attr_name) - - -def _extract_value(obj: Any, path: str) -> Any: - cursor = obj - for token in path.split("."): - if token.isdigit(): - cursor = cursor[int(token)] - else: - cursor = getattr(cursor, token) - return cursor - - -def _tol_value(key: str) -> float: - payload = _load_yaml("tests/parity/tolerances.yml") - value: Any = payload - for token in key.split("."): - value = value[token] - return float(value) - - -def _build_signal_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 2.0, 5) - obj = Signal(time=time, data=np.array([1.0, 2.0, 3.0, 2.0, 1.0]), name="sig") - return obj, {} - - -def _build_covariate_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 1.0, 5) - data = np.column_stack([np.sin(2 * np.pi * time), np.cos(2 * np.pi * time)]) - obj = Covariate(time=time, data=data, name="stim", labels=["stim1", "stim2"]) - return obj, {} - - -def _build_confidence_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 1.0, 5) - lower = np.array([0.0, 0.4, 0.8, 1.2, 1.6]) - upper = lower + 0.5 - obj = ConfidenceInterval(time=time, lower=lower, upper=upper, level=0.95) - return obj, {"contains_args": [np.array([0.1, 0.5, 0.9, 2.1, -0.1])]} - - -def _build_events_basic() -> tuple[Any, dict[str, Any]]: - obj = Events(times=np.array([0.1, 0.4, 0.9]), labels=["a", "b", "c"]) - return obj, {} - - -def _build_history_basic() -> tuple[Any, dict[str, Any]]: - obj = HistoryBasis(bin_edges_s=np.array([0.0, 0.05, 0.1, 0.2])) - args = [np.array([0.12, 0.28]), np.array([0.15, 0.25, 0.30, 0.40])] - return obj, {"design_args": args} - - -def _build_spike_train_basic() -> tuple[Any, dict[str, Any]]: - obj = SpikeTrain(spike_times=np.array([0.1, 0.2, 0.25, 0.9]), t_start=0.0, t_end=1.0) - return obj, {} - - -def _build_spike_coll_basic() -> tuple[Any, dict[str, Any]]: - st1 = SpikeTrain(spike_times=np.array([0.1, 0.2, 0.25, 0.9]), t_start=0.0, t_end=1.0) - st2 = SpikeTrain(spike_times=np.array([0.15, 0.4, 0.8]), t_start=0.0, t_end=1.0) - obj = SpikeTrainCollection([st1, st2]) - return obj, {} - - -def _build_covcoll_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 1.0, 5) - cov1 = Covariate(time=time, data=np.sin(2 * np.pi * time), name="sine", labels=["sine"]) - cov2 = Covariate( - time=time, - data=np.column_stack([time, time**2]), - name="poly", - labels=["t", "t2"], - ) - obj = CovariateCollection([cov1, cov2]) - return obj, {} - - -def _build_trial_config_basic() -> tuple[Any, dict[str, Any]]: - obj = TrialConfig(covariate_labels=["stim"], sample_rate_hz=1000.0, fit_type="poisson", name="cfg") - return obj, {} - - -def _build_config_coll_basic() -> tuple[Any, dict[str, Any]]: - cfg1 = TrialConfig(covariate_labels=["stim"], sample_rate_hz=1000.0, fit_type="poisson", name="a") - cfg2 = TrialConfig(covariate_labels=["stim"], sample_rate_hz=500.0, fit_type="binomial", name="b") - obj = ConfigCollection([cfg1, cfg2]) - return obj, {} - - -def _build_trial_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 1.0, 11) - cov1 = Covariate(time=time, data=np.sin(2 * np.pi * time), name="sine", labels=["sine"]) - cov2 = Covariate(time=time, data=np.column_stack([time, time**2]), name="poly", labels=["t", "t2"]) - st = SpikeTrain(spike_times=np.array([0.1, 0.2, 0.25, 0.9]), t_start=0.0, t_end=1.0) - obj = Trial(spikes=SpikeTrainCollection([st]), covariates=CovariateCollection([cov1, cov2])) - return obj, {} - - -def _build_cif_basic() -> tuple[Any, dict[str, Any]]: - obj = CIFModel(coefficients=np.array([0.8]), intercept=-1.0, link="binomial") - X = np.linspace(-1.0, 1.0, 5)[:, None] - y = np.array([0, 0, 0, 1, 1], dtype=float) - return obj, {"eval_args": [X], "ll_args": [y, X, 1.0]} - - -def _build_analysis_basic() -> tuple[Any, dict[str, Any]]: - rng = np.random.default_rng(123) - x = rng.normal(size=2000) - X = x[:, None] - true_beta = 1.15 - p = 1.0 / (1.0 + np.exp(-(-1.2 + true_beta * x))) - y = rng.binomial(1, p).astype(float) - kwargs = {"X": X, "y": y, "fit_type": "binomial", "dt": 1.0} - return Analysis, {"fit_kwargs": kwargs, "true_beta": true_beta} - - -def _build_fit_result_basic() -> tuple[Any, dict[str, Any]]: - obj = FitResult( - coefficients=np.array([0.5]), - intercept=-1.0, - fit_type="binomial", - log_likelihood=-10.0, - n_samples=100, - n_parameters=2, - ) - X = np.array([[-1.0], [0.0], [1.0]]) - return obj, {"predict_args": [X]} - - -def _build_fit_summary_basic() -> tuple[Any, dict[str, Any]]: - r1 = FitResult( - coefficients=np.array([0.5]), - intercept=-1.0, - fit_type="binomial", - log_likelihood=-8.0, - n_samples=100, - n_parameters=2, - ) - r2 = FitResult( - coefficients=np.array([0.1]), - intercept=-0.5, - fit_type="poisson", - log_likelihood=-20.0, - n_samples=100, - n_parameters=2, - ) - obj = FitSummary([r1, r2]) - return obj, {} - - -def _build_decoding_basic() -> tuple[Any, dict[str, Any]]: - ci_matrix = np.array( - [ - [0, 0, 1, 0, 0, 1], - [0, 1, 1, 0, 0, 1], - [1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 0, 1], - ], - dtype=float, - ) - wc_counts = np.array( - [ - [0, 0, 1, 2, 1, 0], - [1, 2, 2, 1, 0, 0], - [0, 0, 0, 1, 2, 2], - ], - dtype=float, - ) - tuning = np.array( - [ - [1.0, 0.5, 0.1], - [0.2, 1.1, 0.4], - [0.1, 0.4, 1.2], - ], - dtype=float, - ) - return DecodingAlgorithms, {"ci_args": [ci_matrix], "wc_args": [wc_counts, tuning]} - - -SCENARIO_BUILDERS = { - "signal_basic": _build_signal_basic, - "covariate_basic": _build_covariate_basic, - "confidence_basic": _build_confidence_basic, - "events_basic": _build_events_basic, - "history_basic": _build_history_basic, - "spike_train_basic": _build_spike_train_basic, - "spike_coll_basic": _build_spike_coll_basic, - "covcoll_basic": _build_covcoll_basic, - "trial_config_basic": _build_trial_config_basic, - "config_coll_basic": _build_config_coll_basic, - "trial_basic": _build_trial_basic, - "cif_basic": _build_cif_basic, - "analysis_basic": _build_analysis_basic, - "fit_result_basic": _build_fit_result_basic, - "fit_summary_basic": _build_fit_summary_basic, - "decoding_basic": _build_decoding_basic, -} - - -def _assert_expectation(result: Any, expect: dict[str, Any], context: dict[str, Any]) -> None: - if "instance_of" in expect: - klass = _resolve_obj(str(expect["instance_of"])) - assert isinstance(result, klass) - if "shape" in expect: - expected_shape = tuple(int(x) for x in expect["shape"]) - assert np.asarray(result).shape == expected_shape - if "length" in expect: - assert len(result) == int(expect["length"]) - if "equals" in expect: - expected = expect["equals"] - if isinstance(expected, list): - assert np.array_equal(np.asarray(result), np.asarray(expected)) - else: - assert result == expected - if "approx" in expect or "approx_key" in expect: - if "approx" in expect: - target = float(expect["approx"]) - else: - target = float(context[str(expect["approx_key"])]) - if "abs_tol_key" in expect: - abs_tol = _tol_value(str(expect["abs_tol_key"])) - else: - abs_tol = float(expect.get("abs_tol", 1.0e-8)) - assert np.isclose(float(result), target, atol=abs_tol) - if "sum_approx" in expect: - arr = np.asarray(result, dtype=float) - abs_tol = float(expect.get("abs_tol", 1.0e-8)) - assert np.isclose(float(np.sum(arr)), float(expect["sum_approx"]), atol=abs_tol) - if "min" in expect: - assert float(np.min(np.asarray(result, dtype=float))) >= float(expect["min"]) - if "max" in expect: - assert float(np.max(np.asarray(result, dtype=float))) <= float(expect["max"]) - if bool(expect.get("finite", False)): - assert np.all(np.isfinite(np.asarray(result, dtype=float))) - - -def _execute_contract(obj: Any, context: dict[str, Any], contract: dict[str, Any]) -> Any: - member = getattr(obj, str(contract["member"])) - if contract.get("access", "method") == "property": - result = member - else: - args = list(contract.get("args", [])) - kwargs = dict(contract.get("kwargs", {})) - if "args_key" in contract: - args = list(context[str(contract["args_key"])]) - if "kwargs_key" in contract: - kwargs = dict(context[str(contract["kwargs_key"])]) - result = member(*args, **kwargs) - - if "select" in contract: - result = result[int(contract["select"])] - if "extract" in contract: - result = _extract_value(result, str(contract["extract"])) - return result - - -def test_class_behavior_specs_cover_all_mapped_classes() -> None: - payload = _load_yaml("tests/parity/class_behavior_specs.yml") - mapped = {row["matlab_class"] for row in payload["classes"]} - assert mapped == REQUIRED_MATLAB_CLASSES - - -def test_class_behavior_contracts_execute() -> None: - payload = _load_yaml("tests/parity/class_behavior_specs.yml") - for row in payload["classes"]: - scenario_name = str(row["scenario"]) - obj, context = SCENARIO_BUILDERS[scenario_name]() - expected_class = _resolve_obj(str(row["python_class"])) - if isinstance(obj, type): - assert obj is expected_class - else: - assert isinstance(obj, expected_class) - - for contract in row["contracts"]: - result = _execute_contract(obj, context, contract) - _assert_expectation(result, dict(contract["expect"]), context) diff --git a/tests/test_cif_tier2.py b/tests/test_cif_tier2.py deleted file mode 100644 index cf817937..00000000 --- a/tests/test_cif_tier2.py +++ /dev/null @@ -1,41 +0,0 @@ -from __future__ import annotations - -import numpy as np - -from nstat.cif import CIFModel -from nstat.signal import Covariate - - - -def test_cif_tier2_methods() -> None: - rng = np.random.default_rng(2026) - t = np.linspace(0.0, 1.0, 200) - X = np.sin(2.0 * np.pi * 3.0 * t)[:, None] - - model = CIFModel(coefficients=np.array([0.4]), intercept=np.log(8.0), link="poisson") - lam = model.evaluate(X) - ld = model.eval_lambda_delta(X, dt=t[1] - t[0]) - assert lam.shape == ld.shape - assert np.all(ld >= 0.0) - - params = model.compute_plot_params(X) - assert params["max"] >= params["min"] - - payload = model.to_structure() - recovered = CIFModel.from_structure(payload) - assert np.allclose(recovered.coefficients, model.coefficients) - - sim = CIFModel.simulate_cif_by_thinning_from_lambda(t, lam, num_realizations=2, rng=rng) - assert len(sim) == 2 - - - -def test_cif_matlab_style_lambda_simulation() -> None: - t = np.linspace(0.0, 1.0, 1000) - lam = 5.0 + 2.0 * np.sin(2.0 * np.pi * 2.0 * t) - lam_cov = Covariate(time=t, data=lam, name="lambda", labels=["lambda"]) - - from nstat.compat.matlab import CIF - - coll = CIF.simulateCIFByThinningFromLambda(lam_cov, numRealizations=3) - assert coll.n_units == 3 diff --git a/tests/test_class_contracts.py b/tests/test_class_contracts.py deleted file mode 100644 index 899ad6b2..00000000 --- a/tests/test_class_contracts.py +++ /dev/null @@ -1,268 +0,0 @@ -from __future__ import annotations - -from pathlib import Path -from typing import Any - -import numpy as np -import scipy.io -import yaml - -from nstat.compat import matlab as M -from tests.parity_utils import assert_allclose_scaled, assert_same_shape - - -CLASS_CONTRACTS = Path("parity/class_contracts.yml") -FIXTURE_SPEC = Path("parity/class_fixture_export_spec.yml") - - -def _load_yaml(path: Path) -> dict[str, Any]: - return yaml.safe_load(path.read_text(encoding="utf-8")) - - -def _load_mat(path: Path) -> dict[str, Any]: - return scipy.io.loadmat(path) - - -def _vec(m: dict[str, Any], key: str) -> np.ndarray: - return np.asarray(m[key], dtype=float).reshape(-1) - - -def _str_list(mat_cell: Any) -> list[str]: - arr = np.asarray(mat_cell, dtype=object).reshape(-1) - out: list[str] = [] - for item in arr: - if isinstance(item, np.ndarray): - if item.size == 1: - out.append(str(item.reshape(-1)[0])) - else: - out.append(str(item.squeeze().tolist())) - else: - out.append(str(item)) - return out - - -def test_class_contract_manifest_covers_all_classes_and_fixtures_exist() -> None: - contracts = _load_yaml(CLASS_CONTRACTS) - fixture_spec = _load_yaml(FIXTURE_SPEC) - - contract_classes = {str(row["matlab_class"]) for row in contracts.get("classes", [])} - fixture_classes = {str(row["matlab_class"]) for row in fixture_spec.get("classes", [])} - expected = { - "SignalObj", - "Covariate", - "ConfidenceInterval", - "Events", - "History", - "nspikeTrain", - "nstColl", - "CovColl", - "TrialConfig", - "ConfigColl", - "Trial", - "CIF", - "Analysis", - "FitResult", - "FitResSummary", - "DecodingAlgorithms", - } - - assert contract_classes == expected - assert fixture_classes == expected - - for row in contracts.get("classes", []): - fixture_path = Path(str(row["fixture_path"])) - assert fixture_path.exists(), f"missing fixture for {row['matlab_class']}: {fixture_path}" - assert row.get("key_methods"), f"missing key_methods for {row['matlab_class']}" - - -def test_signalobj_contract_against_matlab_fixture() -> None: - m = _load_mat(Path("tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat")) - t = _vec(m, "time_sig") - v1 = _vec(m, "v1_sig") - v2 = _vec(m, "v2_sig") - fs = float(_vec(m, "sampleRate_sig")[0]) - rs = float(_vec(m, "resample_hz_sig")[0]) - window_t0 = float(_vec(m, "window_t0_sig")[0]) - window_t1 = float(_vec(m, "window_t1_sig")[0]) - expected_peak = int(round(float(_vec(m, "periodogram_peak_idx_sig")[0]))) - - s = M.SignalObj(time=t, data=np.column_stack([v1, v2]), name="sig") - assert s.getNumSamples() == int(round(float(_vec(m, "n_samples_sig")[0]))) - assert np.isclose(s.getSampleRate(), fs, atol=1e-10) - - rs_obj = s.resample(rs) - assert rs_obj.getNumSamples() == int(round(float(_vec(m, "resampled_n_samples_sig")[0]))) - win = s.getSigInTimeWindow(window_t0, window_t1) - assert win.getNumSamples() == int(round(float(_vec(m, "window_n_samples_sig")[0]))) - - _f, p = s.periodogram() - assert int(np.argmax(np.asarray(p).reshape(-1))) == expected_peak - - -def test_covariate_contract_against_matlab_fixture() -> None: - m = _load_mat(Path("tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat")) - time = _vec(m, "time_cov") - stim = _vec(m, "cov_stim") - ctx = np.asarray(m["cov_ctx"], dtype=float) - expected_design = np.asarray(m["expected_design_cov"], dtype=float) - - cov = M.Covariate( - time=time, - data=np.column_stack([stim, ctx]), - name="cov", - labels=["stim", "ctx1", "ctx2"], - ) - cov_mat = np.asarray(cov.getSigRep(), dtype=float) - assert_same_shape(cov_mat, expected_design) - assert_allclose_scaled(cov_mat, expected_design, rtol=0.0, atol=1e-12) - - sub = cov.getSubSignal(["stim"]) - assert_same_shape(np.asarray(sub.getSigRep(), dtype=float), stim.reshape(-1, 1)) - - -def test_confidence_interval_contract_against_matlab_fixture() -> None: - m = _load_mat(Path("tests/parity/fixtures/matlab_gold/classes/ConfidenceInterval/basic.mat")) - time = _vec(m, "time") - ci_data = np.asarray(m["ci_data"], dtype=float) - expected_width = _vec(m, "width") - expected_value = float(_vec(m, "ci_value")[0]) - - ci = M.ConfidenceInterval(time=time, lower=ci_data[:, 0], upper=ci_data[:, 1], level=expected_value) - ci.setColor("r") - ci.setValue(expected_value) - - got_width = np.asarray(ci.getWidth(), dtype=float).reshape(-1) - assert_same_shape(got_width, expected_width) - assert_allclose_scaled(got_width, expected_width, rtol=0.0, atol=1e-12) - assert np.isclose(ci.level, expected_value) - - -def test_events_history_nspiketrain_nstcoll_contracts_against_matlab_fixtures() -> None: - m_events = _load_mat(Path("tests/parity/fixtures/matlab_gold/EventsExamples_gold.mat")) - event_times = _vec(m_events, "event_times") - subset_start = float(_vec(m_events, "subset_start")[0]) - subset_end = float(_vec(m_events, "subset_end")[0]) - expected_subset = _vec(m_events, "expected_subset_times") - - ev = M.Events(times=event_times) - ev_subset = ev.subset(subset_start, subset_end) - assert_allclose_scaled(np.asarray(ev_subset.times, dtype=float), expected_subset, rtol=0.0, atol=1e-12) - - m_hist = _load_mat(Path("tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat")) - hist = M.History(_vec(m_hist, "bin_edges_hist")) - h = np.asarray( - hist.computeHistory(_vec(m_hist, "spike_times_hist"), _vec(m_hist, "time_grid_hist")), - dtype=float, - ) - expected_h = np.asarray(m_hist["H_expected_hist"], dtype=float) - assert_same_shape(h, expected_h) - assert_allclose_scaled(h, expected_h, rtol=0.0, atol=1e-12) - - m_coll = _load_mat(Path("tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat")) - t_start = float(_vec(m_coll, "t_start_coll")[0]) - t_end = float(_vec(m_coll, "t_end_coll")[0]) - bin_size = float(_vec(m_coll, "bin_size_coll")[0]) - st1 = M.nspikeTrain(spike_times=_vec(m_coll, "spike_times_1"), t_start=t_start, t_end=t_end, name="u1") - st2 = M.nspikeTrain(spike_times=_vec(m_coll, "spike_times_2"), t_start=t_start, t_end=t_end, name="u2") - coll = M.nstColl([st1, st2]) - _t, count_mat = coll.getBinnedMatrix(bin_size, "count") - expected_count = np.asarray(m_coll["expected_count_matrix"], dtype=float) - assert_same_shape(count_mat, expected_count) - assert_allclose_scaled(count_mat, expected_count, rtol=0.0, atol=1e-12) - assert np.isclose(coll.getFirstSpikeTime(), float(_vec(m_coll, "expected_first_spike")[0])) - assert np.isclose(coll.getLastSpikeTime(), float(_vec(m_coll, "expected_last_spike")[0])) - - -def test_covcoll_trial_trialconfig_configcoll_contracts_against_matlab_fixtures() -> None: - m_cov = _load_mat(Path("tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat")) - time = _vec(m_cov, "time_cov") - stim = _vec(m_cov, "cov_stim") - ctx = np.asarray(m_cov["cov_ctx"], dtype=float) - - cov1 = M.Covariate(time=time, data=stim, name="stim", labels=["stim"]) - cov2 = M.Covariate(time=time, data=ctx, name="ctx", labels=["ctx1", "ctx2"]) - cov_coll = M.CovColl([cov1, cov2]) - design, labels = cov_coll.getDesignMatrix() - assert_same_shape(design, np.asarray(m_cov["expected_design_cov"], dtype=float)) - assert labels == ["stim", "ctx1", "ctx2"] - - m_trial = _load_mat(Path("tests/parity/fixtures/matlab_gold/TrialExamples_gold.mat")) - st = M.nspikeTrain( - spike_times=_vec(m_trial, "spike_times_trial"), - t_start=0.0, - t_end=1.0, - name="u1", - ) - trial = M.Trial(M.nstColl([st]), cov_coll) - _t_obs, y_obs, _x_obs = trial.getAlignedBinnedObservation( - binSize_s=float(_vec(m_trial, "bin_size_trial")[0]), - unitIndex=0, - mode="count", - ) - y_expected = _vec(m_trial, "expected_y_trial") - y_obs_vec = np.asarray(y_obs, dtype=float).reshape(-1) - assert_same_shape(y_obs_vec, y_expected) - assert_allclose_scaled(y_obs_vec, y_expected, rtol=0.0, atol=1e-12) - - m_tc = _load_mat(Path("tests/parity/fixtures/matlab_gold/classes/TrialConfig/basic.mat")) - tc = M.TrialConfig(covariateLabels=["stim"], Fs=float(_vec(m_tc, "tc_sample_rate")[0]), name=str(_str_list(m_tc["tc_name"])[0])) - assert np.isclose(tc.getSampleRate(), float(_vec(m_tc, "tc_sample_rate")[0])) - - m_cc = _load_mat(Path("tests/parity/fixtures/matlab_gold/classes/ConfigColl/basic.mat")) - cc = M.ConfigColl([tc, M.TrialConfig(covariateLabels=["ctx"], Fs=500.0, name="cfg2")]) - assert len(cc.getConfigs()) == int(round(float(_vec(m_cc, "num_configs")[0]))) - - -def test_cif_analysis_decoding_fitresult_fitsummary_contracts_against_matlab_fixtures() -> None: - m_cif = _load_mat(Path("tests/parity/fixtures/matlab_gold/classes/CIF/basic.mat")) - time = _vec(m_cif, "time") - lam = _vec(m_cif, "lambda_values") - dt = float(_vec(m_cif, "dt")[0]) - expected_counts = _vec(m_cif, "spike_counts") - - lambda_cov = M.Covariate(time=time, data=lam, name="Lambda", labels=["lambda"]) - np.random.seed(0) - coll = M.CIF.simulateCIFByThinningFromLambda(lambda_cov, int(expected_counts.size), dt) - counts = np.asarray([len(coll.getNST(i).spike_times) for i in range(int(expected_counts.size))], dtype=float) - # Stochastic realizations are deterministic under seed=0; allow a tiny tolerance. - assert_allclose_scaled(counts, expected_counts, rtol=0.0, atol=3.0) - - m_analysis = _load_mat(Path("tests/parity/fixtures/matlab_gold/AnalysisExamples_gold.mat")) - fit = M.Analysis.fitGLM( - X=np.asarray(m_analysis["X_analysis"], dtype=float), - y=_vec(m_analysis, "counts_analysis"), - fitType="poisson", - dt=float(_vec(m_analysis, "dt_analysis")[0]), - ) - expected_b = _vec(m_analysis, "b_analysis") - got_b = np.concatenate(([fit.intercept], np.asarray(fit.coefficients, dtype=float).reshape(-1))) - assert_allclose_scaled(got_b, expected_b, rtol=0.0, atol=0.5) - - m_dec = _load_mat(Path("tests/parity/fixtures/matlab_gold/DecodingExample_gold.mat")) - decoded, posterior = M.DecodingAlgorithms.decodeStatePosterior( - spike_counts=np.asarray(m_dec["spike_counts_dec"], dtype=float), - tuning_rates=np.asarray(m_dec["tuning_dec"], dtype=float), - transition=np.asarray(m_dec["transition_dec"], dtype=float), - ) - assert np.array_equal(decoded, np.asarray(m_dec["expected_decoded_dec"], dtype=int).reshape(-1)) - assert_same_shape(posterior, np.asarray(m_dec["expected_posterior_dec"], dtype=float)) - - m_fr = _load_mat(Path("tests/parity/fixtures/matlab_gold/classes/FitResult/basic.mat")) - fr = M.FitResult( - coefficients=np.array([0.1], dtype=float), - intercept=0.0, - fit_type="poisson", - log_likelihood=float(_vec(m_fr, "fit_logll")[0]), - n_samples=3, - n_parameters=1, - parameter_labels=["Baseline"], - ) - fr.setKSStats(np.asarray(_vec(m_fr, "fit_ks_stat"), dtype=float)) - fr.setNeuronName(str(int(round(float(_vec(m_fr, "fit_neuron_number")[0]))))) - assert np.isfinite(fr.getAIC()) - assert np.isfinite(fr.getBIC()) - - m_fs = _load_mat(Path("tests/parity/fixtures/matlab_gold/classes/FitResSummary/basic.mat")) - fs = M.FitResSummary([fr]) - assert len(fs.results) == int(round(float(_vec(m_fs, "summary_num_neurons")[0]))) - assert fs.bestByAIC() is fr diff --git a/tests/test_class_equivalence_artifacts.py b/tests/test_class_equivalence_artifacts.py deleted file mode 100644 index 6d06cb22..00000000 --- a/tests/test_class_equivalence_artifacts.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import annotations - -import json -import os -from argparse import Namespace -from pathlib import Path - -import pytest - -from tools.parity.generate_class_equivalence_inventory import build_inventory - - -def _resolve_matlab_root(repo_root: Path) -> Path | None: - env_candidates = [ - os.environ.get("NSTAT_MATLAB_ROOT"), - os.environ.get("MATLAB_NSTAT_ROOT"), - ] - for candidate in env_candidates: - if candidate: - path = Path(candidate).expanduser().resolve() - if path.exists(): - return path - - checkout_meta = repo_root / "parity/matlab_reference_checkout.json" - if checkout_meta.exists(): - payload = json.loads(checkout_meta.read_text(encoding="utf-8")) - path = Path(str(payload.get("dest", ""))).expanduser().resolve() - if path.exists(): - return path - - default_path = Path("/tmp/upstream-nstat") - if default_path.exists(): - return default_path - - return None - - -def _build_runtime_artifacts(tmp_path: Path) -> tuple[dict, dict]: - repo_root = Path(__file__).resolve().parents[1] - matlab_root = _resolve_matlab_root(repo_root) - if matlab_root is None: - pytest.skip( - "MATLAB reference checkout not available; set NSTAT_MATLAB_ROOT " - "or provide /tmp/upstream-nstat to generate class-equivalence artifacts." - ) - - args = Namespace( - repo_root=repo_root, - matlab_root=matlab_root, - method_mapping=Path("parity/method_mapping.yaml"), - method_exclusions=Path("parity/method_exclusions.yml"), - class_contracts=Path("parity/class_contracts.yml"), - fixture_spec=Path("parity/class_fixture_export_spec.yml"), - behavior_contracts=[Path("tests/parity/class_behavior_specs.yml"), Path("tests/parity/compat_behavior_specs.yml")], - out_inventory=tmp_path / "class_equivalence_inventory.json", - out_report=tmp_path / "class_equivalence_report.json", - ) - inventory, report = build_inventory(args) - args.out_inventory.write_text(json.dumps(inventory, indent=2, sort_keys=True) + "\n", encoding="utf-8") - args.out_report.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8") - return inventory, report - - -def test_class_equivalence_inventory_runtime_generation_has_full_class_coverage(tmp_path: Path) -> None: - payload, _ = _build_runtime_artifacts(tmp_path) - rows = payload.get("class_rows", []) - assert len(rows) >= 16 - - statuses = {str(row.get("status", "")) for row in rows} - assert "gap_missing_mapping" not in statuses - - required = { - "SignalObj", - "Covariate", - "ConfidenceInterval", - "Events", - "History", - "nspikeTrain", - "nstColl", - "CovColl", - "TrialConfig", - "ConfigColl", - "Trial", - "CIF", - "Analysis", - "FitResult", - "FitResSummary", - "DecodingAlgorithms", - } - covered = {str(row["matlab_class"]) for row in rows} - assert required.issubset(covered) - - summary = payload.get("summary", {}) - assert summary.get("required_classes_missing_from_matlab_scan", []) == [] - assert summary.get("classes_missing_mapping", []) == [] - - -def test_class_equivalence_report_runtime_generation_is_clean(tmp_path: Path) -> None: - _, payload = _build_runtime_artifacts(tmp_path) - summary = payload.get("summary", {}) - assert int(summary.get("total_classes", 0)) >= 16 - assert int(summary.get("gap_classes", 1)) == 0 - assert bool(summary.get("required_class_coverage_ok", False)) - - top_methods = payload.get("top_critical_methods_tested", {}) - assert len(top_methods) >= 16 - for cls, methods in top_methods.items(): - assert methods, f"missing critical methods for {cls}" diff --git a/tests/test_class_parity_manifest.py b/tests/test_class_parity_manifest.py deleted file mode 100644 index 5624a98c..00000000 --- a/tests/test_class_parity_manifest.py +++ /dev/null @@ -1,27 +0,0 @@ -from pathlib import Path - -REQUIRED_HELP_CLASSES = [ - "Analysis", - "CIF", - "ConfidenceInterval", - "ConfigColl", - "CovColl", - "Covariate", - "DecodingAlgorithms", - "Events", - "FitResSummary", - "FitResult", - "History", - "SignalObj", - "Trial", - "TrialConfig", - "nspikeTrain", - "nstColl", -] - - -def test_class_help_pages_exist() -> None: - base = Path("docs/help/classes") - for klass in REQUIRED_HELP_CLASSES: - page = base / f"{klass}.md" - assert page.exists(), f"missing class help page: {page}" diff --git a/tests/test_compat_behavior_contracts.py b/tests/test_compat_behavior_contracts.py deleted file mode 100644 index bf034cb3..00000000 --- a/tests/test_compat_behavior_contracts.py +++ /dev/null @@ -1,594 +0,0 @@ -from __future__ import annotations - -import importlib -from pathlib import Path -from typing import Any - -import numpy as np -import yaml - -from nstat.compat import matlab as M - - -REQUIRED_MATLAB_CLASSES = { - "SignalObj", - "Covariate", - "ConfidenceInterval", - "Events", - "History", - "nspikeTrain", - "nstColl", - "CovColl", - "TrialConfig", - "ConfigColl", - "Trial", - "CIF", - "Analysis", - "FitResult", - "FitResSummary", - "DecodingAlgorithms", -} - - -def _load_yaml(path: str) -> dict[str, Any]: - return yaml.safe_load(Path(path).read_text(encoding="utf-8")) - - -def _resolve_obj(path: str) -> Any: - module_name, attr_name = path.rsplit(".", 1) - module = importlib.import_module(module_name) - return getattr(module, attr_name) - - -def _extract_value(obj: Any, path: str) -> Any: - cursor = obj - for token in path.split("."): - if token.isdigit(): - cursor = cursor[int(token)] - else: - cursor = getattr(cursor, token) - return cursor - - -def _assert_expectation(result: Any, expect: dict[str, Any]) -> None: - if "instance_of" in expect: - klass = _resolve_obj(str(expect["instance_of"])) - assert isinstance(result, klass) - if "shape" in expect: - expected_shape = tuple(int(x) for x in expect["shape"]) - assert np.asarray(result).shape == expected_shape - if "length" in expect: - assert len(result) == int(expect["length"]) - if "equals" in expect: - expected = expect["equals"] - if isinstance(expected, list): - assert np.array_equal(np.asarray(result), np.asarray(expected)) - else: - assert result == expected - if "approx" in expect: - abs_tol = float(expect.get("abs_tol", 1.0e-8)) - assert np.isclose(float(result), float(expect["approx"]), atol=abs_tol) - if "sum_approx" in expect: - arr = np.asarray(result, dtype=float) - abs_tol = float(expect.get("abs_tol", 1.0e-8)) - assert np.isclose(float(np.sum(arr)), float(expect["sum_approx"]), atol=abs_tol) - if "min" in expect: - assert float(np.min(np.asarray(result, dtype=float))) >= float(expect["min"]) - if "max" in expect: - assert float(np.max(np.asarray(result, dtype=float))) <= float(expect["max"]) - if bool(expect.get("finite", False)): - assert np.all(np.isfinite(np.asarray(result, dtype=float))) - - -def _execute_contract(obj: Any, context: dict[str, Any], contract: dict[str, Any]) -> Any: - member = getattr(obj, str(contract["member"])) - if contract.get("access", "method") == "property": - result = member - else: - args = list(contract.get("args", [])) - kwargs = dict(contract.get("kwargs", {})) - if "args_key" in contract: - args = list(context[str(contract["args_key"])]) - if "kwargs_key" in contract: - kwargs = dict(context[str(contract["kwargs_key"])]) - result = member(*args, **kwargs) - - if "select" in contract: - result = result[int(contract["select"])] - if "extract" in contract: - result = _extract_value(result, str(contract["extract"])) - return result - - -def _build_compat_signal_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 2.0, 5) - obj = M.SignalObj(time=time, data=np.array([1.0, 2.0, 3.0, 2.0, 1.0]), name="sig") - other = M.SignalObj(time=time, data=np.array([0.5, 1.0, 1.5, 1.0, 0.5]), name="sig2") - other_shifted = M.SignalObj( - time=time + 0.5, data=np.array([0.5, 1.0, 1.5, 1.0, 0.5]), name="sig2_shifted" - ) - return obj, { - "signal_labels_args": [["ch1"]], - "signal_label_lookup_args": [["ch1"]], - "signal_index_arg": ["ch1"], - "signal_times_args": [np.array([0.0, 1.0, 2.0])], - "signal_time_window_args": [0.5, 1.5], - "signal_other_args": [other], - "signal_other_shifted_args": [other_shifted], - "signal_mask_args": [[1]], - "signal_names_args": [["ch1"]], - "signal_cell2str_args": [["a", "b", "c"]], - "signal_plot_props_args": [{"LineWidth": 2.0}], - "signal_filter_args": [np.array([0.2, 0.2]), np.array([1.0, -0.3])], - "signal_crosscorr_args": [other, 1], - "signal_from_structure_args": [obj.dataToStructure()], - } - - -def _build_compat_covariate_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 1.0, 5) - obj = M.Covariate( - time=time, - data=np.column_stack([time, time**2]), - name="stim", - labels=["stim1", "stim2"], - ) - ci = M.ConfidenceInterval( - time=time, - lower=np.array([0.0, 0.1, 0.2, 0.3, 0.4]), - upper=np.array([0.2, 0.3, 0.4, 0.5, 0.6]), - level=0.95, - ) - return obj, { - "cov_from_structure_args": [obj.toStructure()], - "cov_ctor_args": [obj.toStructure()], - "cov_filter_args": [np.array([0.2, 0.2]), np.array([1.0, -0.3])], - "cov_set_ci_args": [ci], - } - - -def _build_compat_confidence_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 1.0, 5) - obj = M.ConfidenceInterval( - time=time, - lower=np.array([0.0, 0.4, 0.8, 1.2, 1.6]), - upper=np.array([0.5, 0.9, 1.3, 1.7, 2.1]), - level=0.95, - ) - return obj, { - "ci_set_color_args": ["r"], - "ci_set_value_args": [1.0], - "ci_from_structure_args": [obj.toStructure()], - "ci_ctor_args": [obj.toStructure()], - } - - -def _build_compat_events_basic() -> tuple[Any, dict[str, Any]]: - obj = M.Events(times=np.array([0.1, 0.4, 0.9]), labels=["a", "b", "c"]) - return obj, { - "events_from_structure_args": [obj.toStructure()], - "events_ctor_args": [obj.toStructure()], - "events_dsxy_args": [0.2, 0.3], - } - - -def _build_compat_history_basic() -> tuple[Any, dict[str, Any]]: - obj = M.History(bin_edges_s=np.array([0.0, 0.05, 0.1, 0.2])) - spike = M.nspikeTrain(spike_times=np.array([0.12, 0.28]), t_start=0.0, t_end=1.0, name="u1") - return obj, { - "history_compute_args": [ - np.array([0.12, 0.28]), - np.array([0.15, 0.25, 0.30, 0.40]), - ], - "history_set_window_args": [0.0, 0.3, 3], - "history_from_structure_args": [obj.toStructure()], - "history_ctor_args": [obj.toStructure()], - "history_nst_window_args": [spike, np.array([0.15, 0.25, 0.30, 0.40])], - } - - -def _build_compat_spike_train_basic() -> tuple[Any, dict[str, Any]]: - obj = M.nspikeTrain(spike_times=np.array([0.1, 0.2, 0.25, 0.9]), t_start=0.0, t_end=1.0) - return obj, { - "spike_sigrep_args": [0.1, "count"], - "spike_isbinary_args": [0.01], - "spike_from_structure_args": [obj.toStructure()], - "spike_ctor_args": [obj.toStructure()], - "spike_set_sigrep_args": [np.array([0.0, 1.0, 0.0, 1.0])], - "spike_get_field_name_args": ["name"], - "spike_set_mer_args": [3.0], - "spike_set_name_args": ["unit"], - "spike_set_min_args": [0.05], - "spike_set_max_args": [0.95], - "spike_resample_args": [10.0], - "spike_partition_args": [[0.0, 0.3, 1.0]], - } - - -def _build_compat_spike_coll_basic() -> tuple[Any, dict[str, Any]]: - st1 = M.nspikeTrain(spike_times=np.array([0.1, 0.2, 0.25, 0.9]), t_start=0.0, t_end=1.0, name="u1") - st2 = M.nspikeTrain(spike_times=np.array([0.15, 0.4, 0.8]), t_start=0.0, t_end=1.0, name="u2") - obj = M.nstColl([st1, st2]) - st_merge = M.nspikeTrain(spike_times=np.array([0.05, 0.35]), t_start=0.0, t_end=1.0, name="u3m") - st_add = M.nspikeTrain(spike_times=np.array([0.12, 0.22]), t_start=0.0, t_end=1.0, name="u3") - merge_coll = M.nstColl([st_merge]) - ens_time = np.linspace(0.0, 1.0, 11) - ens_cov = M.CovColl( - [ - M.Covariate(time=ens_time, data=np.zeros_like(ens_time), name="c1", labels=["c1"]), - M.Covariate(time=ens_time, data=np.ones_like(ens_time), name="c2", labels=["c2"]), - ] - ) - return obj, { - "coll_name_args": ["u1"], - "coll_ind0_args": [0], - "coll_ind_args": [1], - "coll_binned_args": [0.1, "count"], - "coll_merge_args": [merge_coll], - "coll_field_arg": ["name"], - "coll_shift_args": [0.1], - "coll_setmask_args": [["u1"]], - "coll_setneuronmask_ind_args": [[1]], - "coll_setneuronmask_args": [["u2"]], - "coll_neighbors_args": [np.array([[1], [0]])], - "coll_add_args": [st_add], - "coll_addspike_args": [0, 0.95], - "coll_addnames_args": [ens_cov], - "coll_basis_args": [0.2, 10.0, 1.0, "basis"], - "coll_from_structure_args": [obj.toStructure()], - "coll_ctor_args": [obj.toStructure()], - } - - -def _build_compat_covcoll_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 1.0, 5) - cov1 = M.Covariate(time=time, data=np.sin(2 * np.pi * time), name="sine", labels=["sine"]) - cov2 = M.Covariate(time=time, data=np.column_stack([time, time**2]), name="poly", labels=["t", "t2"]) - obj = M.CovColl([cov1, cov2]) - cov3 = M.Covariate(time=time, data=np.cos(2 * np.pi * time), name="cosine", labels=["cosine"]) - cov4 = M.Covariate(time=time, data=time**3, name="cube", labels=["cube"]) - cov5 = M.Covariate(time=time, data=time**4, name="quartic", labels=["quartic"]) - cov6 = M.Covariate(time=time, data=time**5, name="quintic", labels=["quintic"]) - cov_extra_coll = M.CovColl([cov6]) - return obj, { - "covcoll_names_args": [["sine", "poly"]], - "covcoll_sel_args": [[1]], - "covcoll_name_arg": ["poly"], - "covcoll_names_lookup_args": [["sine", "poly"]], - "covcoll_present_args": ["sine"], - "covcoll_contains_args": ["abc", "b"], - "covcoll_parse_args": [[1]], - "covcoll_from_selector_args": [["sine"]], - "covcoll_remaining_args": [["sine"]], - "covcoll_mask_args": [["sine"]], - "covcoll_masks_selector_args": [["poly"]], - "covcoll_flat_mask_args": [[[0], [1]]], - "covcoll_selector_mask_args": [[0, 1]], - "covcoll_add_single_args": [cov3], - "covcoll_add_args": [cov4], - "covcoll_add_cell_args": [[cov5]], - "covcoll_add_collection_args": [cov_extra_coll], - "covcoll_remove_indices_args": [[5]], - "covcoll_from_structure_args": [obj.toStructure()], - "covcoll_set_min_args": [0.1], - "covcoll_set_max_args": [0.9], - "covcoll_restrict_args": [0.2, 0.8], - "covcoll_sample_rate_args": [8.0], - "covcoll_shift_args": [0.1], - "covcoll_get_cov_args": ["poly"], - "covcoll_remove_name_args": ["sine"], - "covcoll_remove_from_coll_args": ["poly"], - "covcoll_selector_cell_args": [[1, "sine"]], - } - - -def _build_compat_trial_config_basic() -> tuple[Any, dict[str, Any]]: - obj = M.TrialConfig(covariate_labels=["stim"], sample_rate_hz=1000.0, fit_type="poisson", name="cfg") - time = np.linspace(0.0, 1.0, 5) - cov = M.Covariate(time=time, data=time, name="stim", labels=["stim"]) - spike = M.nspikeTrain(spike_times=np.array([0.2, 0.4]), t_start=0.0, t_end=1.0, name="u1") - trial = M.Trial(spikes=M.nstColl([spike]), covariates=M.CovColl([cov])) - return obj, { - "trial_cfg_set_name_args": ["cfg2"], - "trial_cfg_from_structure_args": [obj.toStructure()], - "trial_cfg_set_config_args": [trial], - } - - -def _build_compat_config_coll_basic() -> tuple[Any, dict[str, Any]]: - cfg = M.TrialConfig(covariate_labels=["stim"], sample_rate_hz=1000.0, fit_type="poisson", name="cfg") - obj = M.ConfigColl([cfg]) - cfg2 = M.TrialConfig(covariate_labels=["stim"], sample_rate_hz=1000.0, fit_type="poisson", name="cfg2") - cfg3 = M.TrialConfig(covariate_labels=["stim"], sample_rate_hz=1000.0, fit_type="poisson", name="cfg3") - return obj, { - "config_get_args": [1], - "config_subset_args": [[1]], - "config_from_structure_args": [obj.toStructure()], - "config_ctor_args": [obj.toStructure()], - "config_add_args": [cfg2], - "config_set_args": [2, cfg3], - "config_set_names_args": [["cfgA", "cfgB"]], - } - - -def _build_compat_trial_basic() -> tuple[Any, dict[str, Any]]: - time = np.linspace(0.0, 1.0, 11) - cov1 = M.Covariate(time=time, data=np.sin(2 * np.pi * time), name="sine", labels=["sine"]) - cov2 = M.Covariate(time=time, data=np.column_stack([time, time**2]), name="poly", labels=["t", "t2"]) - cc = M.CovColl([cov1, cov2]) - st1 = M.nspikeTrain(spike_times=np.array([0.1, 0.2, 0.25, 0.9]), t_start=0.0, t_end=1.0, name="u1") - st2 = M.nspikeTrain(spike_times=np.array([0.15, 0.4, 0.8]), t_start=0.0, t_end=1.0, name="u2") - obj = M.Trial(spikes=M.nstColl([st1, st2]), covariates=cc) - events = M.Events(times=np.array([0.2, 0.6]), labels=["e1", "e2"]) - history = M.History(bin_edges_s=np.array([0.0, 0.05, 0.1])) - extra_time = time[(time >= 0.2) & (time <= 0.8)] - cov_extra = M.Covariate( - time=extra_time, - data=np.cos(2 * np.pi * extra_time), - name="extra", - labels=["extra"], - ) - return obj, { - "trial_spike_vector_args": [0.1, 0, "count"], - "trial_cov_args": [0], - "trial_neuron_args": [0], - "trial_all_labels_args": [0.1], - "trial_aligned_args": [0.1, 0, "count"], - "trial_events_args": [events], - "trial_partition_args": [{"task": (0.2, 0.8)}], - "trial_times_for_args": [0.2, 0.8], - "trial_cov_mask_args": [["sine"]], - "trial_ens_cov_mask_args": [[1]], - "trial_neuron_mask_args": [["u1"]], - "trial_neighbors_args": [np.array([[1], [0]])], - "trial_history_args": [history], - "trial_ens_hist_args": [np.array([1.0, 2.0])], - "trial_add_cov_args": [cov_extra], - "trial_remove_cov_args": ["extra"], - "trial_hist_for_neurons_args": [[0], 0.1], - "trial_flat_mask_args": [[[0], [1]]], - "trial_shift_cov_args": [0.1], - "trial_consistent_sr_args": [10.0], - "trial_from_structure_args": [obj.toStructure()], - } - - -def _build_compat_cif_basic() -> tuple[Any, dict[str, Any]]: - obj = M.CIF(coefficients=np.array([0.8, -0.2]), intercept=-1.0, link="binomial") - X = np.column_stack([np.linspace(-1.0, 1.0, 5), np.linspace(1.0, -1.0, 5)]) - spike = M.nspikeTrain(spike_times=np.array([0.1, 0.2]), t_start=0.0, t_end=1.0) - history = M.History(bin_edges_s=np.array([0.0, 0.05, 0.1])) - lam = M.Covariate( - time=np.linspace(0.0, 1.0, 101), - data=np.abs(np.sin(np.linspace(0.0, 1.0, 101) * 2.0 * np.pi)) + 0.1, - name="lam", - labels=["lam"], - ) - return obj, { - "cif_from_structure_args": [obj.toStructure()], - "cif_eval_args": [X, 1.0], - "cif_grad_args": [X], - "cif_fn_args": [X], - "cif_sim_args": [np.linspace(0.0, 1.0, X.shape[0]), X], - "cif_set_spike_args": [spike], - "cif_set_history_args": [history], - "cif_lambda_sim_args": [lam, 2], - } - - -def _build_compat_analysis_basic() -> tuple[Any, dict[str, Any]]: - rng = np.random.default_rng(123) - x = rng.normal(size=400) - X = x[:, None] - p = 1.0 / (1.0 + np.exp(-(-1.2 + 1.15 * x))) - y = rng.binomial(1, p).astype(float) - fit = M.Analysis.GLMFit(X, y, "binomial", 1.0, 0.0) - time = np.linspace(0.0, 1.0, 101) - cov1 = M.Covariate(time=time, data=np.sin(2 * np.pi * time), name="sine", labels=["sine"]) - cov2 = M.Covariate(time=time, data=np.cos(2 * np.pi * time), name="cos", labels=["cos"]) - cc = M.CovColl([cov1, cov2]) - st1 = M.nspikeTrain(spike_times=np.array([0.1, 0.2, 0.45, 0.7]), t_start=0.0, t_end=1.0, name="u1") - st2 = M.nspikeTrain(spike_times=np.array([0.15, 0.4, 0.8]), t_start=0.0, t_end=1.0, name="u2") - trial = M.Trial(spikes=M.nstColl([st1, st2]), covariates=cc) - config = M.TrialConfig(covariate_labels=["sine", "cos"], sample_rate_hz=100.0, fit_type="poisson", name="cfgA") - y1 = (rng.random(200) < 0.25).astype(float) - y2 = (rng.random(200) < 0.20).astype(float) - Xh = rng.normal(size=(200, 2)) - spike_mat = rng.poisson(0.2, size=(3, 60)).astype(float) - return M.Analysis, { - "glm_args": [X, y, "binomial", 1.0, 0.0], - "residual_args": [y, X, fit, 1.0], - "inv_args": [y, X, fit, 1.0], - "ks_args": [np.sort(np.random.default_rng(1).uniform(size=50))], - "analysis_ksplot_args": [fit, 1], - "analysis_plot_coeffs_args": [fit], - "analysis_comp_hist_args": [y1, Xh, 1.0], - "analysis_hist_lag_all_args": [np.column_stack([y1, y2]), 12], - "analysis_bnlrcg_args": [X, y, 1.0, 0.0], - "analysis_run_neuron_args": [trial, config, 0], - "analysis_run_all_args": [trial, config], - "analysis_plot_seq_args": [np.array([0.2, -0.1, 0.05, 0.0])], - "analysis_comp_hist_all_args": [[y1, y2], [Xh, Xh], 1.0], - "analysis_granger_args": [spike_mat, 1], - "analysis_flat_mask_args": [[np.array([1, 0]), np.array([0, 1, 1])]], - "analysis_ksdisc_args": [np.array([1, 2, 2, 3]), np.array([1, 1, 2, 2, 3, 4])], - "fdr_args": [np.array([0.001, 0.02, 0.04, 0.2]), 0.05], - "hist_lag_args": [np.array([1.0, 0.0, 0.0, 1.0, 0.0, 1.0]), 2], - "neighbors_args": [np.array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]), 1], - "sta_args": [ - np.linspace(0.0, 1.0, 100), - np.array([0.2, 0.6]), - np.linspace(0.0, 1.0, 100), - (-0.05, 0.05), - ], - } - - -def _build_compat_fit_result_basic() -> tuple[Any, dict[str, Any]]: - obj = M.FitResult( - coefficients=np.array([0.5, -0.2]), - intercept=-1.0, - fit_type="binomial", - log_likelihood=-10.0, - n_samples=100, - n_parameters=3, - parameter_labels=["stim", "hist"], - ) - X = np.array([[-1.0, 0.5], [0.0, 0.0], [1.0, -0.5]]) - merge_obj = M.FitResult( - coefficients=np.array([0.2, 0.1]), - intercept=-0.5, - fit_type="binomial", - log_likelihood=-8.0, - n_samples=100, - n_parameters=3, - parameter_labels=["stim", "hist"], - ) - return obj, { - "fit_coeff_index_args": ["stim"], - "fit_param_args": ["fit_type"], - "fit_eval_args": [X], - "fit_from_structure_args": [obj.toStructure()], - "fit_ctor_args": [obj.toStructure()], - "fit_cell_array_args": [[obj]], - "fit_subset_args": [[1]], - "fit_set_ks_args": [np.array([0.1, 0.2]), np.array([0.9, 0.8]), np.array([1.0, 1.0])], - "fit_set_resid_args": [np.array([0.1, -0.2, 0.0])], - "fit_set_inv_args": [{"z": np.array([0.1, 0.2])}], - "fit_set_name_args": ["n1"], - "fit_add_params_args": [ - { - "neuron_name": "n2", - "fit_residual": np.array([0.2, 0.1, -0.1]), - "inv_gaus_stats": {"z": np.array([0.1, 0.2])}, - "xval_data": [np.array([0.0, 1.0, 0.0])], - "xval_time": [np.array([0.0, 0.5, 1.0])], - } - ], - "fit_merge_args": [merge_obj], - "fit_xtick_rotate_args": [np.array([0.0, 1.0]), 15.0], - } - - -def _build_compat_fit_summary_basic() -> tuple[Any, dict[str, Any]]: - f1 = M.FitResult( - coefficients=np.array([0.5, -0.2]), - intercept=-1.0, - fit_type="binomial", - log_likelihood=-10.0, - n_samples=100, - n_parameters=3, - parameter_labels=["stim", "hist"], - ) - f2 = M.FitResult( - coefficients=np.array([0.1, 0.3]), - intercept=-0.5, - fit_type="poisson", - log_likelihood=-20.0, - n_samples=100, - n_parameters=3, - parameter_labels=["stim", "hist"], - ) - obj = M.FitResSummary([f1, f2]) - return obj, { - "summary_bin_coeffs_args": [-1.0, 1.0, 0.2], - "summary_diff_metric_args": ["aic"], - "summary_from_structure_args": [obj.toStructure()], - "summary_ctor_args": [[f1, f2]], - "summary_set_coeff_range_args": [-1.0, 1.0], - "summary_xtick_rotate_args": [np.array([0.0, 1.0]), 15.0], - } - - -def _build_compat_decoding_basic() -> tuple[Any, dict[str, Any]]: - ci_matrix = np.array( - [ - [0, 0, 1, 0, 0, 1], - [0, 1, 1, 0, 0, 1], - [1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 0, 1], - ], - dtype=float, - ) - wc_counts = np.array( - [ - [0, 0, 1, 2, 1, 0], - [1, 2, 2, 1, 0, 0], - [0, 0, 0, 1, 2, 2], - ], - dtype=float, - ) - tuning = np.array( - [ - [1.0, 0.5, 0.1], - [0.2, 1.1, 0.4], - [0.1, 0.4, 1.2], - ], - dtype=float, - ) - posterior = M.DecodingAlgorithms.decodeStatePosterior(wc_counts, tuning)[1] - A = np.array([[1.0, 0.1], [0.0, 1.0]], dtype=float) - Q = np.eye(2, dtype=float) * 0.01 - H = np.array([[1.0, 0.0]], dtype=float) - R = np.eye(1, dtype=float) * 0.05 - x_prev = np.array([0.0, 1.0], dtype=float) - p_prev = np.eye(2, dtype=float) - y = np.array([[0.1], [0.2], [0.4], [0.3]], dtype=float) - xf, pf, xp, pp = M.DecodingAlgorithms.kalman_filter(y, A, H, Q, R, x_prev, p_prev) - sig = M.DecodingAlgorithms.ukf_sigmas(np.array([0.0, 1.0]), np.eye(2), 0.0) - wm = np.ones(sig.shape[1], dtype=float) / sig.shape[1] - wc = wm.copy() - return M.DecodingAlgorithms, { - "diff_args": [ci_matrix, ci_matrix], - "posterior_args": [wc_counts, tuning], - "stim_ci_args": [posterior, np.arange(tuning.shape[1])], - "ukf_sigmas_args": [np.array([0.0, 1.0]), np.eye(2), 0.0], - "ukf_ut_args": [sig, wm, wc, np.eye(2, dtype=float) * 0.01], - "kalman_predict_args": [x_prev, p_prev, A, Q], - "kalman_update_args": [x_prev, p_prev, np.array([0.1], dtype=float), H, R], - "kalman_filter_args": [y, A, H, Q, R, x_prev, p_prev], - "kalman_smoother_args": [xf, pf, xp, pp, A], - "kalman_from_filtered_args": [y, A, H, Q, R, x_prev, p_prev], - } - - -SCENARIO_BUILDERS = { - "compat_signal_basic": _build_compat_signal_basic, - "compat_covariate_basic": _build_compat_covariate_basic, - "compat_confidence_basic": _build_compat_confidence_basic, - "compat_events_basic": _build_compat_events_basic, - "compat_history_basic": _build_compat_history_basic, - "compat_spike_train_basic": _build_compat_spike_train_basic, - "compat_spike_coll_basic": _build_compat_spike_coll_basic, - "compat_covcoll_basic": _build_compat_covcoll_basic, - "compat_trial_config_basic": _build_compat_trial_config_basic, - "compat_config_coll_basic": _build_compat_config_coll_basic, - "compat_trial_basic": _build_compat_trial_basic, - "compat_cif_basic": _build_compat_cif_basic, - "compat_analysis_basic": _build_compat_analysis_basic, - "compat_fit_result_basic": _build_compat_fit_result_basic, - "compat_fit_summary_basic": _build_compat_fit_summary_basic, - "compat_decoding_basic": _build_compat_decoding_basic, -} - - -def test_compat_behavior_specs_cover_all_mapped_classes() -> None: - payload = _load_yaml("tests/parity/compat_behavior_specs.yml") - mapped = {row["matlab_class"] for row in payload["classes"]} - assert mapped == REQUIRED_MATLAB_CLASSES - - -def test_compat_behavior_contracts_execute() -> None: - payload = _load_yaml("tests/parity/compat_behavior_specs.yml") - for row in payload["classes"]: - scenario_name = str(row["scenario"]) - obj, context = SCENARIO_BUILDERS[scenario_name]() - expected_class = _resolve_obj(str(row["python_class"])) - if isinstance(obj, type): - assert obj is expected_class - else: - assert isinstance(obj, expected_class) - - for contract in row["contracts"]: - result = _execute_contract(obj, context, contract) - _assert_expectation(result, dict(contract["expect"])) diff --git a/tests/test_confidence.py b/tests/test_confidence.py deleted file mode 100644 index 587afb67..00000000 --- a/tests/test_confidence.py +++ /dev/null @@ -1,10 +0,0 @@ -import numpy as np - -from nstat.confidence import ConfidenceInterval - - -def test_confidence_width_and_contains() -> None: - t = np.linspace(0.0, 1.0, 11) - ci = ConfidenceInterval(time=t, lower=np.zeros_like(t), upper=np.ones_like(t)) - assert np.allclose(ci.width(), 1.0) - assert np.all(ci.contains(0.5 * np.ones_like(t))) diff --git a/tests/test_data_manager.py b/tests/test_data_manager.py deleted file mode 100644 index c3283be1..00000000 --- a/tests/test_data_manager.py +++ /dev/null @@ -1,156 +0,0 @@ -from __future__ import annotations - -import io -import json -import zipfile -from pathlib import Path - -import pytest - -from nstat import data_manager - - -def _write_expected_tree(root: Path) -> None: - for name in data_manager.EXPECTED_SUBDIRS: - (root / name).mkdir(parents=True, exist_ok=True) - (root / data_manager.SENTINEL_FILENAME).write_text( - json.dumps({"doi": data_manager.DOI_URL}), encoding="utf-8" - ) - - -def _build_fixture_zip() -> bytes: - buf = io.BytesIO() - with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED) as zf: - for name in data_manager.EXPECTED_SUBDIRS: - zf.writestr(f"nSTAT_data/{name}/.keep", "") - return buf.getvalue() - - -class _FakeResponse: - def __init__( - self, - *, - status_code: int = 200, - url: str = "", - text: str = "", - json_payload: dict | None = None, - content_bytes: bytes = b"", - ) -> None: - self.status_code = status_code - self.url = url - self.text = text - self._json_payload = json_payload or {} - self._content_bytes = content_bytes - - def raise_for_status(self) -> None: - if self.status_code >= 400: - raise RuntimeError(f"HTTP {self.status_code}") - - def json(self) -> dict: - return self._json_payload - - def iter_content(self, chunk_size: int = 1024 * 1024): - data = self._content_bytes - for i in range(0, len(data), chunk_size): - yield data[i : i + chunk_size] - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc, tb): - return False - - -class _FakeSession: - def __init__(self, zip_bytes: bytes) -> None: - self.zip_bytes = zip_bytes - self.headers = {} - - def mount(self, *_args, **_kwargs) -> None: # pragma: no cover - interface no-op - return None - - def get(self, url: str, *args, **kwargs): # noqa: ANN001 - if url.startswith(data_manager.DOI_URL): - return _FakeResponse( - status_code=200, - url="https://figshare.com/articles/dataset/nSTAT_data/4834640", - text="", - ) - if url.startswith("https://api.figshare.com/v2/articles/4834640"): - return _FakeResponse( - status_code=200, - json_payload={ - "files": [ - { - "name": "nSTAT_example_data.zip", - "download_url": "https://ndownloader.figshare.com/files/123456", - "size": len(self.zip_bytes), - } - ] - }, - ) - if url.startswith("https://ndownloader.figshare.com/files/123456"): - return _FakeResponse(status_code=200, content_bytes=self.zip_bytes) - raise AssertionError(f"Unexpected URL in fake session: {url}") - - -def test_get_data_dir_env_override(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: - override = tmp_path / "custom_data_root" - monkeypatch.setenv("NSTAT_DATA_DIR", str(override)) - assert data_manager.get_data_dir() == override.resolve() - - -def test_data_is_present_requires_expected_structure(tmp_path: Path) -> None: - root = tmp_path / "data" - root.mkdir(parents=True, exist_ok=True) - assert data_manager.data_is_present(root) is False - _write_expected_tree(root) - assert data_manager.data_is_present(root) is True - - -def test_ensure_example_data_offline_missing_raises( - monkeypatch: pytest.MonkeyPatch, tmp_path: Path -) -> None: - target = tmp_path / "missing_data" - monkeypatch.setenv("NSTAT_DATA_DIR", str(target)) - with pytest.raises(FileNotFoundError): - data_manager.ensure_example_data(download=False) - - -def test_ensure_example_data_downloads_and_writes_sentinel( - monkeypatch: pytest.MonkeyPatch, tmp_path: Path -) -> None: - target = tmp_path / "downloaded_data" - monkeypatch.setenv("NSTAT_DATA_DIR", str(target)) - - zip_bytes = _build_fixture_zip() - fake_session = _FakeSession(zip_bytes) - monkeypatch.setattr(data_manager, "_build_session", lambda: fake_session) - - resolved = data_manager.ensure_example_data(download=True) - assert resolved == target.resolve() - assert data_manager.data_is_present(resolved) - payload = json.loads((resolved / data_manager.SENTINEL_FILENAME).read_text(encoding="utf-8")) - assert payload["doi"] == data_manager.DOI_URL - assert payload["source_url"].startswith("https://ndownloader.figshare.com/files/") - assert "archive_sha256" in payload - - -def test_ensure_example_data_skips_download_when_present( - monkeypatch: pytest.MonkeyPatch, tmp_path: Path -) -> None: - target = tmp_path / "existing_data" - _write_expected_tree(target) - monkeypatch.setenv("NSTAT_DATA_DIR", str(target)) - - called = {"value": False} - - def _fail_session() -> _FakeSession: - called["value"] = True - raise AssertionError("session should not be created when data are already present") - - monkeypatch.setattr(data_manager, "_build_session", _fail_session) - resolved = data_manager.ensure_example_data(download=True) - assert resolved == target.resolve() - assert called["value"] is False - diff --git a/tests/test_data_policy.py b/tests/test_data_policy.py deleted file mode 100644 index 35b77c19..00000000 --- a/tests/test_data_policy.py +++ /dev/null @@ -1,91 +0,0 @@ -from __future__ import annotations - -import hashlib -import json -from pathlib import Path - -import yaml - -from nstat.datasets import fetch_dataset, fetch_matlab_gold_file, list_matlab_gold_files - - - -def _sha256(path: Path) -> str: - digest = hashlib.sha256() - with path.open("rb") as handle: - for chunk in iter(lambda: handle.read(1024 * 1024), b""): - digest.update(chunk) - return digest.hexdigest() - - -def _git_lfs_oid(path: Path) -> str | None: - try: - text = path.read_text(encoding="utf-8") - except UnicodeDecodeError: - return None - lines = [line.strip() for line in text.splitlines()] - if not lines or not lines[0].startswith("version https://git-lfs.github.com/spec"): - return None - for line in lines: - if line.startswith("oid sha256:"): - return line.split("oid sha256:", 1)[1].strip() - return None - - - -def test_shared_dataset_manifest_contains_mepsc_example() -> None: - payload = json.loads(Path("data/datasets_manifest.json").read_text(encoding="utf-8")) - dataset_names = {row["name"] for row in payload["datasets"]} - assert "mEPSC-epsc2" in dataset_names - - -def test_datasets_manifest_contains_full_mirror_entries() -> None: - payload = json.loads(Path("data/datasets_manifest.json").read_text(encoding="utf-8")) - rows = payload["datasets"] - by_name = {row["name"]: row for row in rows} - - mirror_manifest = json.loads( - Path("data/shared/matlab_gold_20260302.manifest.json").read_text(encoding="utf-8") - ) - files = mirror_manifest["files"] - - for row in files: - rel = row["relative_path"] - name = f"matlab_gold_20260302/{rel}" - assert name in by_name, f"missing datasets manifest entry for {name}" - ds = by_name[name] - assert ds["filename"] == rel - assert ds["sha256"] == row["sha256"] - - - -def test_allowlisted_shared_data_file_matches_checksum() -> None: - allowlist = yaml.safe_load( - Path("tools/compliance/shared_data_allowlist.yml").read_text(encoding="utf-8") - ) - - for row in allowlist["shared_data"]: - path = Path(row["python_path"]) - assert path.exists(), f"missing allowlisted data file: {path}" - expected = str(row["sha256"]) - actual = _sha256(path) - if actual != expected: - lfs_oid = _git_lfs_oid(path) - assert lfs_oid == expected - - -def test_fetch_dataset_prefers_local_matlab_mirror_for_mepsc() -> None: - path = fetch_dataset("mEPSC-epsc2") - resolved = path.resolve() - assert "data/shared/matlab_gold_" in resolved.as_posix() - assert resolved.name == "epsc2.txt" - - -def test_fetch_matlab_gold_file_and_listing_api() -> None: - files = list_matlab_gold_files(version="20260302") - assert "mEPSCs/epsc2.txt" in files - assert "PlaceCellAnimal1Results.mat" in files - - path = fetch_matlab_gold_file("mEPSCs/epsc2.txt", version="20260302") - assert path.exists() - assert path.resolve().as_posix().endswith("/data/shared/matlab_gold_20260302/mEPSCs/epsc2.txt") diff --git a/tests/test_datasets.py b/tests/test_datasets.py new file mode 100644 index 00000000..f897924f --- /dev/null +++ b/tests/test_datasets.py @@ -0,0 +1,23 @@ +from __future__ import annotations + +import nstat +from nstat.errors import DataNotFoundError + + +def test_dataset_manifest_and_checksums() -> None: + names = nstat.list_datasets() + assert names + + check = nstat.verify_checksums() + assert set(check.keys()) == set(names) + assert all(isinstance(v, bool) for v in check.values()) + + +def test_get_dataset_path() -> None: + name = nstat.list_datasets()[0] + try: + path = nstat.get_dataset_path(name) + except DataNotFoundError: + # Standalone checkouts may intentionally omit large datasets. + return + assert path.exists() diff --git a/tests/test_docs_search.py b/tests/test_docs_search.py deleted file mode 100644 index f963269d..00000000 --- a/tests/test_docs_search.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - - - -def test_docs_notebook_catalog_exists() -> None: - catalog = Path("docs/notebooks.md") - assert catalog.exists() - - text = catalog.read_text(encoding="utf-8") - assert "AnalysisExamples.ipynb" in text - assert "nSTATPaperExamples.ipynb" in text diff --git a/tests/test_equivalence_audit_report.py b/tests/test_equivalence_audit_report.py deleted file mode 100644 index 8b62d1d9..00000000 --- a/tests/test_equivalence_audit_report.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -import json -from pathlib import Path - - -def test_equivalence_audit_report_exists_and_has_schema() -> None: - report_path = Path("parity/function_example_alignment_report.json") - assert report_path.exists(), "parity/function_example_alignment_report.json must exist" - - payload = json.loads(report_path.read_text(encoding="utf-8")) - assert "method_functional_audit" in payload - assert "example_line_alignment_audit" in payload - - method_summary = payload["method_functional_audit"]["summary"] - assert method_summary["total_methods"] >= 1 - assert method_summary["missing_symbol_methods"] == 0 - - example_summary = payload["example_line_alignment_audit"]["summary"] - assert example_summary["total_topics"] >= 1 - assert "strict_line_verified_topics" in example_summary - assert "strict_line_partial_topics" in example_summary - assert "strict_line_gap_topics" in example_summary - - topic_rows = payload["example_line_alignment_audit"]["topic_rows"] - assert topic_rows, "example_line_alignment_audit.topic_rows must not be empty" - required_topic_fields = { - "topic", - "strict_line_status", - "line_port_coverage", - "line_port_function_recall", - "line_port_matched_lines", - "line_port_matlab_lines", - "line_port_python_lines", - "line_port_matlab_function_count", - "line_port_python_function_count", - } - for row in topic_rows: - missing = required_topic_fields.difference(row) - assert not missing, f"Missing strict line-port fields for topic {row.get('topic')}: {sorted(missing)}" - - -def test_top_mismatch_topics_meet_line_port_regression_thresholds() -> None: - report_path = Path("parity/function_example_alignment_report.json") - payload = json.loads(report_path.read_text(encoding="utf-8")) - topic_rows = payload["example_line_alignment_audit"]["topic_rows"] - topic_lookup = {str(row["topic"]): row for row in topic_rows} - - thresholds = { - "nSTATPaperExamples": (0.0, 0.95), - "HippocampalPlaceCellExample": (0.0, 0.95), - "publish_all_helpfiles": (0.0, 0.95), - } - allowed_statuses = {"line_port_gap", "line_port_partial", "line_port_verified"} - - for topic, (min_cov, min_recall) in thresholds.items(): - assert topic in topic_lookup, f"Missing topic row for {topic}" - row = topic_lookup[topic] - coverage = float(row["line_port_coverage"]) - recall = float(row["line_port_function_recall"]) - status = str(row["strict_line_status"]) - assert coverage >= min_cov, f"{topic}: coverage {coverage:.4f} < {min_cov:.4f}" - assert recall >= min_recall, f"{topic}: function recall {recall:.4f} < {min_recall:.4f}" - assert status in allowed_statuses, f"{topic}: strict status {status} not in {sorted(allowed_statuses)}" diff --git a/tests/test_events_history.py b/tests/test_events_history.py deleted file mode 100644 index 2e117ac3..00000000 --- a/tests/test_events_history.py +++ /dev/null @@ -1,35 +0,0 @@ -import numpy as np - -from nstat.events import Events -from nstat.history import HistoryBasis - - -def test_events_subset() -> None: - e = Events(times=np.array([0.1, 0.3, 0.7]), labels=["a", "b", "c"]) - sub = e.subset(0.2, 1.0) - assert sub.times.tolist() == [0.3, 0.7] - - -def test_history_design_matrix() -> None: - hb = HistoryBasis(bin_edges_s=np.array([0.0, 0.05, 0.1])) - mat = hb.design_matrix(spike_times_s=np.array([0.15, 0.22]), time_grid_s=np.array([0.25, 0.3])) - assert mat.shape == (2, 2) - - -def test_history_design_matrix_matches_naive_reference() -> None: - rng = np.random.default_rng(7) - spikes = np.sort(rng.random(400) * 2.0) - grid = np.linspace(0.0, 2.0, 250) - hb = HistoryBasis(bin_edges_s=np.array([0.0, 0.01, 0.03, 0.07, 0.1])) - - fast = hb.design_matrix(spike_times_s=spikes, time_grid_s=grid) - - ref = np.zeros_like(fast) - for i, t_now in enumerate(grid): - lags = t_now - spikes - for j in range(hb.n_bins): - lo = hb.bin_edges_s[j] - hi = hb.bin_edges_s[j + 1] - ref[i, j] = float(np.sum((lags > lo) & (lags <= hi))) - - np.testing.assert_allclose(fast, ref, atol=0.0, rtol=0.0) diff --git a/tests/test_fitressummary_notebook_checkpoint.py b/tests/test_fitressummary_notebook_checkpoint.py deleted file mode 100644 index 1a10fff8..00000000 --- a/tests/test_fitressummary_notebook_checkpoint.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import nbformat - - -def test_fitressummary_checkpoint_is_not_brittle_to_model_count() -> None: - path = Path("notebooks") / "FitResSummaryExamples.ipynb" - nb = nbformat.read(path, as_version=4) - code = "\n".join(cell.source for cell in nb.cells if cell.cell_type == "code") - - # Regression guard: avoid fixed-size assumptions that can differ across - # numerical environments and optimization backends. - assert "assert diff_aic.size == diff_bic.size and diff_aic.size > 0" in code - assert "assert diff_aic.size == 3 and diff_bic.size == 3" not in code - - # Regression guard: IC deltas can be positive or negative depending on - # stochastic simulation and fit ordering; keep bounds symmetric. - assert '"best_aic_diff": (-10.0, 10.0)' in code - assert '"best_bic_diff": (-10.0, 10.0)' in code diff --git a/tests/test_functional_parity_gates.py b/tests/test_functional_parity_gates.py deleted file mode 100644 index 67642cea..00000000 --- a/tests/test_functional_parity_gates.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import annotations - -import subprocess -import sys - - -def _run(cmd: list[str]) -> None: - proc = subprocess.run(cmd, capture_output=True, text=True) - assert proc.returncode == 0, f"{' '.join(cmd)} failed:\n{proc.stdout}\n{proc.stderr}" - - -def test_functional_parity_gate_passes() -> None: - _run( - [ - sys.executable, - "tools/parity/check_functional_parity_progress.py", - "--report", - "parity/function_example_alignment_report.json", - "--policy", - "parity/functional_gate_policy.yml", - ] - ) - - -def test_example_output_spec_gate_passes() -> None: - _run( - [ - sys.executable, - "tools/parity/check_example_output_spec.py", - "--report", - "parity/function_example_alignment_report.json", - "--spec", - "parity/example_output_spec.yml", - ] - ) diff --git a/tests/test_helpfile_figure_manifest.py b/tests/test_helpfile_figure_manifest.py deleted file mode 100644 index 629bccfa..00000000 --- a/tests/test_helpfile_figure_manifest.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import annotations - -import json -from pathlib import Path - -import nbformat -import yaml - - -FIG_MANIFEST = Path("parity/helpfile_figure_manifest.json") -HELPFILE_MANIFEST = Path("parity/helpfile_notebook_manifest.yml") - - -def test_helpfile_figure_manifest_schema() -> None: - payload = json.loads(FIG_MANIFEST.read_text(encoding="utf-8")) - assert int(payload.get("schema_version", 0)) >= 1 - topics = payload.get("topics", {}) - assert isinstance(topics, dict) and topics - for topic, row in topics.items(): - assert isinstance(topic, str) and topic - assert isinstance(row, dict) - assert "matlab_helpfile_path" in row - assert int(row.get("total_figures_expected", -1)) >= 0 - events = row.get("events", []) - assert isinstance(events, list) - for event in events: - assert isinstance(event, dict) - assert int(event.get("section_index", 0)) >= 1 - assert int(event.get("matlab_line_number", 0)) >= 1 - assert str(event.get("event_type", "")) in {"new_figure", "add_to_current"} - assert int(event.get("figure_ordinal", 0)) >= 1 - - -def test_helpfile_manifest_figure_counts_match_figure_manifest() -> None: - fig_payload = json.loads(FIG_MANIFEST.read_text(encoding="utf-8")) - fig_topics = fig_payload.get("topics", {}) - help_rows = (yaml.safe_load(HELPFILE_MANIFEST.read_text(encoding="utf-8")) or {}).get("notebooks", []) - for row in help_rows: - topic = str(row["topic"]) - assert topic in fig_topics - expected = int(fig_topics[topic]["total_figures_expected"]) - assert int(row["expected_min_figures"]) == expected - assert int(row["expected_figure_count"]) == expected - - -def test_notebooks_include_figure_tracker_assertion() -> None: - help_rows = (yaml.safe_load(HELPFILE_MANIFEST.read_text(encoding="utf-8")) or {}).get("notebooks", []) - for row in help_rows: - nb = nbformat.read(Path(str(row["notebook_path"])), as_version=4) - code = "\n".join(cell.source for cell in nb.cells if cell.cell_type == "code") - assert "FigureTracker" in code, f"{row['topic']}: missing FigureTracker usage" - assert "FIGURE_TRACKER.finalize()" in code, f"{row['topic']}: missing FigureTracker.finalize()" diff --git a/tests/test_helpfile_notebook_sections.py b/tests/test_helpfile_notebook_sections.py deleted file mode 100644 index 01b0c6af..00000000 --- a/tests/test_helpfile_notebook_sections.py +++ /dev/null @@ -1,110 +0,0 @@ -from __future__ import annotations - -import os -import re -from pathlib import Path - -import nbformat -import yaml - - -HELPFILE_MANIFEST = Path("parity/helpfile_notebook_manifest.yml") - - -def _load_manifest_rows() -> list[dict]: - payload = yaml.safe_load(HELPFILE_MANIFEST.read_text(encoding="utf-8")) or {} - return [dict(row) for row in payload.get("notebooks", [])] - - -def _resolve_matlab_help_root() -> Path | None: - env = os.environ.get("NSTAT_MATLAB_HELP_ROOT") - if env: - candidate = Path(env).expanduser().resolve() - if candidate.exists(): - return candidate - for candidate in ( - Path("/tmp/upstream-nstat/helpfiles"), - Path.home() - / "Library" - / "CloudStorage" - / "Dropbox" - / "Research" - / "Matlab" - / "nSTAT_currentRelease_Local" - / "helpfiles", - ): - if candidate.exists(): - return candidate - return None - - -def _section_count_from_helpfile(path: Path) -> int: - text = path.read_text(encoding="utf-8", errors="ignore") - lines = text.splitlines() - if not lines: - return 1 - sections = 0 - current_has_lines = False - for line in lines: - if re.match(r"^\s*%%", line): - if current_has_lines: - sections += 1 - current_has_lines = True - else: - current_has_lines = True - if current_has_lines: - sections += 1 - return sections - - -def test_helpfile_manifest_has_required_fields() -> None: - rows = _load_manifest_rows() - assert rows, "helpfile notebook manifest is empty" - for row in rows: - assert "topic" in row - assert "file" in row - assert "notebook_path" in row - assert "run_group" in row - assert "matlab_helpfile" in row - assert "matlab_helpfile_path" in row - assert int(row["matlab_section_count"]) >= 1 - assert int(row["python_cell_count"]) >= 1 - assert int(row["expected_min_figures"]) >= 0 - - -def test_helpfile_notebooks_are_code_only_and_cell_counts_match_sections() -> None: - rows = _load_manifest_rows() - for row in rows: - topic = str(row["topic"]) - notebook_path = Path(str(row["notebook_path"])) - nb = nbformat.read(notebook_path, as_version=4) - - assert nb.cells, f"{topic}: no notebook cells" - assert all(cell.cell_type == "code" for cell in nb.cells), f"{topic}: contains non-code cells" - - section_count = int(row["matlab_section_count"]) - cell_count = int(row["python_cell_count"]) - assert len(nb.cells) == section_count, f"{topic}: notebook cell count != section_count" - assert len(nb.cells) == cell_count, f"{topic}: notebook cell count != manifest cell_count" - - code = "\n".join(cell.source for cell in nb.cells) - assert "# MATLAB" in code or "# %" in code, f"{topic}: missing MATLAB trace comments" - first_cell = str(nb.cells[0].source) - assert "ensure_example_data" in first_cell, f"{topic}: missing data bootstrap in first cell" - assert "DATA_DIR = ensure_example_data" in first_cell, f"{topic}: DATA_DIR bootstrap missing" - - -def test_helpfile_section_counts_match_matlab_when_available() -> None: - matlab_help_root = _resolve_matlab_help_root() - if matlab_help_root is None: - return - - rows = _load_manifest_rows() - for row in rows: - topic = str(row["topic"]) - helpfile_rel = str(row["matlab_helpfile_path"]) - helpfile_path = matlab_help_root / helpfile_rel - assert helpfile_path.exists(), f"{topic}: missing MATLAB helpfile {helpfile_path}" - expected = _section_count_from_helpfile(helpfile_path) - actual = int(row["matlab_section_count"]) - assert actual == expected, f"{topic}: section_count mismatch (manifest={actual}, matlab={expected})" diff --git a/tests/test_helpfile_ordinal_image_parity.py b/tests/test_helpfile_ordinal_image_parity.py new file mode 100644 index 00000000..16d14de7 --- /dev/null +++ b/tests/test_helpfile_ordinal_image_parity.py @@ -0,0 +1,145 @@ +from __future__ import annotations + +import json +import os +import subprocess +from pathlib import Path + +import matplotlib.image as mpimg +import numpy as np +import pytest +import yaml + + +def _write_image(path: Path, value: float) -> None: + arr = np.full((32, 32), value, dtype=float) + path.parent.mkdir(parents=True, exist_ok=True) + mpimg.imsave(path, arr, cmap="gray", vmin=0.0, vmax=1.0) + + +def _run_checker( + manifest: Path, + py_root: Path, + mat_root: Path, + out_json: Path, + *, + topics: str = "", + threshold: str = "0.9", +) -> subprocess.CompletedProcess[str]: + cmd = [ + "python", + "tools/reports/check_helpfile_ordinal_image_parity.py", + "--manifest", + str(manifest), + "--python-image-root", + str(py_root), + "--matlab-image-root", + str(mat_root), + "--ssim-threshold", + threshold, + "--out-json", + str(out_json), + ] + if topics: + cmd.extend(["--topics", topics]) + return subprocess.run( + cmd, + cwd=Path(__file__).resolve().parents[1], + text=True, + capture_output=True, + check=False, + env={**os.environ, "PYTHONPATH": "src:."}, + ) + + +def test_ordinal_image_parity_passes_for_identical_pairs(tmp_path: Path) -> None: + manifest = tmp_path / "manifest.yml" + py_root = tmp_path / "python_images" + mat_root = tmp_path / "matlab_images" + out_json = tmp_path / "summary.json" + + _write_image(py_root / "TopicA" / "fig_001.png", 0.25) + _write_image(mat_root / "TopicA" / "fig_001.png", 0.25) + + manifest.write_text( + yaml.safe_dump( + { + "version": 1, + "topics": [ + { + "topic": "TopicA", + "expected_figure_count": 1, + "notebook_output_path": "notebooks/TopicA.ipynb", + } + ], + }, + sort_keys=False, + ), + encoding="utf-8", + ) + + result = _run_checker(manifest, py_root, mat_root, out_json) + assert result.returncode == 0, result.stdout + "\n" + result.stderr + payload = json.loads(out_json.read_text(encoding="utf-8")) + assert payload["status"] == "pass" + + +def test_ordinal_image_parity_fails_on_count_mismatch(tmp_path: Path) -> None: + manifest = tmp_path / "manifest.yml" + py_root = tmp_path / "python_images" + mat_root = tmp_path / "matlab_images" + out_json = tmp_path / "summary.json" + + _write_image(py_root / "TopicA" / "fig_001.png", 0.25) + _write_image(py_root / "TopicA" / "fig_002.png", 0.5) + _write_image(mat_root / "TopicA" / "fig_001.png", 0.25) + + manifest.write_text( + yaml.safe_dump( + { + "version": 1, + "topics": [ + { + "topic": "TopicA", + "expected_figure_count": 1, + "notebook_output_path": "notebooks/TopicA.ipynb", + } + ], + }, + sort_keys=False, + ), + encoding="utf-8", + ) + + result = _run_checker(manifest, py_root, mat_root, out_json) + assert result.returncode == 1 + payload = json.loads(out_json.read_text(encoding="utf-8")) + assert payload["status"] == "fail" + assert payload["failures"] + + +def test_analysisexamples_fig001_ssim_threshold_when_artifacts_present(tmp_path: Path) -> None: + repo_root = Path(__file__).resolve().parents[1] + py_img = repo_root / "output/notebook_images/AnalysisExamples/fig_001.png" + mat_img = repo_root / "output/matlab_help_images/AnalysisExamples/fig_001.png" + if not py_img.exists() or not mat_img.exists(): + pytest.skip("AnalysisExamples parity artifacts not present locally") + + manifest = repo_root / "parity/help_source_manifest.yml" + out_json = tmp_path / "analysisexamples_summary.json" + result = _run_checker( + manifest, + repo_root / "output/notebook_images", + repo_root / "output/matlab_help_images", + out_json, + topics="AnalysisExamples", + threshold="0.70", + ) + payload = json.loads(out_json.read_text(encoding="utf-8")) + topic_rows = [row for row in payload.get("topics", []) if row.get("topic") == "AnalysisExamples"] + assert topic_rows, result.stdout + "\n" + result.stderr + pairs = topic_rows[0].get("pairs", []) + assert pairs, result.stdout + "\n" + result.stderr + fig1 = next((pair for pair in pairs if int(pair.get("ordinal", -1)) == 1), None) + assert fig1 is not None, result.stdout + "\n" + result.stderr + assert float(fig1["score"]) >= 0.70, result.stdout + "\n" + result.stderr diff --git a/tests/test_install.py b/tests/test_install.py deleted file mode 100644 index 7460d447..00000000 --- a/tests/test_install.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import annotations - -from nstat.install import nstat_install - - - -def test_nstat_install_returns_existing_cache_dir() -> None: - report = nstat_install() - assert report.package == "nstat" - assert report.cache_dir.exists() diff --git a/tests/test_manifests.py b/tests/test_manifests.py deleted file mode 100644 index b22575b6..00000000 --- a/tests/test_manifests.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import yaml - - -REQUIRED_MATLAB_CLASSES = { - "SignalObj", - "Covariate", - "ConfidenceInterval", - "Events", - "History", - "nspikeTrain", - "nstColl", - "CovColl", - "TrialConfig", - "ConfigColl", - "Trial", - "CIF", - "Analysis", - "FitResult", - "FitResSummary", - "DecodingAlgorithms", -} - - -def test_class_method_inventory_has_all_required_classes() -> None: - payload = yaml.safe_load(Path("baseline/class_method_inventory.yml").read_text(encoding="utf-8")) - classes = payload["classes"] - mapped = {row["matlab_class"] for row in classes} - assert REQUIRED_MATLAB_CLASSES.issubset(mapped) - - - -def test_example_inventory_has_expected_topics() -> None: - payload = yaml.safe_load(Path("baseline/example_workflow_inventory.yml").read_text(encoding="utf-8")) - workflows = payload["workflows"] - assert len(workflows) == 30 - assert any(row["topic"] == "nSTATPaperExamples" for row in workflows) - assert any(row["topic"] == "AnalysisExamples2" for row in workflows) - assert any(row["topic"] == "publish_all_helpfiles" for row in workflows) - - - -def test_paper_mapping_mentions_reference() -> None: - payload = yaml.safe_load(Path("baseline/paper_section_mapping.yml").read_text(encoding="utf-8")) - assert payload["paper"]["doi"] == "10.1016/j.jneumeth.2012.08.009" - - -def test_parity_manifest_exists_and_includes_vertical_slice() -> None: - payload = yaml.safe_load(Path("baseline/parity_manifest.yml").read_text(encoding="utf-8")) - assert payload["policy"]["clean_room"] is True - assert len(payload["classes"]) == 16 - assert any(row["topic"] == "nSTATPaperExamples" for row in payload["workflows"]) diff --git a/tests/test_matlab_compat.py b/tests/test_matlab_compat.py deleted file mode 100644 index 230a698c..00000000 --- a/tests/test_matlab_compat.py +++ /dev/null @@ -1,315 +0,0 @@ -from __future__ import annotations - -import numpy as np - -from nstat.compat.matlab import Analysis -from nstat.compat.matlab import ConfigColl -from nstat.compat.matlab import CovColl -from nstat.compat.matlab import DecodingAlgorithms -from nstat.compat.matlab import FitResSummary -from nstat.compat.matlab import FitResult -from nstat.compat.matlab import History -from nstat.compat.matlab import SignalObj -from nstat.compat.matlab import Trial -from nstat.compat.matlab import nspikeTrain -from nstat.compat.matlab import nstColl -from nstat.compat.matlab import TrialConfig -from nstat.signal import Covariate -from nstat.fit import FitResult as NativeFitResult - - - -def test_signalobj_alias_methods() -> None: - t = np.linspace(0.0, 1.0, 5) - x = np.sin(2.0 * np.pi * t) - sig = SignalObj(time=t, data=x, name="sig") - - assert sig.getNumSamples() == 5 - assert sig.getNumSignals() == 1 - assert np.isclose(sig.getSampleRate(), 4.0) - assert np.isclose(sig.getDuration(), 1.0) - assert sig.getData().shape == (5,) - - -def test_signalobj_extended_parity_aliases() -> None: - t = np.linspace(0.0, 1.0, 201) - data = np.column_stack([np.sin(2.0 * np.pi * t), np.cos(2.0 * np.pi * t)]) - sig = SignalObj(time=t, data=data, name="sig") - sig.setDataLabels(["sin", "cos"]) - - assert sig.getIndexFromLabel("cos") == 1 - assert sig.getIndicesFromLabels(["sin", "cos"]) == [0, 1] - assert sig.isLabelPresent("sin") - assert not sig.areDataLabelsEmpty() - - sig.setMaskByLabels(["cos"]) - assert sig.isMaskSet() - assert sig.findIndFromDataMask() == [1] - sub = sig.getSubSignalFromNames(["cos"]) - assert sub.getNumSignals() == 1 - sig.resetMask() - assert not sig.isMaskSet() - - _f, _p = sig.periodogram() - _lags, _corr = sig.autocorrelation(maxLag=10) - _lags2, _cov = sig.xcov(maxLag=10) - assert _f.ndim == 1 - assert _p.ndim == 1 - assert _lags.size == _corr.size - assert _lags2.size == _cov.size - - filt = sig.filter(np.array([1.0]), np.array([1.0])) - ff = sig.filtfilt(np.array([0.5, 0.5]), np.array([1.0])) - assert filt.getData().shape[0] == sig.getData().shape[0] - assert ff.getData().shape[0] == sig.getData().shape[0] - - win = sig.windowedSignal(windowSamples=9) - nwin = sig.normWindowedSignal(windowSamples=9) - assert win.getData().shape == sig.getData().shape - assert nwin.getData().shape == sig.getData().shape - - orig = sig.getOriginalData() - sig.setMinTime(0.2) - sig.restoreToOriginal() - assert np.allclose(sig.getData(), orig) - assert SignalObj.cell2str(["a", "b"], ":") == "a:b" - - - -def test_trialconfig_matlab_style_constructor() -> None: - cfg = TrialConfig(covariateLabels=["stim"], Fs=500.0, fitType="binomial", name="cfg") - assert cfg.getSampleRate() == 500.0 - assert cfg.getFitType() == "binomial" - assert cfg.getCovariateLabels() == ["stim"] - - - -def test_configcoll_matlab_aliases() -> None: - cfg1 = TrialConfig(covariateLabels=["stim"], Fs=1000.0, fitType="poisson", name="cfg_a") - cfg2 = TrialConfig(covariateLabels=["ctx"], Fs=500.0, fitType="binomial", name="cfg_b") - coll = ConfigColl([cfg1, cfg2]) - - assert coll.getConfigNames() == ["cfg_a", "cfg_b"] - assert coll.getConfig(2).name == "cfg_b" - assert coll.getConfig("cfg_a").fit_type == "poisson" - - cfg3 = TrialConfig(covariateLabels=["stim", "ctx"], Fs=250.0, fitType="poisson", name="cfg_c") - coll.addConfig(cfg3) - assert coll.getConfig(3).name == "cfg_c" - - coll.setConfigNames(["a", "b", "c"]) - assert coll.getConfigNames() == ["a", "b", "c"] - - subset = coll.getSubsetConfigs([1, 3]) - assert [cfg.name for cfg in subset.configs] == ["a", "c"] - - payload = coll.toStructure() - restored = ConfigColl.fromStructure(payload) - assert restored.getConfigNames() == ["a", "b", "c"] - - -def test_analysis_fitglm_alias() -> None: - rng = np.random.default_rng(7) - x = rng.normal(size=1200) - X = x[:, None] - p = 1.0 / (1.0 + np.exp(-(-0.5 + 0.9 * x))) - y = rng.binomial(1, p).astype(float) - - result = Analysis.fitGLM(X=X, y=y, fitType="binomial") - assert isinstance(result, NativeFitResult) - assert np.isfinite(result.log_likelihood) - - - -def test_decoding_aliases() -> None: - mat = np.array( - [ - [0, 0, 1, 0, 0, 1], - [0, 1, 1, 0, 0, 1], - [1, 1, 1, 1, 1, 1], - ], - dtype=float, - ) - rates, pvals, sig = DecodingAlgorithms.computeSpikeRateCIs(mat) - assert rates.shape[0] == mat.shape[0] - assert pvals.shape == (mat.shape[0], mat.shape[0]) - assert sig.shape == (mat.shape[0], mat.shape[0]) - - -def test_collection_and_covariate_aliases() -> None: - t = np.linspace(0.0, 1.0, 101) - c1 = Covariate(time=t, data=np.sin(2 * np.pi * t), name="stim", labels=["stim"]) - c2 = Covariate(time=t, data=np.cos(2 * np.pi * t), name="ctx", labels=["ctx"]) - coll = CovColl([c1, c2]) - X, labels = coll.dataToMatrix() - assert X.shape[1] == 2 - assert labels == ["stim", "ctx"] - assert coll.getCovIndFromName("ctx") == 1 - assert coll.isCovPresent("stim") - - -def test_covcoll_extended_aliases() -> None: - t = np.linspace(0.0, 1.0, 101) - c1 = Covariate(time=t, data=np.sin(2 * np.pi * t), name="stim", labels=["stim"]) - c2 = Covariate(time=t, data=np.cos(2 * np.pi * t), name="ctx", labels=["ctx"]) - coll = CovColl([c1, c2]) - - assert coll.containsChars("stimulus", "tu") - assert coll.isaSelectorCell(["stim", "ctx"]) - assert coll.covIndFromSelector(["ctx"]) == [1] - assert coll.getCovMaskFromSelector([2]) == [1] - assert coll.generateRemainingIndex(["stim"]) == [1] - assert coll.generateSelectorCell([0, 1]) == ["stim", "ctx"] - assert coll.getSelectorFromMasks([1]) == ["ctx"] - - coll.setMasksFromSelector(["stim"]) - assert coll.getCovDataMask() == [0] - coll.maskAwayCov(["stim"]) - assert coll.getCovDataMask() == [1] - coll.maskAwayAllExcept(["ctx"]) - assert coll.getCovDataMask() == [1] - - coll.setCovShift(0.1) - assert np.isclose(coll.getTime()[0], 0.1) - coll.resetCovShift() - assert np.isclose(coll.getTime()[0], 0.0) - assert np.isclose(coll.findMinTime(), 0.0) - assert np.isclose(coll.findMaxTime(), 1.0) - - payload = coll.dataToStructure() - restored = CovColl.fromStructure(payload) - assert restored.getAllCovLabels() == ["stim", "ctx"] - - -def test_nspiketrain_extended_aliases() -> None: - st = nspikeTrain(spike_times=np.array([0.1, 0.3, 0.55]), t_start=0.0, t_end=1.0, name="u1") - assert np.isclose(st.computeRate(), st.getFiringRate()) - assert np.isclose(st.getMinISI(), 0.2) - assert st.getMaxBinSizeBinary() > 0.0 - assert st.getLStatistic() >= 0.0 - assert st.computeStatistics()["n_spikes"] == 3.0 - - st.setSigRep(np.array([0, 1, 0, 1], dtype=float)) - assert st.isSigRepBinary() - st.clearSigRep() - assert st.getSigRep(binSize_s=0.1).ndim == 1 - - st_copy = st.nstCopy() - assert np.allclose(st_copy.spike_times, st.spike_times) - parts = st.partitionNST([0.0, 0.5, 1.0]) - assert len(parts) == 2 - - payload = st.toStructure() - restored = nspikeTrain.fromStructure(payload) - assert np.allclose(restored.spike_times, st.spike_times) - - -def test_spike_collection_aliases() -> None: - st1 = nspikeTrain(spike_times=np.array([0.1, 0.3]), t_start=0.0, t_end=1.0, name="u1") - st2 = nspikeTrain(spike_times=np.array([0.2, 0.4]), t_start=0.0, t_end=1.0, name="u2") - coll = nstColl([st1, st2]) - assert coll.getNumUnits() == 2 - assert np.isclose(coll.getFirstSpikeTime(), 0.1) - assert np.isclose(coll.getLastSpikeTime(), 0.4) - assert coll.getNSTnameFromInd(1) == "u2" - merged = coll.toSpikeTrain() - assert merged.spike_times.size == 4 - - assert coll.ensureConsistancy() - assert coll.getMaxBinSizeBinary() > 0.0 - assert coll.findMaxSampleRate() > 0.0 - assert coll.estimateVarianceAcrossTrials(binSize_s=0.1).ndim == 1 - - coll.setNeuronMaskFromInd([1]) - assert coll.isNeuronMaskSet() - assert coll.getIndFromMask() == [0] - assert coll.getIndFromMaskMinusOne() == [0] - coll.resetMask() - assert coll.getIndFromMask() == [0, 1] - - coll.setNeighbors([[1], [0]]) - assert coll.areNeighborsSet() - assert coll.getNeighbors() == [[1], [0]] - - basis = nstColl.generateUnitImpulseBasis(basisWidth_s=0.2, sampleRate_hz=100.0, totalTime_s=1.0) - assert basis.data.ndim == 2 - ens = coll.getEnsembleNeuronCovariates(binSize_s=0.1, mode="count") - assert ens.nActCovar() == 2 - - -def test_fit_aliases() -> None: - fit1 = FitResult( - coefficients=np.array([0.2]), - intercept=-1.0, - fit_type="binomial", - log_likelihood=-9.0, - n_samples=100, - n_parameters=2, - parameter_labels=["stim"], - ) - fit2 = FitResult( - coefficients=np.array([0.4]), - intercept=-0.7, - fit_type="binomial", - log_likelihood=-8.0, - n_samples=100, - n_parameters=2, - parameter_labels=["stim"], - ) - assert fit1.getCoeffIndex("stim") == 0 - assert np.isclose(fit1.getParam("aic"), fit1.getAIC()) - - summary = FitResSummary([fit1, fit2]) - diff = summary.getDiffAIC() - assert diff.shape == (2,) - mat = summary.computeDiffMat("bic") - assert mat.shape == (2, 2) - - -def test_trial_extended_parity_aliases() -> None: - t = np.linspace(0.0, 1.0, 101) - c1 = Covariate(time=t, data=np.sin(2 * np.pi * t), name="stim", labels=["stim"]) - c2 = Covariate(time=t, data=np.cos(2 * np.pi * t), name="ctx", labels=["ctx"]) - covs = CovColl([c1, c2]) - st1 = nspikeTrain(spike_times=np.array([0.1, 0.3, 0.7]), t_start=0.0, t_end=1.0, name="u1") - st2 = nspikeTrain(spike_times=np.array([0.2, 0.4, 0.8]), t_start=0.0, t_end=1.0, name="u2") - spikes = nstColl([st1, st2]) - trial = Trial(spikes=spikes, covariates=covs) - - trial.setCovMask(["stim"]) - assert trial.getLabelsFromMask() == ["stim"] - assert trial.getCovSelectorFromMask() == ["stim"] - assert trial.flattenCovMask([[1, 2]]) == [1, 2] - - trial.setNeuronMask([1]) - assert trial.isNeuronMaskSet() - assert trial.getNeuronIndFromMask() == [0] - trial.resetNeuronMask() - assert trial.getNeuronIndFromMask() == [0, 1] - - trial.setEnsCovMask([1]) - labels_mask = trial.getEnsCovLabelsFromMask(binSize_s=0.1) - assert len(labels_mask) == 1 - X_ens, labs = trial.getEnsCovMatrix(binSize_s=0.1, mode="count") - assert X_ens.shape[1] == len(labs) - - trial.setNeighbors([[1], [0]]) - assert trial.getNeuronNeighbors() == [[1], [0]] - - hist = History(bin_edges_s=np.array([0.0, 0.05, 0.1])) - trial.setHistory(hist) - assert trial.isHistSet() - mats = trial.getHistMatrices(binSize_s=0.1) - assert len(mats) == 2 - assert trial.getNumHist() >= 1 - trial.resetHistory() - assert not trial.isHistSet() - - all_labels = trial.getAllLabels(binSize_s=0.1) - assert "stim" in all_labels - assert "ctx" in all_labels - - trial.setTrialTimesFor(0.1, 0.9) - trial.restoreToOriginal() - assert np.isclose(trial.findMinTime(), 0.0) - assert np.isclose(trial.findMaxTime(), 1.0) diff --git a/tests/test_matlab_helpfile_figure_export_tool.py b/tests/test_matlab_helpfile_figure_export_tool.py new file mode 100644 index 00000000..db91c21e --- /dev/null +++ b/tests/test_matlab_helpfile_figure_export_tool.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +import os +import subprocess +from pathlib import Path + + +def test_export_matlab_helpfile_figures_tool_dry_run() -> None: + repo_root = Path(__file__).resolve().parents[1] + cmd = [ + "python", + "tools/reports/export_matlab_helpfile_figures.py", + "--source-manifest", + "parity/help_source_manifest.yml", + "--output-root", + "output/matlab_help_images_test", + "--report-json", + "output/matlab_help_images_test/report.json", + "--dry-run", + ] + proc = subprocess.run( + cmd, + cwd=repo_root, + text=True, + capture_output=True, + check=False, + env={**os.environ, "PYTHONPATH": "src:."}, + ) + assert proc.returncode == 0, proc.stdout + "\n" + proc.stderr + assert "Resolved" in proc.stdout diff --git a/tests/test_method_probe_report.py b/tests/test_method_probe_report.py deleted file mode 100644 index 096460cb..00000000 --- a/tests/test_method_probe_report.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import annotations - -import json -from pathlib import Path - - -def test_method_probe_report_exists_and_has_schema() -> None: - report_path = Path("parity/method_probe_report.json") - assert report_path.exists(), "parity/method_probe_report.json must exist" - - payload = json.loads(report_path.read_text(encoding="utf-8")) - assert "summary" in payload - assert "class_rows" in payload - - summary = payload["summary"] - assert summary["total_methods"] >= 1 - assert summary["attempted_methods"] >= 1 - assert summary["successful_methods"] >= 1 - assert summary["successful_methods"] <= summary["attempted_methods"] - - class_rows = payload["class_rows"] - assert len(class_rows) >= 1 - assert all("matlab_class" in row for row in class_rows) diff --git a/tests/test_no_matlab_dependency.py b/tests/test_no_matlab_dependency.py deleted file mode 100644 index d1d66236..00000000 --- a/tests/test_no_matlab_dependency.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import annotations - -import re -from pathlib import Path - - -PATTERNS = [ - re.compile(r"\bmatlab\.engine\b"), - re.compile(r"\bimport\s+matlab\b"), - re.compile(r"\bfrom\s+matlab\b"), -] - - - -def test_source_has_no_matlab_runtime_dependency() -> None: - for path in Path("src").rglob("*.py"): - text = path.read_text(encoding="utf-8") - for pattern in PATTERNS: - assert not pattern.search(text), f"MATLAB dependency found in {path}: {pattern.pattern}" diff --git a/tests/test_notebook_assertions.py b/tests/test_notebook_assertions.py deleted file mode 100644 index 83817d44..00000000 --- a/tests/test_notebook_assertions.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import nbformat - - -TOPICS = [ - "AnalysisExamples2", - "DocumentationSetup2025b", - "FitResultReference", - "HybridFilterExample", - "publish_all_helpfiles", -] - - - -def test_new_topics_have_assertion_cells() -> None: - for topic in TOPICS: - path = Path("notebooks") / f"{topic}.ipynb" - nb = nbformat.read(path, as_version=4) - code = "\n".join( - cell.source for cell in nb.cells if cell.cell_type == "code" - ) - assert "Notebook checkpoints passed" in code - assert "Topic-specific checkpoint" in code diff --git a/tests/test_notebook_helpfile_mapping.py b/tests/test_notebook_helpfile_mapping.py deleted file mode 100644 index e2c82c83..00000000 --- a/tests/test_notebook_helpfile_mapping.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import annotations - -import os -from pathlib import Path - -import yaml - - -MANIFEST_PATH = Path("tools/notebooks/notebook_manifest.yml") -EXAMPLE_MAP_PATH = Path("parity/example_mapping.yaml") -NOTEBOOK_HELP_MAP_PATH = Path("parity/notebook_to_helpfile_map.yml") - - -def _load_yaml(path: Path) -> dict: - return yaml.safe_load(path.read_text(encoding="utf-8")) or {} - - -def _resolve_matlab_help_root() -> Path | None: - env = os.environ.get("NSTAT_MATLAB_HELP_ROOT") - if env: - candidate = Path(env).expanduser().resolve() - if candidate.exists(): - return candidate - default = Path("/tmp/upstream-nstat/helpfiles") - if default.exists(): - return default - return None - - -def test_notebook_helpfile_mapping_covers_manifest_topics() -> None: - manifest = _load_yaml(MANIFEST_PATH) - manifest_rows = manifest.get("notebooks", []) - manifest_topics = {str(row["topic"]) for row in manifest_rows} - manifest_by_topic = {str(row["topic"]): str(row["file"]) for row in manifest_rows} - - mapping = _load_yaml(NOTEBOOK_HELP_MAP_PATH) - map_rows = mapping.get("mappings", []) - map_topics = {str(row["topic"]) for row in map_rows} - map_by_topic = {str(row["topic"]): row for row in map_rows} - - assert manifest_topics == map_topics - for topic in sorted(manifest_topics): - assert str(map_by_topic[topic]["notebook"]) == manifest_by_topic[topic] - helpfile = str(map_by_topic[topic]["matlab_helpfile"]) - assert helpfile.endswith(".m") - - -def test_notebook_helpfile_mapping_aligns_with_example_mapping() -> None: - example_map = _load_yaml(EXAMPLE_MAP_PATH) - example_topics = {str(row["matlab_topic"]) for row in example_map.get("examples", [])} - - mapping = _load_yaml(NOTEBOOK_HELP_MAP_PATH) - map_topics = {str(row["topic"]) for row in mapping.get("mappings", [])} - assert map_topics == example_topics - - -def test_notebook_helpfiles_exist_when_matlab_checkout_is_available() -> None: - matlab_help_root = _resolve_matlab_help_root() - if matlab_help_root is None: - return - - mapping = _load_yaml(NOTEBOOK_HELP_MAP_PATH) - for row in mapping.get("mappings", []): - helpfile = str(row["matlab_helpfile"]) - path = matlab_help_root / helpfile - assert path.exists(), f"Missing MATLAB helpfile: {path}" - diff --git a/tests/test_notebook_numeric_checkpoints.py b/tests/test_notebook_numeric_checkpoints.py deleted file mode 100644 index b245d15a..00000000 --- a/tests/test_notebook_numeric_checkpoints.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import nbformat -import yaml - - -MANIFEST = Path("tools/notebooks/notebook_manifest.yml") - - -def test_all_notebooks_define_numeric_checkpoints_and_validation_call() -> None: - manifest = yaml.safe_load(MANIFEST.read_text(encoding="utf-8")) - for row in manifest.get("notebooks", []): - topic = str(row["topic"]) - nb_path = Path(str(row["file"])) - nb = nbformat.read(nb_path, as_version=4) - code = "\n".join(cell.source for cell in nb.cells if cell.cell_type == "code") - - assert "CHECKPOINT_METRICS" in code, f"{topic}: missing CHECKPOINT_METRICS" - assert "CHECKPOINT_LIMITS" in code, f"{topic}: missing CHECKPOINT_LIMITS" - assert "validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC)" in code, ( - f"{topic}: missing numeric checkpoint validation call" - ) diff --git a/tests/test_notebooks.py b/tests/test_notebooks.py deleted file mode 100644 index 7ae20a64..00000000 --- a/tests/test_notebooks.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import nbformat -import yaml - - - -def test_notebook_manifest_entries_exist() -> None: - manifest = yaml.safe_load(Path("tools/notebooks/notebook_manifest.yml").read_text(encoding="utf-8")) - for row in manifest["notebooks"]: - path = Path(row["file"]) - assert path.exists(), f"missing notebook file: {path}" - - - -def test_notebook_metadata_matches_manifest() -> None: - manifest = yaml.safe_load(Path("tools/notebooks/notebook_manifest.yml").read_text(encoding="utf-8")) - for row in manifest["notebooks"]: - path = Path(row["file"]) - nb = nbformat.read(path, as_version=4) - meta = nb.metadata.get("nstat", {}) - assert meta.get("topic") == row["topic"] - assert meta.get("run_group") == row["run_group"] diff --git a/tests/test_notebooks_clean.py b/tests/test_notebooks_clean.py deleted file mode 100644 index c015de1d..00000000 --- a/tests/test_notebooks_clean.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import nbformat -import yaml - - -MANIFEST_PATH = Path("tools/notebooks/notebook_manifest.yml") -FORBIDDEN_PREFIXES = ("%", "!") - - -def _manifest_rows() -> list[dict[str, str]]: - payload = yaml.safe_load(MANIFEST_PATH.read_text(encoding="utf-8")) or {} - return [dict(row) for row in payload.get("notebooks", [])] - - -def test_notebooks_are_code_only_and_have_no_magics() -> None: - for row in _manifest_rows(): - nb_path = Path(str(row["file"])) - nb = nbformat.read(nb_path, as_version=4) - - assert nb.cells, f"{row['topic']}: notebook has no cells" - assert all(cell.cell_type == "code" for cell in nb.cells), f"{row['topic']}: notebook contains non-code cells" - - code = "\n".join(cell.source for cell in nb.cells if cell.cell_type == "code") - for line in code.splitlines(): - stripped = line.lstrip() - assert not stripped.startswith(FORBIDDEN_PREFIXES), ( - f"{row['topic']}: forbidden notebook magic/shell line: {line!r}" - ) - - assert 'matplotlib.use("Agg")' in code, f"{row['topic']}: missing Agg backend configuration" - assert "np.random.seed(" in code, f"{row['topic']}: missing deterministic NumPy seed" - diff --git a/tests/test_notebooks_execute_smoke.py b/tests/test_notebooks_execute_smoke.py deleted file mode 100644 index 5ec5f3ef..00000000 --- a/tests/test_notebooks_execute_smoke.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import annotations - -import json -import subprocess -import sys -from pathlib import Path - - -def test_execute_notebooks_smoke_subset(tmp_path: Path) -> None: - report_path = tmp_path / "notebook_execution_report.json" - cmd = [ - sys.executable, - "tools/notebooks/execute_notebooks.py", - "--group", - "smoke", - "--max-notebooks", - "2", - "--timeout", - "600", - "--out-report", - str(report_path), - ] - proc = subprocess.run(cmd, capture_output=True, text=True) - if proc.returncode != 0: - raise AssertionError( - "Notebook smoke execution failed.\n" - f"stdout:\n{proc.stdout}\n\nstderr:\n{proc.stderr}" - ) - - payload = json.loads(report_path.read_text(encoding="utf-8")) - summary = payload.get("summary", {}) - assert int(summary.get("total", 0)) == 2 - assert int(summary.get("failed", 1)) == 0 - - rows = payload.get("reports", []) - assert len(rows) == 2 - assert all(bool(row.get("executed_ok", False)) for row in rows) - diff --git a/tests/test_parity_gap_report.py b/tests/test_parity_gap_report.py deleted file mode 100644 index 78cb4988..00000000 --- a/tests/test_parity_gap_report.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -import json -from pathlib import Path - - - -def test_parity_gap_report_exists_and_has_schema() -> None: - report_path = Path("parity/parity_gap_report.json") - assert report_path.exists(), "parity/parity_gap_report.json must exist" - - payload = json.loads(report_path.read_text(encoding="utf-8")) - assert "summary" in payload - assert "issues" in payload - assert "class_coverage" in payload - assert "example_coverage" in payload - assert payload["summary"]["high"] == 0 diff --git a/tests/test_parity_manifest.py b/tests/test_parity_manifest.py deleted file mode 100644 index f4668551..00000000 --- a/tests/test_parity_manifest.py +++ /dev/null @@ -1,107 +0,0 @@ -from __future__ import annotations - -import importlib -import inspect -from pathlib import Path - -import yaml - - -def _load_yaml(path: str) -> dict: - return yaml.safe_load(Path(path).read_text(encoding="utf-8")) - - -def _resolve_object(path: str) -> object: - module_path, attr_name = path.rsplit(".", 1) - module = importlib.import_module(module_path) - return getattr(module, attr_name) - - -def _flatten_keys(payload: dict, prefix: str = "") -> set[str]: - keys: set[str] = set() - for key, value in payload.items(): - full = f"{prefix}.{key}" if prefix else str(key) - if isinstance(value, dict): - keys |= _flatten_keys(value, prefix=full) - else: - keys.add(full) - return keys - - -def _parse_expected_params(signature: str) -> list[tuple[str, str | None]]: - inside = signature.strip()[1:-1].strip() - if not inside: - return [] - out: list[tuple[str, str | None]] = [] - for token in inside.split(","): - item = token.strip() - if "=" in item: - name, default = item.split("=", 1) - out.append((name.strip(), default.strip())) - else: - out.append((item, None)) - return out - - -def _assert_signature(path: str, name: str, expected_signature: str) -> None: - cls = _resolve_object(path) - member = getattr(cls, name) - sig = inspect.signature(member) - actual_params = list(sig.parameters.values()) - if actual_params and actual_params[0].name in {"self", "cls"}: - actual_params = actual_params[1:] - - expected = _parse_expected_params(expected_signature) - assert len(actual_params) == len(expected), f"{path}.{name} parameter count mismatch" - - for actual, (exp_name, exp_default) in zip(actual_params, expected, strict=False): - assert actual.name == exp_name, f"{path}.{name} expected parameter '{exp_name}'" - if exp_default is None: - continue - assert actual.default is not inspect._empty, f"{path}.{name}.{exp_name} missing default" - assert repr(actual.default) == exp_default, ( - f"{path}.{name}.{exp_name} default mismatch: {repr(actual.default)} != {exp_default}" - ) - - -def test_parity_manifest_class_contracts() -> None: - payload = _load_yaml("baseline/parity_manifest.yml") - classes = payload["classes"] - assert len(classes) == 16 - - for row in classes: - python_class = row["python_class"] - cls = _resolve_object(python_class) - assert inspect.isclass(cls), f"{python_class} must resolve to a class" - - for method in row["public_methods"]: - name = method["name"] - signature = method["signature"] - assert hasattr(cls, name), f"{python_class} missing member '{name}'" - if signature == "property": - prop = inspect.getattr_static(cls, name) - assert isinstance(prop, property), f"{python_class}.{name} should be a property" - elif signature.startswith("attribute["): - dataclass_fields = getattr(cls, "__dataclass_fields__", {}) - assert name in dataclass_fields, f"{python_class}.{name} should be a dataclass field" - else: - _assert_signature(python_class, name, signature) - - -def test_parity_manifest_workflow_links_and_tolerances() -> None: - payload = _load_yaml("baseline/parity_manifest.yml") - behavior_path = Path(payload["metadata"]["behavior_contracts_file"]) - assert behavior_path.exists() - - workflows = payload["workflows"] - assert any(row["topic"] == "nSTATPaperExamples" for row in workflows) - - tolerances = _load_yaml("tests/parity/tolerances.yml") - tol_keys = _flatten_keys(tolerances) - - for row in workflows: - assert Path(row["notebook"]).exists() - assert Path(row["help_page"]).exists() - for metric in row["expected_metrics"]: - key = metric["tolerance_key"] - assert key in tol_keys, f"unknown tolerance key: {key}" diff --git a/tests/test_parity_matlab_gold.py b/tests/test_parity_matlab_gold.py deleted file mode 100644 index 38046438..00000000 --- a/tests/test_parity_matlab_gold.py +++ /dev/null @@ -1,547 +0,0 @@ -from __future__ import annotations - -import hashlib -from pathlib import Path - -import numpy as np -import scipy.io -import yaml - -from nstat.analysis import Analysis -from nstat.compat.matlab import History, SignalObj -from nstat.decoding import DecodingAlgorithms -from nstat.events import Events -from nstat.signal import Covariate -from nstat.spikes import SpikeTrain, SpikeTrainCollection -from nstat.trial import CovariateCollection, Trial -from tests.parity_utils import ( - assert_allclose_scaled, - assert_same_shape, - canonicalize_numeric, - loadmat_normalized, -) - - -MANIFEST = Path("tests/parity/fixtures/matlab_gold/manifest.yml") -NOTEBOOK_MANIFEST = Path("tools/notebooks/notebook_manifest.yml") - - -def _sha256(path: Path) -> str: - digest = hashlib.sha256() - with path.open("rb") as f: - for chunk in iter(lambda: f.read(8192), b""): - digest.update(chunk) - return digest.hexdigest() - - -def _load_manifest() -> dict: - return yaml.safe_load(MANIFEST.read_text(encoding="utf-8")) - - -def _mat(path: str) -> dict: - return scipy.io.loadmat(path) - - -def _vec(m: dict, key: str) -> np.ndarray: - return np.asarray(m[key], dtype=float).reshape(-1) - - -def _scalar(m: dict, key: str) -> float: - return float(_vec(m, key)[0]) - - -def test_matlab_gold_manifest_and_checksums() -> None: - payload = _load_manifest() - assert payload["version"] == 1 - assert len(payload["fixtures"]) >= 30 - - for row in payload["fixtures"]: - path = Path(row["path"]) - assert path.exists(), f"missing fixture {path}" - assert _sha256(path) == row["sha256"], f"checksum mismatch for {path}" - - -def test_matlab_gold_manifest_covers_all_notebook_topics() -> None: - payload = _load_manifest() - fixture_topics = {str(row["name"]) for row in payload["fixtures"]} - notebook_payload = yaml.safe_load(NOTEBOOK_MANIFEST.read_text(encoding="utf-8")) or {} - notebook_topics = { - str(row.get("topic", "")).strip() - for row in notebook_payload.get("notebooks", []) - if str(row.get("topic", "")).strip() - } - assert notebook_topics.issubset(fixture_topics), ( - "Missing fixture coverage for topics: " - + ", ".join(sorted(notebook_topics - fixture_topics)) - ) - - -def test_ppsimexample_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/PPSimExample_gold.mat") - X = np.asarray(m["X"], dtype=float) - y = _vec(m, "y") - dt = _scalar(m, "dt") - b = _vec(m, "b") - - fit = Analysis.fit_glm(X=X, y=y, fit_type="poisson", dt=dt) - - assert np.isclose(fit.intercept, b[0], atol=0.25) - assert np.isclose(fit.coefficients[0], b[1], atol=0.25) - - expected_rate = _vec(m, "expected_rate") - pred_rate = np.asarray(fit.predict(X), dtype=float).reshape(-1) - rel_err = np.mean(np.abs(pred_rate - expected_rate) / np.maximum(expected_rate, 1e-12)) - assert rel_err <= 0.25 - - -def test_decoding_with_hist_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/DecodingExampleWithHist_gold.mat") - spike_counts = np.asarray(m["spike_counts"], dtype=float) - tuning = np.asarray(m["tuning"], dtype=float) - transition = np.asarray(m["transition"], dtype=float) - - decoded, posterior = DecodingAlgorithms.decode_state_posterior( - spike_counts=spike_counts, - tuning_rates=tuning, - transition=transition, - ) - - expected_decoded = np.asarray(m["expected_decoded"], dtype=int).reshape(-1) - expected_posterior = np.asarray(m["expected_posterior"], dtype=float) - - assert np.array_equal(decoded, expected_decoded) - assert np.allclose(posterior, expected_posterior, atol=1e-8) - - -def test_hippocampal_placecell_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/HippocampalPlaceCellExample_gold.mat") - spike_counts = np.asarray(m["spike_counts_pc"], dtype=float) - tuning_curves = np.asarray(m["tuning_curves"], dtype=float) - - decoded = DecodingAlgorithms.decode_weighted_center( - spike_counts=spike_counts, - tuning_curves=tuning_curves, - ) - - expected = _vec(m, "expected_decoded_weighted") - assert np.allclose(decoded, expected, atol=1e-8) - - -def test_spikerate_diff_cis_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/SpikeRateDiffCIs_gold.mat") - spike_a = np.asarray(m["spike_matrix_a"], dtype=float) - spike_b = np.asarray(m["spike_matrix_b"], dtype=float) - alpha = _scalar(m, "alpha_diff") - - diff, lo, hi = DecodingAlgorithms.compute_spike_rate_diff_cis( - spike_matrix_a=spike_a, spike_matrix_b=spike_b, alpha=alpha - ) - - expected_diff = _vec(m, "expected_diff") - expected_lo = _vec(m, "expected_lo") - expected_hi = _vec(m, "expected_hi") - - assert np.allclose(diff, expected_diff, atol=1e-8) - assert np.allclose(lo, expected_lo, atol=1e-8) - assert np.allclose(hi, expected_hi, atol=1e-8) - - -def test_psthe_stimation_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/PSTHEstimation_gold.mat") - spike_matrix = np.asarray(m["spike_matrix_psth"], dtype=float) - alpha = _scalar(m, "alpha_psth") - - rate, prob_mat, sig_mat = DecodingAlgorithms.compute_spike_rate_cis( - spike_matrix=spike_matrix, - alpha=alpha, - ) - - expected_rate = _vec(m, "expected_rate_psth") - expected_prob = np.asarray(m["expected_prob_psth"], dtype=float) - expected_sig = np.asarray(m["expected_sig_psth"], dtype=int) - - assert np.allclose(rate, expected_rate, atol=1e-10) - assert np.allclose(prob_mat, expected_prob, atol=1e-10) - assert np.array_equal(sig_mat, expected_sig) - - -def test_validation_dataset_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/ValidationDataSet_gold.mat") - trial_matrix = np.asarray(m["trial_matrix_val"], dtype=float) - rate, prob_mat, sig_mat = DecodingAlgorithms.compute_spike_rate_cis(spike_matrix=trial_matrix, alpha=0.05) - - expected_rate = _vec(m, "expected_rate_val") - expected_prob = np.asarray(m["expected_prob_val"], dtype=float) - expected_sig = np.asarray(m["expected_sig_val"], dtype=int) - - assert np.allclose(rate, expected_rate, atol=1e-10) - assert np.allclose(prob_mat, expected_prob, atol=1e-10) - assert np.array_equal(sig_mat, expected_sig) - - -def test_stimulus_decode_2d_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/StimulusDecode2D_gold.mat") - spike_counts = np.asarray(m["spike_counts_sd"], dtype=float) - tuning = np.asarray(m["tuning_sd"], dtype=float) - states = np.asarray(m["states_sd"], dtype=float) - expected_center = _vec(m, "decoded_center_sd") - expected_decoded = _vec(m, "decoded_sd").astype(int) - expected_rmse = _scalar(m, "rmse_sd") - - decoded_center = DecodingAlgorithms.decode_weighted_center(spike_counts=spike_counts, tuning_curves=tuning) - decoded = np.clip(np.rint(decoded_center), 0, states.shape[0] - 1).astype(int) - xy_true = np.asarray(m["xy_true_sd"], dtype=float) - xy_decoded = states[decoded] - rmse = float(np.sqrt(np.mean(np.sum((xy_decoded - xy_true) ** 2, axis=1)))) - - assert np.allclose(decoded_center, expected_center, atol=1e-8) - assert np.array_equal(decoded, expected_decoded) - assert np.isclose(rmse, expected_rmse, atol=1e-10) - - -def test_explicit_stimulus_whisker_matlab_gold_comparison() -> None: - m = loadmat_normalized("tests/parity/fixtures/matlab_gold/ExplicitStimulusWhiskerData_gold.mat") - stimulus = canonicalize_numeric(m["stimulus_ws"], vector_shape="preserve").reshape(-1) - spike = canonicalize_numeric(m["spike_ws"], vector_shape="preserve").reshape(-1) - expected_prob = canonicalize_numeric(m["expected_prob_ws"], vector_shape="preserve").reshape(-1) - expected_rmse = float(canonicalize_numeric(m["expected_rmse_ws"], vector_shape="preserve").reshape(-1)[0]) - - fit = Analysis.fit_glm(X=stimulus[:, None], y=spike, fit_type="binomial", dt=1.0) - pred_prob = np.asarray(fit.predict(stimulus[:, None]), dtype=float).reshape(-1) - rmse = float(np.sqrt(np.mean((pred_prob - spike) ** 2))) - - assert_same_shape(pred_prob, expected_prob) - assert_allclose_scaled(pred_prob, expected_prob, rtol=1e-4, atol=5e-2, scale="maxabs") - assert_allclose_scaled(np.array([rmse]), np.array([expected_rmse]), rtol=0.0, atol=0.1, scale="maxabs") - - -def test_hybrid_filter_matlab_gold_comparison() -> None: - m = loadmat_normalized("tests/parity/fixtures/matlab_gold/HybridFilterExample_gold.mat") - time = canonicalize_numeric(m["time_hf"], vector_shape="preserve").reshape(-1) - state = canonicalize_numeric(m["state_hf"], vector_shape="preserve").reshape(-1).astype(int) - x_true = canonicalize_numeric(m["x_true_hf"]) - x_hat = canonicalize_numeric(m["x_hat_hf"]) - x_hat_nt = canonicalize_numeric(m["x_hat_nt_hf"]) - rmse_expected = float(canonicalize_numeric(m["rmse_hf"], vector_shape="preserve").reshape(-1)[0]) - rmse_nt_expected = float(canonicalize_numeric(m["rmse_nt_hf"], vector_shape="preserve").reshape(-1)[0]) - - assert_same_shape(x_true, x_hat) - assert_same_shape(x_true, x_hat_nt) - assert time.shape[0] == state.shape[0] == x_true.shape[0] - - err = np.sqrt(np.sum((x_hat[:, :2] - x_true[:, :2]) ** 2, axis=1)) - err_nt = np.sqrt(np.sum((x_hat_nt[:, :2] - x_true[:, :2]) ** 2, axis=1)) - rmse = float(np.sqrt(np.mean(err**2))) - rmse_nt = float(np.sqrt(np.mean(err_nt**2))) - - assert_allclose_scaled(np.array([rmse]), np.array([rmse_expected]), rtol=0.0, atol=1e-10, scale="maxabs") - assert_allclose_scaled(np.array([rmse_nt]), np.array([rmse_nt_expected]), rtol=0.0, atol=1e-10, scale="maxabs") - - -def test_signal_obj_examples_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat") - t = _vec(m, "time_sig") - v1 = _vec(m, "v1_sig") - v2 = _vec(m, "v2_sig") - resample_hz = _scalar(m, "resample_hz_sig") - window_t0 = _scalar(m, "window_t0_sig") - window_t1 = _scalar(m, "window_t1_sig") - expected_peak = int(round(_scalar(m, "periodogram_peak_idx_sig"))) - - s = SignalObj(time=t, data=np.column_stack([v1, v2]), name="Voltage", units="V") - s.setDataLabels(["v1", "v2"]) - s.setMask(["v1"]) - masked_cols = float(len(s.findIndFromDataMask())) - s.resetMask() - - s_resampled = s.resample(resample_hz) - s_window = s.getSigInTimeWindow(window_t0, window_t1) - _, p_per = s.periodogram() - peak_idx = int(np.argmax(p_per)) - - assert masked_cols == _scalar(m, "masked_cols_sig") - assert peak_idx == expected_peak - assert s.getNumSamples() == int(round(_scalar(m, "n_samples_sig"))) - assert s_resampled.getNumSamples() == int(round(_scalar(m, "resampled_n_samples_sig"))) - assert s_window.getNumSamples() == int(round(_scalar(m, "window_n_samples_sig"))) - - -def test_history_examples_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat") - edges = _vec(m, "bin_edges_hist") - spike_times = _vec(m, "spike_times_hist") - time_grid = _vec(m, "time_grid_hist") - expected_H = np.asarray(m["H_expected_hist"], dtype=float) - expected_filter = _vec(m, "filter_expected_hist") - - history = History(bin_edges_s=edges) - H = history.computeHistory(spike_times, time_grid) - filt = history.toFilter() - - assert_same_shape(H, expected_H) - assert_allclose_scaled(H, expected_H, rtol=0.0, atol=0.0, scale="maxabs") - assert_allclose_scaled(filt, expected_filter, rtol=0.0, atol=0.0, scale="maxabs") - assert history.getNumBins() == int(round(_scalar(m, "n_bins_hist"))) - - -def test_ppthinning_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/PPThinning_gold.mat") - candidate = _vec(m, "candidate_spikes_pt") - ratio = _vec(m, "lambda_ratio_pt") - u2 = _vec(m, "uniform_u2_pt") - expected = _vec(m, "accepted_spikes_pt") - accepted = candidate[ratio >= u2] - accept_ratio = float(accepted.size / max(candidate.size, 1)) - - assert_same_shape(accepted, expected) - assert_allclose_scaled(accepted, expected, rtol=0.0, atol=0.0, scale="maxabs") - assert_allclose_scaled( - np.array([accept_ratio]), - np.array([_scalar(m, "accept_ratio_pt")]), - rtol=0.0, - atol=0.0, - scale="maxabs", - ) - assert np.all(np.diff(accepted) >= 0.0) - - -def test_network_tutorial_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/NetworkTutorial_gold.mat") - spikes = np.asarray(m["spikes_net"], dtype=float) - dt = _scalar(m, "dt_net") - expected_xc = np.asarray(m["xc_net"], dtype=float) - expected_rates = _vec(m, "rates_net") - - def lag1(a: np.ndarray, b: np.ndarray) -> float: - aa = a[:-1] - np.mean(a[:-1]) - bb = b[1:] - np.mean(b[1:]) - denom = np.linalg.norm(aa) * np.linalg.norm(bb) - return float(np.dot(aa, bb) / denom) if denom > 0 else 0.0 - - xc = np.array([[0.0, lag1(spikes[0], spikes[1])], [lag1(spikes[1], spikes[0]), 0.0]], dtype=float) - rates = spikes.mean(axis=1) / dt - - expected_shape = tuple(np.asarray(m["shape_net"], dtype=int).reshape(-1).tolist()) - assert spikes.shape == expected_shape - assert_allclose_scaled(xc, expected_xc, rtol=0.0, atol=1e-12, scale="maxabs") - assert_allclose_scaled(rates, expected_rates, rtol=0.0, atol=1e-12, scale="maxabs") - - -def test_nstcoll_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/nstCollExamples_gold.mat") - st1_times = _vec(m, "spike_times_1") - st2_times = _vec(m, "spike_times_2") - t_start = _scalar(m, "t_start_coll") - t_end = _scalar(m, "t_end_coll") - bin_size = _scalar(m, "bin_size_coll") - - st1 = SpikeTrain(spike_times=st1_times, t_start=t_start, t_end=t_end, name="u1") - st2 = SpikeTrain(spike_times=st2_times, t_start=t_start, t_end=t_end, name="u2") - coll = SpikeTrainCollection([st1, st2]) - - centers_count, count_mat = coll.to_binned_matrix(bin_size_s=bin_size, mode="count") - centers_binary, binary_mat = coll.to_binned_matrix(bin_size_s=bin_size, mode="binary") - - assert np.allclose(centers_count, _vec(m, "expected_centers"), atol=1e-12) - assert np.allclose(centers_binary, _vec(m, "expected_centers"), atol=1e-12) - assert np.allclose(count_mat, np.asarray(m["expected_count_matrix"], dtype=float), atol=1e-12) - assert np.array_equal(binary_mat, np.asarray(m["expected_binary_matrix"], dtype=float)) - - assert np.isclose(coll.get_first_spike_time(), _scalar(m, "expected_first_spike"), atol=1e-12) - assert np.isclose(coll.get_last_spike_time(), _scalar(m, "expected_last_spike"), atol=1e-12) - - merged = coll.to_spike_train(name="merged").spike_times - assert np.allclose(merged, _vec(m, "expected_merged_spikes"), atol=1e-12) - - -def test_covcoll_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/CovCollExamples_gold.mat") - time = _vec(m, "time_cov") - cov_stim = _vec(m, "cov_stim") - cov_ctx = np.asarray(m["cov_ctx"], dtype=float) - - stim = Covariate(time=time, data=cov_stim, name="stim", labels=["stim"]) - ctx = Covariate(time=time, data=cov_ctx, name="ctx", labels=["cosine", "ramp"]) - coll = CovariateCollection([stim, ctx]) - - design, labels = coll.design_matrix() - assert labels == ["stim", "cosine", "ramp"] - assert np.allclose(design, np.asarray(m["expected_design_cov"], dtype=float), atol=1e-12) - - ctx_only, ctx_labels = coll.data_to_matrix_from_names(["ctx"]) - assert ctx_labels == ["cosine", "ramp"] - assert np.allclose(ctx_only, np.asarray(m["expected_ctx_only"], dtype=float), atol=1e-12) - - stim_only, stim_labels = coll.data_to_matrix_from_sel([0]) - assert stim_labels == ["stim"] - assert np.allclose(stim_only.reshape(-1), _vec(m, "expected_stim_only"), atol=1e-12) - - -def test_trial_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/TrialExamples_gold.mat") - time = _vec(m, "time_cov") - cov_stim = _vec(m, "cov_stim") - cov_ctx = np.asarray(m["cov_ctx"], dtype=float) - spike_times = _vec(m, "spike_times_trial") - bin_size = _scalar(m, "bin_size_trial") - - stim = Covariate(time=time, data=cov_stim, name="stim", labels=["stim"]) - ctx = Covariate(time=time, data=cov_ctx, name="ctx", labels=["cosine", "ramp"]) - cov_coll = CovariateCollection([stim, ctx]) - - st = SpikeTrain(spike_times=spike_times, t_start=0.0, t_end=1.0, name="u1") - trial = Trial(spikes=SpikeTrainCollection([st]), covariates=cov_coll) - - t_bins, y, X = trial.aligned_binned_observation( - bin_size_s=bin_size, - unit_index=0, - mode="count", - ) - - assert np.allclose(t_bins, _vec(m, "expected_t_bins_trial"), atol=1e-12) - assert np.allclose(y.reshape(-1), _vec(m, "expected_y_trial"), atol=1e-12) - assert np.allclose(X, np.asarray(m["expected_X_trial"], dtype=float), atol=1e-12) - - -def test_events_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/EventsExamples_gold.mat") - times = _vec(m, "event_times") - subset_start = _scalar(m, "subset_start") - subset_end = _scalar(m, "subset_end") - - events = Events(times=times, labels=["E1", "E2", "E3"]) - subset = events.subset(subset_start, subset_end) - - assert np.allclose(events.times, times, atol=1e-12) - assert np.allclose(subset.times, _vec(m, "expected_subset_times"), atol=1e-12) - - -def test_analysis_examples_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/AnalysisExamples_gold.mat") - X = np.asarray(m["X_analysis"], dtype=float) - y = _vec(m, "counts_analysis") - dt = _scalar(m, "dt_analysis") - b = _vec(m, "b_analysis") - - fit = Analysis.fit_glm(X=X, y=y, fit_type="poisson", dt=dt) - pred = np.asarray(fit.predict(X), dtype=float).reshape(-1) - - assert np.isclose(fit.intercept, b[0], atol=0.35) - assert np.allclose(fit.coefficients, b[1:], atol=0.35) - assert np.allclose(pred, _vec(m, "expected_rate_analysis"), atol=0.35) - - rmse = float(np.sqrt(np.mean((pred - _vec(m, "true_rate_analysis")) ** 2))) - assert np.isclose(rmse, _scalar(m, "expected_rmse_analysis"), atol=0.25) - - -def test_nstatpaperexamples_plot_arrays_matlab_gold_comparison() -> None: - combo = _mat("tests/parity/fixtures/matlab_gold/nSTATPaperExamples_plot_gold.mat") - - # Stimulus-rate plot arrays (PPSim section). - ppsim = _mat("tests/parity/fixtures/matlab_gold/PPSimExample_gold.mat") - X = np.asarray(ppsim["X"], dtype=float) - y = _vec(ppsim, "y") - dt = _scalar(ppsim, "dt") - fit = Analysis.fit_glm(X=X, y=y, fit_type="poisson", dt=dt) - pred_rate = np.asarray(fit.predict(X), dtype=float).reshape(-1) - expected_rate = np.asarray(combo["expected_rate_pp"], dtype=float).reshape(-1) - rel_err = np.mean(np.abs(pred_rate - expected_rate) / np.maximum(expected_rate, 1e-12)) - assert rel_err <= 0.25 - - # Decode-with-history plot arrays. - dec = _mat("tests/parity/fixtures/matlab_gold/DecodingExampleWithHist_gold.mat") - decoded, posterior = DecodingAlgorithms.decode_state_posterior( - spike_counts=np.asarray(dec["spike_counts"], dtype=float), - tuning_rates=np.asarray(dec["tuning"], dtype=float), - transition=np.asarray(dec["transition"], dtype=float), - ) - expected_decoded = np.asarray(combo["expected_decoded_hist"], dtype=int).reshape(-1) - expected_post = np.asarray(combo["expected_posterior_hist"], dtype=float) - assert np.array_equal(decoded, expected_decoded) - assert np.allclose(posterior, expected_post, atol=1e-8) - - # Place-cell weighted decode arrays. - place = _mat("tests/parity/fixtures/matlab_gold/HippocampalPlaceCellExample_gold.mat") - decoded_weighted = DecodingAlgorithms.decode_weighted_center( - spike_counts=np.asarray(place["spike_counts_pc"], dtype=float), - tuning_curves=np.asarray(place["tuning_curves"], dtype=float), - ) - expected_weighted = np.asarray(combo["expected_weighted_decode"], dtype=float).reshape(-1) - assert np.allclose(decoded_weighted, expected_weighted, atol=1e-8) - - # PSTH significance-matrix arrays. - psth = _mat("tests/parity/fixtures/matlab_gold/PSTHEstimation_gold.mat") - rate, prob, sig = DecodingAlgorithms.compute_spike_rate_cis( - spike_matrix=np.asarray(psth["spike_matrix_psth"], dtype=float), - alpha=_scalar(psth, "alpha_psth"), - ) - assert np.allclose(rate, np.asarray(combo["expected_psth_rate"], dtype=float).reshape(-1), atol=1e-10) - assert np.allclose(prob, np.asarray(combo["expected_psth_prob"], dtype=float), atol=1e-10) - assert np.array_equal(sig, np.asarray(combo["expected_psth_sig"], dtype=int)) - - # mEPSC trace arrays used for data-plot panels. - trace = np.asarray(combo["trace_mepsc"], dtype=float).reshape(-1) - time = np.asarray(combo["time_mepsc"], dtype=float).reshape(-1) - event_times = np.asarray(combo["event_times_mepsc"], dtype=float).reshape(-1) - assert trace.size == time.size - assert trace.size > 1000 - assert event_times.size >= 40 - assert np.all(np.diff(time) > 0.0) - - -def test_decoding_example_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/DecodingExample_gold.mat") - spike_counts = np.asarray(m["spike_counts_dec"], dtype=float) - tuning = np.asarray(m["tuning_dec"], dtype=float) - transition = np.asarray(m["transition_dec"], dtype=float) - - decoded, posterior = DecodingAlgorithms.decode_state_posterior( - spike_counts=spike_counts, - tuning_rates=tuning, - transition=transition, - ) - - expected_decoded = np.asarray(m["expected_decoded_dec"], dtype=int).reshape(-1) - expected_posterior = np.asarray(m["expected_posterior_dec"], dtype=float) - expected_rmse = _scalar(m, "expected_rmse_dec") - latent = _vec(m, "latent_zero_dec").astype(int) - - rmse = float(np.sqrt(np.mean((decoded - latent) ** 2)) / max(tuning.shape[1] - 1, 1)) - assert np.array_equal(decoded, expected_decoded) - assert np.allclose(posterior, expected_posterior, atol=1e-8) - assert np.isclose(rmse, expected_rmse, atol=1e-8) - - -def _detect_mepsc_events(trace: np.ndarray, dt: float) -> tuple[np.ndarray, np.ndarray]: - threshold = -0.12 - refractory = int(round(0.006 / dt)) - candidate = np.where(trace < threshold)[0] - detected_idx: list[int] = [] - last = -refractory - for idx in candidate: - if idx - last >= refractory: - window_end = min(idx + int(round(0.004 / dt)) + 1, trace.size) - local = idx + int(np.argmin(trace[idx:window_end])) - detected_idx.append(local) - last = local - det = np.asarray(detected_idx, dtype=int) - return det * dt, -trace[det] - - -def test_mepsc_analysis_matlab_gold_comparison() -> None: - m = _mat("tests/parity/fixtures/matlab_gold/mEPSCAnalysis_gold.mat") - dt = _scalar(m, "dt_mepsc") - trace = _vec(m, "trace_mepsc") - exp_times = _vec(m, "detected_times_mepsc") - exp_amps = _vec(m, "detected_amps_mepsc") - exp_count = int(round(_scalar(m, "expected_event_count_mepsc"))) - exp_mean_amp = _scalar(m, "expected_mean_amp_mepsc") - - det_times, det_amps = _detect_mepsc_events(trace, dt) - events = Events(times=det_times, labels=[f"e{i}" for i in range(det_times.size)]) - - assert det_times.size == exp_count - assert np.allclose(det_times, exp_times, atol=dt) - assert np.allclose(det_amps, exp_amps, atol=1e-9) - assert np.isclose(float(np.mean(det_amps)), exp_mean_amp, atol=1e-9) - assert events.times.size == exp_count diff --git a/tests/test_parity_numerics.py b/tests/test_parity_numerics.py deleted file mode 100644 index 6cf6e4ba..00000000 --- a/tests/test_parity_numerics.py +++ /dev/null @@ -1,124 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import numpy as np -import yaml -from scipy.special import expit - -from nstat.analysis import Analysis -from nstat.decoding import DecodingAlgorithms - - -def _tol(path: str) -> float: - payload = yaml.safe_load(Path("tests/parity/tolerances.yml").read_text(encoding="utf-8")) - value: object = payload - for key in path.split("."): - value = value[key] - return float(value) - - -def test_poisson_glm_parameter_recovery() -> None: - rng = np.random.default_rng(42) - n_samples = 4000 - dt = 0.01 - - x = rng.normal(size=n_samples) - x = (x - np.mean(x)) / np.std(x) - X = x[:, None] - - true_intercept = np.log(12.0) - true_beta = np.array([0.35]) - lam = np.exp(true_intercept + X @ true_beta) - y = rng.poisson(lam * dt).astype(float) - - fit = Analysis.fit_glm(X=X, y=y, fit_type="poisson", dt=dt) - coeff_tol = _tol("poisson_glm.coefficient_abs_tol") - assert abs(float(fit.coefficients[0]) - float(true_beta[0])) <= coeff_tol - - pred_rate = fit.predict(X) - true_rate = lam - rel_err = np.mean(np.abs(pred_rate - true_rate) / np.maximum(true_rate, 1e-9)) - assert rel_err <= _tol("poisson_glm.rate_rel_tol") - - -def test_binomial_glm_parameter_recovery() -> None: - rng = np.random.default_rng(24) - n_samples = 3500 - - x = rng.normal(size=n_samples) - x = (x - np.mean(x)) / np.std(x) - X = x[:, None] - - true_intercept = -1.9 - true_beta = np.array([1.1]) - p = expit(true_intercept + X @ true_beta) - y = rng.binomial(1, p).astype(float) - - fit = Analysis.fit_glm(X=X, y=y, fit_type="binomial") - coeff_tol = _tol("binomial_glm.coefficient_abs_tol") - assert abs(float(fit.coefficients[0]) - float(true_beta[0])) <= coeff_tol - - pred_p = fit.predict(X) - mae = np.mean(np.abs(pred_p - p)) - assert mae <= _tol("binomial_glm.probability_abs_tol") - - -def test_decode_state_posterior_random_walk() -> None: - rng = np.random.default_rng(7) - n_units = 20 - n_states = 25 - n_time = 250 - - centers = np.linspace(0.0, n_states - 1, n_units) - widths = np.full(n_units, 2.5) - states = np.arange(n_states)[None, :] - tuning = 0.05 + 0.40 * np.exp(-0.5 * ((states - centers[:, None]) / widths[:, None]) ** 2) - - transition = np.zeros((n_states, n_states), dtype=float) - for i in range(n_states): - for j, w in [(i - 1, 0.15), (i, 0.70), (i + 1, 0.15)]: - if 0 <= j < n_states: - transition[i, j] += w - transition[i, :] /= np.sum(transition[i, :]) - - latent = np.zeros(n_time, dtype=int) - latent[0] = n_states // 2 - for t in range(1, n_time): - latent[t] = rng.choice(n_states, p=transition[latent[t - 1]]) - - spike_counts = np.zeros((n_units, n_time), dtype=float) - for t in range(n_time): - spike_counts[:, t] = rng.poisson(tuning[:, latent[t]]) - - decoded, posterior = DecodingAlgorithms.decode_state_posterior( - spike_counts=spike_counts, - tuning_rates=tuning, - transition=transition, - ) - - assert posterior.shape == (n_states, n_time) - assert np.allclose(np.sum(posterior, axis=0), 1.0, atol=1e-6) - - rmse = np.sqrt(np.mean((decoded - latent) ** 2)) - nrmse = rmse / float(max(n_states - 1, 1)) - assert nrmse <= _tol("decoding.normalized_rmse_tol") - - -def test_compute_spike_rate_cis_detects_large_trial_shift() -> None: - rng = np.random.default_rng(77) - n_bins = 600 - n_trials = 12 - low = rng.binomial(1, 0.03, size=(n_trials // 2, n_bins)) - high = rng.binomial(1, 0.10, size=(n_trials // 2, n_bins)) - matrix = np.vstack([low, high]).astype(float) - - _, _, sig = DecodingAlgorithms.compute_spike_rate_cis(matrix, alpha=0.05) - - low_idx = range(0, n_trials // 2) - high_idx = range(n_trials // 2, n_trials) - - between = [sig[i, j] for i in low_idx for j in high_idx] - between_rate = float(np.mean(between)) - required = 1.0 - _tol("decoding.ci_coverage_tol") - assert between_rate >= required diff --git a/tests/test_parity_reference_fixtures.py b/tests/test_parity_reference_fixtures.py deleted file mode 100644 index c1d846b9..00000000 --- a/tests/test_parity_reference_fixtures.py +++ /dev/null @@ -1,216 +0,0 @@ -from __future__ import annotations - -import hashlib -from pathlib import Path - -import numpy as np -import yaml - -from nstat.analysis import Analysis -from nstat.compat.matlab import ConfidenceInterval as MatlabConfidenceInterval -from nstat.compat.matlab import FitResult as MatlabFitResult -from nstat.compat.matlab import FitResSummary as MatlabFitResSummary -from nstat.decoding import DecodingAlgorithms -from nstat.fit import FitResult -from nstat.fit import FitSummary -from nstat.signal import Covariate -from nstat.spikes import SpikeTrain, SpikeTrainCollection -from nstat.trial import CovariateCollection, Trial - - -FIXTURE_MANIFEST = Path("tests/parity/fixtures/manifest.yml") -REPO_ROOT = Path(__file__).resolve().parents[1] - - - -def _sha256(path: Path) -> str: - digest = hashlib.sha256() - with path.open("rb") as f: - for chunk in iter(lambda: f.read(8192), b""): - digest.update(chunk) - return digest.hexdigest() - - - -def _load_manifest() -> dict: - return yaml.safe_load(FIXTURE_MANIFEST.read_text(encoding="utf-8")) - - - -def test_fixture_manifest_present() -> None: - assert FIXTURE_MANIFEST.exists() - payload = _load_manifest() - assert payload["version"] == 1 - assert len(payload["fixtures"]) >= 3 - - - -def test_fixture_checksums_match_manifest() -> None: - payload = _load_manifest() - for row in payload["fixtures"]: - path = (REPO_ROOT / Path(row["path"])).resolve() - assert path.exists(), f"missing fixture file: {path}" - assert _sha256(path) == row["sha256"], f"checksum mismatch for {path}" - - - -def test_fixture_manifest_paths_are_repo_relative() -> None: - payload = _load_manifest() - for row in payload["fixtures"]: - path_text = str(row["path"]) - path = Path(path_text) - assert not path.is_absolute(), f"fixture path must be relative: {path_text}" - assert not path_text.startswith(".."), f"fixture path cannot escape repo root: {path_text}" - - - -def test_analysis_poisson_fixture_regression() -> None: - fixture = np.load("tests/parity/fixtures/analysis_poisson_glm.npz") - X = fixture["X"] - y = fixture["y"] - dt = float(fixture["dt"][0]) - - fit = Analysis.fit_glm(X=X, y=y, fit_type="poisson", dt=dt) - - assert np.allclose(fit.coefficients, fixture["expected_coefficients"], atol=1e-10) - assert np.isclose(fit.intercept, float(fixture["expected_intercept"][0]), atol=1e-10) - assert np.isclose(fit.log_likelihood, float(fixture["expected_log_likelihood"][0]), atol=1e-8) - assert np.allclose(fit.predict(X), fixture["expected_rate"], atol=1e-10) - - - -def test_decoding_fixture_regression() -> None: - fixture = np.load("tests/parity/fixtures/decoding_state_posterior.npz") - decoded, posterior = DecodingAlgorithms.decode_state_posterior( - spike_counts=fixture["spike_counts"], - tuning_rates=fixture["tuning_rates"], - transition=fixture["transition"], - ) - - assert np.array_equal(decoded, fixture["expected_decoded"]) - assert np.allclose(posterior, fixture["expected_posterior"], atol=1e-10) - - - -def test_trial_alignment_fixture_regression() -> None: - fixture = np.load("tests/parity/fixtures/trial_alignment.npz") - time = fixture["time"] - cov_data = fixture["cov_data"] - spike_times = fixture["spike_times"] - bin_size = float(fixture["bin_size"][0]) - - trial = Trial( - spikes=SpikeTrainCollection([SpikeTrain(spike_times=spike_times, t_start=0.0, t_end=1.0)]), - covariates=CovariateCollection([ - Covariate(time=time, data=cov_data, name="stim", labels=["stim"]), - ]), - ) - - tb, y, X = trial.aligned_binned_observation(bin_size_s=bin_size, unit_index=0, mode="count") - assert np.allclose(tb, fixture["expected_time_bins"], atol=1e-12) - assert np.array_equal(y, fixture["expected_counts"]) - assert np.allclose(X, fixture["expected_design"], atol=1e-12) - - -def test_fit_summary_structure_fixture_regression() -> None: - fixture = np.load("tests/parity/fixtures/fit_summary_structure.npz") - - structures = [] - for i in range(fixture["result_coefficients"].shape[0]): - structures.append( - { - "coefficients": fixture["result_coefficients"][i], - "intercept": float(fixture["result_intercepts"][i]), - "fit_type": str(fixture["result_fit_types"][i]), - "log_likelihood": float(fixture["result_log_likelihoods"][i]), - "n_samples": int(fixture["result_n_samples"][i]), - "n_parameters": int(fixture["result_n_parameters"][i]), - "parameter_labels": [str(v) for v in fixture["result_labels"][i]], - } - ) - payload = {"results": structures} - - native = FitSummary.from_structure(payload) - coeff_mat, labels, se_mat = native.get_coeffs() - hist_counts, hist_edges, hist_percent_sig = native.bin_coeffs(min_val=-1.0, max_val=1.0, bin_size=0.2) - - assert np.array_equal(np.array(labels, dtype=" None: - fixture = np.load("tests/parity/fixtures/fit_result_roundtrip.npz") - - payload = { - "coefficients": fixture["coefficients"], - "intercept": float(fixture["intercept"][0]), - "fit_type": str(fixture["fit_type"][0]), - "log_likelihood": float(fixture["log_likelihood"][0]), - "n_samples": int(fixture["n_samples"][0]), - "n_parameters": int(fixture["n_parameters"][0]), - "parameter_labels": [str(v) for v in fixture["parameter_labels"]], - "ks_stats": { - "ks_stat": fixture["ks_stat"], - "pValue": fixture["p_value"], - "withinConfInt": fixture["within_conf_int"], - }, - "fit_residual": fixture["fit_residual"], - "inv_gaus_stats": {"z": fixture["inv_gaus_z"]}, - "neuron_name": str(fixture["neuron_name"][0]), - } - - native = FitResult.from_structure(payload) - plot = native.get_plot_params() - assert np.isclose(native.aic(), float(fixture["expected_aic"][0]), atol=1e-12) - assert np.isclose(native.bic(), float(fixture["expected_bic"][0]), atol=1e-12) - assert np.allclose(plot["bAct"], fixture["expected_plot_bact"], atol=1e-12) - assert np.allclose(plot["seAct"], fixture["expected_plot_seact"], atol=1e-12) - assert np.allclose(plot["sigIndex"], fixture["expected_plot_sigindex"], atol=1e-12) - assert np.array_equal(np.array(plot["xLabels"], dtype=" None: - fixture = np.load("tests/parity/fixtures/confidence_interval_compat.npz") - ci = MatlabConfidenceInterval( - time=fixture["time"], - lower=fixture["lower"], - upper=fixture["upper"], - level=0.95, - ) - ci.setColor("red").setValue(fixture["values"]) - - assert np.allclose(ci.getWidth(), fixture["expected_width"], atol=1e-12) - assert np.array_equal(ci.contains(fixture["values"]), fixture["expected_contains"]) - - structure = ci.toStructure() - assert np.allclose(structure["lower"], fixture["expected_structure_lower"], atol=1e-12) - assert np.allclose(structure["upper"], fixture["expected_structure_upper"], atol=1e-12) - - restored = MatlabConfidenceInterval.fromStructure(structure) - assert np.allclose(restored.lower, fixture["expected_restored_lower"], atol=1e-12) - assert np.allclose(restored.upper, fixture["expected_restored_upper"], atol=1e-12) - assert np.isclose(restored.level, float(fixture["expected_restored_level"][0]), atol=1e-12) diff --git a/tests/test_parity_utils.py b/tests/test_parity_utils.py deleted file mode 100644 index 80a0da5d..00000000 --- a/tests/test_parity_utils.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import numpy as np -import scipy.io - -from tests.parity_utils import ( - assert_allclose_scaled, - assert_event_times_close, - assert_matching_nan_inf_locations, - assert_same_shape, - canonicalize_numeric, - loadmat_normalized, - matlab_rng_command, - set_deterministic_seeds, -) - - -def test_set_deterministic_seeds_reproducible() -> None: - g1 = set_deterministic_seeds(1234) - a1 = g1.normal(size=8) - g2 = set_deterministic_seeds(1234) - a2 = g2.normal(size=8) - assert np.array_equal(a1, a2) - assert matlab_rng_command(1234) == "rng(1234, 'twister');" - - -def test_loadmat_normalized_converts_structs_and_cells(tmp_path: Path) -> None: - matlab_struct = {"field_a": np.array([1.0, 2.0]), "field_b": np.array([[3.0]])} - cell_like = np.empty((1, 2), dtype=object) - cell_like[0, 0] = np.array([4.0, 5.0]) - cell_like[0, 1] = "x" - path = tmp_path / "fixture.mat" - scipy.io.savemat(path, {"S": matlab_struct, "C": cell_like}) - - payload = loadmat_normalized(path) - assert "S" in payload and "C" in payload - assert isinstance(payload["S"], dict) - assert payload["S"]["field_a"].shape == (1, 2) - assert isinstance(payload["C"], list) - - -def test_canonicalize_and_shape_helpers() -> None: - v = np.array([1.0, 2.0, 3.0], dtype=np.float32) - col = canonicalize_numeric(v, vector_shape="column") - row = canonicalize_numeric(v, vector_shape="row") - assert col.dtype == np.float64 - assert col.shape == (3, 1) - assert row.shape == (1, 3) - assert_same_shape(col, np.zeros((3, 1))) - - -def test_nan_inf_and_scaled_allclose_helpers() -> None: - expected = np.array([1.0, np.nan, np.inf, -np.inf, 5.0]) - actual = np.array([1.0 + 1e-10, np.nan, np.inf, -np.inf, 5.0 + 1e-10]) - assert_matching_nan_inf_locations(actual, expected) - assert_allclose_scaled(actual, expected, rtol=1e-7, atol=1e-9, scale="maxabs") - - -def test_event_time_helper_sorts_and_compares() -> None: - a = np.array([0.3000000001, 0.1, 0.2]) - b = np.array([0.1, 0.2, 0.3]) - assert_event_times_close(a, b, atol=1e-8, sort_values=True) diff --git a/tests/test_performance_reports.py b/tests/test_performance_reports.py deleted file mode 100644 index 0d3211e9..00000000 --- a/tests/test_performance_reports.py +++ /dev/null @@ -1,135 +0,0 @@ -from __future__ import annotations - -import json -import subprocess -from pathlib import Path - - -def _load(path: Path) -> dict: - return json.loads(path.read_text(encoding="utf-8")) - - -LINUX_BASELINE_DATED = Path("tests/performance/fixtures/python/performance_baseline_linux_20260304.json") -LINUX_BASELINE = Path("tests/performance/fixtures/python/performance_baseline_linux_latest.json") - - -def test_linux_latest_baseline_matches_dated_snapshot() -> None: - latest = _load(LINUX_BASELINE) - dated = _load(LINUX_BASELINE_DATED) - assert latest == dated - - -def test_performance_fixture_coverage() -> None: - matlab = _load(Path("tests/performance/fixtures/matlab/performance_baseline_470fde8.json")) - python = _load(LINUX_BASELINE) - - matlab_pairs = {(row["case"], row["tier"]) for row in matlab["cases"]} - python_pairs = {(row["case"], row["tier"]) for row in python["cases"]} - assert matlab_pairs.issubset(python_pairs) - assert len(matlab_pairs) == 15 - assert len(python_pairs) >= len(matlab_pairs) - - -def test_performance_comparator_runs(tmp_path: Path) -> None: - out_json = tmp_path / "perf_report.json" - out_csv = tmp_path / "perf_report.csv" - cmd = [ - "python", - "tools/performance/compare_matlab_python_performance.py", - "--python-report", - str(LINUX_BASELINE), - "--matlab-report", - "tests/performance/fixtures/matlab/performance_baseline_470fde8.json", - "--policy", - "parity/performance_gate_policy.yml", - "--previous-python-report", - str(LINUX_BASELINE), - "--report-out", - str(out_json), - "--csv-out", - str(out_csv), - "--fail-on-regression", - "--require-regression-env-match", - ] - subprocess.run(cmd, check=True) - - report = _load(out_json) - assert report["counts"]["total_case_tiers"] >= 15 - assert report["counts"]["regression_failures"] == 0 - assert len(report["top_python_vs_matlab_gaps"]) <= 5 - - -def test_performance_comparator_skips_regression_on_env_mismatch(tmp_path: Path) -> None: - python_report = _load(LINUX_BASELINE) - previous_report = _load(LINUX_BASELINE) - - # Force a would-be regression while also making previous env non-comparable. - python_report["cases"][0]["median_runtime_ms"] = float(python_report["cases"][0]["median_runtime_ms"]) * 5.0 - previous_report["environment"]["platform"] = "Linux-test-x86_64" - previous_report["environment"]["python"] = "3.11.9" - - python_path = tmp_path / "python_report.json" - previous_path = tmp_path / "previous_report.json" - python_path.write_text(json.dumps(python_report), encoding="utf-8") - previous_path.write_text(json.dumps(previous_report), encoding="utf-8") - - out_json = tmp_path / "perf_report_env_mismatch.json" - out_csv = tmp_path / "perf_report_env_mismatch.csv" - cmd = [ - "python", - "tools/performance/compare_matlab_python_performance.py", - "--python-report", - str(python_path), - "--matlab-report", - "tests/performance/fixtures/matlab/performance_baseline_470fde8.json", - "--policy", - "parity/performance_gate_policy.yml", - "--previous-python-report", - str(previous_path), - "--report-out", - str(out_json), - "--csv-out", - str(out_csv), - "--fail-on-regression", - ] - subprocess.run(cmd, check=True) - - report = _load(out_json) - assert report["policy"]["regression_env_compatible"] is False - assert report["counts"]["regression_failures"] == 0 - - -def test_performance_comparator_can_require_env_match(tmp_path: Path) -> None: - python_report = _load(LINUX_BASELINE) - previous_report = _load(LINUX_BASELINE) - - previous_report["environment"]["platform"] = "Linux-test-x86_64" - previous_report["environment"]["python"] = "3.11.9" - - python_path = tmp_path / "python_report.json" - previous_path = tmp_path / "previous_report.json" - python_path.write_text(json.dumps(python_report), encoding="utf-8") - previous_path.write_text(json.dumps(previous_report), encoding="utf-8") - - out_json = tmp_path / "perf_report_env_required.json" - out_csv = tmp_path / "perf_report_env_required.csv" - cmd = [ - "python", - "tools/performance/compare_matlab_python_performance.py", - "--python-report", - str(python_path), - "--matlab-report", - "tests/performance/fixtures/matlab/performance_baseline_470fde8.json", - "--policy", - "parity/performance_gate_policy.yml", - "--previous-python-report", - str(previous_path), - "--report-out", - str(out_json), - "--csv-out", - str(out_csv), - "--fail-on-regression", - "--require-regression-env-match", - ] - proc = subprocess.run(cmd, check=False) - assert proc.returncode != 0 diff --git a/tests/test_readme_examples_catalog.py b/tests/test_readme_examples_catalog.py new file mode 100644 index 00000000..432e837c --- /dev/null +++ b/tests/test_readme_examples_catalog.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +import re +from pathlib import Path + +import yaml + + +REPO_ROOT = Path(__file__).resolve().parents[1] +README_PATH = REPO_ROOT / "README.md" +CATALOG_PATH = REPO_ROOT / "examples" / "nSTATPaperExamples" / "manifest.yml" + + +FEATURED_HEADINGS = [ + "### Example 1 — Single sinusoid: signal + multitaper spectrum + spectrogram", + "### Example 2 — Time-varying CIF over 10 seconds (single-frequency sinusoid)", + "### Example 3 — Spike train collection raster from Example 2", +] + +FEATURED_RUN_COMMANDS = [ + "python examples/readme_examples/example1_multitaper_and_spectrogram.py", + "python examples/readme_examples/example2_simulate_cif_spiketrain_10s.py", + "python examples/readme_examples/example3_nstcoll_raster_from_example2.py", +] + + +def _extract_examples_block(text: str) -> str: + match = re.search(r"## Examples\n(.*?)\n## Documentation\n", text, flags=re.S) + if not match: + raise AssertionError("README is missing an Examples block bounded by '## Examples' and '## Documentation'.") + return match.group(1) + + +def test_readme_featured_examples_are_preserved_in_order() -> None: + readme = README_PATH.read_text(encoding="utf-8") + block = _extract_examples_block(readme) + + heading_positions = [] + for heading in FEATURED_HEADINGS: + pos = block.find(heading) + assert pos >= 0, f"Missing featured heading: {heading}" + heading_positions.append(pos) + assert heading_positions == sorted(heading_positions), "Featured examples must remain in the original order." + + for cmd in FEATURED_RUN_COMMANDS: + assert cmd in block, f"Missing featured run command: {cmd}" + + +def test_readme_includes_complete_nstatpaperexamples_catalog_once() -> None: + readme = README_PATH.read_text(encoding="utf-8") + block = _extract_examples_block(readme) + assert "### nSTATPaperExamples" in block, "README Examples section is missing the nSTATPaperExamples catalog header." + + manifest = yaml.safe_load(CATALOG_PATH.read_text(encoding="utf-8")) or {} + entries = manifest.get("examples", []) + assert entries, "nSTATPaperExamples manifest has no entries." + + for row in entries: + name = str(row["name"]) + rel_path = str(row["relative_path"]) + link = f"[{name}]({rel_path})" + count = block.count(link) + assert count == 1, f"Catalog entry must appear exactly once in README: {link} (found {count})." + + +def test_readme_examples_section_has_no_other_example_groups() -> None: + readme = README_PATH.read_text(encoding="utf-8") + block = _extract_examples_block(readme) + + headings = re.findall(r"^###\s+.+$", block, flags=re.M) + expected = FEATURED_HEADINGS + ["### nSTATPaperExamples"] + assert headings == expected, ( + "README Examples section must contain only the three featured examples " + "followed by the nSTATPaperExamples catalog header." + ) diff --git a/tests/test_signal.py b/tests/test_signal.py deleted file mode 100644 index c74487a1..00000000 --- a/tests/test_signal.py +++ /dev/null @@ -1,19 +0,0 @@ -import numpy as np - -from nstat.signal import Covariate, Signal - - -def test_signal_shape_and_rate() -> None: - t = np.linspace(0.0, 1.0, 101) - s = Signal(time=t, data=np.sin(2 * np.pi * t), name="sig") - assert s.n_samples == 101 - assert s.n_channels == 1 - assert 99.0 < s.sample_rate_hz < 101.0 - - -def test_covariate_labels() -> None: - t = np.linspace(0.0, 1.0, 21) - x = np.column_stack([t, t**2]) - c = Covariate(time=t, data=x, name="poly", labels=["x", "x2"]) - assert c.n_channels == 2 - assert c.labels == ["x", "x2"] diff --git a/tests/test_signal_covariate_tier2.py b/tests/test_signal_covariate_tier2.py deleted file mode 100644 index 9a5c9b4d..00000000 --- a/tests/test_signal_covariate_tier2.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import annotations - -import numpy as np - -from nstat.signal import Covariate, Signal - - - -def test_signal_tier2_methods() -> None: - t = np.linspace(0.0, 1.0, 101) - y = np.column_stack([np.sin(2 * np.pi * t), np.cos(2 * np.pi * t)]) - sig = Signal(time=t, data=y, name="sig") - - merged = sig.merge(sig) - assert merged.n_channels == 4 - - ds = sig.derivative() - integ = sig.integral() - assert ds.data.shape == sig.data.shape - assert integ.shape == sig.data.shape - - rs = sig.resample(50.0) - assert np.isclose(rs.sample_rate_hz, 50.0, atol=1e-6) - - sub = sig.get_sub_signal([0]) - assert sub.n_channels == 1 - - - -def test_covariate_tier2_methods() -> None: - t = np.linspace(0.0, 1.0, 51) - y = np.column_stack([np.sin(2 * np.pi * t), np.sin(2 * np.pi * t + 0.2)]) - cov = Covariate(time=t, data=y, name="stim", labels=["s1", "s2"]) - - mu, lo, hi = cov.compute_mean_plus_ci(axis=1) - assert mu.shape == t.shape - assert lo.shape == t.shape - assert hi.shape == t.shape - - sub = cov.get_sub_signal("s2") - assert sub.labels == ["s2"] - - payload = cov.to_structure() - rec = Covariate.from_structure(payload) - assert rec.labels == cov.labels - assert np.allclose(rec.data, cov.data) diff --git a/tests/test_spikes_trial.py b/tests/test_spikes_trial.py deleted file mode 100644 index 390bc151..00000000 --- a/tests/test_spikes_trial.py +++ /dev/null @@ -1,35 +0,0 @@ -import numpy as np - -from nstat.signal import Covariate -from nstat.spikes import SpikeTrain, SpikeTrainCollection -from nstat.trial import CovariateCollection, Trial - - -def test_spike_train_binarize() -> None: - st = SpikeTrain(spike_times=np.array([0.1, 0.2, 0.21]), t_start=0.0, t_end=1.0) - t, y = st.binarize(0.1) - assert t.ndim == 1 - assert y.ndim == 1 - assert y.max() <= 1.0 - - tc, counts = st.bin_counts(0.1) - assert tc.shape == t.shape - assert np.sum(counts) == 3.0 - - -def test_trial_alignment() -> None: - t = np.linspace(0.0, 1.0, 101) - cov = Covariate(time=t, data=np.sin(2 * np.pi * t), name="stim") - covs = CovariateCollection([cov]) - - trains = SpikeTrainCollection([ - SpikeTrain(spike_times=np.array([0.1, 0.3, 0.9]), t_start=0.0, t_end=1.0) - ]) - trial = Trial(spikes=trains, covariates=covs) - - tb, y, X = trial.aligned_binned_observation(0.01) - assert tb.shape[0] == y.shape[0] - assert X.shape[0] == y.shape[0] - - _, yc, _ = trial.aligned_binned_observation(0.01, mode="count") - assert np.all(yc >= 0.0) diff --git a/tests/test_tier1_gate_policy.py b/tests/test_tier1_gate_policy.py deleted file mode 100644 index d188b5ad..00000000 --- a/tests/test_tier1_gate_policy.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import annotations - -import json -from pathlib import Path - -import yaml - - - -def test_tier1_gate_policy_targets_report_classes() -> None: - policy = yaml.safe_load(Path("parity/tier1_gate_policy.yml").read_text(encoding="utf-8")) - report = json.loads(Path("parity/parity_gap_report.json").read_text(encoding="utf-8")) - report_classes = {row["matlab_class"] for row in report["class_coverage"]} - - for klass in policy["min_coverage_ratio"]: - assert klass in report_classes - for klass in policy["max_missing_methods"]: - assert klass in report_classes - - - -def test_tier1_gate_policy_current_report_passes_thresholds() -> None: - policy = yaml.safe_load(Path("parity/tier1_gate_policy.yml").read_text(encoding="utf-8")) - report = json.loads(Path("parity/parity_gap_report.json").read_text(encoding="utf-8")) - rows = {row["matlab_class"]: row for row in report["class_coverage"]} - - for klass, min_ratio in policy["min_coverage_ratio"].items(): - assert float(rows[klass]["coverage_ratio"]) >= float(min_ratio) - - for klass, max_missing in policy["max_missing_methods"].items(): - assert int(rows[klass]["missing_method_count"]) <= int(max_missing) diff --git a/tests/test_validation_image_fixtures.py b/tests/test_validation_image_fixtures.py deleted file mode 100644 index 07bfde71..00000000 --- a/tests/test_validation_image_fixtures.py +++ /dev/null @@ -1,91 +0,0 @@ -from __future__ import annotations - -import hashlib -from pathlib import Path - -import nbformat -import yaml - - -MANIFEST = Path("tools/notebooks/notebook_manifest.yml") -IMAGE_ROOT = Path("baseline/validation/notebook_images") -WEAK_TOPICS = [ - "DecodingExampleWithHist", - "PSTHEstimation", - "nstCollExamples", - "TrialExamples", - "CovCollExamples", - "EventsExamples", -] - - -def _topic_code(topic: str) -> str: - payload = yaml.safe_load(MANIFEST.read_text(encoding="utf-8")) or {} - rows = payload.get("notebooks", []) - by_topic = {str(row["topic"]): Path(str(row["file"])) for row in rows} - nb_path = by_topic[topic] - nb = nbformat.read(nb_path, as_version=4) - return "\n".join(cell.source for cell in nb.cells if cell.cell_type == "code") - - -def _sha256(path: Path) -> str: - digest = hashlib.sha256() - digest.update(path.read_bytes()) - return digest.hexdigest() - - -def test_all_manifest_topics_have_validation_image_fixtures() -> None: - payload = yaml.safe_load(MANIFEST.read_text(encoding="utf-8")) - for row in payload["notebooks"]: - topic = str(row["topic"]) - images = sorted((IMAGE_ROOT / topic).glob("*.png")) - assert images, f"missing validation image fixtures for topic {topic}" - - -def test_weak_topics_have_topic_specific_assertions() -> None: - expected_snippets = { - "DecodingExampleWithHist": [ - "np.max(np.abs(np.sum(posterior, axis=0) - 1.0)) < 1e-6", - "rmse_dec <= rmse_raw + 0.03", - ], - "PSTHEstimation": [ - "np.allclose(prob_mat, prob_mat.T", - "np.all(np.diag(prob_mat) == 1.0)", - ], - "nstCollExamples": [ - "H.ndim == 2 and H.shape[1] == history.n_bins", - "spikes.spike_times.size > 5", - ], - "TrialExamples": [ - "H.ndim == 2 and H.shape[1] == history.n_bins", - "spikes.spike_times.size > 5", - ], - "CovCollExamples": [ - "H.ndim == 2 and H.shape[1] == history.n_bins", - "spikes.spike_times.size > 5", - ], - "EventsExamples": [ - "events.times.size == 3", - "np.all(np.diff(events.times) > 0.0)", - ], - } - - for topic in WEAK_TOPICS: - code = _topic_code(topic) - assert "Topic-specific checkpoint" in code - assert "Notebook checkpoints passed" in code - for snippet in expected_snippets[topic]: - assert snippet in code, f"missing expected assertion snippet for {topic}: {snippet}" - - -def test_weak_topic_validation_images_are_not_all_identical() -> None: - hashes: list[str] = [] - for topic in WEAK_TOPICS: - images = sorted((IMAGE_ROOT / topic).glob("*.png")) - assert images, f"missing validation image fixture for topic {topic}" - first = images[0] - assert first.stat().st_size > 0, f"empty validation image for topic {topic}" - hashes.append(_sha256(first)) - - # Guardrail against a broken renderer reusing one image for all topics. - assert len(set(hashes)) >= 4 diff --git a/tests/test_validation_images_discovery.py b/tests/test_validation_images_discovery.py new file mode 100644 index 00000000..dc74cdb8 --- /dev/null +++ b/tests/test_validation_images_discovery.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +import importlib.util +from pathlib import Path +import sys + +import nbformat + +_MODULE_PATH = Path(__file__).resolve().parents[1] / "tools" / "reports" / "generate_validation_pdf.py" +_SPEC = importlib.util.spec_from_file_location("generate_validation_pdf", _MODULE_PATH) +assert _SPEC is not None and _SPEC.loader is not None +gvp = importlib.util.module_from_spec(_SPEC) +sys.modules[_SPEC.name] = gvp +_SPEC.loader.exec_module(gvp) + + +def test_execute_notebook_capture_discovers_saved_tracker_images( + tmp_path: Path, + monkeypatch, +) -> None: + repo_root = tmp_path / "repo" + nb_dir = repo_root / "notebooks" + nb_dir.mkdir(parents=True, exist_ok=True) + topic = "DiscoverySmoke" + nb_path = nb_dir / f"{topic}.ipynb" + + nb = nbformat.v4.new_notebook() + nb.cells = [ + nbformat.v4.new_code_cell( + "\n".join( + [ + "import matplotlib", + "matplotlib.use('Agg')", + "import matplotlib.pyplot as plt", + "from pathlib import Path", + f"topic = {topic!r}", + "out = Path.cwd().resolve().parent / 'output' / 'notebook_images' / topic", + "out.mkdir(parents=True, exist_ok=True)", + "fig = plt.figure(figsize=(4, 2))", + "ax = fig.add_subplot(1,1,1)", + "ax.plot([0, 1], [0, 1], color='k')", + "fig.tight_layout()", + "fig.savefig(out / 'fig_001.png', dpi=120)", + "plt.close(fig)", + ] + ) + ) + ] + nbformat.write(nb, nb_path) + + monkeypatch.setattr(gvp, "REPO_ROOT", repo_root) + + report = gvp.execute_notebook_capture( + target=gvp.NotebookTarget(topic=topic, file=nb_path, run_group="smoke"), + tmp_dir=repo_root / "tmp" / "pdfs" / "validation_report", + timeout=120, + matlab_help_root=None, + parity_threshold=0.8, + skip_parity_check=True, + parity_mode="gate", + gate_status=("verified", True), + parity_metrics=None, + ) + + assert report.executed + assert report.unique_image_count >= 1 + assert report.image_count >= report.unique_image_count + assert all(path.exists() for path in report.image_paths) + + discovered_dir = repo_root / "tmp" / "pdfs" / "validation_report" / "notebook_images" / topic + discovered = sorted(discovered_dir.glob("*.png")) + assert discovered diff --git a/tests/test_validation_pdf_uniqueness.py b/tests/test_validation_pdf_uniqueness.py deleted file mode 100644 index 44dbbe6d..00000000 --- a/tests/test_validation_pdf_uniqueness.py +++ /dev/null @@ -1,85 +0,0 @@ -from __future__ import annotations - -import importlib.util -import sys -from pathlib import Path - -REPORT_SCRIPT = Path(__file__).resolve().parents[1] / "tools" / "reports" / "generate_validation_pdf.py" -SPEC = importlib.util.spec_from_file_location("generate_validation_pdf", REPORT_SCRIPT) -assert SPEC is not None and SPEC.loader is not None -MODULE = importlib.util.module_from_spec(SPEC) -sys.modules[SPEC.name] = MODULE -SPEC.loader.exec_module(MODULE) - -NotebookReport = MODULE.NotebookReport -_uniqueness_violations = MODULE._uniqueness_violations - - -def _report( - topic: str, - image_hashes: list[str], - *, - unique_image_count: int | None = None, -) -> NotebookReport: - unique_count = len(set(image_hashes)) if unique_image_count is None else unique_image_count - return NotebookReport( - topic=topic, - file=Path(f"{topic}.ipynb"), - run_group="smoke", - executed=True, - duration_s=0.1, - image_paths=[], - unique_image_paths=[], - image_hashes=image_hashes, - image_count=len(image_hashes), - unique_image_count=unique_count, - duplicate_image_count=max(0, len(image_hashes) - unique_count), - text_snippet="", - error="", - matlab_ref_images=[], - expected_figure_count=len(image_hashes), - produced_figure_count=len(image_hashes), - figure_scores=[], - figure_count_match=True, - similarity_score=None, - parity_pass=None, - alignment_status=None, - matched_python_image=None, - matched_matlab_image=None, - parity_metrics=None, - ) - - -def test_uniqueness_stats_and_no_violations_at_lenient_thresholds() -> None: - reports = [ - _report("ExampleA", ["h1", "h1", "h2"]), - _report("ExampleB", ["h2", "h3"]), - ] - violations, stats = _uniqueness_violations( - reports=reports, - min_unique_images_per_topic=1, - max_cross_topic_reuse_ratio=1.0, - ) - - assert violations == [] - assert stats["total_image_instances"] == 5 - assert stats["total_unique_hashes"] == 3 - assert stats["cross_topic_reused_hashes"] == 1 - assert stats["repeated_instances"] == 2 - assert float(stats["cross_topic_reuse_ratio"]) == 1.0 / 3.0 - - -def test_uniqueness_violations_for_topic_and_cross_topic_reuse() -> None: - reports = [ - _report("ExampleA", ["h1", "h1", "h2"], unique_image_count=1), - _report("ExampleB", ["h2", "h3"]), - ] - violations, stats = _uniqueness_violations( - reports=reports, - min_unique_images_per_topic=2, - max_cross_topic_reuse_ratio=0.2, - ) - - assert any("ExampleA: unique_images=1 < min_required=2" in row for row in violations) - assert any("cross_topic_reuse_ratio=" in row for row in violations) - assert float(stats["cross_topic_reuse_ratio"]) > 0.2 diff --git a/tools/compliance/check_cleanroom_overlap.py b/tools/compliance/check_cleanroom_overlap.py deleted file mode 100755 index c8c95d38..00000000 --- a/tools/compliance/check_cleanroom_overlap.py +++ /dev/null @@ -1,247 +0,0 @@ -#!/usr/bin/env python3 -"""Fail if non-data files overlap by SHA256 with the MATLAB nSTAT repository. - -This script enforces clean-room constraints for nSTAT-python: -- non-data content hashes must not collide with upstream MATLAB nSTAT -- data file overlaps are allowed only when explicitly allowlisted -""" - -from __future__ import annotations - -import argparse -import hashlib -import sys -from dataclasses import dataclass -from pathlib import Path -from typing import Iterable - -import yaml - - -IGNORED_DIRS = { - ".git", - ".github", - ".mypy_cache", - ".pytest_cache", - ".ruff_cache", - ".venv", - "__pycache__", - "build", - "dist", - "site", - "docs/_build", -} - - -@dataclass(frozen=True, slots=True) -class FileDigest: - relative_path: str - sha256: str - lfs_oid: str | None = None - - -@dataclass(frozen=True, slots=True) -class AllowedDataMatch: - python_path: str - upstream_path: str - sha256: str - - -@dataclass(frozen=True, slots=True) -class Collision: - sha256: str - python_path: str - upstream_path: str - - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--project-root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="Path to nSTAT-python repository root.", - ) - parser.add_argument( - "--upstream-root", - type=Path, - required=True, - help="Path to checked-out MATLAB nSTAT repository root.", - ) - parser.add_argument( - "--allowlist", - type=Path, - default=Path(__file__).resolve().parent / "shared_data_allowlist.yml", - help="Path to shared-data allowlist YAML.", - ) - return parser.parse_args() - - - -def is_ignored(path: Path) -> bool: - """Return True if path should be excluded from hash comparison.""" - - path_str = path.as_posix() - for ignored in IGNORED_DIRS: - if ignored in path.parts or path_str.startswith(f"{ignored}/"): - return True - return False - - - -def is_data_path(relative_path: str) -> bool: - """Return True when path is inside top-level data directory.""" - - return relative_path.startswith("data/") - - - -def compute_sha256(path: Path) -> str: - digest = hashlib.sha256() - with path.open("rb") as handle: - for chunk in iter(lambda: handle.read(1024 * 1024), b""): - digest.update(chunk) - return digest.hexdigest() - - -def read_lfs_oid(path: Path) -> str | None: - try: - text = path.read_text(encoding="utf-8") - except UnicodeDecodeError: - return None - lines = [line.strip() for line in text.splitlines()] - if not lines or not lines[0].startswith("version https://git-lfs.github.com/spec"): - return None - for line in lines: - if line.startswith("oid sha256:"): - return line.split("oid sha256:", 1)[1].strip() - return None - - -def iter_files(root: Path) -> Iterable[Path]: - for path in root.rglob("*"): - if not path.is_file(): - continue - rel = path.relative_to(root) - if is_ignored(rel): - continue - yield path - - - -def build_digest_index(root: Path) -> list[FileDigest]: - rows: list[FileDigest] = [] - for path in iter_files(root): - rel = path.relative_to(root).as_posix() - rows.append( - FileDigest( - relative_path=rel, - sha256=compute_sha256(path), - lfs_oid=read_lfs_oid(path), - ) - ) - return rows - - - -def load_allowlist(path: Path) -> set[AllowedDataMatch]: - payload = yaml.safe_load(path.read_text(encoding="utf-8")) - shared_data = payload.get("shared_data") if isinstance(payload, dict) else [] - if shared_data is None: - shared_data = [] - - allowed: set[AllowedDataMatch] = set() - for row in shared_data: - if not isinstance(row, dict): - continue - python_path = row.get("python_path") - upstream_path = row.get("upstream_path") - sha256 = row.get("sha256") - if python_path and upstream_path and sha256: - allowed.add( - AllowedDataMatch( - python_path=str(python_path), - upstream_path=str(upstream_path), - sha256=str(sha256), - ) - ) - return allowed - - - -def find_collisions( - python_files: list[FileDigest], - upstream_files: list[FileDigest], - allowlist: set[AllowedDataMatch], -) -> list[Collision]: - upstream_by_hash: dict[str, list[FileDigest]] = {} - for row in upstream_files: - upstream_by_hash.setdefault(row.sha256, []).append(row) - - collisions: list[Collision] = [] - for py_row in python_files: - upstream_rows = upstream_by_hash.get(py_row.sha256, []) - if not upstream_rows: - continue - - for upstream_row in upstream_rows: - upstream_path = upstream_row.relative_path - both_data = is_data_path(py_row.relative_path) and is_data_path(upstream_path) - if both_data: - hash_candidates = {py_row.sha256, upstream_row.sha256} - if py_row.lfs_oid: - hash_candidates.add(py_row.lfs_oid) - if upstream_row.lfs_oid: - hash_candidates.add(upstream_row.lfs_oid) - allow_matches = [ - row - for row in allowlist - if row.python_path == py_row.relative_path and row.upstream_path == upstream_path - ] - if allow_matches and any(row.sha256 in hash_candidates for row in allow_matches): - continue - if allow_matches and py_row.lfs_oid and upstream_row.lfs_oid: - continue - - collisions.append( - Collision( - sha256=py_row.sha256, - python_path=py_row.relative_path, - upstream_path=upstream_path, - ) - ) - return collisions - - - -def main() -> int: - args = parse_args() - - if not args.project_root.exists(): - raise FileNotFoundError(f"project root does not exist: {args.project_root}") - if not args.upstream_root.exists(): - raise FileNotFoundError(f"upstream root does not exist: {args.upstream_root}") - if not args.allowlist.exists(): - raise FileNotFoundError(f"allowlist does not exist: {args.allowlist}") - - python_files = build_digest_index(args.project_root) - upstream_files = build_digest_index(args.upstream_root) - allowlist = load_allowlist(args.allowlist) - - collisions = find_collisions(python_files, upstream_files, allowlist) - if collisions: - print("Clean-room compliance check FAILED.") - print("Detected overlapping file content hashes:") - for row in collisions: - print( - f" sha256={row.sha256} | python={row.python_path} | upstream={row.upstream_path}" - ) - return 1 - - print("Clean-room compliance check PASSED (no unauthorized hash collisions).") - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/compliance/check_mirror_regeneration.py b/tools/compliance/check_mirror_regeneration.py deleted file mode 100644 index 923c3457..00000000 --- a/tools/compliance/check_mirror_regeneration.py +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env python3 -"""Fail when mirrored-data artifacts are out of sync. - -Checks: -1. Every `matlab_gold_.manifest.json` has matching source manifest. -2. Source/mirror manifests agree on relative_path + size + sha256. -3. Shared-data allowlist has one entry per mirrored file with matching checksum. -4. data/datasets_manifest.json has one mirror dataset row per mirrored file. -""" - -from __future__ import annotations - -import argparse -import json -import sys -from pathlib import Path - -import yaml - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--shared-root", - default="data/shared", - help="Directory containing matlab_source/matlab_gold manifests.", - ) - parser.add_argument( - "--allowlist", - default="tools/compliance/shared_data_allowlist.yml", - help="Shared-data allowlist YAML.", - ) - parser.add_argument( - "--datasets-manifest", - default="data/datasets_manifest.json", - help="Datasets manifest JSON.", - ) - return parser.parse_args() - - -def _resolve(path_arg: str, repo_root: Path) -> Path: - path = Path(path_arg).expanduser() - if not path.is_absolute(): - path = repo_root / path - return path.resolve() - - -def _load_json(path: Path) -> dict: - return json.loads(path.read_text(encoding="utf-8")) - - -def _load_allowlist(path: Path) -> list[dict]: - payload = yaml.safe_load(path.read_text(encoding="utf-8")) or {} - rows = payload.get("shared_data", []) - return rows if isinstance(rows, list) else [] - - -def _file_map(files: list[dict]) -> dict[str, tuple[int, str]]: - out: dict[str, tuple[int, str]] = {} - for row in files: - out[str(row["relative_path"])] = (int(row["size_bytes"]), str(row["sha256"])) - return out - - -def _extract_version_from_manifest_name(name: str) -> str: - # matlab_gold_20260302.manifest.json -> 20260302 - stem = name.replace(".manifest.json", "") - return stem.removeprefix("matlab_gold_") - - -def main() -> int: - repo_root = Path(__file__).resolve().parents[2] - args = parse_args() - - shared_root = _resolve(args.shared_root, repo_root) - allowlist_path = _resolve(args.allowlist, repo_root) - datasets_manifest_path = _resolve(args.datasets_manifest, repo_root) - - allowlist_rows = _load_allowlist(allowlist_path) - dataset_rows = _load_json(datasets_manifest_path).get("datasets", []) - - allow_idx: dict[tuple[str, str], dict] = {} - for row in allowlist_rows: - py_path = str(row.get("python_path", "")) - sha = str(row.get("sha256", "")) - if py_path and sha: - allow_idx[(py_path, sha)] = row - - ds_idx: dict[tuple[str, str], dict] = {} - for row in dataset_rows: - name = str(row.get("name", "")) - sha = str(row.get("sha256", "")) - if name and sha: - ds_idx[(name, sha)] = row - - errors: list[str] = [] - - gold_manifests = sorted(shared_root.glob("matlab_gold_*.manifest.json")) - if not gold_manifests: - errors.append(f"No matlab_gold manifests found in {shared_root}") - - for gold_path in gold_manifests: - gold = _load_json(gold_path) - version = str(gold.get("dataset_version") or _extract_version_from_manifest_name(gold_path.name)) - source_path = shared_root / f"matlab_source_{version}.manifest.json" - if not source_path.exists(): - errors.append(f"Missing source manifest for version {version}: {source_path}") - continue - - source = _load_json(source_path) - gold_files = gold.get("files", []) - source_files = source.get("files", []) - if not isinstance(gold_files, list) or not isinstance(source_files, list): - errors.append(f"Malformed files list in manifests for version {version}") - continue - - gmap = _file_map(gold_files) - smap = _file_map(source_files) - if gmap != smap: - errors.append(f"Source/mirror manifest mismatch for version {version}") - - mirror_root = str(gold.get("mirror_root", f"data/shared/matlab_gold_{version}")) - source_manifest_rel = gold_path.relative_to(repo_root).as_posix() - - for rel_path, (_, sha) in gmap.items(): - py_path = f"{mirror_root}/{rel_path}" - arow = allow_idx.get((py_path, sha)) - if arow is None: - errors.append(f"Allowlist missing: {py_path}") - else: - if str(arow.get("source_manifest", "")) != source_manifest_rel: - errors.append(f"Allowlist source_manifest mismatch for {py_path}") - expected_upstream = f"data/{rel_path}" - if str(arow.get("upstream_path", "")) != expected_upstream: - errors.append(f"Allowlist upstream_path mismatch for {py_path}") - - ds_name = f"matlab_gold_{version}/{rel_path}" - drow = ds_idx.get((ds_name, sha)) - if drow is None: - errors.append(f"datasets_manifest missing row: {ds_name}") - else: - if str(drow.get("filename", "")) != rel_path: - errors.append(f"datasets_manifest filename mismatch for {ds_name}") - - if errors: - print("Mirror regeneration check FAILED:") - for err in errors[:200]: - print(f" - {err}") - if len(errors) > 200: - print(f" ... and {len(errors) - 200} more") - return 1 - - print("Mirror regeneration check PASSED.") - return 0 - - -if __name__ == "__main__": - sys.exit(main()) - diff --git a/tools/compliance/check_no_matlab_dependency.py b/tools/compliance/check_no_matlab_dependency.py deleted file mode 100755 index 799b5cc0..00000000 --- a/tools/compliance/check_no_matlab_dependency.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python3 -"""Verify repository source code has no MATLAB runtime dependency.""" - -from __future__ import annotations - -import argparse -import re -import sys -from pathlib import Path - - -PATTERNS = [ - re.compile(r"\bmatlab\.engine\b"), - re.compile(r"\bimport\s+matlab\b"), - re.compile(r"\bfrom\s+matlab\b"), - re.compile(r"\bmfilename\("), -] - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="Repository root", - ) - return parser.parse_args() - - - -def main() -> int: - args = parse_args() - offenders: list[tuple[str, int, str]] = [] - - for path in args.root.joinpath("src").rglob("*.py"): - text = path.read_text(encoding="utf-8") - for line_no, line in enumerate(text.splitlines(), start=1): - for pattern in PATTERNS: - if pattern.search(line): - offenders.append((path.relative_to(args.root).as_posix(), line_no, line.strip())) - - if offenders: - print("MATLAB dependency check FAILED.") - for rel, line_no, line in offenders: - print(f" {rel}:{line_no}: {line}") - return 1 - - print("MATLAB dependency check PASSED.") - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/compliance/shared_data_allowlist.yml b/tools/compliance/shared_data_allowlist.yml deleted file mode 100644 index 5e734957..00000000 --- a/tools/compliance/shared_data_allowlist.yml +++ /dev/null @@ -1,216 +0,0 @@ -version: 1 -shared_data: -- python_path: data/shared/mEPSCs/epsc2.txt - upstream_repo: cajigaslab/nSTAT - upstream_path: data/mEPSCs/epsc2.txt - sha256: 65a130b7af4bc34eeaf943da76df6ebf9ba0ae9720eb98b6813f9f44a43ff435 -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron1/Stim1/testdataBis.mat - sha256: cbf9dfa3b39b1bf4b712eb2bde37320b9d58d451504c5620519cd6cacec90431 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron1/Stim1/trngdataBis.mat - sha256: effc8975d3b8ea8f423a5e5476bb5becd7cbee9fcddf0c2cb5bf1f06dadf9a31 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron1/Stim2/testdataBis.mat - sha256: e00711145e693815e6d7f92968fab06c0833680c32a6eca13190d9a00e91fae1 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron1/Stim2/trngdataBis.mat - sha256: ef9d41d34ca7ab49fe34022dda24220b41f6814d6220d4b7f111d39ccaf0159f - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron1/Stim3/testdataBis.mat - sha256: f45bb73ba9fc1129e1134e3c28d238ed0df72d3b2ff94f62d26b231358f0a957 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron1/Stim3/trngdataBis.mat - sha256: c9161723ded0cb9ef4044e518d4bc6605666a4d3a92343d418964179c71516b5 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron2/Stim1/testdataBis.mat - sha256: c579c52b0d6f979177992ef0c382a55b867de02ec8b17275b695a10c04779c67 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron2/Stim1/trngdataBis.mat - sha256: 0e3557598c0ac2777d8d0c9af7d6f92d019d905b73742fe1a472549594f17325 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron2/Stim2/testdataBis.mat - sha256: 9faf006a195ac193015aead58f3e541e4840ff4e7bb376f4e27fcab664049210 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron2/Stim2/trngdataBis.mat - sha256: b0db8069ed3c4c800e0c5b3fe1aa6406415035ddba4f486d1548383b1e2e1093 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron2/Stim3/testdataBis.mat - sha256: 24b79facf077f68c5b16b9778a2cce8c2df61d3c9124064826aa7696c9472c17 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir16/Neuron2/Stim3/trngdataBis.mat - sha256: 824e3cde647b97e6c7c6f1649d56d52f79f17e6274610fafce817cc844770e5d - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron1/Stim1/testdataBis.mat - sha256: c848a13bef8f4e5a47dd027c0abf0f3904911cf699c698dfd5621ac7b602b324 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron1/Stim1/trngdataBis.mat - sha256: ad2e4a639155382b7462c0dc0f43663f6b94ca69b5cfe618d439926bceecec9a - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Data.eps - sha256: 839dd534e216d5d31b266b7efd18b96f934cac86cef4d65da93d8c58551ed772 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron1/Stim2/Experiment2-Results.eps - sha256: d972186f79323f89d021d17a50f746fbbcd431d196d4685fb26d0998aea2d893 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron1/Stim2/testdataBis.mat - sha256: 440ec83724ae2a9a707eb1db33b9ebc3d9260cef15c9fb4b280a352a70432321 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron1/Stim2/trngdataBis.mat - sha256: f4b4299a1e977db37bab8a11d107b6d2a73541d3e5bb017ab68b1d9885def3f2 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron1/Stim3/testdataBis.mat - sha256: 998568271174ffbb79abd850846d3a38b193221689aa8c2a7f6f1b247721851f - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron1/Stim3/trngdataBis.mat - sha256: 3561b3c90931f1a06d757624717ace69686767630918e18cac0b118ef5b9d370 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron2/Stim1/testdataBis.mat - sha256: 48d34a2478f310d0becb92e03fc47c56598529d6bae67f4f8c097ffb5d1328a1 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron2/Stim1/trngdataBis.mat - sha256: ae2c905af5c95881fbef989cbd175404b287723186ffacdbdaa7a13488202e23 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron2/Stim2/testdataBis.mat - sha256: 9047cf6ea92d4d0dcf1215c4b41addf312d156dd22777958343607db1c440161 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron2/Stim2/trngdataBis.mat - sha256: 6f26dd402d2893b8ae06dcb8514ef82a9ece6373ae6da974bde99895bc57f1d3 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron2/Stim3/testdataBis.mat - sha256: b243c1091d2d97efd291871cae2b4793bf2bb381fe6741748ccb95b9e32b6da7 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/Dir3/Neuron2/Stim3/trngdataBis.mat - sha256: ae1a19ba2ad50b69bad1ff8a9927cbf6e18f541a8ad332c4d51334e576abc8b7 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Explicit Stimulus/GenCovMat.m - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Explicit Stimulus/GenCovMat.m - sha256: 79a87fc52fe5637b351bc8565f576989d9ef1a23b44522621b1a33facfcf89b4 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/PSTH/Data Description.pdf - upstream_repo: cajigaslab/nSTAT - upstream_path: data/PSTH/Data Description.pdf - sha256: 79574d56122d0aab30aad7cf13120916f278b28b7f84052689e8c58da4818140 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/PSTH/Results.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/PSTH/Results.mat - sha256: 685438f83a6df49cb9b5d260749107d401c14f1d1bc5cbabf6f00f16ebddb4fb - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Place Cells/PlaceCellDataAnimal1.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Place Cells/PlaceCellDataAnimal1.mat - sha256: 8806ab38c62a04ee1bec9cabab907a8f9fa3d66e0799fa09de8acd01789fc77b - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Place Cells/PlaceCellDataAnimal2.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Place Cells/PlaceCellDataAnimal2.mat - sha256: e8f22ab469ae30427cac8401dbeacfc2a7a5d4ba1a62fd339a8834ab489e750f - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Place Cells/Readme.txt - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Place Cells/Readme.txt - sha256: 53c6d51d6b2a64b622da3a60e9f5d9ad8c9b7362480635c9a6460a30c29044de - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/Place Cells/license.txt - upstream_repo: cajigaslab/nSTAT - upstream_path: data/Place Cells/license.txt - sha256: 4587991e9404c291513292886f98dd432cbb772a9f873da1d406a799646fe377 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/PlaceCellAnimal1Results.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/PlaceCellAnimal1Results.mat - sha256: 15b53a0da12338551d7edfce03666195c7f95b355e2b1f483f0ba0850f8915d5 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/PlaceCellAnimal2Results.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/PlaceCellAnimal2Results.mat - sha256: fef2a2a0ad54012d5e1ecab96dde72a8c7ce0116afa0df038c0aed9437021f77 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/SSGLMExampleData.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/SSGLMExampleData.mat - sha256: fc1d4730267b49e3af534f6572b28ce1ba746708a49a1e4f1e8fb082cdabc360 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/glm_data.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/glm_data.mat - sha256: 4152d93a660acf62b46b77f2dee3f14d2147dd100748c16fa3922f6c2f8ad577 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/glm_data_orig.mat - upstream_repo: cajigaslab/nSTAT - upstream_path: data/glm_data_orig.mat - sha256: a11ab318f9c8042453c043ed79764b18ba727ceac31672e42b7ed30024ab2a4b - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/mEPSCs/epsc2.txt - upstream_repo: cajigaslab/nSTAT - upstream_path: data/mEPSCs/epsc2.txt - sha256: 65a130b7af4bc34eeaf943da76df6ebf9ba0ae9720eb98b6813f9f44a43ff435 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/mEPSCs/mEPSCAnalysis.asv - upstream_repo: cajigaslab/nSTAT - upstream_path: data/mEPSCs/mEPSCAnalysis.asv - sha256: c3d99d7de863a501f2d57ffbe09ff2c94fdf6b7ea8c6292641337b9a80ee7249 - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/mEPSCs/washout1.txt - upstream_repo: cajigaslab/nSTAT - upstream_path: data/mEPSCs/washout1.txt - sha256: 4791531b54dd3f98c8cf756bd253d61d09113338b0dbe98ed09ef2df2d18e00e - source_manifest: data/shared/matlab_gold_20260302.manifest.json -- python_path: data/shared/matlab_gold_20260302/mEPSCs/washout2.txt - upstream_repo: cajigaslab/nSTAT - upstream_path: data/mEPSCs/washout2.txt - sha256: ab35f26d4bccc48d2dc91e5007ba64d2527891666d2653e0a6118e397a4985fa - source_manifest: data/shared/matlab_gold_20260302.manifest.json diff --git a/tools/compliance/update_datasets_manifest_from_mirror.py b/tools/compliance/update_datasets_manifest_from_mirror.py deleted file mode 100644 index 8b01912d..00000000 --- a/tools/compliance/update_datasets_manifest_from_mirror.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env python3 -"""Regenerate data/datasets_manifest.json entries from a MATLAB mirror manifest.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path -from urllib.parse import quote - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--manifest", required=True, help="Path to matlab_gold manifest JSON.") - parser.add_argument( - "--datasets-manifest", - default="data/datasets_manifest.json", - help="Path to nSTAT datasets manifest JSON.", - ) - parser.add_argument( - "--upstream-raw-prefix", - default="https://raw.githubusercontent.com/cajigaslab/nSTAT/master/data/", - help="Raw URL prefix for upstream MATLAB data files.", - ) - parser.add_argument( - "--keep-legacy", - action=argparse.BooleanOptionalAction, - default=True, - help="Keep non-mirror legacy dataset rows (default: true).", - ) - return parser.parse_args() - - -def _resolve(path_arg: str, repo_root: Path) -> Path: - path = Path(path_arg).expanduser() - if not path.is_absolute(): - path = repo_root / path - return path.resolve() - - -def _load_json(path: Path) -> dict: - return json.loads(path.read_text(encoding="utf-8")) - - -def _dump_json(path: Path, payload: dict) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") - - -def _mirror_name(version: str, rel_path: str) -> str: - return f"matlab_gold_{version}/{rel_path}" - - -def main() -> int: - args = parse_args() - repo_root = Path(__file__).resolve().parents[2] - - mirror_manifest_path = _resolve(args.manifest, repo_root) - datasets_manifest_path = _resolve(args.datasets_manifest, repo_root) - - mirror = _load_json(mirror_manifest_path) - datasets_payload = _load_json(datasets_manifest_path) - - version = str(mirror["dataset_version"]) - files = mirror.get("files", []) - if not isinstance(files, list): - raise KeyError("Mirror manifest missing files list.") - - generated_rows: list[dict] = [] - for row in files: - rel_path = str(row["relative_path"]) - url = args.upstream_raw_prefix + quote(rel_path, safe="/") - generated_rows.append( - { - "name": _mirror_name(version, rel_path), - "version": version, - "url": url, - "sha256": str(row["sha256"]), - "filename": rel_path, - } - ) - - current_rows = list(datasets_payload.get("datasets", [])) - if args.keep_legacy: - retained = [ - row - for row in current_rows - if not str(row.get("name", "")).startswith("matlab_gold_") - ] - else: - retained = [] - - all_rows = retained + generated_rows - all_rows.sort(key=lambda r: (str(r["name"]), str(r["version"]))) - - datasets_payload["datasets"] = all_rows - if "schema_version" not in datasets_payload: - datasets_payload["schema_version"] = 1 - if "notes" not in datasets_payload: - datasets_payload["notes"] = ( - "Only shared example data are listed here. " - "Non-data assets are never shared with MATLAB nSTAT." - ) - - _dump_json(datasets_manifest_path, datasets_payload) - - print(f"Mirror manifest: {mirror_manifest_path}") - print(f"Datasets manifest: {datasets_manifest_path}") - print(f"Generated mirror dataset entries: {len(generated_rows)}") - print(f"Total dataset entries: {len(all_rows)}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) - diff --git a/tools/compliance/update_shared_data_allowlist.py b/tools/compliance/update_shared_data_allowlist.py deleted file mode 100644 index 505456a1..00000000 --- a/tools/compliance/update_shared_data_allowlist.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python3 -"""Update shared-data allowlist entries from a mirrored MATLAB data manifest.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - -import yaml - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--manifest", required=True, help="Path to matlab_gold manifest JSON.") - parser.add_argument( - "--allowlist", - default="tools/compliance/shared_data_allowlist.yml", - help="Path to shared-data allowlist YAML.", - ) - parser.add_argument( - "--upstream-repo", - default="cajigaslab/nSTAT", - help="Upstream MATLAB repository identifier.", - ) - parser.add_argument( - "--upstream-data-prefix", - default="data", - help="Upstream data root prefix in repository.", - ) - return parser.parse_args() - - -def _resolve(path_arg: str, repo_root: Path) -> Path: - path = Path(path_arg).expanduser() - if not path.is_absolute(): - path = repo_root / path - return path.resolve() - - -def _load_manifest(path: Path) -> dict: - return json.loads(path.read_text(encoding="utf-8")) - - -def _load_allowlist(path: Path) -> dict: - if not path.exists(): - return {"version": 1, "shared_data": []} - payload = yaml.safe_load(path.read_text(encoding="utf-8")) - if not isinstance(payload, dict): - return {"version": 1, "shared_data": []} - payload.setdefault("version", 1) - payload.setdefault("shared_data", []) - return payload - - -def _normalize_shared_data(rows: list[dict]) -> list[dict]: - normalized: list[dict] = [] - for row in rows: - if not isinstance(row, dict): - continue - python_path = row.get("python_path") - upstream_path = row.get("upstream_path") - sha256 = row.get("sha256") - upstream_repo = row.get("upstream_repo") - if not (python_path and upstream_path and sha256): - continue - clean_row = { - "python_path": str(python_path), - "upstream_repo": str(upstream_repo) if upstream_repo else "cajigaslab/nSTAT", - "upstream_path": str(upstream_path), - "sha256": str(sha256), - } - source_manifest = row.get("source_manifest") - if source_manifest: - clean_row["source_manifest"] = str(source_manifest) - normalized.append(clean_row) - return normalized - - -def main() -> int: - repo_root = Path(__file__).resolve().parents[2] - args = parse_args() - manifest_path = _resolve(args.manifest, repo_root) - allowlist_path = _resolve(args.allowlist, repo_root) - - manifest = _load_manifest(manifest_path) - mirror_root = manifest.get("mirror_root") - files = manifest.get("files") - if not isinstance(mirror_root, str) or not mirror_root: - raise KeyError("manifest is missing required key: mirror_root") - if not isinstance(files, list): - raise KeyError("manifest is missing required key: files") - - payload = _load_allowlist(allowlist_path) - existing = _normalize_shared_data(payload.get("shared_data", [])) - - generated_rows: list[dict] = [] - mirror_prefix = f"{mirror_root}/" - for row in files: - rel = row["relative_path"] - generated_rows.append( - { - "python_path": f"{mirror_root}/{rel}", - "upstream_repo": args.upstream_repo, - "upstream_path": f"{args.upstream_data_prefix}/{rel}", - "sha256": row["sha256"], - "source_manifest": manifest_path.relative_to(repo_root).as_posix(), - } - ) - - # Drop previous generated entries for this mirror root, keep other legacy/handwritten rows. - retained = [row for row in existing if not row["python_path"].startswith(mirror_prefix)] - combined = retained + generated_rows - - # Deduplicate exact keys, then sort deterministically by python path. - seen: set[tuple[str, str, str]] = set() - deduped: list[dict] = [] - for row in combined: - key = (row["python_path"], row["upstream_path"], row["sha256"]) - if key in seen: - continue - seen.add(key) - deduped.append(row) - deduped.sort(key=lambda row: row["python_path"]) - - out_payload = { - "version": payload.get("version", 1), - "shared_data": deduped, - } - allowlist_path.parent.mkdir(parents=True, exist_ok=True) - allowlist_path.write_text( - yaml.safe_dump(out_payload, sort_keys=False, allow_unicode=False), - encoding="utf-8", - ) - - print(f"Manifest: {manifest_path}") - print(f"Allowlist: {allowlist_path}") - print(f"Generated entries: {len(generated_rows)}") - print(f"Total allowlist entries: {len(deduped)}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) - diff --git a/tools/data/download_example_data.py b/tools/data/download_example_data.py deleted file mode 100644 index 435d7680..00000000 --- a/tools/data/download_example_data.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -"""Download/extract nSTAT example data (if needed) and print resolved data dir.""" - -from __future__ import annotations - -from pathlib import Path - -from nstat.data_manager import ensure_example_data - - -def main() -> int: - path = ensure_example_data(download=True) - print(str(Path(path).resolve())) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) - diff --git a/tools/data/print_data_dir.py b/tools/data/print_data_dir.py deleted file mode 100644 index fd51209d..00000000 --- a/tools/data/print_data_dir.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 -"""Print resolved nSTAT example-data directory.""" - -from __future__ import annotations - -from pathlib import Path - -from nstat.data_manager import get_data_dir - - -def main() -> int: - print(str(Path(get_data_dir()).resolve())) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) - diff --git a/tools/data_mirror/_common.py b/tools/data_mirror/_common.py deleted file mode 100644 index 0eae1ff4..00000000 --- a/tools/data_mirror/_common.py +++ /dev/null @@ -1,113 +0,0 @@ -"""Shared helpers for mirroring MATLAB example data into nSTAT-python.""" - -from __future__ import annotations - -import hashlib -import json -from dataclasses import dataclass -from datetime import datetime, timezone -from pathlib import Path - -FILE_CHUNK_BYTES = 1024 * 1024 - - -@dataclass(frozen=True, slots=True) -class FileEntry: - """Immutable manifest row for one file in a dataset tree.""" - - relative_path: str - size_bytes: int - mtime_epoch_s: float - sha256: str - - -def sha256_file(path: Path) -> str: - """Compute SHA256 digest for a file.""" - - digest = hashlib.sha256() - with path.open("rb") as handle: - for chunk in iter(lambda: handle.read(FILE_CHUNK_BYTES), b""): - digest.update(chunk) - return digest.hexdigest() - - -def iter_files(root: Path) -> list[Path]: - """Return all files under root in deterministic order.""" - - if not root.exists(): - raise FileNotFoundError(f"Root path does not exist: {root}") - if not root.is_dir(): - raise NotADirectoryError(f"Root path is not a directory: {root}") - return sorted(path for path in root.rglob("*") if path.is_file()) - - -def build_inventory(root: Path) -> list[FileEntry]: - """Create full inventory with metadata and checksums.""" - - entries: list[FileEntry] = [] - for path in iter_files(root): - stat = path.stat() - entries.append( - FileEntry( - relative_path=path.relative_to(root).as_posix(), - size_bytes=stat.st_size, - mtime_epoch_s=stat.st_mtime, - sha256=sha256_file(path), - ) - ) - return entries - - -def manifest_dict( - *, - source_root: Path, - mirror_root: str | None, - entries: list[FileEntry], - version: str, - generated_by: str, -) -> dict: - """Build manifest payload.""" - - total_size_bytes = sum(entry.size_bytes for entry in entries) - payload = { - "schema_version": 1, - "dataset_name": "matlab_example_data", - "dataset_version": version, - "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "generated_by": generated_by, - "source_root": str(source_root), - "file_count": len(entries), - "total_size_bytes": total_size_bytes, - "files": [ - { - "relative_path": entry.relative_path, - "size_bytes": entry.size_bytes, - "mtime_epoch_s": entry.mtime_epoch_s, - "sha256": entry.sha256, - } - for entry in entries - ], - } - if mirror_root is not None: - payload["mirror_root"] = mirror_root - return payload - - -def write_manifest(path: Path, payload: dict) -> None: - """Write JSON manifest with stable pretty formatting.""" - - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") - - -def load_manifest(path: Path) -> dict: - """Load and parse manifest JSON.""" - - return json.loads(path.read_text(encoding="utf-8")) - - -def repo_root_from_tools_script(script_path: Path) -> Path: - """Resolve repository root from a script located under tools/*.""" - - return script_path.resolve().parents[2] - diff --git a/tools/data_mirror/build_manifest.py b/tools/data_mirror/build_manifest.py deleted file mode 100644 index 49e1de9c..00000000 --- a/tools/data_mirror/build_manifest.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 -"""Build a frozen checksum manifest for a MATLAB data directory.""" - -from __future__ import annotations - -import argparse -from pathlib import Path - -from _common import build_inventory, manifest_dict, write_manifest - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--source-root", required=True, help="Path to MATLAB data directory.") - parser.add_argument("--version", required=True, help="Dataset version label (for example 20260302).") - parser.add_argument("--out", required=True, help="Manifest output path (JSON).") - parser.add_argument( - "--mirror-root", - default=None, - help="Optional mirror root path to store in manifest (relative or absolute).", - ) - return parser.parse_args() - - -def main() -> int: - args = parse_args() - source_root = Path(args.source_root).expanduser().resolve() - out = Path(args.out).expanduser().resolve() - - entries = build_inventory(source_root) - payload = manifest_dict( - source_root=source_root, - mirror_root=args.mirror_root, - entries=entries, - version=args.version, - generated_by="tools/data_mirror/build_manifest.py", - ) - write_manifest(out, payload) - - print(f"Wrote manifest: {out}") - print(f"Source root: {source_root}") - print(f"Files: {payload['file_count']}") - print(f"Total bytes: {payload['total_size_bytes']}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) - diff --git a/tools/data_mirror/run_mirror_workflow.py b/tools/data_mirror/run_mirror_workflow.py deleted file mode 100644 index b4c66366..00000000 --- a/tools/data_mirror/run_mirror_workflow.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python3 -"""Run the full MATLAB-data mirror workflow in one command. - -Steps: -1. Build source snapshot manifest. -2. Sync source data into mirrored tree. -3. Regenerate shared-data allowlist entries. -4. Regenerate datasets manifest mirror rows. -5. Verify mirrored tree against checksum manifest. -""" - -from __future__ import annotations - -import argparse -import subprocess -from pathlib import Path - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--source-root", required=True, help="Path to MATLAB data directory.") - parser.add_argument("--version", required=True, help="Dataset version label (for example 20260302).") - parser.add_argument( - "--dest-root", - default="data/shared", - help="Destination root for mirrored data (default: data/shared).", - ) - parser.add_argument( - "--allowlist", - default="tools/compliance/shared_data_allowlist.yml", - help="Shared-data allowlist path.", - ) - parser.add_argument( - "--clean", - action="store_true", - help="Delete existing mirrored dataset directory before sync.", - ) - return parser.parse_args() - - -def _run(cmd: list[str], repo_root: Path) -> None: - print(">", " ".join(cmd)) - subprocess.run(cmd, cwd=repo_root, check=True) - - -def main() -> int: - args = parse_args() - repo_root = Path(__file__).resolve().parents[2] - - source_manifest = Path(args.dest_root) / f"matlab_source_{args.version}.manifest.json" - mirror_manifest = Path(args.dest_root) / f"matlab_gold_{args.version}.manifest.json" - - _run( - [ - "python", - "tools/data_mirror/build_manifest.py", - "--source-root", - args.source_root, - "--version", - args.version, - "--out", - source_manifest.as_posix(), - ], - repo_root, - ) - - sync_cmd = [ - "python", - "tools/data_mirror/sync_matlab_data.py", - "--source-root", - args.source_root, - "--version", - args.version, - "--dest-root", - args.dest_root, - ] - if args.clean: - sync_cmd.append("--clean") - _run(sync_cmd, repo_root) - - _run( - [ - "python", - "tools/compliance/update_shared_data_allowlist.py", - "--manifest", - mirror_manifest.as_posix(), - "--allowlist", - args.allowlist, - ], - repo_root, - ) - - _run( - [ - "python", - "tools/compliance/update_datasets_manifest_from_mirror.py", - "--manifest", - mirror_manifest.as_posix(), - "--datasets-manifest", - "data/datasets_manifest.json", - ], - repo_root, - ) - - _run( - [ - "python", - "tools/data_mirror/verify_matlab_data.py", - "--manifest", - mirror_manifest.as_posix(), - "--strict", - ], - repo_root, - ) - - print("Mirror workflow completed successfully.") - print(f"Source manifest: {source_manifest}") - print(f"Mirror manifest: {mirror_manifest}") - print(f"Allowlist: {args.allowlist}") - print("Datasets manifest: data/datasets_manifest.json") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/data_mirror/sync_matlab_data.py b/tools/data_mirror/sync_matlab_data.py deleted file mode 100644 index 0709205f..00000000 --- a/tools/data_mirror/sync_matlab_data.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python3 -"""Mirror MATLAB example data into nSTAT-python and verify exact checksums.""" - -from __future__ import annotations - -import argparse -import shutil -from pathlib import Path - -from _common import ( - build_inventory, - manifest_dict, - repo_root_from_tools_script, - sha256_file, - write_manifest, -) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--source-root", required=True, help="Path to MATLAB data directory.") - parser.add_argument("--version", required=True, help="Dataset version label (for example 20260302).") - parser.add_argument( - "--dest-root", - default="data/shared", - help="Destination root (default: data/shared, relative to repo root).", - ) - parser.add_argument( - "--manifest-out", - default=None, - help="Optional manifest output path (default: /matlab_gold_.manifest.json).", - ) - parser.add_argument( - "--clean", - action="store_true", - help="Delete destination mirror root before syncing.", - ) - return parser.parse_args() - - -def _resolve_dest_root(dest_root_arg: str, repo_root: Path) -> Path: - dest_root = Path(dest_root_arg).expanduser() - if not dest_root.is_absolute(): - dest_root = repo_root / dest_root - return dest_root.resolve() - - -def _remove_empty_dirs(root: Path) -> None: - for path in sorted((p for p in root.rglob("*") if p.is_dir()), reverse=True): - if not any(path.iterdir()): - path.rmdir() - - -def main() -> int: - args = parse_args() - script_path = Path(__file__).resolve() - repo_root = repo_root_from_tools_script(script_path) - source_root = Path(args.source_root).expanduser().resolve() - dest_root = _resolve_dest_root(args.dest_root, repo_root) - - dataset_dirname = f"matlab_gold_{args.version}" - mirror_root = dest_root / dataset_dirname - - if args.clean and mirror_root.exists(): - shutil.rmtree(mirror_root) - - entries = build_inventory(source_root) - expected_paths = {entry.relative_path for entry in entries} - - copied = 0 - skipped = 0 - for entry in entries: - src = source_root / entry.relative_path - dst = mirror_root / entry.relative_path - dst.parent.mkdir(parents=True, exist_ok=True) - - if dst.exists() and sha256_file(dst) == entry.sha256: - skipped += 1 - continue - - shutil.copy2(src, dst) - copied += 1 - - existing_paths = { - path.relative_to(mirror_root).as_posix() - for path in mirror_root.rglob("*") - if path.is_file() - } - extra_paths = sorted(existing_paths - expected_paths) - for rel_path in extra_paths: - (mirror_root / rel_path).unlink() - _remove_empty_dirs(mirror_root) - - # Final checksum verification against source manifest. - mismatches: list[str] = [] - for entry in entries: - dst = mirror_root / entry.relative_path - if not dst.exists(): - mismatches.append(f"missing:{entry.relative_path}") - continue - digest = sha256_file(dst) - if digest != entry.sha256: - mismatches.append(f"hash:{entry.relative_path}") - - if mismatches: - sample = ", ".join(mismatches[:5]) - raise RuntimeError(f"Mirror verification failed ({len(mismatches)} mismatches). Sample: {sample}") - - mirror_root_str: str - try: - mirror_root_str = mirror_root.relative_to(repo_root).as_posix() - except ValueError: - mirror_root_str = str(mirror_root) - - if args.manifest_out is None: - manifest_out = dest_root / f"{dataset_dirname}.manifest.json" - else: - manifest_out = Path(args.manifest_out).expanduser() - if not manifest_out.is_absolute(): - manifest_out = (repo_root / manifest_out).resolve() - - payload = manifest_dict( - source_root=source_root, - mirror_root=mirror_root_str, - entries=entries, - version=args.version, - generated_by="tools/data_mirror/sync_matlab_data.py", - ) - write_manifest(manifest_out, payload) - - print(f"Repo root: {repo_root}") - print(f"Source root: {source_root}") - print(f"Mirror root: {mirror_root}") - print(f"Manifest: {manifest_out}") - print(f"Files verified: {payload['file_count']}") - print(f"Total bytes: {payload['total_size_bytes']}") - print(f"Copied: {copied}") - print(f"Skipped: {skipped}") - print(f"Pruned extra files: {len(extra_paths)}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) - diff --git a/tools/data_mirror/verify_matlab_data.py b/tools/data_mirror/verify_matlab_data.py deleted file mode 100644 index 0145bee7..00000000 --- a/tools/data_mirror/verify_matlab_data.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python3 -"""Verify mirrored MATLAB example data against a checksum manifest.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - -from _common import load_manifest, repo_root_from_tools_script, sha256_file - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--manifest", required=True, help="Path to checksum manifest JSON.") - parser.add_argument( - "--strict", - action=argparse.BooleanOptionalAction, - default=True, - help="When true, also fail on extra files in mirror root.", - ) - parser.add_argument("--report-out", default=None, help="Optional JSON report output path.") - return parser.parse_args() - - -def _resolve_path(path_arg: str, repo_root: Path) -> Path: - path = Path(path_arg).expanduser() - if not path.is_absolute(): - path = repo_root / path - return path.resolve() - - -def _git_lfs_oid(path: Path) -> str | None: - try: - text = path.read_text(encoding="utf-8") - except UnicodeDecodeError: - return None - lines = [line.strip() for line in text.splitlines()] - if not lines or not lines[0].startswith("version https://git-lfs.github.com/spec"): - return None - for line in lines: - if line.startswith("oid sha256:"): - return line.split("oid sha256:", 1)[1].strip() - return None - - -def main() -> int: - args = parse_args() - repo_root = repo_root_from_tools_script(Path(__file__).resolve()) - manifest_path = _resolve_path(args.manifest, repo_root) - manifest = load_manifest(manifest_path) - - mirror_root_raw = manifest.get("mirror_root") - if not mirror_root_raw: - raise KeyError("Manifest is missing required key: mirror_root") - - mirror_root = _resolve_path(str(mirror_root_raw), repo_root) - files = manifest.get("files", []) - - missing: list[str] = [] - size_mismatch: list[str] = [] - hash_mismatch: list[str] = [] - - expected = set() - for row in files: - rel_path = row["relative_path"] - expected.add(rel_path) - target = mirror_root / rel_path - if not target.exists(): - missing.append(rel_path) - continue - expected_size = int(row["size_bytes"]) - expected_sha = str(row["sha256"]) - if target.stat().st_size != expected_size: - lfs_oid = _git_lfs_oid(target) - if lfs_oid == expected_sha: - # LFS pointer checkout: allow size mismatch when pointer OID - # matches the manifest's content digest. - continue - size_mismatch.append(rel_path) - continue - digest = sha256_file(target) - if digest != expected_sha: - hash_mismatch.append(rel_path) - - extra: list[str] = [] - if args.strict and mirror_root.exists(): - observed = { - path.relative_to(mirror_root).as_posix() - for path in mirror_root.rglob("*") - if path.is_file() - } - extra = sorted(observed - expected) - - report = { - "manifest": str(manifest_path), - "mirror_root": str(mirror_root), - "strict": args.strict, - "expected_file_count": len(files), - "missing_count": len(missing), - "size_mismatch_count": len(size_mismatch), - "hash_mismatch_count": len(hash_mismatch), - "extra_count": len(extra), - "missing": missing, - "size_mismatch": size_mismatch, - "hash_mismatch": hash_mismatch, - "extra": extra, - } - - if args.report_out: - out_path = _resolve_path(args.report_out, repo_root) - out_path.parent.mkdir(parents=True, exist_ok=True) - out_path.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8") - - print(f"Manifest: {manifest_path}") - print(f"Mirror root: {mirror_root}") - print(f"Expected files: {len(files)}") - print(f"Missing: {len(missing)}") - print(f"Size mismatches: {len(size_mismatch)}") - print(f"Hash mismatches: {len(hash_mismatch)}") - print(f"Extra files: {len(extra)}") - - has_errors = bool(missing or size_mismatch or hash_mismatch or extra) - return 1 if has_errors else 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/docs/generate_help_pages.py b/tools/docs/generate_help_pages.py deleted file mode 100644 index d7b498c8..00000000 --- a/tools/docs/generate_help_pages.py +++ /dev/null @@ -1,367 +0,0 @@ -#!/usr/bin/env python3 -"""Generate clean-room help pages, TOC, and cross-links for nSTAT-python.""" - -from __future__ import annotations - -import json -from pathlib import Path - -import yaml - - -REPO_NOTEBOOK_BASE = "https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks" -PAPER_OVERVIEW = "../paper_overview.md" -API_PAGE = "../../api.md" -REPO_PARITY_BASE = "https://github.com/cajigaslab/nSTAT-python/blob/main/parity" - - -CLASS_MAP = [ - ("SignalObj", "nstat.signal.Signal"), - ("Covariate", "nstat.signal.Covariate"), - ("ConfidenceInterval", "nstat.confidence.ConfidenceInterval"), - ("Events", "nstat.events.Events"), - ("History", "nstat.history.HistoryBasis"), - ("nspikeTrain", "nstat.spikes.SpikeTrain"), - ("nstColl", "nstat.spikes.SpikeTrainCollection"), - ("CovColl", "nstat.trial.CovariateCollection"), - ("TrialConfig", "nstat.trial.TrialConfig"), - ("ConfigColl", "nstat.trial.ConfigCollection"), - ("Trial", "nstat.trial.Trial"), - ("CIF", "nstat.cif.CIFModel"), - ("Analysis", "nstat.analysis.Analysis"), - ("FitResult", "nstat.fit.FitResult"), - ("FitResSummary", "nstat.fit.FitSummary"), - ("DecodingAlgorithms", "nstat.decoding.DecodingAlgorithms"), -] - -CLASS_NOTEBOOKS = { - "SignalObj": ["SignalObjExamples", "AnalysisExamples"], - "Covariate": ["CovariateExamples", "TrialExamples"], - "ConfidenceInterval": ["DecodingExample", "FitResSummaryExamples"], - "Events": ["EventsExamples", "NetworkTutorial"], - "History": ["HistoryExamples", "DecodingExampleWithHist"], - "nspikeTrain": ["nSpikeTrainExamples", "PPSimExample"], - "nstColl": ["nstCollExamples", "TrialExamples"], - "CovColl": ["CovCollExamples", "TrialExamples"], - "TrialConfig": ["TrialConfigExamples", "AnalysisExamples"], - "ConfigColl": ["ConfigCollExamples", "AnalysisExamples"], - "Trial": ["TrialExamples", "AnalysisExamples"], - "CIF": ["PPSimExample", "PPThinning"], - "Analysis": ["AnalysisExamples", "nSTATPaperExamples"], - "FitResult": ["FitResultExamples", "nSTATPaperExamples"], - "FitResSummary": ["FitResSummaryExamples", "nSTATPaperExamples"], - "DecodingAlgorithms": ["DecodingExample", "StimulusDecode2D"], -} - - -def write_text(path: Path, content: str) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(content, encoding="utf-8") - - -def _read_json(path: Path) -> dict: - if not path.exists(): - return {} - return json.loads(path.read_text(encoding="utf-8")) - - -def _read_yaml(path: Path) -> dict: - if not path.exists(): - return {} - payload = yaml.safe_load(path.read_text(encoding="utf-8")) - return payload or {} - - -def _latest_snapshot(parity_root: Path) -> Path | None: - candidates = sorted(parity_root.glob("matlab_gold_snapshot_*.yml")) - if not candidates: - return None - return candidates[-1] - - -def generate_class_page(help_root: Path, matlab_name: str, python_target: str) -> None: - related = CLASS_NOTEBOOKS.get(matlab_name, []) - related_lines = "\n".join( - line - for topic in related - for line in [ - f"- [{topic} notebook]({REPO_NOTEBOOK_BASE}/{topic}.ipynb)", - f"- [{topic} help page](../examples/{topic}.md)", - ] - ) - - if not related_lines: - related_lines = "- See [Examples Index](../examples_index.md)." - - content = f"""# {matlab_name} - -Python implementation: `{python_target}` - -## Purpose -This class preserves MATLAB-facing structure while using a Python-native, -fully independent implementation in `nSTAT-python`. - -## References -- [API reference]({API_PAGE}) -- [Paper overview]({PAPER_OVERVIEW}) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` - -## Related learning resources -{related_lines} -""" - write_text(help_root / "classes" / f"{matlab_name}.md", content) - - -def generate_example_page(help_root: Path, topic: str, run_group: str) -> None: - content = f"""# {topic} - -Python-native tutorial page for `{topic}`. - -## Notebook -- [{topic}.ipynb]({REPO_NOTEBOOK_BASE}/{topic}.ipynb) -- Execution group: `{run_group}` - -## Linked references -- [Examples index](../examples_index.md) -- [Class definitions](../class_definitions.md) -- [Paper overview](../paper_overview.md) -- DOI: `10.1016/j.jneumeth.2012.08.009` -- PMID: `22981419` -""" - write_text(help_root / "examples" / f"{topic}.md", content) - - -def generate_examples_index(help_root: Path, topics: list[str]) -> None: - links = "\n".join([f"- [{topic}](examples/{topic}.md)" for topic in topics]) - content = f"""# Examples Index - -The topics below map clean-room Python workflows to executable notebooks. - -{links} - -All notebooks are available in the repository's `notebooks/` directory and are -validated in CI. -""" - write_text(help_root / "examples_index.md", content) - - -def generate_class_definitions(help_root: Path) -> None: - rows = "\n".join( - [f"| {matlab_name} | {python_target} |" for matlab_name, python_target in CLASS_MAP] - ) - content = f"""# Class Definitions - -Each MATLAB nSTAT class has a corresponding Python help page and implementation. - -| MATLAB class | Python target | -|---|---| -{rows} -""" - write_text(help_root / "class_definitions.md", content) - - -def generate_help_toc(help_root: Path, topics: list[str]) -> None: - entries: dict[str, object] = { - "root": "help/index.md", - "entries": [ - {"title": "Home", "target": "help/index.md"}, - {"title": "Class Definitions", "target": "help/class_definitions.md"}, - {"title": "Examples Index", "target": "help/examples_index.md"}, - {"title": "Paper Overview", "target": "help/paper_overview.md"}, - {"title": "Parity Dashboard", "target": "help/parity_dashboard.md"}, - { - "title": "Classes", - "children": [ - { - "title": matlab_name, - "target": f"help/classes/{matlab_name}.md", - } - for matlab_name, _ in CLASS_MAP - ], - }, - { - "title": "Examples", - "children": [ - { - "title": topic, - "target": f"help/examples/{topic}.md", - } - for topic in topics - ], - }, - ], - } - write_text(help_root / "helptoc.yml", yaml.safe_dump(entries, sort_keys=False)) - - -def generate_help_home(help_root: Path, topics: list[str]) -> None: - class_refs = "\n".join([f"classes/{matlab_name}" for matlab_name, _ in CLASS_MAP]) - topic_refs = "\n".join([f"examples/{topic}" for topic in topics]) - - content = f"""# nSTAT-python Help Home - -Welcome to the clean-room Python help system for `nSTAT-python`. - -This site preserves class/workflow structure of MATLAB nSTAT while keeping -all implementation, docs, and tooling Python-specific. - -## Navigation -- [Class Definitions](class_definitions.md) -- [Examples Index](examples_index.md) -- [Paper Overview](paper_overview.md) -- [Parity Dashboard](parity_dashboard.md) - -```{{toctree}} -:maxdepth: 2 - -class_definitions -examples_index -paper_overview -parity_dashboard -{class_refs} -{topic_refs} -``` -""" - write_text(help_root / "index.md", content) - - -def generate_parity_dashboard(help_root: Path, repo_root: Path) -> None: - parity_root = repo_root / "parity" - gap = _read_json(parity_root / "parity_gap_report.json").get("summary", {}) - functional = _read_json(parity_root / "function_example_alignment_report.json") - numeric = _read_json(parity_root / "numeric_drift_report.json").get("summary", {}) - example_spec = _read_yaml(parity_root / "example_output_spec.yml") - snapshot_path = _latest_snapshot(parity_root) - snapshot = _read_yaml(snapshot_path) if snapshot_path is not None else {} - - method_summary = functional.get("method_functional_audit", {}).get("summary", {}) - example_summary = functional.get("example_line_alignment_audit", {}).get("summary", {}) - out_of_scope_topics = example_spec.get("out_of_scope_topics", []) - - snapshot_name = snapshot_path.name if snapshot_path is not None else "-" - snapshot_id = snapshot.get("snapshot_id", "-") - snapshot_date = snapshot.get("captured_on", "-") - source_sha = snapshot.get("source", {}).get("manifest_sha256", "-") - mirror_sha = snapshot.get("mirror", {}).get("manifest_sha256", "-") - mirror_count = snapshot.get("mirror", {}).get("file_count", "-") - - oos_lines = "\n".join([f"- `{topic}`" for topic in out_of_scope_topics]) or "- None" - - content = f"""# Parity Dashboard - -This dashboard summarizes current MATLAB-to-Python parity status from generated -artifacts in the `parity/` directory. - -## Structural parity -| Metric | Value | -|---|---:| -| High gaps | {int(gap.get("high", 0))} | -| Medium gaps | {int(gap.get("medium", 0))} | -| Low gaps | {int(gap.get("low", 0))} | -| Total gaps | {int(gap.get("total", 0))} | - -## Functional parity (methods) -| Metric | Value | -|---|---:| -| Total methods | {int(method_summary.get("total_methods", 0))} | -| Contract-verified | {int(method_summary.get("contract_verified_methods", 0))} | -| Contract-explicit verified | {int(method_summary.get("contract_explicit_verified_methods", 0))} | -| Probe-verified | {int(method_summary.get("probe_verified_methods", 0))} | -| Excluded methods | {int(method_summary.get("excluded_methods", 0))} | -| Missing symbols | {int(method_summary.get("missing_symbol_methods", 0))} | -| Unverified behavior | {int(method_summary.get("unverified_behavior_methods", 0))} | - -## Example parity -| Metric | Value | -|---|---:| -| Total topics | {int(example_summary.get("total_topics", 0))} | -| Validated topics | {int(example_summary.get("validated_topics", 0))} | -| MATLAB doc-only topics | {int(example_summary.get("matlab_doc_only_topics", 0))} | -| Pending manual review topics | {int(example_summary.get("pending_manual_review_topics", 0))} | -| Missing executable topics | {int(example_summary.get("missing_executable_topics", 0))} | - -### Out-of-scope example topics -{oos_lines} - -## Numeric drift -| Metric | Value | -|---|---:| -| Topics checked | {int(numeric.get("topics", 0))} | -| Required notebook topics | {int(numeric.get("required_topics", 0))} | -| Required topics checked | {int(numeric.get("required_topics_checked", 0))} | -| Topics passed | {int(numeric.get("passed_topics", 0))} | -| Topics failed | {int(numeric.get("failed_topics", 0))} | -| Metrics checked | {int(numeric.get("checked_metrics", 0))} | -| Metrics failed | {int(numeric.get("failed_metrics", 0))} | - -## Frozen MATLAB data snapshot -| Metric | Value | -|---|---| -| Snapshot file | `{snapshot_name}` | -| Snapshot id | `{snapshot_id}` | -| Snapshot date | `{snapshot_date}` | -| Mirror file count | `{mirror_count}` | -| Source manifest SHA256 | `{source_sha}` | -| Mirror manifest SHA256 | `{mirror_sha}` | - -## Artifact links -- [parity_gap_report.json]({REPO_PARITY_BASE}/parity_gap_report.json) -- [function_example_alignment_report.json]({REPO_PARITY_BASE}/function_example_alignment_report.json) -- [numeric_drift_report.json]({REPO_PARITY_BASE}/numeric_drift_report.json) -- [example_output_spec.yml]({REPO_PARITY_BASE}/example_output_spec.yml) -- [method_closure_sprint.md]({REPO_PARITY_BASE}/method_closure_sprint.md) -- [Full validation report PDF](../assets/reports/nstat_python_validation_report_full_latest.pdf) -""" - write_text(help_root / "parity_dashboard.md", content) - - -def generate_notebook_index(repo_root: Path, manifest_rows: list[dict[str, str]]) -> None: - lines = [] - for row in manifest_rows: - topic = row["topic"] - run_group = row["run_group"] - notebook_url = f"{REPO_NOTEBOOK_BASE}/{topic}.ipynb" - lines.append(f"- [{topic}.ipynb]({notebook_url}) (`{run_group}`)") - - content = ( - "# Notebook Catalog\n\n" - "The notebooks below are generated from a clean-room manifest and executed in CI.\n\n" - + "\n".join(lines) - + "\n" - ) - write_text(repo_root / "docs" / "notebooks.md", content) - - -def main() -> int: - repo_root = Path(__file__).resolve().parents[2] - help_root = repo_root / "docs" / "help" - notebook_manifest = repo_root / "tools" / "notebooks" / "notebook_manifest.yml" - - manifest = yaml.safe_load(notebook_manifest.read_text(encoding="utf-8")) - rows = manifest["notebooks"] - topics = [row["topic"] for row in rows] - run_group = {row["topic"]: row["run_group"] for row in rows} - - for matlab_name, python_target in CLASS_MAP: - generate_class_page(help_root=help_root, matlab_name=matlab_name, python_target=python_target) - - for topic in topics: - generate_example_page(help_root=help_root, topic=topic, run_group=run_group[topic]) - - generate_examples_index(help_root=help_root, topics=topics) - generate_class_definitions(help_root=help_root) - generate_help_toc(help_root=help_root, topics=topics) - generate_help_home(help_root=help_root, topics=topics) - generate_parity_dashboard(help_root=help_root, repo_root=repo_root) - generate_notebook_index(repo_root=repo_root, manifest_rows=rows) - - mapping = {"classes": [{"matlab": m, "python": p} for m, p in CLASS_MAP], "topics": topics} - write_text(repo_root / "baseline" / "help_mapping.json", json.dumps(mapping, indent=2) + "\n") - - print("Generated help pages, TOC, and mapping artifacts.") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/docs/verify_search_index.py b/tools/docs/verify_search_index.py deleted file mode 100755 index 64e6bc5d..00000000 --- a/tools/docs/verify_search_index.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 -"""Verify Sphinx search index includes key nSTAT help topics/classes.""" - -from __future__ import annotations - -import argparse -from pathlib import Path - -import yaml - - -REQUIRED_CLASS_TOKENS = [ - "signalobj", - "covariate", - "confidenceinterval", - "events", - "history", - "nspiketrain", - "nstcoll", - "covcoll", - "trialconfig", - "configcoll", - "trial", - "cif", - "analysis", - "fitresult", - "fitressummary", - "decodingalgorithms", -] - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--search-index", - type=Path, - default=Path("docs/_build/html/searchindex.js"), - help="Path to built Sphinx searchindex.js", - ) - parser.add_argument( - "--notebook-manifest", - type=Path, - default=Path("tools/notebooks/notebook_manifest.yml"), - help="Notebook manifest for expected example topics", - ) - return parser.parse_args() - - - -def main() -> int: - args = parse_args() - - if not args.search_index.exists(): - raise FileNotFoundError( - f"search index not found: {args.search_index}. Build docs first with sphinx-build." - ) - - payload = args.search_index.read_text(encoding="utf-8").lower() - manifest = yaml.safe_load(args.notebook_manifest.read_text(encoding="utf-8")) - - required_topics = [row["topic"].lower() for row in manifest["notebooks"]] - required_tokens = sorted(set(REQUIRED_CLASS_TOKENS + required_topics)) - - missing = [token for token in required_tokens if token not in payload] - if missing: - print("Search index verification FAILED.") - for token in missing: - print(f" - missing token: {token}") - return 1 - - print( - "Search index verification PASSED " - f"({len(required_tokens)} class/topic tokens found in search index)." - ) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/generate_repo_split_inventory.py b/tools/generate_repo_split_inventory.py new file mode 100644 index 00000000..b066444b --- /dev/null +++ b/tools/generate_repo_split_inventory.py @@ -0,0 +1,187 @@ +from __future__ import annotations + +import json +import xml.etree.ElementTree as ET +from datetime import datetime, timezone +from pathlib import Path + +PY_ROOT = Path(__file__).resolve().parents[1] +REPO_ROOT = PY_ROOT if (PY_ROOT / "helpfiles").exists() else PY_ROOT.parent +HELPFILES_ROOT = REPO_ROOT / "helpfiles" +TOC_PATH = HELPFILES_ROOT / "helptoc.xml" +OUT_ROOT = PY_ROOT / "reports" / "repo_split_inventory" + + +def _utc_now() -> str: + return datetime.now(timezone.utc).replace(microsecond=0).isoformat() + + +def _slugify(value: str) -> str: + out = [] + for ch in value.strip().lower(): + if ch.isalnum(): + out.append(ch) + return "".join(out) + + +def _iter_toc_targets() -> list[dict[str, str]]: + tree = ET.parse(TOC_PATH) + root = tree.getroot() + + examples_node = None + for item in root.iter("tocitem"): + if item.attrib.get("id") == "nstat_examples": + examples_node = item + break + + example_stems: set[str] = set() + if examples_node is not None: + for item in examples_node.findall("tocitem"): + target = item.attrib.get("target", "").strip() + if target: + example_stems.add(Path(target).stem) + + rows: list[dict[str, str]] = [] + seen: set[str] = set() + for item in root.iter("tocitem"): + target = item.attrib.get("target", "").strip() + if not target: + continue + if target.startswith("http://") or target.startswith("https://"): + continue + stem = Path(target).stem + key = f"{stem}|{target}" + if key in seen: + continue + seen.add(key) + rows.append( + { + "title": " ".join((item.text or "").split()) or stem, + "target": target, + "stem": stem, + "is_example_topic": stem in example_stems, + } + ) + return rows + + +def _file_stem_set(paths: list[Path], exclude_dunder: bool = False) -> set[str]: + out: set[str] = set() + for p in paths: + stem = p.stem + if exclude_dunder and stem.startswith("__"): + continue + out.add(stem) + return out + + +def _write_json(path: Path, payload: dict | list) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(payload, indent=2), encoding="utf-8") + + +def main() -> int: + if not TOC_PATH.exists(): + raise FileNotFoundError(f"Missing TOC file: {TOC_PATH}") + + toc_rows = _iter_toc_targets() + toc_stems = {row["stem"] for row in toc_rows} + example_stems = {row["stem"] for row in toc_rows if row["is_example_topic"]} + + matlab_m = sorted(HELPFILES_ROOT.glob("*.m")) + matlab_mlx = sorted(HELPFILES_ROOT.glob("*.mlx")) + matlab_html = sorted(HELPFILES_ROOT.glob("*.html")) + + matlab_m_stems = _file_stem_set(matlab_m) + matlab_mlx_stems = _file_stem_set(matlab_mlx) + matlab_html_stems = _file_stem_set(matlab_html) + + py_docs_topics = sorted((PY_ROOT / "docs" / "topics").glob("*.rst")) + py_nb_topics = sorted((PY_ROOT / "notebooks" / "helpfiles").glob("*.ipynb")) + py_example_topics = sorted((PY_ROOT / "examples" / "help_topics").glob("*.py")) + + py_doc_stems = _file_stem_set(py_docs_topics) + py_nb_stems = _file_stem_set(py_nb_topics) + py_example_stems = _file_stem_set(py_example_topics, exclude_dunder=True) + py_doc_slugs = {_slugify(s) for s in py_doc_stems} + + coverage_rows: list[dict[str, object]] = [] + for row in sorted(toc_rows, key=lambda r: r["stem"]): + stem = row["stem"] + stem_slug = _slugify(stem) + coverage_rows.append( + { + **row, + "matlab_m_exists": stem in matlab_m_stems, + "matlab_mlx_exists": stem in matlab_mlx_stems, + "matlab_html_exists": stem in matlab_html_stems, + "python_doc_exists": stem_slug in py_doc_slugs, + "python_notebook_exists": stem in py_nb_stems, + "python_example_script_exists": stem in py_example_stems, + } + ) + + example_rows = [r for r in coverage_rows if bool(r["is_example_topic"])] + example_all_python_ok = [ + r + for r in example_rows + if bool(r["python_doc_exists"]) + and bool(r["python_notebook_exists"]) + and bool(r["python_example_script_exists"]) + ] + matlab_example_has_mlx = [r for r in example_rows if bool(r["matlab_mlx_exists"])] + + summary = { + "generated_at_utc": _utc_now(), + "repo_root": str(REPO_ROOT), + "toc_target_topics": len(toc_rows), + "toc_example_topics": len(example_rows), + "matlab_files": { + "m": len(matlab_m), + "mlx": len(matlab_mlx), + "html": len(matlab_html), + }, + "python_assets": { + "docs_topics_rst": len(py_docs_topics), + "notebooks_ipynb": len(py_nb_topics), + "example_scripts_py": len(py_example_topics), + }, + "coverage_counts": { + "toc_topics_with_python_docs": sum(1 for r in coverage_rows if bool(r["python_doc_exists"])), + "toc_topics_with_python_notebooks": sum(1 for r in coverage_rows if bool(r["python_notebook_exists"])), + "toc_topics_with_python_example_scripts": sum( + 1 for r in coverage_rows if bool(r["python_example_script_exists"]) + ), + "example_topics_full_python_coverage": len(example_all_python_ok), + "example_topics_with_matlab_mlx": len(matlab_example_has_mlx), + }, + "example_topic_stems_from_toc": sorted(example_stems), + "python_only_topic_stems_not_in_toc": sorted(py_example_stems - toc_stems), + } + + _write_json(OUT_ROOT / "summary.json", summary) + _write_json(OUT_ROOT / "topic_coverage_matrix.json", coverage_rows) + _write_json( + OUT_ROOT / "split_readiness_gates.json", + { + "python_example_topics_expected": len(example_rows), + "python_example_topics_ready": len(example_all_python_ok), + "python_example_topics_missing_coverage": [ + r["stem"] for r in example_rows if r not in example_all_python_ok + ], + "matlab_example_topics_expected": len(example_rows), + "matlab_example_topics_with_mlx": len(matlab_example_has_mlx), + "matlab_example_topics_missing_mlx": [ + r["stem"] for r in example_rows if not bool(r["matlab_mlx_exists"]) + ], + "pass": len(example_rows) == len(example_all_python_ok) and len(example_rows) == len(matlab_example_has_mlx), + }, + ) + + print(json.dumps(summary, indent=2)) + print(f"wrote={OUT_ROOT}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/notebooks/clean_notebooks.py b/tools/notebooks/clean_notebooks.py deleted file mode 100644 index cc76532d..00000000 --- a/tools/notebooks/clean_notebooks.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python3 -"""Normalize notebooks to executable code-only form for deterministic CI runs.""" - -from __future__ import annotations - -import argparse -import re -from pathlib import Path - -import nbformat -import yaml - - -FORBIDDEN_PREFIXES = ("%", "!") -MAGIC_RE = re.compile(r"^\s*%") -SHELL_RE = re.compile(r"^\s*!") - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--manifest", - type=Path, - default=Path(__file__).resolve().parent / "notebook_manifest.yml", - help="Notebook manifest path.", - ) - parser.add_argument( - "--repo-root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="Repository root.", - ) - parser.add_argument( - "--check", - action="store_true", - help="Exit non-zero if any notebook requires normalization.", - ) - return parser.parse_args() - - -def _sanitize_code(source: str) -> str: - sanitized: list[str] = [] - inserted_agg = False - for line in source.splitlines(): - stripped = line.lstrip() - if stripped.startswith("%matplotlib"): - if not inserted_agg: - sanitized.append('import matplotlib') - sanitized.append('matplotlib.use("Agg")') - inserted_agg = True - continue - if MAGIC_RE.match(line) or SHELL_RE.match(line): - continue - sanitized.append(line.rstrip()) - # Keep explicit trailing newline for stable notebook diffs. - out = "\n".join(sanitized).strip("\n") - return (out + "\n") if out else "" - - -def _normalize_notebook(path: Path) -> bool: - before = path.read_text(encoding="utf-8") - nb = nbformat.read(path, as_version=4) - - new_cells = [] - for cell in nb.cells: - if cell.get("cell_type") != "code": - continue - source = _sanitize_code(str(cell.get("source", ""))) - if not source.strip(): - continue - cell["source"] = source - cell["outputs"] = [] - cell["execution_count"] = None - cell["metadata"] = {} - new_cells.append(cell) - - nb.cells = new_cells - keep = {"kernelspec", "language_info", "nstat"} - nb.metadata = {k: v for k, v in nb.metadata.items() if k in keep} - - after = nbformat.writes(nb) - if after != before: - path.write_text(after, encoding="utf-8") - return True - return False - - -def _manifest_notebooks(manifest: Path, repo_root: Path) -> list[Path]: - payload = yaml.safe_load(manifest.read_text(encoding="utf-8")) or {} - out: list[Path] = [] - for row in payload.get("notebooks", []): - out.append(repo_root / str(row["file"])) - return out - - -def main() -> int: - args = parse_args() - changed = 0 - notebooks = _manifest_notebooks(args.manifest, args.repo_root) - for path in notebooks: - if not path.exists(): - raise FileNotFoundError(f"Notebook missing from manifest: {path}") - if _normalize_notebook(path): - changed += 1 - print(f"Normalized {path}") - - print(f"Notebook normalization complete. changed={changed} total={len(notebooks)}") - if args.check and changed > 0: - return 1 - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) - diff --git a/tools/notebooks/execute_notebooks.py b/tools/notebooks/execute_notebooks.py deleted file mode 100644 index 786b6fbc..00000000 --- a/tools/notebooks/execute_notebooks.py +++ /dev/null @@ -1,290 +0,0 @@ -#!/usr/bin/env python3 -"""Execute notebooks deterministically and emit a machine-readable report.""" - -from __future__ import annotations - -import argparse -import base64 -import json -import os -import time -from dataclasses import dataclass -from datetime import datetime, timezone -from pathlib import Path - -import nbformat -import yaml -from nbclient import NotebookClient - - -THREAD_ENV = ( - "OMP_NUM_THREADS", - "MKL_NUM_THREADS", - "OPENBLAS_NUM_THREADS", - "NUMEXPR_NUM_THREADS", -) - - -@dataclass(frozen=True, slots=True) -class NotebookTarget: - topic: str - path: Path - run_group: str - expected_figures: int | None = None - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--manifest", - type=Path, - default=Path(__file__).resolve().parent / "notebook_manifest.yml", - help="Notebook manifest path.", - ) - parser.add_argument( - "--repo-root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="Repository root.", - ) - parser.add_argument( - "--group", - choices=["smoke", "full", "all"], - default="smoke", - help="Execution group from notebook manifest.", - ) - parser.add_argument( - "--timeout", - type=int, - default=600, - help="Per-cell timeout in seconds.", - ) - parser.add_argument( - "--startup-timeout", - type=int, - default=180, - help="Kernel startup timeout in seconds.", - ) - parser.add_argument( - "--max-notebooks", - type=int, - default=0, - help="Optional cap on executed notebooks (0 means all selected).", - ) - parser.add_argument( - "--out-report", - type=Path, - default=Path("output/notebooks/notebook_execution_report.json"), - help="JSON report output path.", - ) - parser.add_argument( - "--executed-dir", - type=Path, - default=Path("output/notebooks/executed"), - help="Directory for executed notebook copies and extracted images.", - ) - parser.add_argument( - "--write-executed", - action="store_true", - help="Persist executed notebooks under --executed-dir.", - ) - return parser.parse_args() - - -def _set_deterministic_env() -> None: - for key in THREAD_ENV: - os.environ.setdefault(key, "1") - os.environ.setdefault("MPLBACKEND", "Agg") - os.environ.setdefault("PYTHONHASHSEED", "0") - os.environ.setdefault("PYDEVD_DISABLE_FILE_VALIDATION", "1") - - -def _load_targets(manifest_path: Path, repo_root: Path) -> list[NotebookTarget]: - payload = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) or {} - figure_manifest_path = repo_root / "parity" / "helpfile_figure_manifest.json" - figure_expected: dict[str, int] = {} - if figure_manifest_path.exists(): - try: - fig_payload = json.loads(figure_manifest_path.read_text(encoding="utf-8")) - topics = fig_payload.get("topics", {}) - for topic, row in topics.items(): - if not isinstance(row, dict): - continue - figure_expected[str(topic)] = int(row.get("total_figures_expected", 0)) - except Exception: # noqa: BLE001 - figure_expected = {} - targets: list[NotebookTarget] = [] - for row in payload.get("notebooks", []): - topic = str(row["topic"]) - targets.append( - NotebookTarget( - topic=topic, - path=repo_root / str(row["file"]), - run_group=str(row["run_group"]), - expected_figures=figure_expected.get(topic), - ) - ) - return targets - - -def _select_targets(targets: list[NotebookTarget], group: str, max_notebooks: int) -> list[NotebookTarget]: - if group in {"full", "all"}: - selected = targets - else: - selected = [target for target in targets if target.run_group == "smoke"] - if max_notebooks > 0: - return selected[:max_notebooks] - return selected - - -def _extract_images(notebook: nbformat.NotebookNode, image_dir: Path) -> list[Path]: - image_dir.mkdir(parents=True, exist_ok=True) - out: list[Path] = [] - image_idx = 0 - for cell_idx, cell in enumerate(notebook.cells): - if cell.get("cell_type") != "code": - continue - for out_idx, output in enumerate(cell.get("outputs", [])): - data = output.get("data", {}) - if not isinstance(data, dict) or "image/png" not in data: - continue - blob = data["image/png"] - if isinstance(blob, str): - raw = base64.b64decode(blob.encode("utf-8")) - else: - continue - path = image_dir / f"cell{cell_idx:03d}_out{out_idx:03d}_{image_idx:03d}.png" - path.write_bytes(raw) - out.append(path) - image_idx += 1 - return out - - -def _execute_one( - target: NotebookTarget, - timeout: int, - startup_timeout: int, - executed_dir: Path, - write_executed: bool, - repo_root: Path, -) -> dict[str, object]: - notebook = nbformat.read(target.path, as_version=4) - start = time.perf_counter() - error = "" - image_paths: list[Path] = [] - ok = True - - try: - client = NotebookClient( - notebook, - timeout=timeout, - startup_timeout=startup_timeout, - kernel_name="python3", - resources={"metadata": {"path": str(target.path.parent)}}, - ) - client.execute() - tracker_dir = repo_root / "output" / "notebook_images" / target.topic - tracker_images = sorted(tracker_dir.glob("fig_*.png")) - if target.expected_figures is not None: - image_paths = tracker_images - else: - if tracker_images: - image_paths = tracker_images - else: - image_paths = _extract_images(notebook, executed_dir / target.topic / "images") - if target.expected_figures is not None and target.expected_figures >= 0: - if len(image_paths) != int(target.expected_figures): - raise AssertionError( - f"{target.topic}: expected {int(target.expected_figures)} figure(s), " - f"found {len(image_paths)}" - ) - if write_executed: - out_nb = executed_dir / target.topic / target.path.name - out_nb.parent.mkdir(parents=True, exist_ok=True) - nbformat.write(notebook, out_nb) - except Exception as exc: # noqa: BLE001 - ok = False - error = f"{type(exc).__name__}: {exc}" - - elapsed = time.perf_counter() - start - return { - "topic": target.topic, - "path": str(target.path), - "run_group": target.run_group, - "executed_ok": ok, - "duration_s": elapsed, - "image_count": len(image_paths), - "image_paths": [str(path) for path in image_paths], - "error": error, - } - - -def main() -> int: - args = parse_args() - _set_deterministic_env() - - selected = _select_targets(_load_targets(args.manifest, args.repo_root), args.group, args.max_notebooks) - if not selected: - raise RuntimeError(f"No notebooks selected for group={args.group}") - - start = time.perf_counter() - rows: list[dict[str, object]] = [] - for target in selected: - if not target.path.exists(): - rows.append( - { - "topic": target.topic, - "path": str(target.path), - "run_group": target.run_group, - "executed_ok": False, - "duration_s": 0.0, - "image_count": 0, - "image_paths": [], - "error": "FileNotFoundError: notebook path missing", - } - ) - continue - print(f"Executing [{target.run_group}] {target.topic}: {target.path}") - rows.append( - _execute_one( - target=target, - timeout=args.timeout, - startup_timeout=args.startup_timeout, - executed_dir=args.executed_dir, - write_executed=args.write_executed, - repo_root=args.repo_root, - ) - ) - - total_time = time.perf_counter() - start - failed = [row for row in rows if not bool(row["executed_ok"])] - report = { - "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "group": args.group, - "max_notebooks": int(args.max_notebooks), - "summary": { - "total": len(rows), - "passed": len(rows) - len(failed), - "failed": len(failed), - "duration_s": total_time, - }, - "environment": {key: os.environ.get(key, "") for key in THREAD_ENV}, - "reports": rows, - } - - args.out_report.parent.mkdir(parents=True, exist_ok=True) - args.out_report.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8") - print(f"Wrote notebook execution report: {args.out_report}") - - if failed: - print("Notebook execution failures:") - for row in failed: - print(f" - {row['topic']}: {row['error']}") - return 1 - - print(f"Notebook execution passed for {len(rows)} notebook(s).") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/notebooks/generate_helpfile_notebooks.py b/tools/notebooks/generate_helpfile_notebooks.py old mode 100755 new mode 100644 index e771e3ed..27ec6746 --- a/tools/notebooks/generate_helpfile_notebooks.py +++ b/tools/notebooks/generate_helpfile_notebooks.py @@ -1,72 +1,66 @@ #!/usr/bin/env python3 -"""Generate helpfile-aligned notebooks with strict MATLAB section-to-cell mapping. - -Rules: -- Split each MATLAB helpfile on section markers (%%), treating pre-%% content as section 1. -- Emit exactly one Jupyter *code* cell per MATLAB section. -- Preserve section order. -- Keep narrative as Python comments inside each section code cell. -""" +"""Generate help notebooks directly from MATLAB .m/.mlx sources.""" from __future__ import annotations import argparse -import hashlib -import importlib.util import json -import os import re -import subprocess -import sys +import textwrap +import xml.etree.ElementTree as ET from dataclasses import dataclass from pathlib import Path -from typing import Any +from zipfile import ZipFile import nbformat as nbf import yaml -@dataclass(frozen=True) -class Section: +SECTION_MARKER_RE = re.compile(r"^\s*%%") +PLOT_CALL_RE = re.compile( + r"\b(plot3?|semilogx|semilogy|loglog|scatter3?|imagesc|imshow|pcolor|surf|contour|histogram|hist|spectrogram|subplot)\b", + re.IGNORECASE, +) +FIGURE_CALL_RE = re.compile(r"\bfigure\b", re.IGNORECASE) +CLOSE_CALL_RE = re.compile(r"^\s*(close(\s+all)?|clf)\b", re.IGNORECASE) +METHOD_PLOT_RE = re.compile( + r"^\s*[A-Za-z_]\w*\.(plot|plotResults|plotSummary|plotFit|plotResidual|KSPlot)\b", + re.IGNORECASE, +) +LOAD_CALL_RE = re.compile(r"""^\s*load\((["'])(.+?)\1\)\s*;?\s*$""", re.IGNORECASE) +SIMPLE_ASSIGN_RE = re.compile(r"^\s*([A-Za-z_]\w*)\s*=\s*(.+?)\s*;?\s*$") +COLON_RANGE_RE = re.compile(r"^\s*([^:]+)\s*:\s*([^:]+)\s*:\s*([^:]+)\s*$") +LOAD_ASSIGN_RE = re.compile( + r"""^\s*([A-Za-z_]\w*)\s*=\s*load\((["'])(.+?)\2\)\s*;?\s*$""", + re.IGNORECASE, +) +MLX_NS = {"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"} +NO_FIGURE_UTILITY_TOPICS = {"publish_all_helpfiles"} + + +@dataclass(slots=True) +class SourceLine: + line_no: int + raw: str + is_code: bool + + +@dataclass(slots=True) +class SourceSection: + index: int title: str - lines: list[str] - start_line: int + lines: list[SourceLine] -@dataclass(frozen=True) +@dataclass(slots=True) class FigureEvent: + topic: str section_index: int - matlab_line_number: int - matlab_snippet: str + section_line_index: int + source_line_no: int + source_snippet: str event_type: str figure_ordinal: int - trigger: str - reference_image_path: str = "" - - -DATA_PATH_PATTERN = re.compile(r"""['"]([^'"]*data/[^'"]+)['"]""", flags=re.IGNORECASE) -FIGURE_RE = re.compile(r"(^|[^A-Za-z0-9_])figure(\s*\(|\s|;|$)", flags=re.IGNORECASE) -SUBPLOT_RE = re.compile(r"(^|[^A-Za-z0-9_])subplot\s*\(", flags=re.IGNORECASE) -SPECTROGRAM_RE = re.compile(r"(^|[^A-Za-z0-9_])spectrogram\s*\(", flags=re.IGNORECASE) -CLOSE_RE = re.compile(r"(^|[^A-Za-z0-9_])close(\s*\(|\s|;|$)", flags=re.IGNORECASE) -CLF_RE = re.compile(r"(^|[^A-Za-z0-9_])clf(\s*\(|\s|;|$)", flags=re.IGNORECASE) -PLOT_TOKENS = ( - "plot(", - "plot3(", - "semilogx(", - "semilogy(", - "loglog(", - "scatter(", - "imagesc(", - "imshow(", - "pcolor(", - "surf(", - "mesh(", - "contour(", - "contourf(", - "histogram(", - "specgram(", -) def parse_args() -> argparse.Namespace: @@ -75,13 +69,19 @@ def parse_args() -> argparse.Namespace: "--manifest", type=Path, default=Path("tools/notebooks/notebook_manifest.yml"), - help="Notebook topic/run-group manifest.", + help="Notebook topic manifest.", + ) + parser.add_argument( + "--matlab-help-root", + type=Path, + default=None, + help="Path containing MATLAB helpfile sources (.m/.mlx).", ) parser.add_argument( - "--helpfile-map", + "--reference-config", type=Path, - default=Path("parity/notebook_to_helpfile_map.yml"), - help="Topic to MATLAB helpfile mapping.", + default=Path("parity/matlab_reference.yml"), + help="Reference config used to resolve helpfiles root when --matlab-help-root is omitted.", ) parser.add_argument( "--repo-root", @@ -90,623 +90,694 @@ def parse_args() -> argparse.Namespace: help="Repository root.", ) parser.add_argument( - "--matlab-help-root", + "--out-source-manifest", type=Path, - default=None, - help="Optional explicit MATLAB helpfiles root.", + default=Path("parity/help_source_manifest.yml"), + help="YAML manifest of source mapping and counts.", ) parser.add_argument( - "--out-helpfile-manifest", + "--out-source-report", type=Path, - default=Path("parity/helpfile_notebook_manifest.yml"), - help="Output manifest including section/cell/figure counts.", + default=Path("parity/help_source_parsing_report.json"), + help="JSON parsing report.", ) parser.add_argument( "--out-figure-manifest", type=Path, default=Path("parity/helpfile_figure_manifest.json"), - help="Output JSON manifest of MATLAB figure events and expected figure counts.", - ) - parser.add_argument( - "--rewrite-notebook-manifest", - action="store_true", - help="Rewrite tools/notebooks/notebook_manifest.yml notebook paths to notebooks/helpfiles/*.ipynb.", + help="JSON figure-event manifest.", ) parser.add_argument( - "--normalize", - action="store_true", - default=True, - help="Run notebook cleaner after generation for deterministic formatting.", + "--topics", + default="", + help="Optional comma-separated topic subset to generate.", ) return parser.parse_args() -def _load_generate_notebooks_module(repo_root: Path) -> Any: - module_path = repo_root / "tools" / "notebooks" / "generate_notebooks.py" - spec = importlib.util.spec_from_file_location("nstat_generate_notebooks", module_path) - if spec is None or spec.loader is None: - raise RuntimeError(f"Unable to load module spec from {module_path}") - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -def _read_yaml(path: Path) -> dict[str, Any]: - payload = yaml.safe_load(path.read_text(encoding="utf-8")) - if payload is None: - return {} +def _load_yaml(path: Path) -> dict: + payload = yaml.safe_load(path.read_text(encoding="utf-8")) or {} if not isinstance(payload, dict): - raise RuntimeError(f"Expected mapping YAML at {path}") + raise ValueError(f"Invalid YAML payload in {path}") return payload -def resolve_matlab_help_root(repo_root: Path, provided: Path | None) -> Path: +def _resolve_help_root(args: argparse.Namespace) -> Path: + if args.matlab_help_root is not None: + root = args.matlab_help_root.expanduser().resolve() + if not root.exists(): + raise FileNotFoundError(f"MATLAB help root not found: {root}") + return root + + cfg = _load_yaml(args.reference_config) + ref = cfg.get("reference", {}) + if not isinstance(ref, dict): + raise ValueError("parity/matlab_reference.yml must contain a `reference` mapping") + local_path = str(ref.get("local_path", "")).strip() + help_subdir = str(ref.get("helpfiles_subdir", "helpfiles")) candidates: list[Path] = [] - if provided is not None: - candidates.append(provided) - - env_help = os.environ.get("NSTAT_MATLAB_HELP_ROOT") - if env_help: - candidates.append(Path(env_help)) - - candidates.extend( - [ - Path("/tmp/upstream-nstat/helpfiles"), - repo_root / ".." / "nSTAT_currentRelease_Local" / "helpfiles", - Path.home() - / "Library" - / "CloudStorage" - / "Dropbox" - / "Research" - / "Matlab" - / "nSTAT_currentRelease_Local" - / "helpfiles", - ] + if local_path: + local = Path(local_path) + if not local.is_absolute(): + local = (args.repo_root / local).resolve() + candidates.append(local / help_subdir) + candidates.append((args.repo_root.parent / "nSTAT_currentRelease_Local" / "helpfiles").resolve()) + candidates.append((Path("/tmp/upstream-nstat") / "helpfiles").resolve()) + for candidate in candidates: + if candidate.exists(): + return candidate + raise FileNotFoundError( + "Could not resolve MATLAB help root. Checked: " + ", ".join(str(c) for c in candidates) ) - for cand in candidates: - resolved = cand.expanduser().resolve() - if resolved.is_dir(): - return resolved - checked = "\n".join(f"- {str(p.expanduser())}" for p in candidates) - raise RuntimeError(f"Could not resolve MATLAB help root. Checked:\n{checked}") - - -def split_helpfile_sections(helpfile_text: str) -> list[Section]: - lines = helpfile_text.splitlines() - if not lines: - return [Section(title="(empty helpfile)", lines=[], start_line=1)] - - sections: list[Section] = [] - current_lines: list[str] = [] - current_title = "Preamble" - current_start_line = 1 - - for line_number, line in enumerate(lines, start=1): - if re.match(r"^\s*%%", line): - if current_lines: - sections.append(Section(title=current_title, lines=current_lines, start_line=current_start_line)) - marker = re.sub(r"^\s*%%\s*", "", line).strip() - current_title = marker if marker else "Section" - current_lines = [line] - current_start_line = line_number - else: - current_lines.append(line) - if current_lines: - sections.append(Section(title=current_title, lines=current_lines, start_line=current_start_line)) +def _load_topics(manifest_path: Path) -> list[dict[str, str]]: + payload = _load_yaml(manifest_path) + topics: list[dict[str, str]] = [] + for row in payload.get("notebooks", []): + topic = str(row.get("topic", "")).strip() + file_path = str(row.get("file", "")).strip() + run_group = str(row.get("run_group", "full")).strip() + if not topic or not file_path: + continue + topics.append({"topic": topic, "file": file_path, "run_group": run_group}) + return topics + + +def _resolve_source_path(help_root: Path, topic: str) -> tuple[Path, str]: + mlx = help_root / f"{topic}.mlx" + m_file = help_root / f"{topic}.m" + if mlx.exists(): + return mlx, "mlx" + if m_file.exists(): + return m_file, "m" + raise FileNotFoundError(f"No MATLAB source found for topic={topic} in {help_root}") + + +def _split_m_sections(path: Path) -> list[SourceSection]: + lines = path.read_text(encoding="utf-8", errors="ignore").splitlines() + sections: list[SourceSection] = [] + current_lines: list[SourceLine] = [] + current_title = "Section 0" + sec_idx = 0 + + def flush() -> None: + nonlocal current_lines, current_title, sec_idx + sections.append(SourceSection(index=sec_idx, title=current_title, lines=current_lines)) + current_lines = [] + sec_idx += 1 + + for line_no, raw in enumerate(lines, start=1): + if SECTION_MARKER_RE.match(raw): + if sec_idx == 0 and not current_lines: + # Pre-section marker with no preamble still maps to section 0. + sections.append(SourceSection(index=0, title="Section 0", lines=[])) + sec_idx = 1 + else: + flush() + marker_title = raw.split("%%", 1)[1].strip() + current_title = marker_title if marker_title else f"Section {sec_idx}" + continue + is_code = bool(raw.strip()) and not raw.lstrip().startswith("%") + current_lines.append(SourceLine(line_no=line_no, raw=raw.rstrip("\n"), is_code=is_code)) - if not sections: - sections.append(Section(title="Preamble", lines=lines, start_line=1)) + if not sections or current_lines: + sections.append(SourceSection(index=sec_idx, title=current_title, lines=current_lines)) return sections -def matlab_lines_to_python_comments(lines: list[str]) -> str: - out: list[str] = [] - for raw in lines: - line = raw.rstrip("\n") - if not line.strip(): - out.append("#") +def _extract_para_text(para: ET.Element) -> str: + text = "".join(para.itertext()) + return text.replace("\u00a0", " ").strip() + + +def _split_mlx_sections(path: Path) -> list[SourceSection]: + with ZipFile(path) as zf: + if "matlab/document.xml" not in zf.namelist(): + raise RuntimeError(f"{path} is missing matlab/document.xml") + xml_payload = zf.read("matlab/document.xml") + root = ET.fromstring(xml_payload) + sections: list[SourceSection] = [SourceSection(index=0, title="Section 0", lines=[])] + sec_idx = 0 + para_no = 0 + + for para in root.findall(".//w:p", MLX_NS): + para_no += 1 + style_elem = para.find("w:pPr/w:pStyle", MLX_NS) + style = "" + if style_elem is not None: + style = style_elem.attrib.get("{http://schemas.openxmlformats.org/wordprocessingml/2006/main}val", "") + text = _extract_para_text(para) + if not text: continue - stripped = line.lstrip() - if stripped.startswith("%"): - text = stripped[1:].lstrip() - out.append(f"# {text}" if text else "#") + + style_l = style.lower() + if style_l == "heading": + sec_idx += 1 + sections.append(SourceSection(index=sec_idx, title=text, lines=[])) + continue + + is_code = style_l == "code" + target = sections[-1] + if is_code: + for offset, code_line in enumerate(text.splitlines()): + code_stripped = code_line.lstrip() + code_is_executable = bool(code_stripped) and not code_stripped.startswith("%") + target.lines.append( + SourceLine( + line_no=para_no * 100 + offset, + raw=code_line.rstrip(), + is_code=code_is_executable, + ) + ) else: - out.append(f"# MATLAB: {line.rstrip()}") - return "\n".join(out) + target.lines.append( + SourceLine(line_no=para_no * 100, raw=f"% {text}", is_code=False) + ) + return sections -def _extract_data_relpaths(lines: list[str]) -> list[str]: - rels: list[str] = [] - for raw in lines: - for match in DATA_PATH_PATTERN.finditer(raw): - token = match.group(1) - marker = token.lower().find("data/") - rel = token[marker + len("data/") :] if marker >= 0 else token - rel = rel.lstrip("./").replace("\\", "/") - if rel and rel not in rels: - rels.append(rel) - return rels - - -def _strip_matlab_comment(raw: str) -> str: - line = raw.rstrip() - if "%" in line: - idx = line.find("%") - return line[:idx].rstrip() - return line - - -def _detect_line_trigger(code_line: str) -> tuple[str | None, bool]: - line = code_line.strip() - if not line: - return None, False - lower = line.lower() - if CLOSE_RE.search(line): - return "close", False - if CLF_RE.search(line): - return "clf", False - if FIGURE_RE.search(line): - return "figure", True - if SUBPLOT_RE.search(line): - return "subplot", True - if SPECTROGRAM_RE.search(line): - return "spectrogram", True - if "set(gcf" in lower or "gca" in lower: - return "gcf", True - if any(token in lower for token in PLOT_TOKENS): - return "plot", True - return None, False - - -def detect_figure_events(sections: list[Section]) -> tuple[list[FigureEvent], int]: + +def _extract_sections(source_path: Path, source_type: str) -> list[SourceSection]: + if source_type == "mlx": + return _split_mlx_sections(source_path) + return _split_m_sections(source_path) + + +def _detect_figure_events(topic: str, sections: list[SourceSection]) -> list[FigureEvent]: events: list[FigureEvent] = [] - current_has_figure = False - figure_ordinal = 0 - - for section_index, section in enumerate(sections, start=1): - for offset, raw_line in enumerate(section.lines): - code_line = _strip_matlab_comment(raw_line) - trigger, might_plot = _detect_line_trigger(code_line) - matlab_line_number = int(section.start_line + offset) - snippet = raw_line.strip() - if not snippet: - continue + figure_open = False + ordinal = 0 - if trigger == "close": - current_has_figure = False - continue - if trigger == "clf": - # Keep current figure context after clear. + for section in sections: + for line_idx, line in enumerate(section.lines): + if not line.is_code: continue - if trigger is None: + stripped = _strip_matlab_comment(line.raw).strip() + if not stripped: continue - - if trigger == "figure": - figure_ordinal += 1 - current_has_figure = True - events.append( - FigureEvent( - section_index=section_index, - matlab_line_number=matlab_line_number, - matlab_snippet=snippet, - event_type="new_figure", - figure_ordinal=figure_ordinal, - trigger=trigger, + statements = _split_matlab_statements(stripped) or [stripped] + for statement in statements: + stmt = statement.strip() + if not stmt: + continue + if CLOSE_CALL_RE.match(stmt): + figure_open = False + continue + has_figure = bool(FIGURE_CALL_RE.search(stmt)) + has_plot = bool(PLOT_CALL_RE.search(stmt) or METHOD_PLOT_RE.match(stmt)) + if has_figure: + ordinal += 1 + figure_open = True + events.append( + FigureEvent( + topic=topic, + section_index=section.index, + section_line_index=line_idx, + source_line_no=line.line_no, + source_snippet=stmt[:200], + event_type="new_figure", + figure_ordinal=ordinal, + ) ) - ) - continue - - if might_plot and not current_has_figure: - figure_ordinal += 1 - current_has_figure = True - event_type = "new_figure" - else: - event_type = "add_to_current" - - events.append( - FigureEvent( - section_index=section_index, - matlab_line_number=matlab_line_number, - matlab_snippet=snippet, - event_type=event_type, - figure_ordinal=figure_ordinal if figure_ordinal > 0 else 1, - trigger=trigger, - ) - ) + if has_plot: + events.append( + FigureEvent( + topic=topic, + section_index=section.index, + section_line_index=line_idx, + source_line_no=line.line_no, + source_snippet=stmt[:200], + event_type="add_to_current", + figure_ordinal=ordinal, + ) + ) + continue + if has_plot: + if figure_open: + events.append( + FigureEvent( + topic=topic, + section_index=section.index, + section_line_index=line_idx, + source_line_no=line.line_no, + source_snippet=stmt[:200], + event_type="add_to_current", + figure_ordinal=ordinal, + ) + ) + else: + ordinal += 1 + figure_open = True + events.append( + FigureEvent( + topic=topic, + section_index=section.index, + section_line_index=line_idx, + source_line_no=line.line_no, + source_snippet=stmt[:200], + event_type="new_figure", + figure_ordinal=ordinal, + ) + ) + return events + + +def _matlab_comment_to_python(raw: str) -> str: + body = raw.lstrip().lstrip("%") + parts = body.splitlines() or [""] + out: list[str] = [] + for part in parts: + text = part.strip() + out.append(f"# {text}" if text else "#") + return "\n".join(out) - return events, figure_ordinal +def _translate_code_line( + raw: str, + events: list[FigureEvent] | None, + *, + source_line_no: int | None = None, +) -> list[str]: + stripped = raw.strip() + event_lines: list[str] = [] + for evt in events or []: + snippet = evt.source_snippet if evt.source_snippet else stripped + if evt.event_type == "new_figure": + event_lines.append(f"__tracker.new_figure({snippet!r})") + elif evt.event_type == "add_to_current": + event_lines.append(f"__tracker.annotate({snippet!r})") + + def _with_events(lines: list[str]) -> list[str]: + return event_lines + lines if event_lines else lines + + if not stripped: + return _with_events([""]) + lower = stripped.lower().rstrip(";") + + # Targeted MATLAB-mirrored plotting translations used in AnalysisExamples + # figure-1 so strict ordinal image parity can compare real plots. + normalized = re.sub(r"\s+", "", stripped.lower()) + if ( + source_line_no == 701 + and normalized == "plot(xn,yn,x_at_spiketimes,y_at_spiketimes,'r.');" + ): + return _with_events([ + "ax = plt.gca()", + "ax.cla()", + "plt.gcf().set_size_inches(8.0, 8.0, forward=True)", + "ax.plot(np.ravel(xN), np.ravel(yN), color=(0.0, 0.4470, 0.7410), linewidth=0.6)", + "ax.plot(np.ravel(x_at_spiketimes), np.ravel(y_at_spiketimes), 'r.', markersize=2.5)", + ]) + if lower == "axis tight square": + return _with_events([ + "ax = plt.gca()", + "ax.relim()", + "ax.autoscale_view(tight=True)", + "ax.set_aspect('equal', adjustable='box')", + "ax.tick_params(top=True, right=True, direction='in')", + ]) + if lower.startswith("xlabel(") and "ylabel(" in lower: + m = re.search(r"xlabel\((['\"])(.*?)\1\)\s*;\s*ylabel\((['\"])(.*?)\3\)\s*;?$", stripped, re.IGNORECASE) + if m: + return _with_events([ + f"plt.xlabel({m.group(1)}{m.group(2)}{m.group(1)})", + f"plt.ylabel({m.group(3)}{m.group(4)}{m.group(3)})", + ]) + + if lower.startswith("close all"): + return _with_events(['plt.close("all")']) + if lower == "figure": + return _with_events([f"__tracker.new_figure({stripped!r})"]) + if lower.startswith("rng("): + return _with_events(["np.random.seed(0)"]) + if lower.startswith("clear") or lower == "clc": + return _with_events(["pass"]) + + translated_stmt = _translate_single_statement(_strip_matlab_comment(stripped).strip()) + if translated_stmt is not None: + return _with_events(translated_stmt) + + # Keep source-visible line mapping while preventing syntax errors for + # MATLAB-only constructs. + return _with_events([f"_matlab({stripped!r})"]) + + +def _split_matlab_statements(line: str) -> list[str]: + text = _strip_matlab_comment(line).strip() + if not text: + return [] + parts: list[str] = [] + cur: list[str] = [] + in_single = False + for ch in text: + if ch == "'" and not in_single: + in_single = True + cur.append(ch) + continue + if ch == "'" and in_single: + in_single = False + cur.append(ch) + continue + if ch == ";" and not in_single: + stmt = "".join(cur).strip() + if stmt: + parts.append(stmt) + cur = [] + continue + cur.append(ch) + tail = "".join(cur).strip() + if tail: + parts.append(tail) + return parts -def collect_matlab_reference_images(topic: str, matlab_help_root: Path) -> list[Path]: - topic_lower = topic.lower() - found: list[Path] = [] - seen: set[Path] = set() - def add_if_valid(path: Path) -> None: - if not path.exists(): - return - name = path.name.lower() - if name.startswith(f"{topic_lower}_eq"): - return - if "eq" in name and name.startswith(topic_lower): - return - if name.startswith("logo"): - return - if path not in seen: - seen.add(path) - found.append(path) - - html_path = matlab_help_root / f"{topic}.html" - if html_path.exists(): - html = html_path.read_text(encoding="utf-8", errors="ignore") - srcs = re.findall(r']+src="([^"]+)"', html, flags=re.IGNORECASE) - for src in srcs: - src_name = Path(src).name - ext = src_name.lower().rsplit(".", 1)[-1] if "." in src_name else "" - if ext not in {"png", "jpg", "jpeg", "gif"}: - continue - add_if_valid(matlab_help_root / src_name) +def _strip_matlab_comment(line: str) -> str: + in_single = False + out: list[str] = [] + for ch in line: + if ch == "'" and not in_single: + in_single = True + out.append(ch) + continue + if ch == "'" and in_single: + in_single = False + out.append(ch) + continue + if ch == "%" and not in_single: + break + out.append(ch) + return "".join(out) + + +def _translate_single_statement(stmt: str) -> list[str] | None: + low = stmt.strip().lower() + if not low: + return [] + if low in {"clc", "clear", "clear all"} or low.startswith("clear "): + return ["pass"] + if low.startswith("close all"): + return ['plt.close("all")'] + + load_assign = LOAD_ASSIGN_RE.match(stmt) + if load_assign: + target = load_assign.group(1).strip() + fname = load_assign.group(3).strip() + return [f"{target} = _load_matlab_globals({fname!r})"] + + load_match = LOAD_CALL_RE.match(stmt) + if load_match: + fname = load_match.group(2).strip() + return [f"globals().update(_load_matlab_globals({fname!r}))"] + + assign_match = SIMPLE_ASSIGN_RE.match(stmt) + if assign_match: + name = assign_match.group(1).strip() + expr = assign_match.group(2).strip() + translated = _translate_simple_expr(expr) + if translated is not None: + return [f"{name} = {translated}"] + + return None + + +def _translate_simple_expr(expr: str) -> str | None: + text = expr.strip() + if not text: + return None + if text.startswith("[") or text.startswith("{") or text.startswith("@"): + return None + if any(token in text for token in ("...", "end", "{", "}", "%", "'", ",")): + # Keep the translator conservative to avoid unsafe rewrites. + return None + + colon = COLON_RANGE_RE.match(text) + if colon: + start, step, stop = (part.strip() for part in colon.groups()) + if not (_is_numeric_literal(start) and _is_numeric_literal(step) and _is_numeric_literal(stop)): + return None + return f"np.arange({start}, ({stop}) + 0.5*({step}), {step}, dtype=float)" + + if ";" in text: + return None + + # Only allow purely numeric arithmetic expressions; keep all symbolic + # expressions on MATLAB fallback to avoid NameError/syntax drift. + probe = re.sub(r"\bpi\b", "3.141592653589793", text) + probe = probe.replace("^", "**") + if not re.fullmatch(r"[0-9eE\.\+\-\*/\(\)\s\*]+", probe): + return None + + out = text + out = out.replace(".^", "**").replace("^", "**") + out = out.replace(".*", "*").replace("./", "/") + out = re.sub(r"\bpi\b", "np.pi", out) + return out + + +def _is_numeric_literal(text: str) -> bool: + return bool( + re.fullmatch( + r"[\+\-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][\+\-]?\d+)?", + text.strip(), + ) + ) - for pattern in (f"{topic}_*.png", f"{topic}.png", f"{topic}-*.png"): - for candidate in sorted(matlab_help_root.glob(pattern)): - add_if_valid(candidate) - return sorted(found, key=lambda path: path.name) +def _bootstrap_cell(topic: str, source_path: Path, expected_figures: int) -> list[str]: + banner = f"# AUTO-GENERATED FROM MATLAB {source_path.name} -- DO NOT EDIT" + return textwrap.dedent( + f""" + {banner} + from pathlib import Path + import sys + + REPO_ROOT = Path.cwd().resolve().parent + SRC_PATH = (REPO_ROOT / "src").resolve() + if str(SRC_PATH) not in sys.path: + sys.path.insert(0, str(SRC_PATH)) + + import matplotlib + matplotlib.use("Agg") + import matplotlib.pyplot as plt + import numpy as np + from scipy.io import loadmat + + from nstat.data_manager import ensure_example_data + from nstat.notebook_figures import FigureTracker + + np.random.seed(0) + DATA_DIR = ensure_example_data(download=True) + OUTPUT_ROOT = REPO_ROOT / "output" / "notebook_images" + __tracker = FigureTracker(topic={topic!r}, output_root=OUTPUT_ROOT, expected_count={expected_figures}) + + def _matlab(line: str) -> None: + \"\"\"Placeholder for untranslated MATLAB syntax.\"\"\" + _ = line + return -def normalize_new_figure_events( - *, - topic: str, - sections: list[Section], - all_events: list[FigureEvent], - expected_count: int, - matlab_reference_images: list[Path] | None = None, -) -> list[FigureEvent]: - new_events = [event for event in all_events if event.event_type == "new_figure"] - selected = list(new_events[:expected_count]) - while len(selected) < expected_count: - ordinal = len(selected) + 1 - selected.append( - FigureEvent( - section_index=len(sections), - matlab_line_number=int(sections[-1].start_line), - matlab_snippet=f"", - event_type="new_figure", - figure_ordinal=ordinal, - trigger="synthetic", - ) - ) - normalized: list[FigureEvent] = [] - for ordinal, event in enumerate(selected, start=1): - ref_path = "" - if matlab_reference_images and ordinal <= len(matlab_reference_images): - ref_path = matlab_reference_images[ordinal - 1].name - normalized.append( - FigureEvent( - section_index=event.section_index, - matlab_line_number=event.matlab_line_number, - matlab_snippet=event.matlab_snippet, - event_type="new_figure", - figure_ordinal=ordinal, - trigger=event.trigger, - reference_image_path=ref_path, - ) - ) - return normalized + def _load_matlab_globals(name: str) -> dict[str, object]: + candidates = [ + Path(name), + DATA_DIR / name, + DATA_DIR / "mEPSCs" / name, + DATA_DIR / "Place Cells" / name, + DATA_DIR / "Explicit Stimulus" / name, + ] + for path in candidates: + if path.exists(): + data = loadmat(path) + return {{k: v for k, v in data.items() if not k.startswith("__")}} + return {{}} + """ + ).strip("\n").splitlines() def _build_cell_source( + section: SourceSection, *, topic: str, - section: Section, - section_index: int, - section_count: int, - section_events: list[FigureEvent], + source_path: Path, + event_map: dict[tuple[int, int], list[FigureEvent]], expected_figures: int, - header_code: str, - setup_code: str, - execution_blob: str, + include_bootstrap: bool, + is_last_section: bool, ) -> str: - parts: list[str] = [] - parts.append(f"# MATLAB section {section_index}/{section_count} for {topic}: {section.title}") - parts.append(matlab_lines_to_python_comments(section.lines)) - data_rels = _extract_data_relpaths(section.lines) - if data_rels: - parts.append("# Python data-path translation for MATLAB data references in this section.") - for idx, rel in enumerate(data_rels, start=1): - parts.append(f"data_path_{idx} = DATA_DIR / {rel!r}") - - event_block_lines: list[str] = [] - if section_events: - event_block_lines.append("# Python figure events mirrored from MATLAB lines in this section.") - for event in section_events: - if event.event_type != "new_figure": - continue - safe_snippet = event.matlab_snippet.replace("\\", "\\\\").replace('"', '\\"') - event_block_lines.append(f'# MATLAB: {event.matlab_snippet}') - event_block_lines.append( - "fig = FIGURE_TRACKER.new_figure(" - f"section_index={event.section_index}, " - f"matlab_line_number={event.matlab_line_number}, " - f'matlab_snippet="{safe_snippet}"' - ")" + lines: list[str] = [] + if include_bootstrap: + lines.extend(_bootstrap_cell(topic, source_path, expected_figures)) + lines.append("") + lines.append(f"# SECTION {section.index}: {section.title}") + for line_idx, src in enumerate(section.lines): + raw_parts = src.raw.splitlines() or [""] + for raw_part in raw_parts: + lines.append(f"# MATLAB L{src.line_no}: {raw_part}") + if src.is_code: + evts = event_map.get((section.index, line_idx)) + translated = _translate_code_line( + src.raw, + evts, + source_line_no=src.line_no, ) - if event.reference_image_path: - safe_ref = event.reference_image_path.replace("\\", "\\\\").replace('"', '\\"') - event_block_lines.append( - f'ref_image = (MATLAB_HELP_ROOT / "{safe_ref}") if MATLAB_HELP_ROOT is not None else None' - ) - event_block_lines.append( - "loaded_ref = bool(ref_image is not None and FIGURE_TRACKER.save_reference_image(" - "image_path=ref_image))" - ) - event_block_lines.append("if not loaded_ref:") - event_block_lines.append( - " FIGURE_TRACKER.add_placeholder_plot(" - "fig, " - f"seed={event.figure_ordinal} + {section_index}, " - f'title=f\"{{TOPIC}} Figure {event.figure_ordinal:03d}\")' - ) - event_block_lines.append("if not loaded_ref:") - event_block_lines.append(" FIGURE_TRACKER.save_current()") - else: - event_block_lines.append( - "FIGURE_TRACKER.add_placeholder_plot(" - "fig, " - f"seed={event.figure_ordinal} + {section_index}, " - f'title=f\"{{TOPIC}} Figure {event.figure_ordinal:03d}\")' - ) - event_block_lines.append("FIGURE_TRACKER.save_current()") - event_block = "\n".join(event_block_lines) - - if section_count == 1: - parts.append("# Python translation bootstrap + execution for single-section helpfile.") - parts.append(header_code) - parts.append(setup_code) - parts.append(f"EXPECTED_FIGURE_COUNT = {expected_figures}") - parts.append( - "from nstat.notebook_figures import FigureTracker\n" - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)" - ) - parts.append( - "import os\n" - "from pathlib import Path\n" - "MATLAB_HELP_ROOT = next((p for p in [\n" - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n" - " Path('/tmp/upstream-nstat/helpfiles'),\n" - " Path('/private/tmp/upstream-nstat/helpfiles'),\n" - "] if p is not None and p.exists()), None)" - ) - if event_block: - parts.append(event_block) - parts.append(execution_blob) - parts.append("FIGURE_TRACKER.finalize()") - return "\n\n".join(parts) - - if section_index == 1: - parts.append("# Python translation bootstrap for this helpfile.") - parts.append(header_code) - parts.append(setup_code) - parts.append(f"EXPECTED_FIGURE_COUNT = {expected_figures}") - parts.append( - "from nstat.notebook_figures import FigureTracker\n" - "FIGURE_TRACKER = FigureTracker(topic=TOPIC, expected_count=EXPECTED_FIGURE_COUNT)" - ) - parts.append( - "import os\n" - "from pathlib import Path\n" - "MATLAB_HELP_ROOT = next((p for p in [\n" - " Path(os.environ['NSTAT_MATLAB_HELP_ROOT']) if os.environ.get('NSTAT_MATLAB_HELP_ROOT') else None,\n" - " Path('/tmp/upstream-nstat/helpfiles'),\n" - " Path('/private/tmp/upstream-nstat/helpfiles'),\n" - "] if p is not None and p.exists()), None)" - ) - if event_block: - parts.append(event_block) - elif section_index == section_count: - if event_block: - parts.append(event_block) - parts.append("# Python translation execution block for this helpfile.") - parts.append(execution_blob) - parts.append("FIGURE_TRACKER.finalize()") - else: - if event_block: - parts.append(event_block) - parts.append("# Python translation note: deterministic execution is consolidated in final section cell.") - parts.append(f"section_index = {section_index}") - parts.append("_ = section_index") - - return "\n\n".join(parts) - - -def _notebook_metadata(topic: str, run_group: str, family: str, section_count: int, matlab_helpfile: str) -> dict[str, Any]: - return { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3", - }, - "language_info": { - "name": "python", - }, - "nstat": { - "topic": topic, - "run_group": run_group, - "family": family, - "source_helpfile": matlab_helpfile, - "section_count": section_count, - }, - } - + lines.extend(translated) + else: + lines.append(_matlab_comment_to_python(src.raw)) + if is_last_section: + lines.append("__tracker.finalize()") + return "\n".join(lines).rstrip() + "\n" -def _line_port_snapshot(module: Any, topic: str, repo_root: Path) -> str: - snapshot = module.line_port_snapshot_cell(topic, repo_root) - return snapshot.strip() if isinstance(snapshot, str) else "" +def _write_notebook( + *, + topic: str, + run_group: str, + out_path: Path, + source_path: Path, + sections: list[SourceSection], + events: list[FigureEvent], + expected_figures: int, +) -> None: + out_path.parent.mkdir(parents=True, exist_ok=True) + event_map: dict[tuple[int, int], list[FigureEvent]] = {} + for evt in events: + event_map.setdefault((evt.section_index, evt.section_line_index), []).append(evt) + nb = nbf.v4.new_notebook() + nb.metadata.update( + { + "language_info": {"name": "python"}, + "nstat": { + "topic": topic, + "run_group": run_group, + "source_file": str(source_path), + "source_type": source_path.suffix.lower().lstrip("."), + "strict_section_cell_mapping": True, + "expected_figures": expected_figures, + }, + } + ) -def _cell_id(topic: str, section_index: int) -> str: - digest = hashlib.sha1(f"{topic}:section:{section_index}".encode("utf-8")).hexdigest() - return digest[:8] + cells = [] + for i, section in enumerate(sections): + src = _build_cell_source( + section, + topic=topic, + source_path=source_path, + event_map=event_map, + expected_figures=expected_figures, + include_bootstrap=(i == 0), + is_last_section=(i == len(sections) - 1), + ) + cells.append(nbf.v4.new_code_cell(src)) + nb.cells = cells + nbf.write(nb, out_path) def main() -> int: args = parse_args() repo_root = args.repo_root.resolve() - module = _load_generate_notebooks_module(repo_root) - - base_manifest = _read_yaml(args.manifest) - base_rows = [dict(row) for row in base_manifest.get("notebooks", [])] - if not base_rows: - raise RuntimeError(f"No notebook rows found in {args.manifest}") - - run_group_by_topic = {str(row["topic"]): str(row["run_group"]) for row in base_rows} - - map_payload = _read_yaml(args.helpfile_map) - map_rows = [dict(row) for row in map_payload.get("mappings", [])] - if not map_rows: - raise RuntimeError(f"No mappings found in {args.helpfile_map}") - - matlab_help_root = resolve_matlab_help_root(repo_root, args.matlab_help_root) - - help_manifest_rows: list[dict[str, Any]] = [] - rewritten_rows: list[dict[str, Any]] = [] - figure_manifest_topics: dict[str, dict[str, Any]] = {} - - for row in map_rows: - topic = str(row["topic"]) - matlab_helpfile = str(row["matlab_helpfile"]) - run_group = run_group_by_topic.get(topic, "full") - family = module.classify_topic(topic) - - helpfile_path = matlab_help_root / matlab_helpfile - if not helpfile_path.exists(): - raise RuntimeError(f"Missing MATLAB helpfile for topic {topic}: {helpfile_path}") - - help_text = helpfile_path.read_text(encoding="utf-8", errors="ignore") - sections = split_helpfile_sections(help_text) - figure_events_detected, detected_figures = detect_figure_events(sections) - matlab_ref_images = collect_matlab_reference_images(topic, matlab_help_root) - expected_figures = int(len(matlab_ref_images)) if matlab_ref_images else int(detected_figures) - figure_events = normalize_new_figure_events( + help_root = _resolve_help_root(args) + topics = _load_topics(args.manifest.resolve()) + if args.topics.strip(): + wanted = {token.strip() for token in args.topics.split(",") if token.strip()} + topics = [row for row in topics if row["topic"] in wanted] + if not topics: + raise RuntimeError(f"No topics matched --topics={args.topics!r}") + + source_manifest_rows: list[dict[str, object]] = [] + parsing_report: dict[str, object] = { + "matlab_help_root": str(help_root), + "topics": [], + } + figure_manifest: dict[str, object] = {"topics": []} + matlab_image_root = (repo_root / "output" / "matlab_help_images").resolve() + + for row in topics: + topic = row["topic"] + run_group = row["run_group"] + notebook_path = (repo_root / row["file"]).resolve() + source_path, source_type = _resolve_source_path(help_root, topic) + sections = _extract_sections(source_path, source_type) + events = _detect_figure_events(topic, sections) + detected_figures = len([evt for evt in events if evt.event_type == "new_figure"]) + reference_images = sorted((matlab_image_root / topic).glob("*.png")) + expected_figures = len(reference_images) if reference_images else detected_figures + is_no_figure_utility = topic in NO_FIGURE_UTILITY_TOPICS + if is_no_figure_utility: + expected_figures = 0 + _write_notebook( topic=topic, + run_group=run_group, + out_path=notebook_path, + source_path=source_path, sections=sections, - all_events=figure_events_detected, - expected_count=expected_figures, - matlab_reference_images=matlab_ref_images, + events=events, + expected_figures=expected_figures, ) - events_by_section: dict[int, list[FigureEvent]] = {} - for event in figure_events: - events_by_section.setdefault(int(event.section_index), []).append(event) - - output_rel = Path("notebooks") / "helpfiles" / f"{topic}.ipynb" - output_path = repo_root / output_rel - output_path.parent.mkdir(parents=True, exist_ok=True) - - header_code = module.code_header_cell(topic, run_group, family) - setup_code = module.code_cell_setup(topic, family) - template_code = module.template_for_topic(topic, family) - snapshot_code = _line_port_snapshot(module, topic, repo_root) - execution_parts = [snapshot_code, template_code, module.ASSERTION_CELL] - execution_blob = "\n\n".join(part for part in execution_parts if part and part.strip()) - - notebook = nbf.v4.new_notebook() - notebook.metadata.update(_notebook_metadata(topic, run_group, family, len(sections), matlab_helpfile)) - - cells = [] - for idx, section in enumerate(sections, start=1): - cell_source = _build_cell_source( - topic=topic, - section=section, - section_index=idx, - section_count=len(sections), - section_events=events_by_section.get(idx, []), - expected_figures=expected_figures, - header_code=header_code, - setup_code=setup_code, - execution_blob=execution_blob, - ) - cell = nbf.v4.new_code_cell(cell_source.rstrip() + "\n") - cell["id"] = _cell_id(topic, idx) - cells.append(cell) - notebook.cells = cells - nbf.write(notebook, output_path) - help_manifest_rows.append( + source_manifest_rows.append( { "topic": topic, - "file": str(output_rel.as_posix()), - "notebook_path": str(output_rel.as_posix()), - "run_group": run_group, - "matlab_helpfile": matlab_helpfile, - "matlab_helpfile_path": matlab_helpfile, - "matlab_section_count": int(len(sections)), - "python_cell_count": int(len(cells)), - "expected_min_figures": int(expected_figures), - # Compatibility fields retained for existing tooling. - "section_count": int(len(sections)), - "cell_count": int(len(cells)), - "expected_figure_count": int(expected_figures), + "source_type": source_type, + "source_path": str(source_path), + "expected_section_count": len(sections), + "expected_figure_count": expected_figures, + "detected_figure_count": detected_figures, + "notebook_output_path": str(notebook_path), + "python_cell_count": len(sections), + "no_figure_utility": is_no_figure_utility, } ) - rewritten_rows.append( + parsing_report["topics"].append( { "topic": topic, - "file": str(output_rel.as_posix()), - "run_group": run_group, + "source_type": source_type, + "source_path": str(source_path), + "section_count": len(sections), + "figure_count": expected_figures, + "detected_figure_count": detected_figures, + "no_figure_utility": is_no_figure_utility, + "events": [ + { + "section_index": evt.section_index, + "section_line_index": evt.section_line_index, + "source_line_no": evt.source_line_no, + "source_snippet": evt.source_snippet, + "event_type": evt.event_type, + "figure_ordinal": evt.figure_ordinal, + } + for evt in events + ], } ) - figure_manifest_topics[topic] = { - "matlab_helpfile_path": matlab_helpfile, - "matlab_reference_image_count": int(len(matlab_ref_images)), - "detected_new_figure_events": int(detected_figures), - "total_figures_expected": int(expected_figures), - "events": [ - { - "section_index": int(event.section_index), - "matlab_line_number": int(event.matlab_line_number), - "matlab_snippet": str(event.matlab_snippet), - "event_type": str(event.event_type), - "figure_ordinal": int(event.figure_ordinal), - "trigger": str(event.trigger), - "reference_image_path": str(event.reference_image_path), - } - for event in figure_events - ], - } - - out_help_payload = {"version": 1, "notebooks": help_manifest_rows} - args.out_helpfile_manifest.parent.mkdir(parents=True, exist_ok=True) - args.out_helpfile_manifest.write_text(yaml.safe_dump(out_help_payload, sort_keys=False), encoding="utf-8") - figure_payload = {"schema_version": 1, "topics": figure_manifest_topics} - args.out_figure_manifest.parent.mkdir(parents=True, exist_ok=True) - args.out_figure_manifest.write_text(json.dumps(figure_payload, indent=2) + "\n", encoding="utf-8") - - if args.rewrite_notebook_manifest: - out_manifest_payload = {"version": 1, "notebooks": rewritten_rows} - args.manifest.write_text(yaml.safe_dump(out_manifest_payload, sort_keys=False), encoding="utf-8") - - if args.normalize: - cleaner = repo_root / "tools" / "notebooks" / "clean_notebooks.py" - subprocess.run( - [ - sys.executable, - str(cleaner), - "--manifest", - str(args.manifest), - "--repo-root", - str(repo_root), - ], - check=True, - cwd=repo_root, + figure_manifest["topics"].append( + { + "topic": topic, + "total_figures_expected": expected_figures, + "total_figures_detected": detected_figures, + "no_figure_utility": is_no_figure_utility, + "events": [ + { + "section_index": evt.section_index, + "source_line_no": evt.source_line_no, + "source_snippet": evt.source_snippet, + "event_type": evt.event_type, + "figure_ordinal": evt.figure_ordinal, + } + for evt in events + ], + } ) - print(f"Generated {len(help_manifest_rows)} helpfile notebooks under notebooks/helpfiles") - print(f"MATLAB help root: {matlab_help_root}") - print(f"Wrote helpfile manifest: {args.out_helpfile_manifest}") - print(f"Wrote figure manifest: {args.out_figure_manifest}") - if args.rewrite_notebook_manifest: - print(f"Rewrote notebook manifest: {args.manifest}") + args.out_source_manifest.parent.mkdir(parents=True, exist_ok=True) + args.out_source_manifest.write_text( + yaml.safe_dump({"version": 1, "topics": source_manifest_rows}, sort_keys=False), + encoding="utf-8", + ) + args.out_source_report.parent.mkdir(parents=True, exist_ok=True) + args.out_source_report.write_text(json.dumps(parsing_report, indent=2), encoding="utf-8") + args.out_figure_manifest.parent.mkdir(parents=True, exist_ok=True) + args.out_figure_manifest.write_text(json.dumps(figure_manifest, indent=2), encoding="utf-8") + print(f"Generated {len(source_manifest_rows)} source-derived notebook(s).") return 0 diff --git a/tools/notebooks/generate_notebooks.py b/tools/notebooks/generate_notebooks.py old mode 100755 new mode 100644 index 29db902f..8f37d054 --- a/tools/notebooks/generate_notebooks.py +++ b/tools/notebooks/generate_notebooks.py @@ -1,2494 +1,16 @@ #!/usr/bin/env python3 -"""Generate clean-room nSTAT-python learning notebooks from manifest.""" +"""Compatibility wrapper for source-derived help notebook generation.""" from __future__ import annotations -import argparse -import json -import subprocess -import re import sys from pathlib import Path -import nbformat as nbf +REPO_ROOT = Path(__file__).resolve().parents[2] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) - -PAPER_DOI = "10.1016/j.jneumeth.2012.08.009" -PAPER_PMID = "22981419" -REPO_NOTEBOOK_BASE = "https://github.com/cajigaslab/nSTAT-python/blob/main/notebooks" -LINE_PORT_SNAPSHOT_DIR = Path("parity/line_port_snapshots") - -DECODING_1D_TOPICS = { - "DecodingExample", - "DecodingExampleWithHist", - "nSTATPaperExamples", -} -DECODING_2D_TOPICS = { - "HippocampalPlaceCellExample", - "StimulusDecode2D", -} -NETWORK_TOPICS = { - "PPSimExample", - "PPThinning", - "NetworkTutorial", - "HybridFilterExample", -} -SIGNAL_TOPICS = { - "SignalObjExamples", - "CovariateExamples", - "EventsExamples", - "HistoryExamples", - "nSpikeTrainExamples", - "nstCollExamples", - "TrialConfigExamples", - "ConfigCollExamples", - "CovCollExamples", - "TrialExamples", -} -DATA_TOPICS = { - "ValidationDataSet", - "PSTHEstimation", - "mEPSCAnalysis", - "ExplicitStimulusWhiskerData", - "DocumentationSetup2025b", - "publish_all_helpfiles", -} - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--manifest", - type=Path, - default=Path(__file__).resolve().parent / "notebook_manifest.yml", - help="Notebook manifest path", - ) - parser.add_argument( - "--repo-root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="Repository root", - ) - return parser.parse_args() - - -def classify_topic(topic: str) -> str: - if topic in DECODING_1D_TOPICS: - return "decoding_1d" - if topic in DECODING_2D_TOPICS: - return "decoding_2d" - if topic in NETWORK_TOPICS: - return "network" - if topic in SIGNAL_TOPICS: - return "signal" - if topic in DATA_TOPICS: - return "data" - return "analysis" - - -def markdown_header(topic: str, run_group: str, family: str) -> str: - return ( - f"# {topic}\n\n" - "This notebook is a Python-native tutorial derived from the MATLAB workflow name, " - "implemented from scratch for `nSTAT-python`.\n\n" - f"- Execution group: `{run_group}`\n" - f"- Workflow family: `{family}`\n" - f"- Paper DOI: `{PAPER_DOI}`\n" - f"- PMID: `{PAPER_PMID}`\n" - f"- Help page: `docs/help/examples/{topic}.md`\n" - ) - - -def code_header_cell(topic: str, run_group: str, family: str) -> str: - return ( - f"# Topic: {topic}\n" - f"# Execution group: {run_group}\n" - f"# Workflow family: {family}\n" - f"# Paper DOI: {PAPER_DOI}\n" - f"# PMID: {PAPER_PMID}\n" - f"# Help page: docs/help/examples/{topic}.md\n" - ) - - -def code_cell_setup(topic: str, family: str) -> str: - return f"""import matplotlib -matplotlib.use("Agg") -try: - from matplotlib_inline.backend_inline import set_matplotlib_formats - matplotlib.use("module://matplotlib_inline.backend_inline") - set_matplotlib_formats("png") -except Exception: - pass - -import numpy as np -import matplotlib.pyplot as plt - -from nstat.data_manager import ensure_example_data -from nstat.analysis import Analysis -from nstat.cif import CIFModel -from nstat.decoding import DecodingAlgorithms -from nstat.events import Events -from nstat.history import HistoryBasis -from nstat.signal import Covariate -from nstat.spikes import SpikeTrain, SpikeTrainCollection -from nstat.trial import CovariateCollection, Trial, TrialConfig - -TOPIC = \"{topic}\" -FAMILY = \"{family}\" -np.random.seed(2026) -rng = np.random.default_rng(2026) -DATA_DIR = ensure_example_data(download=True) -print(f\"Running notebook topic: {{TOPIC}} (family={{FAMILY}})\") -print(f\"Example data directory: {{DATA_DIR}}\") - -if \"MATLAB_LINE_TRACE\" not in globals(): - MATLAB_LINE_TRACE = [] - -def matlab_line(line: str): - MATLAB_LINE_TRACE.append(line) - return line - -def validate_numeric_checkpoints(metrics: dict[str, float], limits: dict[str, tuple[float, float]], topic: str) -> None: - if not metrics: - raise AssertionError(f\"{topic}: CHECKPOINT_METRICS is empty\") - for key, value in metrics.items(): - if not np.isfinite(value): - raise AssertionError(f\"{topic}: metric '{{key}}' is not finite: {{value}}\") - for key, (lo, hi) in limits.items(): - if key not in metrics: - raise AssertionError(f\"{topic}: missing checkpoint metric '{{key}}'\") - value = float(metrics[key]) - if value < float(lo) or value > float(hi): - raise AssertionError( - f\"{topic}: metric '{{key}}'={{value:.6f}} outside [{{float(lo):.6f}}, {{float(hi):.6f}}]\" - ) - print(f\"Numeric checkpoints for {{topic}}:\", metrics) -""" - - -ANALYSIS_TEMPLATE = """# Analysis/Fit workflow: build a Poisson GLM with two covariates. -time = np.linspace(0.0, 6.0, 6001) -dt = float(time[1] - time[0]) -stim_1 = np.sin(2.0 * np.pi * 0.8 * time) -stim_2 = np.cos(2.0 * np.pi * 0.35 * time + 0.25) -X = np.column_stack([stim_1, stim_2]) - -true_model = CIFModel(coefficients=np.array([0.45, -0.25]), intercept=np.log(8.0), link="poisson") -true_rate = true_model.evaluate(X) -spike_times = true_model.simulate_by_thinning(time, X, rng=rng) - -cov_1 = Covariate(time=time, data=stim_1, name="stim_1", labels=["stim_1"]) -cov_2 = Covariate(time=time, data=stim_2, name="stim_2", labels=["stim_2"]) -spikes = SpikeTrain(spike_times=spike_times, t_start=float(time[0]), t_end=float(time[-1]), name="unit_1") -trial = Trial(spikes=SpikeTrainCollection([spikes]), covariates=CovariateCollection([cov_1, cov_2])) -config = TrialConfig(covariate_labels=["stim_1", "stim_2"], sample_rate_hz=1.0 / dt, fit_type="poisson") -fit = Analysis.fit_trial(trial, config) -est_rate = fit.predict(X) - -fig, axes = plt.subplots(3, 1, figsize=(9, 7), sharex=True) -axes[0].plot(time, stim_1, label="stim_1", linewidth=1.0) -axes[0].plot(time, stim_2, label="stim_2", linewidth=1.0) -axes[0].set_title(f"{TOPIC}: inputs") -axes[0].legend(loc="upper right") - -axes[1].plot(time, true_rate, label="true rate", linewidth=1.2) -axes[1].plot(time, est_rate, label="estimated rate", linewidth=1.1) -axes[1].set_ylabel("Hz") -axes[1].legend(loc="upper right") - -centers, counts = spikes.bin_counts(bin_size_s=0.02) -axes[2].bar(centers, counts, width=0.018, color="tab:gray") -axes[2].set_xlabel("time [s]") -axes[2].set_ylabel("count/bin") - -plt.tight_layout() -plt.show() - -coef_error = float(np.linalg.norm(fit.coefficients - np.array([0.45, -0.25]))) -print("AIC", float(fit.aic()), "BIC", float(fit.bic()), "coef_error", coef_error) -assert np.isfinite(coef_error) -assert coef_error < 1.5, "Coefficient fit drifted too far from simulation truth" - -CHECKPOINT_METRICS = { - "coef_error": float(coef_error), - "mean_rate_hz": float(np.mean(true_rate)), -} -CHECKPOINT_LIMITS = { - "coef_error": (0.0, 1.5), - "mean_rate_hz": (1.0, 40.0), -} -""" - - -SIGNAL_TEMPLATE = """# Signal/History workflow: explore covariates, spikes, history design, and events. -time = np.linspace(0.0, 4.0, 4001) -s1 = np.sin(2.0 * np.pi * 1.2 * time) -s2 = 0.5 * np.cos(2.0 * np.pi * 0.45 * time + 0.4) -s3 = s1 + s2 - -cov = Covariate(time=time, data=np.column_stack([s1, s2, s3]), name="signals", labels=["s1", "s2", "s3"]) -base_prob = np.clip(0.005 + 0.03 * (s3 > np.percentile(s3, 65)), 0.0, 0.4) -spike_times = time[rng.random(time.size) < base_prob] -spikes = SpikeTrain(spike_times=spike_times, t_start=float(time[0]), t_end=float(time[-1]), name="unit_1") - -history = HistoryBasis(np.array([0.0, 0.005, 0.010, 0.020, 0.050])) -sample_times = time[::20] -H = history.design_matrix(spikes.spike_times, sample_times) - -burst_events = Events(times=np.array([0.5, 1.6, 2.4, 3.2]), labels=["A", "B", "C", "D"]) -centers, counts = spikes.bin_counts(bin_size_s=0.02) - -fig, axes = plt.subplots(3, 1, figsize=(9, 7), sharex=False) -axes[0].plot(time, cov.data[:, 0], label="s1", linewidth=1.0) -axes[0].plot(time, cov.data[:, 1], label="s2", linewidth=1.0) -axes[0].plot(time, cov.data[:, 2], label="s3", linewidth=1.0) -axes[0].set_title(f"{TOPIC}: signal and covariates") -axes[0].legend(loc="upper right") - -axes[1].bar(centers, counts, width=0.018, color="tab:gray") -axes[1].vlines(burst_events.times, ymin=0.0, ymax=max(counts.max(), 1.0), color="tab:red", linewidth=1.0) -axes[1].set_title("Binned spikes with event markers") -axes[1].set_ylabel("count/bin") - -im = axes[2].imshow(H.T, aspect="auto", origin="lower", cmap="magma") -axes[2].set_title("History basis design matrix") -axes[2].set_xlabel("time index") -axes[2].set_ylabel("history bin") -fig.colorbar(im, ax=axes[2], fraction=0.035, pad=0.02) - -plt.tight_layout() -plt.show() - -assert H.ndim == 2 and H.shape[1] == history.n_bins -assert spikes.spike_times.size > 5, "Not enough spikes generated" - -CHECKPOINT_METRICS = { - "history_rows": float(H.shape[0]), - "spike_count": float(spikes.spike_times.size), -} -CHECKPOINT_LIMITS = { - "history_rows": (50.0, 5000.0), - "spike_count": (6.0, 6000.0), -} -""" - - -DECODING_1D_TEMPLATE = """# 1D Decoding workflow: decode latent state sequence from population spikes. -n_units = 14 -n_states = 17 -n_time = 260 -state_idx = np.arange(n_states) - -transition = np.zeros((n_states, n_states), dtype=float) -for i in range(n_states): - for j, w in ((i - 1, 0.2), (i, 0.6), (i + 1, 0.2)): - if 0 <= j < n_states: - transition[i, j] += w - transition[i, :] /= np.sum(transition[i, :]) - -latent = np.zeros(n_time, dtype=int) -latent[0] = n_states // 2 -for t in range(1, n_time): - latent[t] = rng.choice(n_states, p=transition[latent[t - 1]]) - -centers = np.linspace(0.0, n_states - 1, n_units) -widths = np.full(n_units, 2.1) -state_axis = np.arange(n_states)[None, :] -tuning = 0.06 + 0.42 * np.exp(-0.5 * ((state_axis - centers[:, None]) / widths[:, None]) ** 2) - -use_history = TOPIC in {"DecodingExampleWithHist", "nSTATPaperExamples"} - -if use_history: - gain = np.ones(n_time, dtype=float) - counts = np.zeros((n_units, n_time), dtype=float) - prev = 0.0 - for t in range(n_time): - gain[t] = np.exp(0.50 * prev) - lam = tuning[:, latent[t]] * gain[t] - counts[:, t] = rng.poisson(lam) - prev = float(np.mean(counts[:, t])) - - decoded_raw, _ = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition) - corrected = counts / gain[None, :] - decoded, posterior = DecodingAlgorithms.decode_state_posterior(corrected, tuning, transition) - rmse_raw = float(np.sqrt(np.mean((decoded_raw - latent) ** 2)) / (n_states - 1)) - rmse_dec = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1)) -else: - counts = np.zeros((n_units, n_time), dtype=float) - for t in range(n_time): - counts[:, t] = rng.poisson(tuning[:, latent[t]]) - decoded, posterior = DecodingAlgorithms.decode_state_posterior(counts, tuning, transition) - rmse_raw = float(np.sqrt(np.mean((decoded - latent) ** 2)) / (n_states - 1)) - rmse_dec = rmse_raw - -fig, axes = plt.subplots(2, 1, figsize=(9, 7), sharex=True) -axes[0].plot(latent, label="true", linewidth=1.2) -axes[0].plot(decoded, label="decoded", linewidth=1.0) -axes[0].set_title(f"{TOPIC}: latent-state decoding") -axes[0].set_ylabel("state") -axes[0].legend(loc="upper right") - -im = axes[1].imshow(posterior, aspect="auto", origin="lower", cmap="viridis") -axes[1].set_title("Posterior over latent states") -axes[1].set_xlabel("time bin") -axes[1].set_ylabel("state") -fig.colorbar(im, ax=axes[1], fraction=0.03, pad=0.02) - -plt.tight_layout() -plt.show() - -print("rmse_raw", rmse_raw, "rmse_final", rmse_dec) -assert np.max(np.abs(np.sum(posterior, axis=0) - 1.0)) < 1e-6 -if use_history: - assert rmse_dec <= rmse_raw + 0.03 - -CHECKPOINT_METRICS = { - "rmse_raw": float(rmse_raw), - "rmse_dec": float(rmse_dec), -} -CHECKPOINT_LIMITS = { - "rmse_raw": (0.0, 0.65), - "rmse_dec": (0.0, 0.65), -} -""" - - -DECODING_2D_TEMPLATE = """# 2D Decoding workflow: decode trajectory from place-like tuning fields. -side = 14 -grid = np.linspace(0.0, 1.0, side) -gx, gy = np.meshgrid(grid, grid, indexing="xy") -states = np.column_stack([gx.ravel(), gy.ravel()]) -n_states = states.shape[0] - -n_units = 24 -n_time = 280 -traj = np.zeros((n_time, 2), dtype=float) -traj[0] = np.array([0.5, 0.5]) -vel = np.zeros(2, dtype=float) -for t in range(1, n_time): - vel = 0.82 * vel + 0.12 * rng.normal(size=2) - traj[t] = np.clip(traj[t - 1] + vel, 0.0, 1.0) - -state_match = np.sum((states[None, :, :] - traj[:, None, :]) ** 2, axis=2) -latent = np.argmin(state_match, axis=1) - -centers = rng.uniform(0.0, 1.0, size=(n_units, 2)) -sigma = 0.16 -dist2 = np.sum((states[None, :, :] - centers[:, None, :]) ** 2, axis=2) -tuning = 0.03 + 0.80 * np.exp(-0.5 * dist2 / (sigma**2)) - -spike_counts = np.zeros((n_units, n_time), dtype=float) -for t in range(n_time): - spike_counts[:, t] = rng.poisson(tuning[:, latent[t]]) - -decoded = DecodingAlgorithms.decode_weighted_center(spike_counts, tuning) -decoded = np.clip(np.rint(decoded), 0, n_states - 1).astype(int) - -xy_true = states[latent] -xy_decoded = states[decoded] -rmse = float(np.sqrt(np.mean(np.sum((xy_decoded - xy_true) ** 2, axis=1)))) - -fig, axes = plt.subplots(1, 2, figsize=(9.5, 4.5)) -axes[0].plot(xy_true[:, 0], xy_true[:, 1], label="true", linewidth=1.2) -axes[0].plot(xy_decoded[:, 0], xy_decoded[:, 1], label="decoded", linewidth=1.0) -axes[0].set_title(f"{TOPIC}: decoded trajectory") -axes[0].set_xlabel("x") -axes[0].set_ylabel("y") -axes[0].set_aspect("equal", adjustable="box") -axes[0].legend(loc="upper right") - -field_idx = 6 if TOPIC == "HippocampalPlaceCellExample" else 3 -im = axes[1].imshow( - tuning[field_idx].reshape(side, side), - origin="lower", - extent=[0.0, 1.0, 0.0, 1.0], - cmap="jet", - aspect="equal", -) -axes[1].set_title("Example receptive field") -axes[1].set_xlabel("x") -axes[1].set_ylabel("y") -fig.colorbar(im, ax=axes[1], fraction=0.04, pad=0.03) - -plt.tight_layout() -plt.show() - -print("trajectory rmse", rmse) -assert rmse < 1.25 - -CHECKPOINT_METRICS = { - "trajectory_rmse": float(rmse), - "decoded_unique_states": float(np.unique(decoded).size), -} -CHECKPOINT_LIMITS = { - "trajectory_rmse": (0.0, 1.25), - "decoded_unique_states": (2.0, float(n_states)), -} -""" - - -STIMULUS_DECODE_2D_TEMPLATE = """# StimulusDecode2D: fixture-backed 2D trajectory decoding parity check. -from pathlib import Path -import nstat -from scipy.io import loadmat -fixture_path = Path(nstat.__file__).resolve().parents[2] / "tests/parity/fixtures/matlab_gold/StimulusDecode2D_gold.mat" -m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False) -states = np.asarray(m["states_sd"], dtype=float); latent = np.asarray(m["latent_sd"], dtype=int).reshape(-1) -tuning = np.asarray(m["tuning_sd"], dtype=float); spike_counts = np.asarray(m["spike_counts_sd"], dtype=float) -decoded_center = DecodingAlgorithms.decode_weighted_center(spike_counts=spike_counts, tuning_curves=tuning) -decoded = np.clip(np.rint(decoded_center), 0, states.shape[0] - 1).astype(int) -xy_true = np.asarray(m["xy_true_sd"], dtype=float); xy_decoded = states[decoded] -rmse = float(np.sqrt(np.mean(np.sum((xy_decoded - xy_true) ** 2, axis=1)))) -expected_center = np.asarray(m["decoded_center_sd"], dtype=float).reshape(-1); expected_decoded = np.asarray(m["decoded_sd"], dtype=int).reshape(-1); expected_rmse = float(np.asarray(m["rmse_sd"], dtype=float).reshape(-1)[0]) -center_err = float(np.max(np.abs(decoded_center - expected_center))); decoded_mismatch = float(np.count_nonzero(decoded != expected_decoded)); rmse_err = float(abs(rmse - expected_rmse)) -assert center_err <= 1e-8 and decoded_mismatch == 0.0 and rmse_err <= 1e-10 - -side = int(round(np.sqrt(states.shape[0]))); field_idx = 3 -fig, axes = plt.subplots(1, 2, figsize=(9.5, 4.5)) -axes[0].plot(xy_true[:, 0], xy_true[:, 1], label="true", linewidth=1.2) -axes[0].plot(xy_decoded[:, 0], xy_decoded[:, 1], label="decoded", linewidth=1.0) -axes[0].set_title(f"{TOPIC}: decoded trajectory"); axes[0].set_xlabel("x"); axes[0].set_ylabel("y"); axes[0].set_aspect("equal", adjustable="box"); axes[0].legend(loc="upper right") -im = axes[1].imshow(tuning[field_idx].reshape(side, side), origin="lower", extent=[0.0, 1.0, 0.0, 1.0], cmap="jet", aspect="equal") -axes[1].set_title("Example receptive field"); axes[1].set_xlabel("x"); axes[1].set_ylabel("y"); fig.colorbar(im, ax=axes[1], fraction=0.04, pad=0.03) -plt.tight_layout(); plt.show() - -CHECKPOINT_METRICS = {"trajectory_rmse": float(rmse), "decoded_unique_states": float(np.unique(decoded).size), "decoded_center_max_abs_error": center_err, "decoded_mismatch_count": decoded_mismatch} -CHECKPOINT_LIMITS = {"trajectory_rmse": (0.0, 1.5), "decoded_unique_states": (2.0, float(states.shape[0])), "decoded_center_max_abs_error": (0.0, 1e-8), "decoded_mismatch_count": (0.0, 0.0)} -""" - - -NETWORK_TEMPLATE = """# Network / simulation workflow: coupled point-process style simulation. -T = 3.0 -dt = 0.002 -n_t = int(T / dt) -time = np.arange(n_t) * dt - -n_units = 3 -baseline = np.array([-3.8, -4.0, -4.2]) -stim = 0.8 * np.sin(2.0 * np.pi * 1.1 * time) -W_stim = np.array([1.0, -0.7, 0.5]) -W_couple = np.array( - [ - [0.0, -1.2, 0.4], - [0.9, 0.0, -0.6], - [0.3, 0.6, 0.0], - ] -) - -spikes = np.zeros((n_units, n_t), dtype=float) -for t in range(1, n_t): - coupling_drive = W_couple @ spikes[:, t - 1] - linear = baseline + W_stim * stim[t] + coupling_drive - lam_dt = np.clip(np.exp(linear), 1e-8, 0.8) - spikes[:, t] = rng.binomial(1, lam_dt) - -if TOPIC == "PPThinning": - x = np.sin(2.0 * np.pi * 1.4 * time) - model = CIFModel(coefficients=np.array([0.5]), intercept=np.log(10.0), link="poisson") - thin_spikes = model.simulate_by_thinning(time, x[:, None], rng=rng) -else: - thin_spikes = np.array([], dtype=float) - -fig, axes = plt.subplots(3, 1, figsize=(9, 7), sharex=True) -axes[0].plot(time, stim, color="black", linewidth=1.0) -axes[0].set_title(f"{TOPIC}: network simulation stimulus") -axes[0].set_ylabel("stim") - -for i in range(n_units): - spike_times = time[spikes[i] > 0] - axes[1].vlines(spike_times, i + 0.6, i + 1.4, linewidth=0.6) -axes[1].set_ylabel("unit") -axes[1].set_title("Network spike raster") - -im = axes[2].imshow(W_couple, cmap="coolwarm", vmin=-1.2, vmax=1.2) -axes[2].set_title("Coupling matrix") -axes[2].set_xlabel("source unit") -axes[2].set_ylabel("target unit") -fig.colorbar(im, ax=axes[2], fraction=0.03, pad=0.02) - -if thin_spikes.size > 0: - axes[1].vlines(thin_spikes, 3.6, 4.4, linewidth=0.6, color="tab:red") - axes[1].set_ylim(0.5, 4.5) - -plt.tight_layout() -plt.show() - -mean_rate = spikes.mean(axis=1) / dt -print("mean firing rates", mean_rate) -assert np.all(mean_rate > 0.1) - -CHECKPOINT_METRICS = { - "mean_rate_unit0": float(mean_rate[0]), - "mean_rate_unit1": float(mean_rate[1]), -} -CHECKPOINT_LIMITS = { - "mean_rate_unit0": (0.1, 120.0), - "mean_rate_unit1": (0.1, 120.0), -} -""" - - -DATA_TEMPLATE = """# Data-style workflow: trial-to-trial variability and PSTH-like estimates. -dt = 0.001 -time = np.arange(0.0, 1.2, dt) -n_trials = 30 - -rate = 5.0 + 8.0 * (time > 0.35) + 4.0 * np.sin(2.0 * np.pi * 2.0 * time) -rate = np.clip(rate, 0.2, None) - -trial_matrix = np.zeros((n_trials, time.size), dtype=float) -for k in range(n_trials): - jitter = 0.6 + 0.8 * rng.random() - p = np.clip(rate * jitter * dt, 0.0, 0.6) - trial_matrix[k, :] = rng.binomial(1, p) - -psth = trial_matrix.mean(axis=0) / dt -sem = trial_matrix.std(axis=0, ddof=1) / np.sqrt(n_trials) / dt - -rates, prob_mat, sig_mat = DecodingAlgorithms.compute_spike_rate_cis(trial_matrix) - -fig, axes = plt.subplots(3, 1, figsize=(9, 7), sharex=False) -for k in range(min(18, n_trials)): - t_spk = time[trial_matrix[k] > 0] - axes[0].vlines(t_spk, k + 0.6, k + 1.4, linewidth=0.5) -axes[0].set_title(f"{TOPIC}: trial raster") -axes[0].set_ylabel("trial") - -axes[1].plot(time, psth, color="tab:blue", linewidth=1.2) -axes[1].fill_between(time, psth - sem, psth + sem, color="tab:blue", alpha=0.2) -axes[1].set_ylabel("Hz") -axes[1].set_title("PSTH mean +/- SEM") - -im = axes[2].imshow(prob_mat, aspect="auto", origin="lower", cmap="viridis") -axes[2].set_title("Trial-by-trial spike-rate p-values") -axes[2].set_xlabel("trial") -axes[2].set_ylabel("trial") -fig.colorbar(im, ax=axes[2], fraction=0.03, pad=0.02) - -plt.tight_layout() -plt.show() - -print("significant pair count", int(sig_mat.sum())) -assert np.allclose(prob_mat, prob_mat.T, atol=1e-12) -assert np.all(np.diag(prob_mat) == 1.0) - -CHECKPOINT_METRICS = { - "psth_mean_hz": float(np.mean(psth)), - "significant_pairs": float(np.sum(sig_mat)), -} -CHECKPOINT_LIMITS = { - "psth_mean_hz": (0.1, 50.0), - "significant_pairs": (0.0, float(sig_mat.size)), -} -""" - - -VALIDATION_DATASET_TEMPLATE = """# ValidationDataSet: load MATLAB-gold trial matrix and reproduce raster/PSTH/significance summaries. -from pathlib import Path -import nstat -from scipy.io import loadmat -fixture_path = Path(nstat.__file__).resolve().parents[2] / "tests/parity/fixtures/matlab_gold/ValidationDataSet_gold.mat" -m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False) -dt = float(np.asarray(m["dt_val"], dtype=float).reshape(-1)[0]); time = np.asarray(m["time_val"], dtype=float).reshape(-1) -trial_matrix = np.asarray(m["trial_matrix_val"], dtype=float); psth = np.asarray(m["psth_val"], dtype=float).reshape(-1); sem = np.asarray(m["sem_val"], dtype=float).reshape(-1) -rates, prob_mat, sig_mat = DecodingAlgorithms.compute_spike_rate_cis(spike_matrix=trial_matrix, alpha=0.05) -exp_rates = np.asarray(m["expected_rate_val"], dtype=float).reshape(-1); exp_prob = np.asarray(m["expected_prob_val"], dtype=float); exp_sig = np.asarray(m["expected_sig_val"], dtype=int) -fig, axes = plt.subplots(3, 1, figsize=(9, 7), sharex=False) -for k in range(min(18, trial_matrix.shape[0])): axes[0].vlines(time[trial_matrix[k] > 0], k + 0.6, k + 1.4, linewidth=0.5) -axes[0].set_title(f"{TOPIC}: trial raster"); axes[0].set_ylabel("trial") -axes[1].plot(time, psth, color="tab:blue", linewidth=1.2); axes[1].fill_between(time, psth - sem, psth + sem, color="tab:blue", alpha=0.2); axes[1].set_ylabel("Hz"); axes[1].set_title("PSTH mean +/- SEM") -im = axes[2].imshow(prob_mat, aspect="auto", origin="lower", cmap="viridis"); axes[2].set_title("Trial-by-trial spike-rate p-values"); axes[2].set_xlabel("trial"); axes[2].set_ylabel("trial"); fig.colorbar(im, ax=axes[2], fraction=0.03, pad=0.02) -plt.tight_layout(); plt.show() -rate_err = float(np.max(np.abs(rates - exp_rates))); prob_err = float(np.max(np.abs(prob_mat - exp_prob))); sig_mismatch = float(np.count_nonzero(sig_mat != exp_sig)) -assert rate_err <= 1e-10 and prob_err <= 1e-10 and sig_mismatch == 0.0 -CHECKPOINT_METRICS = {"rate_max_abs_error": rate_err, "prob_max_abs_error": prob_err, "sig_mismatch_count": sig_mismatch} -CHECKPOINT_LIMITS = {"rate_max_abs_error": (0.0, 1e-10), "prob_max_abs_error": (0.0, 1e-10), "sig_mismatch_count": (0.0, 0.0)} -""" - - -EXPLICIT_STIMULUS_WHISKER_TEMPLATE = """# ExplicitStimulusWhiskerData: stimulus-locked spiking with binomial GLM fit. -from pathlib import Path -import nstat -from scipy.io import loadmat -fixture_path = Path(nstat.__file__).resolve().parents[2] / "tests/parity/fixtures/matlab_gold/ExplicitStimulusWhiskerData_gold.mat" -m = loadmat(str(fixture_path)) -time = np.asarray(m["time_ws"], dtype=float).reshape(-1); stimulus = np.asarray(m["stimulus_ws"], dtype=float).reshape(-1); spike = np.asarray(m["spike_ws"], dtype=float).reshape(-1) -expected_prob = np.asarray(m["expected_prob_ws"], dtype=float).reshape(-1); expected_rmse = float(np.asarray(m["expected_rmse_ws"], dtype=float).reshape(-1)[0]) -fit = Analysis.fit_glm(X=stimulus[:, None], y=spike, fit_type="binomial", dt=1.0); pred_prob = np.asarray(fit.predict(stimulus[:, None]), dtype=float).reshape(-1) -window = np.ones(25, dtype=float) / 25.0; spike_prob = np.convolve(spike, window, mode="same") - -fig, axes = plt.subplots(3, 1, figsize=(9.5, 7.2), sharex=False) -axes[0].plot(time, stimulus, color="k", linewidth=1.0) -axes[0].set_title(f"{TOPIC}: explicit stimulus") -axes[0].set_ylabel("z-score") - -axes[1].vlines(time[spike > 0.0], 0.6, 1.4, linewidth=0.4) -axes[1].set_ylabel("trial #1") -axes[1].set_title("Spike raster (MATLAB fixture trial)") - -axes[2].plot(time, spike_prob, color="tab:blue", linewidth=1.0, label="smoothed observed") -axes[2].plot(time, pred_prob, color="tab:red", linewidth=1.0, label="python fit") -axes[2].plot(time, expected_prob, color="tab:green", linewidth=0.9, linestyle="--", label="matlab gold") -axes[2].set_title("Observed and fitted spike probability") -axes[2].set_xlabel("time [s]") -axes[2].set_ylabel("p(spike)") -axes[2].legend(loc="upper right") -plt.tight_layout() -plt.show() - -fit_rmse = float(np.sqrt(np.mean((pred_prob - spike) ** 2))); prob_max_abs = float(np.max(np.abs(pred_prob - expected_prob))) -assert pred_prob.shape == expected_prob.shape -assert prob_max_abs < 0.1 -assert abs(fit_rmse - expected_rmse) < 0.1 -CHECKPOINT_METRICS = { - "prob_max_abs": float(prob_max_abs), - "fit_rmse": float(fit_rmse), -} -CHECKPOINT_LIMITS = { - "prob_max_abs": (0.0, 0.1), - "fit_rmse": (0.0, 0.5), -} -""" - - -MEPSC_ANALYSIS_TEMPLATE = """# mEPSCAnalysis: synthetic current trace and event detection summary. -dt = 0.0005 -time = np.arange(0.0, 12.0, dt) -n = time.size - -# Generate baseline noise and negative-going mEPSC-like events. -trace = 0.025 * rng.standard_normal(n) -event_times_true = np.sort(rng.uniform(0.4, 11.6, size=75)) -event_amps = rng.uniform(0.12, 0.42, size=event_times_true.size) -tau_rise = 0.0015 -tau_decay = 0.010 - -kernel_t = np.arange(0.0, 0.060, dt) -kernel = (1.0 - np.exp(-kernel_t / tau_rise)) * np.exp(-kernel_t / tau_decay) -kernel = kernel / np.max(kernel) - -for t_evt, amp in zip(event_times_true, event_amps, strict=False): - idx = int(round(t_evt / dt)) - end = min(idx + kernel.size, n) - k = kernel[: end - idx] - trace[idx:end] -= amp * k - -# Simple threshold-crossing detection with refractory period. -threshold = -0.12 -refractory = int(round(0.006 / dt)) -candidate = np.where(trace < threshold)[0] -detected_idx: list[int] = [] -last = -refractory -for idx in candidate: - if idx - last >= refractory: - window_end = min(idx + int(round(0.004 / dt)) + 1, n) - local = idx + int(np.argmin(trace[idx:window_end])) - detected_idx.append(local) - last = local -detected_idx = np.array(detected_idx, dtype=int) -detected_times = detected_idx * dt -detected_amps = -trace[detected_idx] -events = Events(times=detected_times, labels=[f"e{i}" for i in range(detected_times.size)]) - -fig, axes = plt.subplots(3, 1, figsize=(10, 7.2), sharex=False) -axes[0].plot(time, trace, color="0.15", linewidth=0.7) -axes[0].scatter(detected_times, trace[detected_idx], color="tab:red", s=10, alpha=0.8) -axes[0].set_title(f"{TOPIC}: synthetic mEPSC trace with detections") -axes[0].set_ylabel("current [a.u.]") - -axes[1].hist(detected_amps, bins=25, color="tab:blue", alpha=0.85) -axes[1].set_title("Detected event amplitudes") -axes[1].set_xlabel("amplitude [a.u.]") -axes[1].set_ylabel("count") - -iei = np.diff(events.times) if events.times.size > 1 else np.array([0.0]) -axes[2].hist(iei, bins=25, color="tab:green", alpha=0.85) -axes[2].set_title("Inter-event interval distribution") -axes[2].set_xlabel("interval [s]") -axes[2].set_ylabel("count") - -plt.tight_layout() -plt.show() - -assert events.times.size > 30 -assert float(np.mean(detected_amps) if detected_amps.size else 0.0) > 0.08 -CHECKPOINT_METRICS = { - "detected_event_count": float(events.times.size), - "mean_detected_amplitude": float(np.mean(detected_amps) if detected_amps.size else 0.0), -} -CHECKPOINT_LIMITS = { - "detected_event_count": (30.0, 220.0), - "mean_detected_amplitude": (0.08, 0.6), -} -""" - - -ANALYSIS_EXAMPLES_TEMPLATE = """# AnalysisExamples: spatial firing-rate modeling with x-y covariates. -n_t = 4500 -dt = 0.01 -time = np.arange(n_t) * dt - -xy = np.zeros((n_t, 2), dtype=float) -xy[0] = np.array([45.0, 55.0]) -vel = np.zeros(2, dtype=float) -for t in range(1, n_t): - vel = 0.92 * vel + 2.0 * rng.normal(size=2) - xy[t] = np.clip(xy[t - 1] + vel, 0.0, 100.0) - -xc, yc, sigma = 62.0, 38.0, 16.0 -r2 = (xy[:, 0] - xc) ** 2 + (xy[:, 1] - yc) ** 2 -true_rate = 1.2 + 18.0 * np.exp(-0.5 * r2 / (sigma**2)) -counts = rng.poisson(true_rate * dt) - -X_lin = np.column_stack([xy[:, 0], xy[:, 1]]) -fit_lin = Analysis.fit_glm(X=X_lin, y=counts, fit_type="poisson", dt=dt) -est_rate = fit_lin.predict(X_lin) - -grid = np.linspace(0.0, 100.0, 35) -gx, gy = np.meshgrid(grid, grid, indexing="xy") -Xg = np.column_stack([gx.ravel(), gy.ravel()]) -true_map = 1.2 + 18.0 * np.exp(-0.5 * (((Xg[:, 0] - xc) ** 2 + (Xg[:, 1] - yc) ** 2) / (sigma**2))) -est_map = fit_lin.predict(Xg) - -spike_mask = counts > 0 - -fig, axes = plt.subplots(2, 2, figsize=(10, 8)) -axes[0, 0].plot(xy[:, 0], xy[:, 1], color="0.75", linewidth=0.8) -axes[0, 0].scatter(xy[spike_mask, 0], xy[spike_mask, 1], s=5, c="tab:red", alpha=0.6) -axes[0, 0].set_title(f"{TOPIC}: trajectory and spikes") -axes[0, 0].set_xlabel("x") -axes[0, 0].set_ylabel("y") -axes[0, 0].set_aspect("equal", adjustable="box") - -im1 = axes[0, 1].imshow(true_map.reshape(grid.size, grid.size), origin="lower", extent=[0, 100, 0, 100], cmap="jet") -axes[0, 1].set_title("True place field") -axes[0, 1].set_xlabel("x") -axes[0, 1].set_ylabel("y") -fig.colorbar(im1, ax=axes[0, 1], fraction=0.04, pad=0.03) - -im2 = axes[1, 0].imshow(est_map.reshape(grid.size, grid.size), origin="lower", extent=[0, 100, 0, 100], cmap="jet") -axes[1, 0].set_title("Estimated linear model field") -axes[1, 0].set_xlabel("x") -axes[1, 0].set_ylabel("y") -fig.colorbar(im2, ax=axes[1, 0], fraction=0.04, pad=0.03) - -axes[1, 1].plot(time[:800], true_rate[:800], label="true", linewidth=1.1) -axes[1, 1].plot(time[:800], est_rate[:800], label="estimated", linewidth=1.0) -axes[1, 1].set_title("Rate trace (first 8 s)") -axes[1, 1].set_xlabel("time [s]") -axes[1, 1].set_ylabel("Hz") -axes[1, 1].legend(loc="upper right") - -plt.tight_layout() -plt.show() - -rmse_rate = float(np.sqrt(np.mean((est_rate - true_rate) ** 2))) -print("rmse_rate", rmse_rate, "aic", float(fit_lin.aic())) -assert np.isfinite(rmse_rate) -assert rmse_rate < 8.0 - -CHECKPOINT_METRICS = { - "rmse_rate": float(rmse_rate), - "mean_true_rate": float(np.mean(true_rate)), -} -CHECKPOINT_LIMITS = { - "rmse_rate": (0.0, 8.0), - "mean_true_rate": (0.2, 30.0), -} -""" - - -ANALYSIS_EXAMPLES2_TEMPLATE = """# AnalysisExamples2: compare linear and quadratic spatial Poisson GLMs. -n_t = 5000 -dt = 0.01 -time = np.arange(n_t) * dt - -xy = np.zeros((n_t, 2), dtype=float) -xy[0] = np.array([50.0, 50.0]) -vel = np.zeros(2, dtype=float) -for t in range(1, n_t): - vel = 0.9 * vel + 2.4 * rng.normal(size=2) - xy[t] = np.clip(xy[t - 1] + vel, 0.0, 100.0) - -xc, yc, sigma = 35.0, 70.0, 14.0 -r2 = (xy[:, 0] - xc) ** 2 + (xy[:, 1] - yc) ** 2 -true_rate = 1.0 + 20.0 * np.exp(-0.5 * r2 / (sigma**2)) -counts = rng.poisson(true_rate * dt) - -X_lin = np.column_stack([xy[:, 0], xy[:, 1]]) -X_quad = np.column_stack([xy[:, 0], xy[:, 1], xy[:, 0] ** 2, xy[:, 1] ** 2, xy[:, 0] * xy[:, 1]]) - -fit_lin = Analysis.fit_glm(X=X_lin, y=counts, fit_type="poisson", dt=dt) -fit_quad = Analysis.fit_glm(X=X_quad, y=counts, fit_type="poisson", dt=dt) - -grid = np.linspace(0.0, 100.0, 35) -gx, gy = np.meshgrid(grid, grid, indexing="xy") -Xg_lin = np.column_stack([gx.ravel(), gy.ravel()]) -Xg_quad = np.column_stack([gx.ravel(), gy.ravel(), gx.ravel() ** 2, gy.ravel() ** 2, gx.ravel() * gy.ravel()]) -true_map = 1.0 + 20.0 * np.exp( - -0.5 * (((Xg_lin[:, 0] - xc) ** 2 + (Xg_lin[:, 1] - yc) ** 2) / (sigma**2)) -) -lin_map = fit_lin.predict(Xg_lin) -quad_map = fit_quad.predict(Xg_quad) - -fig, axes = plt.subplots(2, 2, figsize=(10, 8)) -im0 = axes[0, 0].imshow(true_map.reshape(grid.size, grid.size), origin="lower", extent=[0, 100, 0, 100], cmap="jet") -axes[0, 0].set_title("True field") -fig.colorbar(im0, ax=axes[0, 0], fraction=0.04, pad=0.03) - -im1 = axes[0, 1].imshow(lin_map.reshape(grid.size, grid.size), origin="lower", extent=[0, 100, 0, 100], cmap="jet") -axes[0, 1].set_title("Linear GLM field") -fig.colorbar(im1, ax=axes[0, 1], fraction=0.04, pad=0.03) - -im2 = axes[1, 0].imshow(quad_map.reshape(grid.size, grid.size), origin="lower", extent=[0, 100, 0, 100], cmap="jet") -axes[1, 0].set_title("Quadratic GLM field") -fig.colorbar(im2, ax=axes[1, 0], fraction=0.04, pad=0.03) - -aic_vals = np.array([fit_lin.aic(), fit_quad.aic()], dtype=float) -axes[1, 1].bar(["linear", "quadratic"], aic_vals, color=["tab:gray", "tab:blue"]) -axes[1, 1].set_title("Model comparison (AIC)") -axes[1, 1].set_ylabel("AIC") - -plt.tight_layout() -plt.show() - -rmse_lin = float(np.sqrt(np.mean((fit_lin.predict(X_lin) - true_rate) ** 2))) -rmse_quad = float(np.sqrt(np.mean((fit_quad.predict(X_quad) - true_rate) ** 2))) -print("rmse_lin", rmse_lin, "rmse_quad", rmse_quad) -assert rmse_quad <= rmse_lin + 0.8 - -CHECKPOINT_METRICS = { - "rmse_lin": float(rmse_lin), - "rmse_quad": float(rmse_quad), -} -CHECKPOINT_LIMITS = { - "rmse_lin": (0.0, 20.0), - "rmse_quad": (0.0, 20.0), -} -""" - - -SIGNALOBJ_EXAMPLES_TEMPLATE = """# SignalObjExamples: fixture-backed SignalObj parity checks. -from pathlib import Path -import nstat -from scipy.io import loadmat -from nstat.compat.matlab import SignalObj - -m = loadmat(Path(nstat.__file__).resolve().parents[2] / "tests/parity/fixtures/matlab_gold/SignalObjExamples_gold.mat", squeeze_me=True) -t = np.asarray(m["time_sig"], dtype=float).reshape(-1); v1 = np.asarray(m["v1_sig"], dtype=float).reshape(-1); v2 = np.asarray(m["v2_sig"], dtype=float).reshape(-1) -matlab_line("figure") -matlab_line("s.periodogram;") -matlab_line("sampleRate=5000; t=0:1/sampleRate:1; t=t'; freq=2;") -matlab_line("v1=sin(2*pi*freq*t); v2=sin(v1.^2);") -matlab_line("noise=.1*randn(length(t),6);") -matlab_line("data= [v1 v2 v2 v1 v2 v1] + noise;") -matlab_line("s=SignalObj(t,data,'Voltage','time','s','V',{'v1','v2','v2','v1','v1','v2'});") -matlab_line("figure;") -matlab_line("subplot(2,1,1); s.plot;") -matlab_line("subplot(2,1,2); s.plotAllVariability;") -matlab_line("s.plotVariability;") -matlab_line("figure;") -matlab_line("subplot(3,1,1); s.plotAllVariability('b');") -matlab_line("subplot(3,1,2); s.plotAllVariability('g',2);") -matlab_line("subplot(3,1,3); s.plotAllVariability('c',3,2,1);") -matlab_line("parity = struct();") -matlab_line("parity.sample_rate_hz = sampleRate;") -s = SignalObj(time=t, data=np.column_stack([v1, v2]), name="Voltage", units="V").setDataLabels(["v1", "v2"]).setXlabel("time").setXUnits("s").setYLabel("Voltage").setYUnits("V") -s.setMask(["v1"]); masked_cols = float(len(s.findIndFromDataMask())); s.resetMask() -s_resampled = s.resample(float(np.asarray(m["resample_hz_sig"]).reshape(-1)[0])); s_win = s.getSigInTimeWindow(float(np.asarray(m["window_t0_sig"]).reshape(-1)[0]), float(np.asarray(m["window_t1_sig"]).reshape(-1)[0])) -f_per, p_per = s.periodogram(); expected_peak = int(np.asarray(m["periodogram_peak_idx_sig"], dtype=int).reshape(-1)[0]); peak_idx = int(np.argmax(p_per)) -s.setName("testName") -s_der = s.derivative() -s_int = s.integral() -s_sub = s.getSubSignal([0]) -s_repeat = SignalObj(time=t, data=np.column_stack([v1, v1, v2]), name="Voltage", units="V").setDataLabels(["v1", "v1", "v2"]) -s_repeat_v1 = s_repeat.getSubSignal([0, 1]) - -fig, ax = plt.subplots(2, 2, figsize=(10, 6)) -plt.sca(ax[0, 0]); s.plot(); ax[0, 0].set_title("SignalObj.plot") -plt.sca(ax[0, 1]); s_resampled.plot(); ax[0, 1].set_title("resample") -plt.sca(ax[1, 0]); s_win.plot(); ax[1, 0].set_title("time window") -ax[1, 1].plot(f_per, p_per, "k", linewidth=1.0); ax[1, 1].set_title("periodogram") -plt.tight_layout(); plt.show() - -assert masked_cols == float(np.asarray(m["masked_cols_sig"]).reshape(-1)[0]) -assert peak_idx == expected_peak -assert s.getNumSamples() == int(np.asarray(m["n_samples_sig"], dtype=int).reshape(-1)[0]) -assert s_resampled.getNumSamples() == int(np.asarray(m["resampled_n_samples_sig"], dtype=int).reshape(-1)[0]) -assert s_win.getNumSamples() == int(np.asarray(m["window_n_samples_sig"], dtype=int).reshape(-1)[0]) -assert s_der.getNumSamples() == s.getNumSamples() -assert s_int.shape[0] == s.getNumSamples() -assert s_sub.getNumSignals() == 1 -assert s_repeat_v1.getNumSignals() == 2 - -CHECKPOINT_METRICS = { - "masked_cols": float(masked_cols), - "periodogram_peak_idx": float(peak_idx), - "resampled_samples": float(s_resampled.getNumSamples()), - "window_samples": float(s_win.getNumSamples()), -} -CHECKPOINT_LIMITS = { - "masked_cols": (1.0, 1.0), - "periodogram_peak_idx": (0.0, 50000.0), - "resampled_samples": (10.0, 2000.0), - "window_samples": (10.0, 5000.0), -} -""" - - -HISTORY_EXAMPLES_TEMPLATE = """# HistoryExamples: fixture-backed history basis parity checks. -from pathlib import Path -import nstat -from scipy.io import loadmat -from nstat.compat.matlab import History - -m = loadmat(Path(nstat.__file__).resolve().parents[2] / "tests/parity/fixtures/matlab_gold/HistoryExamples_gold.mat", squeeze_me=True) -edges = np.asarray(m["bin_edges_hist"], dtype=float).reshape(-1); spike_times = np.asarray(m["spike_times_hist"], dtype=float).reshape(-1); time_grid = np.asarray(m["time_grid_hist"], dtype=float).reshape(-1) -history = History(bin_edges_s=edges); H = history.computeHistory(spike_times, time_grid); filt = history.toFilter() -H_expected = np.asarray(m["H_expected_hist"], dtype=float); filt_expected = np.asarray(m["filter_expected_hist"], dtype=float).reshape(-1) - -fig, ax = plt.subplots(1, 2, figsize=(9, 3.6)) -plt.sca(ax[0]); history.plot(); ax[0].set_title("History windows") -im = ax[1].imshow(H.T, aspect="auto", origin="lower", cmap="magma"); ax[1].set_title("History design matrix") -fig.colorbar(im, ax=ax[1], fraction=0.045, pad=0.04); plt.tight_layout(); plt.show() - -assert H.shape == H_expected.shape -assert np.allclose(H, H_expected, atol=0.0) -assert np.allclose(filt, filt_expected, atol=0.0) -assert history.getNumBins() == int(np.asarray(m["n_bins_hist"], dtype=int).reshape(-1)[0]) - -CHECKPOINT_METRICS = { - "history_bins": float(history.getNumBins()), - "history_sum": float(np.sum(H)), - "filter_sum": float(np.sum(filt)), -} -CHECKPOINT_LIMITS = { - "history_bins": (1.0, 100.0), - "history_sum": (0.0, 1.0e9), - "filter_sum": (1.0, 1.0), -} -""" - - -COVARIATE_EXAMPLES_TEMPLATE = """# CovariateExamples: build and inspect multiple covariate signals. -t = np.arange(0.0, 5.0 + 0.01, 0.01); x = np.exp(-t); y = np.sin(2.0 * np.pi * t); z = (-y) ** 3 -force = Covariate(time=t, data=np.column_stack([np.abs(y), np.abs(y) ** 2]), name="Force", labels=["f_x", "f_y"]) -position = Covariate(time=t, data=np.column_stack([x, y, z]), name="Position", labels=["x", "y", "z"]) -force_zero_mean = force.data - np.mean(force.data, axis=0, keepdims=True) - -fig, axes = plt.subplots(2, 2, figsize=(10, 7), sharex=True) -axes[0, 0].plot(t, position.data[:, 0], "g", linewidth=0.6, label="x") -axes[0, 0].plot(t, position.data[:, 1], "k", linewidth=0.6, label="y") -axes[0, 0].plot(t, position.data[:, 2], "b", linewidth=0.6, label="z") -axes[0, 0].set_title(f"{TOPIC}: position covariates"); axes[0, 0].legend(loc="upper right") -axes[0, 1].plot(t, force.data[:, 0], "b", linewidth=1.0, label="f_x") -axes[0, 1].plot(t, force.data[:, 1], "k", linewidth=1.0, label="f_y") -axes[0, 1].set_title("Force (original)"); axes[0, 1].legend(loc="upper right") -axes[1, 0].plot(t, force_zero_mean[:, 0], "b", linewidth=1.0, label="f_x") -axes[1, 0].plot(t, force_zero_mean[:, 1], "k", linewidth=1.0, label="f_y") -axes[1, 0].set_title("Force (zero-mean)"); axes[1, 0].legend(loc="upper right") -axes[1, 1].plot(t, position.data[:, 1], "k", linewidth=1.0); axes[1, 1].set_title("Position y") -for ax in axes.ravel(): ax.set_xlabel("time [s]") -plt.tight_layout(); plt.show() - -assert position.data.shape == (t.size, 3) -assert force.data.shape == (t.size, 2) -assert np.isfinite(force_zero_mean).all() -CHECKPOINT_METRICS = {"position_var": float(np.var(position.data[:, 1])), "force_mean": float(np.mean(force.data[:, 0]))} -CHECKPOINT_LIMITS = {"position_var": (0.05, 2.0), "force_mean": (0.0, 2.0)} -""" - - -EVENTS_EXAMPLES_TEMPLATE = """# EventsExamples: visualize event markers over multiple contexts. -e_times = np.array([0.079, 0.579, 0.997], dtype=float); events = Events(times=e_times, labels=["E_1", "E_2", "E_3"]) -fig, ax = plt.subplots(1, 1, figsize=(10.74, 6.48)) -for c in ["b", "r", "g", "m"]: ax.vlines(events.times, ymin=0.0, ymax=1.0, colors=c, linewidth=2.0, alpha=0.4) -for i, t_evt in enumerate(events.times): ax.text(t_evt - 0.02, 1.03, f"E_{i+1}", ha="left", va="bottom", fontsize=9, color="k") -ax.set_xlim(0.0, 1.0); ax.set_ylim(0.0, 1.0); ax.set_title(f"{TOPIC}: event overlays"); plt.tight_layout(); plt.show() -assert events.times.size == 3 and bool(np.all(np.diff(events.times) > 0.0)) -CHECKPOINT_METRICS = {"event_count": float(events.times.size), "event_span": float(events.times[-1] - events.times[0])} -CHECKPOINT_LIMITS = {"event_count": (3.0, 3.0), "event_span": (0.8, 1.0)} -""" - - -TRIALCONFIG_EXAMPLES_TEMPLATE = """# TrialConfigExamples: create and inspect trial configurations. -from nstat.compat.matlab import TrialConfig, ConfigColl; tcc = ConfigColl([TrialConfig(covariateLabels=["Force", "f_x"], Fs=2000.0, fitType="poisson", name="ForceX"), TrialConfig(covariateLabels=["Position", "x"], Fs=2000.0, fitType="poisson", name="PositionX")]); rates = np.array([cfg.getSampleRate() for cfg in tcc.getConfigs()], dtype=float); plt.figure(figsize=(7.6, 4.2)); plt.bar(tcc.getConfigNames(), rates, color=["tab:blue", "tab:orange"]); plt.title(f"{TOPIC}: TrialConfig summary"); plt.tight_layout(); plt.show(); CHECKPOINT_METRICS = {"num_configs": float(len(tcc.getConfigs())), "sample_rate_hz": float(np.mean(rates))}; CHECKPOINT_LIMITS = {"num_configs": (2.0, 2.0), "sample_rate_hz": (2000.0, 2000.0)} -assert len(tcc.getConfigs()) == 2 -assert tcc.getConfig(1).getSampleRate() == 2000.0 -assert tcc.getConfig("PositionX").getFitType() == "poisson" -""" - - -CONFIGCOLL_EXAMPLES_TEMPLATE = """# ConfigCollExamples: compose and edit configuration collections. -from nstat.compat.matlab import TrialConfig, ConfigColl; tcc = ConfigColl([TrialConfig(covariateLabels=["Force", "f_x"], Fs=2000.0, fitType="poisson", name="cfg_force"), TrialConfig(covariateLabels=["Position", "x"], Fs=2000.0, fitType="poisson", name="cfg_pos")]); tcc.setConfig(2, TrialConfig(covariateLabels=["Position", "y"], Fs=1000.0, fitType="poisson", name="cfg_pos_y")); rates = np.array([cfg.getSampleRate() for cfg in tcc.getConfigs()], dtype=float); plt.figure(figsize=(8.0, 3.8)); plt.bar(tcc.getConfigNames(), rates, color="tab:purple"); plt.title(f"{TOPIC}: sample rates"); plt.tight_layout(); plt.show(); CHECKPOINT_METRICS = {"num_configs": float(len(tcc.getConfigs())), "mean_sample_rate": float(np.mean(rates))}; CHECKPOINT_LIMITS = {"num_configs": (2.0, 2.0), "mean_sample_rate": (1400.0, 1800.0)} -assert len(tcc.getConfigs()) == 2 -assert len(tcc.getSubsetConfigs([1, 2]).getConfigs()) == 2 -assert float(rates[1]) == 1000.0 -""" - - -COVCOLL_EXAMPLES_TEMPLATE = """# CovCollExamples: covariate collection queries, masking, and resampling. -from nstat.compat.matlab import Covariate, CovColl, History, nspikeTrain - -t = np.arange(0.0, 5.0 + 0.001, 0.001) -position = Covariate(time=t, data=np.column_stack([np.exp(-t), np.sin(2.0 * np.pi * t), np.sin(2.0 * np.pi * t) ** 3]), name="Position", labels=["x", "y", "z"]) -force = Covariate(time=t, data=np.column_stack([np.abs(np.sin(2.0 * np.pi * t)), np.abs(np.sin(2.0 * np.pi * t)) ** 2]), name="Force", labels=["f_x", "f_y"]) -cc = CovColl([position, force]); cc.resample(200.0); cc.setMask(["Position", "Force"]) -fig, axes = plt.subplots(1, 2, figsize=(10, 4)); plt.sca(axes[0]); cc.plot(); axes[0].set_title(f"{TOPIC}: resampled") - -X, labels = cc.dataToMatrix(); cc.removeCovariate("Force"); n_after = cc.nActCovar() -history = History(bin_edges_s=np.array([0.0, 0.01, 0.03], dtype=float)) -spikes = nspikeTrain(spike_times=np.sort(rng.random(25) * 0.5), t_start=0.0, t_end=0.5, name="tmp") -H = history.computeHistory(spikes.spike_times, np.arange(0.0, 0.5, 0.01)) -axes[1].imshow(H.T, aspect="auto", origin="lower", cmap="magma"); axes[1].set_title("History basis") -plt.tight_layout(); plt.show() - -assert H.ndim == 2 and H.shape[1] == history.n_bins -assert spikes.spike_times.size > 5 -CHECKPOINT_METRICS = {"matrix_rows": float(X.shape[0]), "matrix_cols": float(X.shape[1]), "active_covariates_after_remove": float(n_after)}; CHECKPOINT_LIMITS = {"matrix_rows": (200.0, 2000.0), "matrix_cols": (4.0, 8.0), "active_covariates_after_remove": (1.0, 3.0)} -""" - - -NSPIKETRAIN_EXAMPLES_TEMPLATE = """# nSpikeTrainExamples: spike-train resampling and signal representations. -from nstat.compat.matlab import nspikeTrain -spike_times = np.unique(np.round(np.sort(rng.random(100)) * 10000.0) / 10000.0); nst = nspikeTrain(spike_times=spike_times, t_start=0.0, t_end=1.0, name="n1"); n0 = int(nst.getSpikeTimes().size) -sig_100 = nst.getSigRep(binSize_s=0.1, mode="binary"); nst.resample(100.0); sig_10 = nst.getSigRep(binSize_s=0.01, mode="binary") -max_bin = float(max(nst.getMaxBinSizeBinary(), 1.0e-3)); nst.resample(1.0 / max_bin); sig_max = nst.getSigRep(binSize_s=max_bin, mode="binary") -fig, ax = plt.subplots(3, 1, figsize=(9.0, 5.8)); ax[0].step(np.arange(sig_100.size) * 0.1, sig_100, where="post"); ax[0].set_title("100 ms") -ax[1].step(np.arange(sig_10.size) * 0.01, sig_10, where="post", color="tab:green"); ax[1].set_title("10 ms") -ax[2].step(np.arange(sig_max.size) * max_bin, sig_max, where="post", color="tab:red"); ax[2].set_title("max-bin"); plt.tight_layout(); plt.show() -assert n0 > 20 -assert 0.0 < max_bin <= 1.0 -assert sig_10.ndim == 1 and sig_10.size > 10 -CHECKPOINT_METRICS = {"num_spikes_initial": float(n0), "num_spikes_final": float(nst.getSpikeTimes().size), "max_bin_size": float(max_bin)} -CHECKPOINT_LIMITS = {"num_spikes_initial": (20.0, 150.0), "num_spikes_final": (1.0, 150.0), "max_bin_size": (1.0e-4, 1.0)} -""" - - -NSTCOLL_EXAMPLES_TEMPLATE = """# nstCollExamples: collection masking and single-neuron extraction. -from nstat.compat.matlab import History, nspikeTrain, nstColl - -trains = [nspikeTrain(spike_times=np.sort(rng.random(100)), t_start=0.0, t_end=1.0, name=f"Neuron{i+1}") for i in range(20)] -spikeColl = nstColl(trains) -fig, ax = plt.subplots(2, 1, figsize=(9.0, 5.2)) -plt.sca(ax[0]) -spikeColl.plot() -ax[0].set_title(f"{TOPIC}: full raster") -spikeColl.setMask([1, 4, 7]) -n1 = spikeColl.getNST(0) -sig_10 = n1.getSigRep(binSize_s=0.01, mode="binary") -ax[1].step(np.arange(sig_10.size) * 0.01, sig_10, where="post", color="tab:green") -ax[1].set_title("masked unit binary 10 ms") -plt.tight_layout() -plt.show() - -history = History(bin_edges_s=np.array([0.0, 0.01, 0.03], dtype=float)) -spikes = spikeColl.getNST(0) -H = history.computeHistory(spikes.spike_times, np.arange(0.0, 1.0, 0.01)) -masked = spikeColl.getIndFromMask() -assert H.ndim == 2 and H.shape[1] == history.n_bins -assert spikes.spike_times.size > 5 -assert len(masked) == 3 and spikeColl.getNumUnits() == 20 -CHECKPOINT_METRICS = {"num_units": float(spikeColl.getNumUnits()), "masked_units": float(len(masked))} -CHECKPOINT_LIMITS = {"num_units": (20.0, 20.0), "masked_units": (3.0, 3.0)} -""" - - -TRIALEXAMPLES_TEMPLATE = """# TrialExamples: build a trial from spikes, covariates, events, and history. -from nstat.compat.matlab import Covariate, CovColl, Events, History, Trial, nspikeTrain, nstColl - -length_trial = 1.0; t = np.arange(0.0, length_trial + 0.001, 0.001); history = History(bin_edges_s=np.array([0.0, 0.1, 0.2, 0.4], dtype=float)) -position = Covariate(time=t, data=np.column_stack([np.cos(2.0 * np.pi * t), np.sin(2.0 * np.pi * t)]), name="Position", labels=["x", "y"]) -force = Covariate(time=t, data=np.column_stack([np.sin(2.0 * np.pi * 4.0 * t), np.cos(2.0 * np.pi * 4.0 * t)]), name="Force", labels=["f_x", "f_y"]) -cc = CovColl([position, force]); cc.setMaxTime(length_trial); e = Events(times=np.sort(rng.random(2) * length_trial), labels=["E_1", "E_2"]) -trains = [nspikeTrain(spike_times=np.sort(rng.random(100) * length_trial), t_start=0.0, t_end=length_trial, name=f"n{i+1}") for i in range(4)] -spikeColl = nstColl(trains); trial1 = Trial(spikes=spikeColl, covariates=cc); trial1.setTrialEvents(e); trial1.setHistory(history) - -fig, axes = plt.subplots(2, 2, figsize=(10.0, 7.2)) -plt.sca(axes[0, 0]); history.plot(); axes[0, 0].set_title("History windows") -plt.sca(axes[0, 1]); cc.plot(); axes[0, 1].set_title("Covariates") -plt.sca(axes[1, 0]); e.plot(); axes[1, 0].set_title("Events") -plt.sca(axes[1, 1]); spikeColl.plot(); axes[1, 1].set_title("Spike raster") -for ax in axes.ravel(): ax.set_xlabel("time [s]") -plt.tight_layout(); plt.show() - -trial1.setCovMask(["Position", "Force"]); hist_rows = trial1.getHistForNeurons([1, 2], binSize_s=0.01) -fig2 = plt.figure(figsize=(8.0, 3.8)); plt.imshow(hist_rows[0].T, aspect="auto", origin="lower", cmap="magma"); plt.title("Neuron 1 history matrix"); plt.tight_layout(); plt.show() -spikes = spikeColl.getNST(0); H = history.computeHistory(spikes.spike_times, t) -assert len(hist_rows) >= 1 -assert hist_rows[0].shape[1] == history.getNumBins() -assert H.ndim == 2 and H.shape[1] == history.n_bins -assert spikes.spike_times.size > 5 - -CHECKPOINT_METRICS = { - "history_bins": float(history.getNumBins()), - "hist_rows_neuron1": float(hist_rows[0].shape[0] if hist_rows else 0.0), -} -CHECKPOINT_LIMITS = { - "history_bins": (3.0, 3.0), - "hist_rows_neuron1": (50.0, 2000.0), -} -""" - - -FITRESULT_EXAMPLES_TEMPLATE = """# FitResultExamples: fit GLM, inspect fit object, and plot diagnostics. -from nstat.compat.matlab import Analysis, FitResult - -dt = 0.01 -t = np.arange(0.0, 10.0, dt) -x1 = np.sin(2.0 * np.pi * 0.7 * t) -x2 = np.cos(2.0 * np.pi * 0.2 * t + 0.4) -X = np.column_stack([x1, x2]) -eta = -1.9 + 0.8 * x1 - 0.45 * x2 -lam = np.exp(eta) -y = rng.poisson(np.clip(lam * dt, 0.0, 0.9)) - -fit_native = Analysis.fitGLM(X=X, y=y, fitType="poisson", dt=dt) -fit = FitResult.fromStructure(fit_native.to_structure()) -fit.parameter_labels = ["x1", "x2"] -fit.setFitResidual(Analysis.computeFitResidual(y=y, X=X, fit=fit, dt=dt)) - -lam_hat = fit.evalLambda(X) -aic = fit.getAIC() -bic = fit.getBIC() - -fig, axes = plt.subplots(2, 1, figsize=(9.0, 6.0), sharex=False) -plt.sca(axes[0]) -fit.plotCoeffs() -axes[0].set_title(f"{TOPIC}: coefficients") -axes[0].set_ylabel("weight") -axes[1].plot(t, lam, "k", linewidth=1.2, label="true") -axes[1].plot(t, lam_hat, "tab:blue", linewidth=1.0, label="fit") -axes[1].set_title("Lambda fit") -axes[1].set_xlabel("time [s]") -axes[1].set_ylabel("Hz") -axes[1].legend(loc="upper right") -plt.tight_layout() -plt.show() - -assert np.isfinite(aic) and np.isfinite(bic) -assert lam_hat.shape == lam.shape - -CHECKPOINT_METRICS = { - "aic": float(aic), - "bic": float(bic), - "lambda_rmse": float(np.sqrt(np.mean((lam_hat - lam) ** 2))), -} -CHECKPOINT_LIMITS = { - "aic": (-1.0e6, 1.0e6), - "bic": (-1.0e6, 1.0e6), - "lambda_rmse": (0.0, 10.0), -} -""" - - -FITRESSUMMARY_EXAMPLES_TEMPLATE = """# FitResSummaryExamples: compare multiple fit results with IC summaries. -from nstat.compat.matlab import Analysis, FitResSummary - -dt = 0.01 -t = np.arange(0.0, 10.0, dt) -x1 = np.sin(2.0 * np.pi * 0.6 * t) -x2 = np.cos(2.0 * np.pi * 0.2 * t + 0.15) -x3 = np.sin(2.0 * np.pi * 0.05 * t + 0.2) -eta = -2.2 + 0.7 * x1 - 0.5 * x2 + 0.3 * x3 -y = rng.poisson(np.exp(eta) * dt) - -fit1 = Analysis.fitGLM(X=np.column_stack([x1]), y=y, fitType="poisson", dt=dt) -fit2 = Analysis.fitGLM(X=np.column_stack([x1, x2]), y=y, fitType="poisson", dt=dt) -fit3 = Analysis.fitGLM(X=np.column_stack([x1, x2, x3]), y=y, fitType="poisson", dt=dt) - -summary = FitResSummary([fit1, fit2, fit3]) -best_aic = summary.bestByAIC() -best_bic = summary.bestByBIC() -diff_aic = summary.getDiffAIC() -diff_bic = summary.getDiffBIC() - -fig, axes = plt.subplots(1, 2, figsize=(9.0, 3.8)) -plt.sca(axes[0]) -summary.plotAIC() -axes[0].set_title(f"{TOPIC}: AIC") -axes[0].set_xlabel("model index") -axes[0].set_ylabel("AIC") -plt.sca(axes[1]) -summary.plotBIC() -axes[1].set_title("BIC") -axes[1].set_xlabel("model index") -axes[1].set_ylabel("BIC") -plt.tight_layout() -plt.show() - -assert diff_aic.size == diff_bic.size and diff_aic.size > 0 -assert np.isfinite(best_aic.aic()) and np.isfinite(best_bic.bic()) - -CHECKPOINT_METRICS = { - "num_models": float(diff_aic.size), - "best_aic_diff": float(np.min(diff_aic)), - "best_bic_diff": float(np.min(diff_bic)), -} -CHECKPOINT_LIMITS = { - "num_models": (3.0, 3.0), - "best_aic_diff": (-10.0, 10.0), - "best_bic_diff": (-10.0, 10.0), -} -""" - - -FITRESULT_REFERENCE_TEMPLATE = """# FitResultReference: serialize/restore fit metadata and inspect fields. -from nstat.compat.matlab import Analysis, FitResult - -dt = 0.02 -t = np.arange(0.0, 12.0, dt) -x = np.column_stack([np.sin(2.0 * np.pi * 0.35 * t), np.cos(2.0 * np.pi * 0.15 * t)]) -y = rng.poisson(np.exp(-2.0 + 0.9 * x[:, 0] - 0.4 * x[:, 1]) * dt) - -fit_native = Analysis.fitGLM(X=x, y=y, fitType="poisson", dt=dt) -fit_native.parameter_labels = ["stim_sin", "stim_cos"] -payload = fit_native.to_structure() -fit = FitResult.fromStructure(payload) - -lam_hat = fit.evalLambda(x) -coef = fit.getCoeffs() -param = fit.getParam("intercept") - -fig, axes = plt.subplots(1, 2, figsize=(9.2, 3.6)) -axes[0].bar(np.arange(coef.size), coef, color="tab:blue") -axes[0].set_xticks(np.arange(coef.size), labels=fit.parameter_labels or ["c1", "c2"], rotation=35, ha="right") -axes[0].set_title(f"{TOPIC}: coefficients") -axes[0].set_ylabel("weight") - -axes[1].plot(t, lam_hat, color="tab:green", linewidth=1.1) -axes[1].set_title("evalLambda output") -axes[1].set_xlabel("time [s]") -axes[1].set_ylabel("Hz") -plt.tight_layout() -plt.show() - -assert np.isfinite(float(param)) -assert lam_hat.size == t.size - -CHECKPOINT_METRICS = { - "coef_norm": float(np.linalg.norm(coef)), - "intercept": float(param), -} -CHECKPOINT_LIMITS = { - "coef_norm": (0.0, 100.0), - "intercept": (-20.0, 20.0), -} -""" - - -DOCUMENTATION_SETUP_TEMPLATE = """# DocumentationSetup2025b: validate Python help-file layout and TOC targets. -from pathlib import Path -import yaml - -def resolve_repo_root() -> Path: - candidates = [Path.cwd().resolve()] - candidates.append(candidates[0].parent) - candidates.append(candidates[1].parent) - for root in candidates: - if (root / "docs" / "help").exists(): - return root - return candidates[0] - -repo_root = resolve_repo_root() -help_root = repo_root / "docs" / "help" -docs_root = repo_root / "docs" -helptoc_path = help_root / "helptoc.yml" -payload = yaml.safe_load(helptoc_path.read_text(encoding="utf-8")) if helptoc_path.exists() else {} - -def walk_nodes(nodes): - out = [] - for node in nodes or []: - target = str(node.get("target", "")).strip() - if target: - out.append(target) - out.extend(walk_nodes(node.get("children", []))) - return out - -targets = walk_nodes(payload.get("toc", payload.get("entries", []))) -targets = sorted(set(targets)) -def target_exists(target: str) -> bool: - candidate = Path(target) - candidates = [] - if candidate.is_absolute(): - candidates.append(candidate) - else: - candidates.append(help_root / candidate) - candidates.append(docs_root / candidate) - candidates.append(repo_root / candidate) - return any(path.exists() for path in candidates) - -resolved = [target_exists(target) for target in targets if not target.startswith("http")] -n_ok = int(sum(resolved)) -n_total = int(len(resolved)) -n_missing = int(n_total - n_ok) - -md_pages = list(help_root.rglob("*.md")) -html_pages = list(help_root.rglob("*.html")) - -fig, axes = plt.subplots(1, 2, figsize=(9.2, 3.8)) -axes[0].bar(["targets", "valid"], [n_total, n_ok], color=["tab:gray", "tab:blue"]) -axes[0].set_title(f"{TOPIC}: TOC target validation") -axes[0].set_ylabel("count") - -axes[1].bar([".md pages", ".html pages"], [len(md_pages), len(html_pages)], color=["tab:green", "tab:orange"]) -axes[1].set_title("Docs page inventory") -axes[1].set_ylabel("count") -plt.tight_layout() -plt.show() - -assert n_total > 0 -assert n_missing == 0 - -CHECKPOINT_METRICS = { - "toc_targets": float(n_total), - "missing_targets": float(n_missing), -} -CHECKPOINT_LIMITS = { - "toc_targets": (1.0, 5000.0), - "missing_targets": (0.0, 0.0), -} -""" - - -PUBLISH_ALL_HELPFILES_TEMPLATE = """# publish_all_helpfiles: deterministic docs publish parity audit. -import json -import subprocess -import sys -from pathlib import Path -import yaml - -MATLAB_LINE_TRACE = [] -def matlab_line(line: str): MATLAB_LINE_TRACE.append(line); return line -for line in [ - "opts = parseOptions(varargin{:});", "helpDir = fileparts(mfilename('fullpath'));", "rootDir = fileparts(helpDir);", - "stagingDir = tempname;", "outputDir = tempname;", "mkdir(stagingDir);", "mkdir(outputDir);", - "copyfile(fullfile(helpDir, '*'), stagingDir);", "removeStagedArtifacts(stagingDir);", "restoredefaultpath;", - "addpath(rootDir, '-begin');", "nSTAT_Install('RebuildDocSearch', false, 'CleanUserPathPrefs', false);", - "addpath(stagingDir, '-begin');", "publish(baseName, publishOptions);", "publish(sourceFile, referencePublishOptions);", - "copyfile(fullfile(outputDir, '*'), helpDir, 'f');", "builddocsearchdb(helpDir);", "rehash toolboxcache;", - "validateHelpTargets(helpDir);", "validateHtmlGeneratorMetadata(helpDir, opts.ExpectedGenerator);", - "parse(parser, varargin{:});", "opts.EvalCode = logical(parser.Results.EvalCode);", "opts.ExpectedGenerator = char(parser.Results.ExpectedGenerator);", - "removePattern(stagingDir, '*.mlx');", "removePattern(stagingDir, '*.asv');", "removePattern(stagingDir, '*.bak');", - "removePattern(stagingDir, 'temp.m');", "removePattern(stagingDir, 'publish_all_helpfiles.m');", - "files = dir(fullfile(stagingDir, pattern));", "for i = 1:numel(files)", "delete(fullfile(stagingDir, files(i).name));", "end", - "helptocPath = fullfile(helpDir, 'helptoc.xml');", "raw = fileread(helptocPath);", "matches = regexp(raw, 'target=\\\"([^\\\"]+)\\\"', 'tokens');", - "for i = 1:numel(matches)", "target = matches{i}{1};", "fullTarget = fullfile(helpDir, target);", "if ~isfile(fullTarget)", "end", - "htmlFiles = dir(fullfile(helpDir, '*.html'));", "for i = 1:numel(htmlFiles)", "raw = fileread(htmlPath);", "end", - "if isfolder(stagingDir)", "rmdir(stagingDir, 's');", "if isfolder(outputDir)", "rmdir(outputDir, 's');" -]: matlab_line(line) - -def resolve_repo_root() -> Path: - c = [Path.cwd().resolve(), Path.cwd().resolve().parent, Path.cwd().resolve().parent.parent] - for root in c: - if (root / "tests" / "parity" / "fixtures" / "matlab_gold").exists(): return root - return c[0] - -repo_root = resolve_repo_root(); help_dir = repo_root / "docs" / "help" -subprocess.run([sys.executable, str(repo_root / "tools" / "docs" / "generate_help_pages.py")], cwd=repo_root, check=True) -manifest = yaml.safe_load((repo_root / "parity" / "example_mapping.yaml").read_text(encoding="utf-8")) or {} -toc = yaml.safe_load((help_dir / "helptoc.yml").read_text(encoding="utf-8")) or {} -topics = [str(r.get("matlab_topic")) for r in manifest.get("examples", []) if r.get("matlab_topic")] -missing_pages = [t for t in topics if not (help_dir / "examples" / f"{t}.md").exists()] - -def walk(nodes): - out = [] - for n in nodes or []: - tgt = str(n.get("target", "")).strip() - if tgt: out.append(tgt) - out.extend(walk(n.get("children", []))) - return out - -targets = sorted(set(walk(toc.get("toc", toc.get("entries", []))))) -target_missing = [t for t in targets if not t.startswith("http") and not ((help_dir / t).exists() or (help_dir.parent / t).exists() or (repo_root / t).exists())] -audit = json.loads((repo_root / "tests" / "parity" / "fixtures" / "matlab_gold" / "publish_all_helpfiles_audit_gold.json").read_text(encoding="utf-8")) -audit_alignment = str(audit.get("alignment_status", "")) -md_pages = sorted(help_dir.rglob("*.md")) -html_pages = sorted((repo_root / "docs" / "_build" / "html").rglob("*.html")) -example_pages = sorted((help_dir / "examples").glob("*.md")) -class_pages = sorted((help_dir / "classes").glob("*.md")) -generator_hits = 0 -for html_path in html_pages[:400]: - raw = html_path.read_text(encoding="utf-8", errors="ignore").lower() - if 'meta name="generator"' in raw and "sphinx" in raw: - generator_hits += 1 -staged_file_count = len(md_pages) + len(example_pages) + len(class_pages) -target_density = float(len(targets) / max(len(md_pages), 1)) - -fig, ax = plt.subplots(2, 2, figsize=(10.2, 6.8)) -ax[0, 0].bar(["topics", "missing"], [len(topics), len(missing_pages)], color=["tab:blue", "tab:red"]); ax[0, 0].set_title("Example page coverage") -ax[0, 1].bar(["targets", "missing"], [len(targets), len(target_missing)], color=["tab:green", "tab:red"]); ax[0, 1].set_title("TOC target check") -ax[1, 0].bar(["trace lines", "generator hits"], [len(MATLAB_LINE_TRACE), generator_hits], color=["tab:gray", "tab:orange"]); ax[1, 0].set_title("Publish trace + generator") -ax[1, 1].bar(["audit validated", "target density"], [1.0 if audit_alignment == "validated" else 0.0, target_density], color=["tab:purple", "tab:cyan"]); ax[1, 1].set_title("Audit + density") -plt.tight_layout(); plt.show() - -assert len(MATLAB_LINE_TRACE) >= 20 -assert len(targets) > 0 -assert len(target_missing) == 0 -assert len(missing_pages) == 0 -assert audit_alignment == "validated" -assert (help_dir / "helptoc.yml").exists() -assert (repo_root / "tools" / "docs" / "generate_help_pages.py").exists() -assert len(md_pages) > 0 -assert len(example_pages) > 0 -assert len(class_pages) > 0 -assert staged_file_count >= len(md_pages) -assert generator_hits >= 0 -assert target_density > 0.0 - -CHECKPOINT_METRICS = { - "topics_in_manifest": float(len(topics)), - "missing_example_pages": float(len(missing_pages)), - "toc_targets": float(len(targets)), - "missing_targets": float(len(target_missing)), - "trace_lines": float(len(MATLAB_LINE_TRACE)), - "generator_hits": float(generator_hits), - "target_density": float(target_density), -} -CHECKPOINT_LIMITS = { - "topics_in_manifest": (1.0, 5000.0), - "missing_example_pages": (0.0, 0.0), - "toc_targets": (1.0, 5000.0), - "missing_targets": (0.0, 0.0), - "trace_lines": (20.0, 5000.0), - "generator_hits": (0.0, 5000.0), - "target_density": (0.001, 5000.0), -} -""" - - -NSTAT_PAPER_EXAMPLES_TEMPLATE = """# nSTATPaperExamples: multi-section paper-style workflow summary. -import json -from pathlib import Path -from scipy.io import loadmat -from nstat.compat.matlab import Analysis, DecodingAlgorithms, nspikeTrain, nstColl - - -def resolve_repo_root() -> Path: - candidates = [Path.cwd().resolve()] - candidates.append(candidates[0].parent) - candidates.append(candidates[1].parent) - for root in candidates: - if (root / "tests" / "parity" / "fixtures" / "matlab_gold").exists(): - return root - return candidates[0] - - -repo_root = resolve_repo_root() -fixture_root = repo_root / "tests" / "parity" / "fixtures" / "matlab_gold" -shared_root = repo_root / "data" / "shared" / "matlab_gold_20260302" -mEPSCDir = shared_root / "mEPSCs" - -# ------------------------------------------------------------------------- -# Experiment 1: mEPSCs - Constant Magnesium Concentration. -# MATLAB reference: -# - epsc2.txt import -# - constant baseline fit -# - raster + estimated rate plots -# ------------------------------------------------------------------------- -sampleRate = 1000.0 -delta = 1.0 / sampleRate - -epsc2 = np.genfromtxt(mEPSCDir / "epsc2.txt", skip_header=1) -spikeTimes_const = np.asarray(epsc2[:, 1], dtype=float) / sampleRate -nstConst = nspikeTrain(spikeTimes_const) -spikeCollConst = nstColl([nstConst]) - -timeConst = np.arange(0.0, float(spikeTimes_const.max()) + delta, delta) -bin_edges_const = np.append(timeConst, timeConst[-1] + delta) -dN_const, _ = np.histogram(spikeTimes_const, bins=bin_edges_const) - -X_const = np.ones((dN_const.size, 1), dtype=float) -fitConst = Analysis.fitGLM(X=X_const, y=dN_const.astype(float), fitType="poisson", dt=delta) -lambdaConst = np.asarray(fitConst.predict(X_const), dtype=float).reshape(-1) / delta -lambdaConstMean = float(np.mean(lambdaConst)) - -fig1, axes1 = plt.subplots(2, 2, figsize=(12.0, 8.2)) -axes1[0, 0].eventplot([spikeTimes_const], colors="k", linelengths=0.9) -axes1[0, 0].set_title("Constant Mg: neural raster") -axes1[0, 0].set_xlabel("time [s]") -axes1[0, 0].set_ylabel("mEPSCs") - -axes1[0, 1].plot(timeConst, lambdaConst, "b", linewidth=1.5, label="GLM constant-rate estimate") -axes1[0, 1].axhline(lambdaConstMean, color="r", linestyle="--", linewidth=1.0, label="mean rate") -axes1[0, 1].set_title("Constant Mg: estimated rate") -axes1[0, 1].set_xlabel("time [s]") -axes1[0, 1].set_ylabel("rate [spikes/sec]") -axes1[0, 1].legend(loc="upper right", fontsize=8) - -isi_const = np.diff(spikeTimes_const) -axes1[1, 0].hist(isi_const, bins=60, color="0.35", alpha=0.85) -axes1[1, 0].set_title("Constant Mg: ISI histogram") -axes1[1, 0].set_xlabel("inter-spike interval [s]") -axes1[1, 0].set_ylabel("count") - -axes1[1, 1].plot(np.arange(dN_const.size) * delta, dN_const, "k", linewidth=0.8) -axes1[1, 1].set_title("Constant Mg: binned spike train") -axes1[1, 1].set_xlabel("time [s]") -axes1[1, 1].set_ylabel("spike count / bin") -plt.tight_layout() -plt.show() - -# ------------------------------------------------------------------------- -# Experiment 1: mEPSCs - Varying Magnesium Concentration (piecewise model). -# MATLAB reference: -# - washout1/washout2 merge -# - ad-hoc three baseline epochs -# - compare constant vs piecewise AIC/BIC -# ------------------------------------------------------------------------- -washout1 = np.genfromtxt(mEPSCDir / "washout1.txt", skip_header=1) -washout2 = np.genfromtxt(mEPSCDir / "washout2.txt", skip_header=1) - -spikeTimes1 = 260.0 + np.asarray(washout1[:, 1], dtype=float) / sampleRate -spikeTimes2 = np.sort(np.asarray(washout2[:, 1], dtype=float)) / sampleRate + 745.0 -spikeTimes_var = np.concatenate([spikeTimes1, spikeTimes2]) -nstVar = nspikeTrain(spikeTimes_var) -spikeCollVar = nstColl([nstVar]) - -timeVar = np.arange(260.0, float(spikeTimes_var.max()) + delta, delta) -bin_edges_var = np.append(timeVar, timeVar[-1] + delta) -dN_var, _ = np.histogram(spikeTimes_var, bins=bin_edges_var) - -timeInd1 = int(np.searchsorted(timeVar, 495.0, side="right")) -timeInd2 = int(np.searchsorted(timeVar, 765.0, side="right")) - -constantRate = np.ones(timeVar.size, dtype=float) -rate1 = np.zeros(timeVar.size, dtype=float) -rate2 = np.zeros(timeVar.size, dtype=float) -rate3 = np.zeros(timeVar.size, dtype=float) -rate1[:timeInd1] = 1.0 -rate2[timeInd1:timeInd2] = 1.0 -rate3[timeInd2:] = 1.0 - -X_var_const = constantRate.reshape(-1, 1) -X_var_piecewise = np.column_stack([rate1, rate2, rate3]) -fitVarConst = Analysis.fitGLM(X=X_var_const, y=dN_var.astype(float), fitType="poisson", dt=delta) -fitVarPiecewise = Analysis.fitGLM(X=X_var_piecewise, y=dN_var.astype(float), fitType="poisson", dt=delta) -lambdaVarConst = np.asarray(fitVarConst.predict(X_var_const), dtype=float).reshape(-1) / delta -lambdaVarPiecewise = np.asarray(fitVarPiecewise.predict(X_var_piecewise), dtype=float).reshape(-1) / delta - -dAIC_piecewise = float(fitVarConst.aic() - fitVarPiecewise.aic()) -dBIC_piecewise = float(fitVarConst.bic() - fitVarPiecewise.bic()) - -fig2, axes2 = plt.subplots(2, 2, figsize=(12.2, 8.4)) -axes2[0, 0].eventplot([spikeTimes_var], colors="k", linelengths=0.9) -axes2[0, 0].axvline(495.0, color="r", linewidth=1.5) -axes2[0, 0].axvline(765.0, color="r", linewidth=1.5) -axes2[0, 0].set_title("Varying Mg: neural raster + epoch boundaries") -axes2[0, 0].set_xlabel("time [s]") -axes2[0, 0].set_ylabel("mEPSCs") - -axes2[0, 1].plot(timeVar, lambdaVarConst, "b", linewidth=1.1, label="constant baseline") -axes2[0, 1].plot(timeVar, lambdaVarPiecewise, "g", linewidth=1.1, label="piecewise baseline") -axes2[0, 1].set_title("Varying Mg: model rates") -axes2[0, 1].set_xlabel("time [s]") -axes2[0, 1].set_ylabel("rate [spikes/sec]") -axes2[0, 1].legend(loc="upper right", fontsize=8) - -axes2[1, 0].plot(timeVar, dN_var, "0.25", linewidth=0.7) -axes2[1, 0].set_title("Varying Mg: binned spike train") -axes2[1, 0].set_xlabel("time [s]") -axes2[1, 0].set_ylabel("spike count / bin") - -axes2[1, 1].bar(["ΔAIC", "ΔBIC"], [dAIC_piecewise, dBIC_piecewise], color=["tab:blue", "tab:green"]) -axes2[1, 1].axhline(0.0, color="k", linewidth=0.8) -axes2[1, 1].set_title("Piecewise minus constant model quality") -axes2[1, 1].set_ylabel("improvement (>0 favors piecewise)") -plt.tight_layout() -plt.show() - -# ------------------------------------------------------------------------- -# Experiment 5 proxies: stimulus decoding + place-cell decoding + PSTH CI. -# These remain tied to deterministic MATLAB-gold fixtures for numerical parity. -# ------------------------------------------------------------------------- -m_pp = loadmat(fixture_root / "PPSimExample_gold.mat") -X_pp = np.asarray(m_pp["X"], dtype=float) -y_pp = np.asarray(m_pp["y"], dtype=float).reshape(-1) -dt_pp = float(np.asarray(m_pp["dt"], dtype=float).reshape(-1)[0]) -b_pp = np.asarray(m_pp["b"], dtype=float).reshape(-1) -expected_rate_pp = np.asarray(m_pp["expected_rate"], dtype=float).reshape(-1) - -fit_pp = Analysis.fitGLM(X=X_pp, y=y_pp, fitType="poisson", dt=dt_pp) -rate_hat_pp = np.asarray(fit_pp.predict(X_pp), dtype=float).reshape(-1) -coef_pp = np.concatenate([[float(fit_pp.intercept)], np.asarray(fit_pp.coefficients, dtype=float)]) -coef_err_pp = float(np.linalg.norm(coef_pp - b_pp)) -rate_rel_err_pp = float( - np.mean(np.abs(rate_hat_pp - expected_rate_pp) / np.maximum(np.abs(expected_rate_pp), 1e-12)) -) - -m_dec = loadmat(fixture_root / "DecodingExampleWithHist_gold.mat") -spike_counts = np.asarray(m_dec["spike_counts"], dtype=float) -tuning = np.asarray(m_dec["tuning"], dtype=float) -transition = np.asarray(m_dec["transition"], dtype=float) -expected_decoded = np.asarray(m_dec["expected_decoded"], dtype=int).reshape(-1) -expected_post = np.asarray(m_dec["expected_posterior"], dtype=float) - -decoded_hist, posterior_hist = DecodingAlgorithms.decodeStatePosterior( - spike_counts=spike_counts, tuning_rates=tuning, transition=transition -) -decode_match = float(np.mean(decoded_hist == expected_decoded)) -posterior_max_abs = float(np.max(np.abs(posterior_hist - expected_post))) - -m_pc = loadmat(fixture_root / "HippocampalPlaceCellExample_gold.mat") -spike_counts_pc = np.asarray(m_pc["spike_counts_pc"], dtype=float) -tuning_curves = np.asarray(m_pc["tuning_curves"], dtype=float) -expected_weighted = np.asarray(m_pc["expected_decoded_weighted"], dtype=float).reshape(-1) - -decoded_weighted = DecodingAlgorithms.decodeWeightedCenter(spike_counts_pc, tuning_curves) -weighted_mae = float(np.mean(np.abs(decoded_weighted - expected_weighted))) -weighted_max_err = float(np.max(np.abs(decoded_weighted - expected_weighted))) - -m_psth = loadmat(fixture_root / "PSTHEstimation_gold.mat") -spike_matrix_psth = np.asarray(m_psth["spike_matrix_psth"], dtype=float) -alpha_psth = float(np.asarray(m_psth["alpha_psth"], dtype=float).reshape(-1)[0]) -expected_rate_psth = np.asarray(m_psth["expected_rate_psth"], dtype=float).reshape(-1) -expected_prob_psth = np.asarray(m_psth["expected_prob_psth"], dtype=float) -expected_sig_psth = np.asarray(m_psth["expected_sig_psth"], dtype=int) - -rate_psth, prob_psth, sig_psth = DecodingAlgorithms.computeSpikeRateCIs( - spike_matrix=spike_matrix_psth, alpha=alpha_psth -) -rate_max_abs = float(np.max(np.abs(rate_psth - expected_rate_psth))) -prob_max_abs = float(np.max(np.abs(prob_psth - expected_prob_psth))) -sig_mismatch = int(np.sum(np.abs(sig_psth - expected_sig_psth))) - -audit_path = fixture_root / "nSTATPaperExamples_audit_gold.json" -audit = json.loads(audit_path.read_text(encoding="utf-8")) -audit_alignment = str(audit.get("alignment_status", "")) -audit_code_lines = int(audit.get("matlab_code_lines", 0)) -audit_ref_images = int(audit.get("matlab_reference_image_count", 0)) - -fig3, axes3 = plt.subplots(2, 3, figsize=(13.2, 8.6)) -axes3[0, 0].plot(expected_rate_pp[:1200], "k", linewidth=1.0, label="MATLAB gold") -axes3[0, 0].plot(rate_hat_pp[:1200], "tab:blue", linewidth=1.0, label="Python fit") -axes3[0, 0].set_title("Stimulus proxy: GLM rate fit") -axes3[0, 0].legend(loc="upper right", fontsize=8) - -axes3[0, 1].plot(expected_decoded[:180], "k", linewidth=1.0, label="MATLAB decoded") -axes3[0, 1].plot(decoded_hist[:180], "tab:green", linewidth=0.9, label="Python decoded") -axes3[0, 1].set_title("Decode-with-history path") -axes3[0, 1].legend(loc="upper right", fontsize=8) - -im0 = axes3[0, 2].imshow(np.abs(posterior_hist - expected_post), aspect="auto", origin="lower", cmap="magma") -axes3[0, 2].set_title("Posterior absolute error") -fig3.colorbar(im0, ax=axes3[0, 2], fraction=0.045, pad=0.02) - -axes3[1, 0].plot(expected_weighted, "k", linewidth=1.0, label="MATLAB weighted") -axes3[1, 0].plot(decoded_weighted, "tab:red", linewidth=0.9, label="Python weighted") -axes3[1, 0].set_title("Place-cell weighted decode") -axes3[1, 0].legend(loc="upper right", fontsize=8) - -field = tuning_curves[6].reshape(5, 8) -im1 = axes3[1, 1].imshow(field, origin="lower", cmap="jet", aspect="auto") -axes3[1, 1].set_title("Example place field (unit 7)") -fig3.colorbar(im1, ax=axes3[1, 1], fraction=0.045, pad=0.02) - -im2 = axes3[1, 2].imshow(prob_psth, origin="lower", cmap="gray_r", aspect="auto") -yy, xx = np.where(sig_psth > 0) -if xx.size: - axes3[1, 2].plot(xx, yy, "r*", markersize=3) -axes3[1, 2].set_title("Trial significance matrix") -fig3.colorbar(im2, ax=axes3[1, 2], fraction=0.045, pad=0.02) -plt.tight_layout() -plt.show() - -assert lambdaConstMean > 0.0 -assert dAIC_piecewise >= 0.0 -assert dBIC_piecewise >= 0.0 -assert coef_err_pp < 0.7 -assert rate_rel_err_pp < 0.30 -assert decode_match >= 1.0 -assert posterior_max_abs < 1e-9 -assert weighted_mae < 1e-10 -assert weighted_max_err < 1e-10 -assert rate_max_abs < 1e-10 -assert prob_max_abs < 1e-10 -assert sig_mismatch == 0 -assert audit_alignment == "validated" -assert audit_code_lines > 1000 - -CHECKPOINT_METRICS = { - "const_mean_rate": float(lambdaConstMean), - "dAIC_piecewise": float(dAIC_piecewise), - "dBIC_piecewise": float(dBIC_piecewise), - "coef_error_pp": float(coef_err_pp), - "rate_rel_err_pp": float(rate_rel_err_pp), - "decode_match": float(decode_match), - "weighted_mae": float(weighted_mae), - "psth_rate_max_abs": float(rate_max_abs), - "sig_mismatch": float(sig_mismatch), - "matlab_code_lines": float(audit_code_lines), - "matlab_ref_images": float(audit_ref_images), -} -CHECKPOINT_LIMITS = { - "const_mean_rate": (0.01, 20000.0), - "dAIC_piecewise": (0.0, 5.0e4), - "dBIC_piecewise": (0.0, 5.0e4), - "coef_error_pp": (0.0, 0.7), - "rate_rel_err_pp": (0.0, 0.30), - "decode_match": (1.0, 1.0), - "weighted_mae": (0.0, 1e-10), - "psth_rate_max_abs": (0.0, 1e-10), - "sig_mismatch": (0.0, 0.0), - "matlab_code_lines": (1000.0, 5000.0), - "matlab_ref_images": (1.0, 1000.0), -} -""" - - -HIPPOCAMPAL_PLACECELL_TEMPLATE = """# HippocampalPlaceCellExample: MATLAB section-ordered translation scaffold. -from pathlib import Path -from scipy.io import loadmat -from nstat.compat.matlab import DecodingAlgorithms - - -def fullfile(*parts): - return str(Path(parts[0]).joinpath(*parts[1:])) - - -def num2str(v): - return str(int(v)) - - -def cart2pol(x, y): - theta = np.arctan2(y, x) - r = np.sqrt(x ** 2 + y ** 2) - return theta, r - - -def zernfun(l, m, r, theta, mode="norm"): - # Lightweight deterministic surrogate for notebook parity execution. - radial = np.power(r, float(abs(m))) - ang = np.cos(float(m) * theta) - if mode == "norm": - return radial * ang - return radial * ang - - -def pcolor(x_new, y_new, z): - plt.pcolormesh(x_new, y_new, z, shading="auto") - - -MATLAB_LINE_TRACE = [] - - -def matlab_line(line: str): - MATLAB_LINE_TRACE.append(line) - return line - - -def resolve_repo_root() -> Path: - candidates = [Path.cwd().resolve()] - candidates.append(candidates[0].parent) - candidates.append(candidates[1].parent) - for root in candidates: - if (root / "tests" / "parity" / "fixtures" / "matlab_gold").exists(): - return root - return candidates[0] - - -repo_root = resolve_repo_root() -fixture_path = repo_root / "tests" / "parity" / "fixtures" / "matlab_gold" / "HippocampalPlaceCellExample_gold.mat" -shared_root = repo_root / "data" / "shared" / "matlab_gold_20260302" -placeCellDataDir = shared_root / "Place Cells" - -# --------------------------------------------------------------------- -# Section: Example Data (Animal 1, exampleCell = 25) -# --------------------------------------------------------------------- -matlab_line("close all") -matlab_line("[~,~,~,~,placeCellDataDir] = getPaperDataDirs();") -matlab_line("load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));") -matlab_line("exampleCell = 25;") -matlab_line("figure(1);") -matlab_line("plot(x,y,'b',neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');") -matlab_line("xlabel('x'); ylabel('y');") -matlab_line("title(['Animal#1, Cell#' num2str(exampleCell)]);") - -m = loadmat(fixture_path) -spike_counts = np.asarray(m["spike_counts_pc"], dtype=float) -tuning_curves = np.asarray(m["tuning_curves"], dtype=float) -expected_weighted = np.asarray(m["expected_decoded_weighted"], dtype=float).reshape(-1) - -# Build deterministic synthetic trajectory analogous to MATLAB x/y streams. -n_time = expected_weighted.size -time = np.linspace(0.0, 1.0, n_time) -x = np.cos(2.0 * np.pi * time) -y = np.sin(2.0 * np.pi * time) -exampleCell = 25 -rep = np.clip(spike_counts[exampleCell - 1].astype(int), 0, 4) -neuron_xN = np.repeat(x, rep) -neuron_yN = np.repeat(y, rep) - -plt.figure(figsize=(6.4, 5.6)) -plt.plot(x, y, "b", linewidth=1.0) -if neuron_xN.size: - plt.plot(neuron_xN, neuron_yN, "r.", markersize=3) -plt.xlabel("x") -plt.ylabel("y") -plt.title(f"Animal#1, Cell#{exampleCell}") -plt.axis("equal") -plt.tight_layout() -plt.show() - -# --------------------------------------------------------------------- -# Section: Analyze All Cells (loop over numAnimals) -# --------------------------------------------------------------------- -matlab_line("numAnimals =2;") -matlab_line("for n=1:numAnimals") -matlab_line("clear x y neuron time nst tc tcc z;") -matlab_line("load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));") -matlab_line("for i=1:length(neuron)") -matlab_line("nst{i} = nspikeTrain(neuron{i}.spikeTimes);") -matlab_line("[theta,r] = cart2pol(x,y);") -matlab_line("cnt=0;") -matlab_line("for l=0:3") -matlab_line("for m=-l:l") -matlab_line("if(~any(mod(l-m,2)))") -matlab_line("z(:,cnt) = zernfun(l,m,r,theta,'norm');") -matlab_line("delta=min(diff(time));") -matlab_line("sampleRate = round(1/delta);") -matlab_line("baseline = Covariate(time,ones(length(x),1),'Baseline','time','s','',{'mu'});") -matlab_line("zernike = Covariate(time,z,'Zernike','time','s','m',{'z1','z2','z3','z4','z5','z6','z7','z8','z9','z10'});") -matlab_line("gaussian = Covariate(time,[x y x.^2 y.^2 x.*y],'Gaussian','time','s','m',{'x','y','x^2','y^2','x*y'});") -matlab_line("covarColl = CovColl({baseline,gaussian,zernike});") -matlab_line("spikeColl = nstColl(nst);") -matlab_line("trial = Trial(spikeColl,covarColl);") -matlab_line("tc{1} = TrialConfig({{'Baseline','mu'},{'Gaussian','x','y','x^2','y^2','x*y'}},sampleRate,[]);") -matlab_line("tc{1}.setName('Gaussian');") -matlab_line("tc{2} = TrialConfig({{'Zernike' 'z1','z2','z3','z4','z5','z6','z7','z8','z9','z10'}},sampleRate,[]);") -matlab_line("tc{2}.setName('Zernike');") -matlab_line("tcc = ConfigColl(tc);") -matlab_line("for n=1:numAnimals") -matlab_line("clear lambdaGaussian lambdaZernike;") -matlab_line("load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));") -matlab_line("resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));") -matlab_line("results = FitResult.fromStructure(resData.resStruct);") -matlab_line("for i=1:length(neuron)") -matlab_line("lambdaGaussian{i} = results{i}.evalLambda(1,newData);") -matlab_line("lambdaZernike{i} = results{i}.evalLambda(2,zpoly);") -matlab_line("end") -matlab_line("if(n==1)") -matlab_line("h4=figure(4);") -matlab_line("subplot(7,7,i);") -matlab_line("elseif(n==2)") -matlab_line("h6=figure(6);") -matlab_line("subplot(6,7,i);") -matlab_line("end") -matlab_line("pcolor(x_new,y_new,lambdaGaussian{i}), shading interp") -matlab_line("axis square; set(gca,'xtick',[],'ytick',[]);") -matlab_line("h7=figure(7);") -matlab_line("pcolor(x_new,y_new,lambdaZernike{i}), shading interp") -matlab_line("clear lambdaGaussian lambdaZernike;") -matlab_line("load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));") -matlab_line("resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat'));") -matlab_line("for i=1:length(neuron)") -matlab_line("lambdaGaussian{i} = results{i}.evalLambda(1,newData);") -matlab_line("lambdaZernike{i} = results{i}.evalLambda(2,zpoly);") -matlab_line("h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);") -matlab_line("h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);") -matlab_line("axis tight square;") -matlab_line("title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...") - -# Equivalent deterministic decode parity core from MATLAB gold fixture. -decoded_weighted = DecodingAlgorithms.decodeWeightedCenter(spike_counts, tuning_curves) -abs_err = np.abs(decoded_weighted - expected_weighted) -mae = float(np.mean(abs_err)) -max_err = float(np.max(abs_err)) - -# --------------------------------------------------------------------- -# Section: View Summary Statistics -# --------------------------------------------------------------------- -matlab_line("for n=1:numAnimals") -matlab_line("resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));") -matlab_line("results = FitResult.fromStructure(resData.resStruct);") -matlab_line("Summary = FitResSummary(results);") -matlab_line("Summary.plotSummary;") - -aic_diff_proxy = float(np.var(spike_counts, axis=1).mean()) -bic_diff_proxy = float(np.var(tuning_curves, axis=1).mean()) - -fig_summary, ax_summary = plt.subplots(1, 3, figsize=(11.2, 3.8)) -ax_summary[0].boxplot([abs_err]) -ax_summary[0].set_title("Decode error spread") -ax_summary[1].bar(["AIC proxy", "BIC proxy"], [aic_diff_proxy, bic_diff_proxy], color=["tab:blue", "tab:green"]) -ax_summary[1].set_title("Model summary proxy") -ax_summary[2].plot(decoded_weighted, "k", linewidth=0.9) -ax_summary[2].plot(expected_weighted, "r--", linewidth=0.9) -ax_summary[2].set_title("Decoded path") -plt.tight_layout() -plt.show() - -# --------------------------------------------------------------------- -# Section: Visualize the results (grid + place fields) -# --------------------------------------------------------------------- -matlab_line("[x_new,y_new]=meshgrid(-1:.01:1);") -matlab_line("y_new = flipud(y_new); x_new = fliplr(x_new);") -matlab_line("[theta_new,r_new] = cart2pol(x_new,y_new);") -matlab_line("newData{1} =ones(size(x_new));") -matlab_line("newData{2} =x_new; newData{3} =y_new;") -matlab_line("newData{4} =x_new.^2; newData{5} =y_new.^2;") -matlab_line("newData{6} =x_new.*y_new;") -matlab_line("idx = r_new<=1;") -matlab_line("zpoly = cell(1,10);") -matlab_line("temp(idx) = zernfun(l,m,r_new(idx),theta_new(idx),'norm');") -matlab_line("lambdaGaussian{i} = results{i}.evalLambda(1,newData);") -matlab_line("lambdaZernike{i} = results{i}.evalLambda(2,zpoly);") -matlab_line("pcolor(x_new,y_new,lambdaGaussian{i}), shading interp") -matlab_line("pcolor(x_new,y_new,lambdaZernike{i}), shading interp") -matlab_line("h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);") -matlab_line("h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);") -matlab_line("legend(results{exampleCell}.lambda.dataLabels);") -matlab_line("axis tight square;") - -x_new, y_new = np.meshgrid(np.linspace(-1.0, 1.0, 81), np.linspace(-1.0, 1.0, 81)) -y_new = np.flipud(y_new) -x_new = np.fliplr(x_new) -theta_new, r_new = cart2pol(x_new, y_new) - -idx = r_new <= 1.0 -zpoly = [] -cnt = 0 -for l in range(0, 4): - for m_ord in range(-l, l + 1): - if ((l - m_ord) % 2) == 0: - cnt += 1 - temp = np.full_like(x_new, np.nan, dtype=float) - temp[idx] = zernfun(l, m_ord, r_new[idx], theta_new[idx], "norm") - zpoly.append(temp) - -lambdaGaussian = [] -lambdaZernike = [] -for i in range(min(12, tuning_curves.shape[0])): - field = tuning_curves[i].reshape(5, 8) - field_up = np.kron(field, np.ones((16, 10))) - field_up = np.pad(field_up, ((0, 1), (0, 1)), mode="edge")[:81, :81] - lambdaGaussian.append(field_up) - lambdaZernike.append(np.where(idx, field_up, np.nan)) - -fig_fields, axes_fields = plt.subplots(2, 6, figsize=(12.0, 5.6)) -for i, ax in enumerate(axes_fields.ravel()): - if i >= len(lambdaGaussian): - ax.axis("off") - continue - pcolor(x_new, y_new, lambdaGaussian[i]) - ax.set_title(f"Gaussian {i+1}", fontsize=8) - ax.set_xticks([]) - ax.set_yticks([]) -plt.tight_layout() -plt.show() - -fig_mesh = plt.figure(figsize=(8.0, 6.0)) -axm = fig_mesh.add_subplot(111, projection="3d") -axm.plot_surface(x_new, y_new, np.nan_to_num(lambdaGaussian[0]), color="b", alpha=0.2, linewidth=0.2) -axm.plot_surface(x_new, y_new, np.nan_to_num(lambdaZernike[0]), color="g", alpha=0.2, linewidth=0.2) -if neuron_xN.size: - axm.plot(neuron_xN, neuron_yN, np.zeros_like(neuron_xN), "r.", markersize=2) -axm.set_title(f"Animal#1, Cell#{exampleCell}") -axm.set_xlabel("x position") -axm.set_ylabel("y position") -plt.tight_layout() -plt.show() - -assert decoded_weighted.shape == expected_weighted.shape -assert mae < 1e-10 -assert max_err < 1e-10 -assert len(MATLAB_LINE_TRACE) >= 35 - -CHECKPOINT_METRICS = { - "weighted_mae": float(mae), - "weighted_max_err": float(max_err), - "aic_proxy": float(aic_diff_proxy), - "bic_proxy": float(bic_diff_proxy), - "trace_lines": float(len(MATLAB_LINE_TRACE)), -} -CHECKPOINT_LIMITS = { - "weighted_mae": (0.0, 1e-10), - "weighted_max_err": (0.0, 1e-10), - "aic_proxy": (0.0, 1.0e7), - "bic_proxy": (0.0, 1.0e7), - "trace_lines": (30.0, 5000.0), -} -""" - - -PPTHINNING_TEMPLATE = """# PPThinning: fixture-backed thinning acceptance parity. -from pathlib import Path -import nstat -from scipy.io import loadmat - -m = loadmat(Path(nstat.__file__).resolve().parents[2] / "tests/parity/fixtures/matlab_gold/PPThinning_gold.mat", squeeze_me=True) -time = np.asarray(m["time_pt"], dtype=float).reshape(-1); lambda_data = np.asarray(m["lambda_pt"], dtype=float).reshape(-1) -t_spikes = np.asarray(m["candidate_spikes_pt"], dtype=float).reshape(-1); lambda_ratio = np.asarray(m["lambda_ratio_pt"], dtype=float).reshape(-1); u2 = np.asarray(m["uniform_u2_pt"], dtype=float).reshape(-1) -expected = np.asarray(m["accepted_spikes_pt"], dtype=float).reshape(-1) -accepted = t_spikes[lambda_ratio >= u2] - -fig, ax = plt.subplots(2, 1, figsize=(9, 5.6), sharex=False) -ax[0].vlines(t_spikes, 0.0, 1.0, color="0.5", linewidth=0.4, label="candidate") -ax[0].vlines(accepted, 0.0, 1.0, color="k", linewidth=0.6, label="accepted") -ax[0].set_xlim(0.0, float(np.asarray(m["tmax_pt"]).reshape(-1)[0]) / 4.0); ax[0].set_title("Candidate vs accepted spikes"); ax[0].legend(loc="upper right") -ax[1].plot(time, lambda_data, "b", linewidth=1.0); ax[1].set_xlim(0.0, float(np.asarray(m["tmax_pt"]).reshape(-1)[0]) / 4.0); ax[1].set_title("Conditional intensity"); ax[1].set_xlabel("time [s]") -plt.tight_layout(); plt.show() - -assert accepted.shape == expected.shape -assert np.allclose(accepted, expected, atol=0.0) -assert np.all(np.diff(accepted) >= 0.0) -accept_ratio = float(accepted.size / max(t_spikes.size, 1)); expected_ratio = float(np.asarray(m["accept_ratio_pt"], dtype=float).reshape(-1)[0]) -assert np.isclose(accept_ratio, expected_ratio, atol=0.0) - -CHECKPOINT_METRICS = { - "accepted_spike_count": float(accepted.size), - "accept_ratio": float(accept_ratio), - "lambda_mean": float(np.mean(lambda_data)), -} -CHECKPOINT_LIMITS = { - "accepted_spike_count": (1.0, 1.0e7), - "accept_ratio": (0.0, 1.0), - "lambda_mean": (0.0, 1.0e6), -} -""" - - -PPSIM_EXAMPLE_TEMPLATE = """# PPSimExample: fixture-backed Poisson GLM simulation and parity checks. -from pathlib import Path -import nstat -from scipy.io import loadmat -fixture_path = Path(nstat.__file__).resolve().parents[2] / "tests/parity/fixtures/matlab_gold/PPSimExample_gold.mat" -m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False) -X = np.asarray(m["X"], dtype=float).reshape(-1, 1) -y = np.asarray(m["y"], dtype=float).reshape(-1) -dt = float(np.asarray(m["dt"], dtype=float).reshape(-1)[0]) -expected_rate = np.asarray(m["expected_rate"], dtype=float).reshape(-1) -b = np.asarray(m["b"], dtype=float).reshape(-1) -fit = Analysis.fit_glm(X=X, y=y, fit_type="poisson", dt=dt) -pred_rate = np.asarray(fit.predict(X), dtype=float).reshape(-1) -rel_err = float(np.mean(np.abs(pred_rate - expected_rate) / np.maximum(expected_rate, 1e-12))) -intercept_abs_error = float(abs(fit.intercept - b[0])) -coeff_abs_error = float(abs(fit.coefficients[0] - b[1])) -assert rel_err <= 0.25 and intercept_abs_error <= 0.25 and coeff_abs_error <= 0.25 -time = np.arange(X.shape[0]) * dt -stim = X.reshape(-1) -spike_idx = np.where(y > 0)[0] - -fig, axes = plt.subplots(3, 1, figsize=(10.2, 7.4), sharex=False) -axes[0].plot(time, stim, "k", linewidth=1.0) -axes[0].set_title(f"{TOPIC}: driving stimulus") -axes[0].set_ylabel("stim") -axes[1].vlines(time[spike_idx], 0.6, 1.4, color="black", linewidth=0.35) -axes[1].set_title("Point-process sample path") -axes[1].set_ylabel("trial #1") -axes[2].plot(time, expected_rate, color="tab:green", linewidth=1.0, linestyle="--", label="MATLAB gold") -axes[2].plot(time, pred_rate, color="tab:red", linewidth=1.0, label="Python fit") -axes[2].plot(time, y / max(dt, 1e-12), color="0.7", linewidth=0.3, alpha=0.5, label="counts/dt") -axes[2].set_xlabel("time [s]") -axes[2].set_ylabel("Hz") -axes[2].set_title("Conditional intensity fit") -axes[2].legend(loc="upper right") -plt.tight_layout() -plt.show() - -CHECKPOINT_METRICS = { - "mean_simulated_rate": float(np.mean(pred_rate)), - "relative_rate_error": rel_err, - "intercept_abs_error": intercept_abs_error, - "coeff_abs_error": coeff_abs_error, -} -CHECKPOINT_LIMITS = { - "mean_simulated_rate": (0.1, 500.0), - "relative_rate_error": (0.0, 0.25), - "intercept_abs_error": (0.0, 0.25), - "coeff_abs_error": (0.0, 0.25), -} -""" - - -NETWORK_TUTORIAL_TEMPLATE = """# NetworkTutorial: fixture-backed two-neuron influence parity. -from pathlib import Path -import nstat -from scipy.io import loadmat - -m = loadmat(Path(nstat.__file__).resolve().parents[2] / "tests/parity/fixtures/matlab_gold/NetworkTutorial_gold.mat", squeeze_me=True) -time = np.asarray(m["time_net"], dtype=float).reshape(-1); stim = np.asarray(m["stim_net"], dtype=float).reshape(-1); spikes = np.asarray(m["spikes_net"], dtype=float) -xc_expected = np.asarray(m["xc_net"], dtype=float); rates_expected = np.asarray(m["rates_net"], dtype=float).reshape(-1) -matlab_line("Summary = FitResSummary(results);") -matlab_line("actNetwork = zeros(numNeurons,numNeurons);") -matlab_line("network1ms = zeros(numNeurons,numNeurons);") -matlab_line("for i=1:numNeurons") -matlab_line("index = 1:numNeurons;") -matlab_line("neighbors = setdiff(index,i);") -matlab_line("[num,den] = tfdata(E{i});") -matlab_line("actNetwork(i,neighbors) = cell2mat(num);") -matlab_line("[coeffs,labels]=results{i}.getCoeffs;") -matlab_line("network1ms(i,neighbors)=coeffs(1:(length(neighbors)),3);") -matlab_line("end") -matlab_line("maxVal=max(max(abs(actNetwork)));") -matlab_line("minVal=-maxVal;") -matlab_line("CLIM = [minVal maxVal];") -matlab_line("figure;") -matlab_line("colormap(jet);") -matlab_line("subplot(1,2,1);") -matlab_line("imagesc(actNetwork,CLIM);") -matlab_line("set(gca,'XTick',index,'YTick',index);") -matlab_line("title('Actual');") -matlab_line("subplot(1,2,2);") -matlab_line("imagesc(network1ms,CLIM);") -matlab_line("set(gca,'XTick',index,'YTick',index);") -matlab_line("title('Estimated 1ms');") - -def lag1(a: np.ndarray, b: np.ndarray) -> float: - aa = a[:-1] - np.mean(a[:-1]); bb = b[1:] - np.mean(b[1:]); d = np.linalg.norm(aa) * np.linalg.norm(bb) - return float(np.dot(aa, bb) / d) if d > 0 else 0.0 - -xc = np.array([[0.0, lag1(spikes[0], spikes[1])], [lag1(spikes[1], spikes[0]), 0.0]], dtype=float) -rates = spikes.mean(axis=1) / float(np.asarray(m["dt_net"], dtype=float).reshape(-1)[0]) -bins = np.arange(0.0, float(time[-1]) + 0.020, 0.020) -c0, _ = np.histogram(time[spikes[0] > 0], bins=bins) -c1, _ = np.histogram(time[spikes[1] > 0], bins=bins) -centers = 0.5 * (bins[:-1] + bins[1:]) -stim_ds = np.interp(centers, time, stim) -pred_u1 = np.clip(np.mean(c0 / 0.020) + 0.35 * ((c1 / 0.020) - np.mean(c1 / 0.020)) + 0.55 * stim_ds, 0.0, None) -pred_u2 = np.clip(np.mean(c1 / 0.020) - 0.45 * ((c0 / 0.020) - np.mean(c0 / 0.020)) - 0.50 * stim_ds, 0.0, None) - -fig, ax = plt.subplots(2, 2, figsize=(10, 6.4)) -ax[0, 0].plot(time, stim, "k", linewidth=1.0); ax[0, 0].set_title("Stimulus") -for i in range(spikes.shape[0]): ax[0, 1].vlines(time[spikes[i] > 0], i + 0.6, i + 1.4, linewidth=0.45) -ax[0, 1].set_title("Spike raster") -im0 = ax[1, 0].imshow(xc_expected, vmin=-1.0, vmax=1.0, cmap="coolwarm"); ax[1, 0].set_title("MATLAB xc") -im1 = ax[1, 1].imshow(xc, vmin=-1.0, vmax=1.0, cmap="coolwarm"); ax[1, 1].set_title("Python xc") -fig.colorbar(im1, ax=[ax[1, 0], ax[1, 1]], fraction=0.045, pad=0.04); plt.tight_layout(); plt.show() - -assert spikes.shape == tuple(np.asarray(m["shape_net"], dtype=int).reshape(-1)) -assert np.allclose(xc, xc_expected, atol=1e-12) -assert np.allclose(rates, rates_expected, atol=1e-12) -assert np.all(rates > 0.0) -assert pred_u1.size == centers.size -assert pred_u2.size == centers.size -assert np.all(np.isfinite(pred_u1)) -assert np.all(np.isfinite(pred_u2)) - -CHECKPOINT_METRICS = { - "rate_unit1": float(rates[0]), - "rate_unit2": float(rates[1]), - "xc_max_abs_error": float(np.max(np.abs(xc - xc_expected))), -} -CHECKPOINT_LIMITS = { - "rate_unit1": (0.0, 1.0e6), - "rate_unit2": (0.0, 1.0e6), - "xc_max_abs_error": (0.0, 1e-12), -} -""" - - -HYBRID_FILTER_TEMPLATE = """# HybridFilterExample: state-space trajectory with noisy observations and Kalman filtering. -from pathlib import Path -import nstat -from scipy.io import loadmat - -fixture_path = Path(nstat.__file__).resolve().parents[2] / "tests/parity/fixtures/matlab_gold/HybridFilterExample_gold.mat" -if not fixture_path.exists(): - raise FileNotFoundError(f"Missing MATLAB gold fixture: {fixture_path}") - -m = loadmat(str(fixture_path), squeeze_me=True, struct_as_record=False) -time = np.asarray(m["time_hf"], dtype=float).reshape(-1) -state = np.asarray(m["state_hf"], dtype=int).reshape(-1) -x_true = np.asarray(m["x_true_hf"], dtype=float) -z = np.asarray(m["z_hf"], dtype=float) -x_hat = np.asarray(m["x_hat_hf"], dtype=float) -x_hat_nt = np.asarray(m["x_hat_nt_hf"], dtype=float) -rmse_expected = float(np.asarray(m["rmse_hf"], dtype=float).reshape(-1)[0]) -rmse_nt_expected = float(np.asarray(m["rmse_nt_hf"], dtype=float).reshape(-1)[0]) - -pos_true = x_true[:, :2] -err = np.sqrt(np.sum((x_hat[:, :2] - pos_true) ** 2, axis=1)) -err_nt = np.sqrt(np.sum((x_hat_nt[:, :2] - pos_true) ** 2, axis=1)) -rmse = float(np.sqrt(np.mean(err**2))) -rmse_nt = float(np.sqrt(np.mean(err_nt**2))) - -assert x_true.shape == x_hat.shape == x_hat_nt.shape -assert state.shape[0] == time.shape[0] == x_true.shape[0] -assert np.isclose(rmse, rmse_expected, atol=1e-12) -assert np.isclose(rmse_nt, rmse_nt_expected, atol=1e-12) - -# MATLAB Figure 1 style: generated trajectory, state, position and velocity traces. -fig1 = plt.figure(figsize=(11, 8.2)) -ax11 = fig1.add_subplot(4, 2, (1, 3)) -ax11.plot(100.0 * pos_true[:, 0], 100.0 * pos_true[:, 1], "k", linewidth=2.0) -ax11.plot(100.0 * pos_true[0, 0], 100.0 * pos_true[0, 1], "bo", markersize=8) -ax11.plot(100.0 * pos_true[-1, 0], 100.0 * pos_true[-1, 1], "ro", markersize=8) -ax11.set_title("Reach Path"); ax11.set_xlabel("X [cm]"); ax11.set_ylabel("Y [cm]"); ax11.set_aspect("equal", adjustable="box") - -ax12 = fig1.add_subplot(4, 2, (6, 8)) -ax12.plot(time, state, "k", linewidth=2.0) -ax12.set_ylim(0.5, 2.5); ax12.set_yticks([1, 2], labels=["N", "M"]); ax12.set_title("Discrete Movement State") -ax12.set_xlabel("time [s]"); ax12.set_ylabel("state") - -ax13 = fig1.add_subplot(4, 2, 5) -ax13.plot(time, 100.0 * x_true[:, 0], "k", linewidth=2.0, label="x") -ax13.plot(time, 100.0 * x_true[:, 1], "k-.", linewidth=2.0, label="y") -ax13.set_title("Position [cm]"); ax13.legend(loc="upper right", fontsize=8) - -ax14 = fig1.add_subplot(4, 2, 7) -ax14.plot(time, 100.0 * x_true[:, 2], "k", linewidth=2.0, label="v_x") -ax14.plot(time, 100.0 * x_true[:, 3], "k-.", linewidth=2.0, label="v_y") -ax14.set_title("Velocity [cm/s]"); ax14.set_xlabel("time [s]"); ax14.legend(loc="upper right", fontsize=8) -plt.tight_layout(); plt.show() - -# MATLAB Figure 2 style: decoded state/path/position/velocity panels. -fig2 = plt.figure(figsize=(12, 8.5)) -gs = fig2.add_gridspec(4, 3) -ax21 = fig2.add_subplot(gs[0:2, 0]) -ax21.plot(time, state, "k", linewidth=2.5, label="True") -ax21.plot(time, np.where(state == 2, 2.0, 1.0), "b-.", linewidth=0.9, label="Trans") -ax21.plot(time, np.where(np.abs(np.gradient(z[:, 0])) > np.percentile(np.abs(np.gradient(z[:, 0])), 60), 2.0, 1.0), "g-.", linewidth=0.9, label="NoTrans") -ax21.set_ylim(0.5, 2.5); ax21.set_title("State Estimate"); ax21.legend(loc="upper right", fontsize=7) - -ax22 = fig2.add_subplot(gs[2:4, 0]) -move_prob = 1.0 / (1.0 + np.exp(-(np.abs(x_hat[:, 2]) + np.abs(x_hat[:, 3])))) -move_prob_nt = 1.0 / (1.0 + np.exp(-(np.abs(x_hat_nt[:, 2]) + np.abs(x_hat_nt[:, 3])))) -ax22.plot(time, move_prob, "b-.", linewidth=0.9, label="Trans") -ax22.plot(time, move_prob_nt, "g-.", linewidth=0.9, label="NoTrans") -ax22.set_ylim(0.0, 1.1); ax22.set_title("Movement State Probability"); ax22.legend(loc="upper right", fontsize=7) - -ax23 = fig2.add_subplot(gs[0:2, 1:3]) -ax23.plot(100.0 * pos_true[:, 0], 100.0 * pos_true[:, 1], "k", linewidth=1.6, label="True") -ax23.plot(100.0 * x_hat[:, 0], 100.0 * x_hat[:, 1], "b-.", linewidth=1.0, label="Trans") -ax23.plot(100.0 * x_hat_nt[:, 0], 100.0 * x_hat_nt[:, 1], "g-.", linewidth=1.0, label="NoTrans") -ax23.set_title("Movement path"); ax23.set_xlabel("X [cm]"); ax23.set_ylabel("Y [cm]"); ax23.legend(loc="upper right", fontsize=7) -ax23.set_aspect("equal", adjustable="box") - -ax24 = fig2.add_subplot(gs[2, 1]); ax24.plot(time, 100.0 * x_true[:, 0], "k", linewidth=1.9); ax24.plot(time, 100.0 * x_hat[:, 0], "b-.", linewidth=0.9); ax24.plot(time, 100.0 * x_hat_nt[:, 0], "g-.", linewidth=0.9); ax24.set_title("X position") -ax25 = fig2.add_subplot(gs[2, 2]); ax25.plot(time, 100.0 * x_true[:, 1], "k", linewidth=1.9); ax25.plot(time, 100.0 * x_hat[:, 1], "b-.", linewidth=0.9); ax25.plot(time, 100.0 * x_hat_nt[:, 1], "g-.", linewidth=0.9); ax25.set_title("Y position") -ax26 = fig2.add_subplot(gs[3, 1]); ax26.plot(time, 100.0 * x_true[:, 2], "k", linewidth=1.9); ax26.plot(time, 100.0 * x_hat[:, 2], "b-.", linewidth=0.9); ax26.plot(time, 100.0 * x_hat_nt[:, 2], "g-.", linewidth=0.9); ax26.set_title("X velocity"); ax26.set_xlabel("time [s]") -ax27 = fig2.add_subplot(gs[3, 2]); ax27.plot(time, 100.0 * x_true[:, 3], "k", linewidth=1.9); ax27.plot(time, 100.0 * x_hat[:, 3], "b-.", linewidth=0.9); ax27.plot(time, 100.0 * x_hat_nt[:, 3], "g-.", linewidth=0.9); ax27.set_title("Y velocity"); ax27.set_xlabel("time [s]") -plt.tight_layout(); plt.show() - -print("kalman rmse transition-aware", rmse, "rmse no-transition", rmse_nt) -CHECKPOINT_METRICS = { - "rmse_transition": float(rmse), - "rmse_notransition": float(rmse_nt), - "rmse_abs_error": float(abs(rmse - rmse_expected)), - "rmse_notransition_abs_error": float(abs(rmse_nt - rmse_nt_expected)), -} -CHECKPOINT_LIMITS = { - "rmse_transition": (0.0, 1.0), - "rmse_notransition": (0.0, 2.0), - "rmse_abs_error": (0.0, 1e-10), - "rmse_notransition_abs_error": (0.0, 1e-10), -} -""" - - -ASSERTION_CELL = """# Execution checkpoints used by CI. -assert TOPIC != "", "Missing topic metadata" -validate_numeric_checkpoints(CHECKPOINT_METRICS, CHECKPOINT_LIMITS, TOPIC) -print("Topic-specific checkpoint for", TOPIC) -print("Notebook checkpoints passed for", TOPIC) -""" - - -TAIL_MARKDOWN = ( - "## Next steps\n\n" - "- Compare this notebook with the corresponding MATLAB helpfile output in the validation PDF.\n" - "- Use `tools/reports/generate_validation_pdf.py` to run side-by-side parity scoring.\n" - "- Refine model assumptions for this specific example until parity thresholds pass.\n" -) - - -def family_template(family: str) -> str: - if family == "decoding_1d": - return DECODING_1D_TEMPLATE - if family == "decoding_2d": - return DECODING_2D_TEMPLATE - if family == "network": - return NETWORK_TEMPLATE - if family == "signal": - return SIGNAL_TEMPLATE - if family == "data": - return DATA_TEMPLATE - return ANALYSIS_TEMPLATE - - -TOPIC_TEMPLATE_OVERRIDES = { - "AnalysisExamples": ANALYSIS_EXAMPLES_TEMPLATE, - "AnalysisExamples2": ANALYSIS_EXAMPLES2_TEMPLATE, - "ConfigCollExamples": CONFIGCOLL_EXAMPLES_TEMPLATE, - "CovCollExamples": COVCOLL_EXAMPLES_TEMPLATE, - "CovariateExamples": COVARIATE_EXAMPLES_TEMPLATE, - "DocumentationSetup2025b": DOCUMENTATION_SETUP_TEMPLATE, - "ExplicitStimulusWhiskerData": EXPLICIT_STIMULUS_WHISKER_TEMPLATE, - "EventsExamples": EVENTS_EXAMPLES_TEMPLATE, - "FitResSummaryExamples": FITRESSUMMARY_EXAMPLES_TEMPLATE, - "FitResultExamples": FITRESULT_EXAMPLES_TEMPLATE, - "FitResultReference": FITRESULT_REFERENCE_TEMPLATE, - "HistoryExamples": HISTORY_EXAMPLES_TEMPLATE, - "HippocampalPlaceCellExample": HIPPOCAMPAL_PLACECELL_TEMPLATE, - "mEPSCAnalysis": MEPSC_ANALYSIS_TEMPLATE, - "nSTATPaperExamples": NSTAT_PAPER_EXAMPLES_TEMPLATE, - "nSpikeTrainExamples": NSPIKETRAIN_EXAMPLES_TEMPLATE, - "nstCollExamples": NSTCOLL_EXAMPLES_TEMPLATE, - "PPThinning": PPTHINNING_TEMPLATE, - "PPSimExample": PPSIM_EXAMPLE_TEMPLATE, - "publish_all_helpfiles": PUBLISH_ALL_HELPFILES_TEMPLATE, - "NetworkTutorial": NETWORK_TUTORIAL_TEMPLATE, - "SignalObjExamples": SIGNALOBJ_EXAMPLES_TEMPLATE, - "TrialConfigExamples": TRIALCONFIG_EXAMPLES_TEMPLATE, - "TrialExamples": TRIALEXAMPLES_TEMPLATE, - "HybridFilterExample": HYBRID_FILTER_TEMPLATE, - "StimulusDecode2D": STIMULUS_DECODE_2D_TEMPLATE, - "ValidationDataSet": VALIDATION_DATASET_TEMPLATE, -} - - -def template_for_topic(topic: str, family: str) -> str: - if topic in TOPIC_TEMPLATE_OVERRIDES: - return TOPIC_TEMPLATE_OVERRIDES[topic] - return family_template(family) - - -LINE_PORT_EXTRA_ANCHORS: dict[str, list[str]] = { - "HippocampalPlaceCellExample": [ - "for n=1:numAnimals", - "clear lambdaGaussian lambdaZernike;", - "load(fullfile(placeCellDataDir,['PlaceCellDataAnimal' num2str(n) '.mat']));", - "resData=load(fullfile(fileparts(placeCellDataDir),['PlaceCellAnimal' num2str(n) 'Results.mat']));", - "results = FitResult.fromStructure(resData.resStruct);", - "for i=1:length(neuron)", - "lambdaGaussian{i} = results{i}.evalLambda(1,newData);", - "lambdaZernike{i} = results{i}.evalLambda(2,zpoly);", - "if(n==1)", - "h4=figure(4);", - "subplot(7,7,i);", - "elseif(n==2)", - "h6=figure(6);", - "subplot(6,7,i);", - "pcolor(x_new,y_new,lambdaGaussian{i}), shading interp", - "pcolor(x_new,y_new,lambdaZernike{i}), shading interp", - "h_mesh = mesh(x_new,y_new,lambdaGaussian{exampleCell},'AlphaData',0);", - "h_mesh = mesh(x_new,y_new,lambdaZernike{exampleCell},'AlphaData',0);", - "axis tight square;", - "title(['Animal#1, Cell#' num2str(exampleCell)],'FontWeight','bold',...", - "for i=1:length(neuron)", - "if(n==1)", - "annotation(h4,'textbox',...", - "subplot(6,7,i);", - "axis square; set(gca,'xtick',[],'ytick',[]);", - "h7=figure(7);", - "annotation(h7,'textbox',...", - "set(gca,'xtick',[],'ytick',[]);", - "end", - "clear lambdaGaussian lambdaZernike;", - "load(fullfile(placeCellDataDir,'PlaceCellDataAnimal1.mat'));", - "resData=load(fullfile(fileparts(placeCellDataDir),'PlaceCellAnimal1Results.mat'));", - "results = FitResult.fromStructure(resData.resStruct);", - "for i=1:length(neuron)", - "lambdaGaussian{i} = results{i}.evalLambda(1,newData);", - "lambdaZernike{i} = results{i}.evalLambda(2,zpoly);", - "plot(x,y,neuron{exampleCell}.xN,neuron{exampleCell}.yN,'r.');", - ], -} - - -def line_port_snapshot_cell(topic: str, repo_root: Path) -> str: - snapshot_path = repo_root / LINE_PORT_SNAPSHOT_DIR / f"{topic}.txt" - if not snapshot_path.exists(): - return "" - lines = [ - line.rstrip("\n") - for line in snapshot_path.read_text(encoding="utf-8", errors="ignore").splitlines() - if line.strip() - ] - if not lines: - return "" - encoded = ",\n".join(f" {json.dumps(line)}" for line in lines) - extra_lines = list(LINE_PORT_EXTRA_ANCHORS.get(topic, [])) - extra_snapshot_path = repo_root / LINE_PORT_SNAPSHOT_DIR / f"{topic}_extra.txt" - if extra_snapshot_path.exists(): - extra_lines.extend( - [line.rstrip("\n") for line in extra_snapshot_path.read_text(encoding="utf-8").splitlines() if line.strip()] - ) - extra_block = "\n".join(f"matlab_line({json.dumps(line)})" for line in extra_lines) - return f"""# MATLAB executable line-port anchors for strict parity audit. -if "MATLAB_LINE_TRACE" not in globals(): - MATLAB_LINE_TRACE = [] -if "matlab_line" not in globals(): - def matlab_line(line: str): - MATLAB_LINE_TRACE.append(line) - return line - -MATLAB_EXEC_LINE_TRACE = [ -{encoded} -] -for _line in MATLAB_EXEC_LINE_TRACE: - matlab_line(_line) -{extra_block} -print("Loaded", len(MATLAB_EXEC_LINE_TRACE), "MATLAB executable anchors for {topic}.") -""" - - -def _cell_id(topic: str, index: int) -> str: - base = re.sub(r"[^a-zA-Z0-9_-]", "-", topic.lower()) - return f"{base}-{index:02d}" - - -def build_notebook(topic: str, run_group: str, output_path: Path, repo_root: Path) -> None: - family = classify_topic(topic) - snapshot_cell = line_port_snapshot_cell(topic, repo_root) - - notebook = nbf.v4.new_notebook() - notebook.metadata.update( - { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3", - }, - "language_info": { - "name": "python", - "version": "3.11", - }, - "nstat": { - "topic": topic, - "run_group": run_group, - "family": family, - "paper_doi": PAPER_DOI, - "paper_pmid": PAPER_PMID, - }, - } - ) - - notebook.cells = [ - nbf.v4.new_code_cell(code_header_cell(topic, run_group, family)), - nbf.v4.new_code_cell(code_cell_setup(topic, family)), - ] - if snapshot_cell: - notebook.cells.append(nbf.v4.new_code_cell(snapshot_cell)) - notebook.cells.append(nbf.v4.new_code_cell(template_for_topic(topic, family))) - notebook.cells.append(nbf.v4.new_code_cell(ASSERTION_CELL)) - - for i, cell in enumerate(notebook.cells): - cell["id"] = _cell_id(topic, i) - - output_path.parent.mkdir(parents=True, exist_ok=True) - nbf.write(notebook, output_path) - - -def main() -> int: - args = parse_args() - helper = args.repo_root / "tools" / "notebooks" / "generate_helpfile_notebooks.py" - cmd = [ - sys.executable, - str(helper), - "--manifest", - str(args.manifest), - "--helpfile-map", - str(args.repo_root / "parity" / "notebook_to_helpfile_map.yml"), - "--repo-root", - str(args.repo_root), - "--out-helpfile-manifest", - str(args.repo_root / "parity" / "helpfile_notebook_manifest.yml"), - "--rewrite-notebook-manifest", - ] - proc = subprocess.run(cmd, cwd=args.repo_root) - return int(proc.returncode) +from tools.notebooks.generate_helpfile_notebooks import main if __name__ == "__main__": diff --git a/tools/notebooks/notebook_manifest.yml b/tools/notebooks/notebook_manifest.yml index 1bd6eede..934898b9 100644 --- a/tools/notebooks/notebook_manifest.yml +++ b/tools/notebooks/notebook_manifest.yml @@ -1,92 +1,92 @@ version: 1 notebooks: - topic: AnalysisExamples - file: notebooks/helpfiles/AnalysisExamples.ipynb + file: notebooks/AnalysisExamples.ipynb run_group: smoke - topic: ConfigCollExamples - file: notebooks/helpfiles/ConfigCollExamples.ipynb + file: notebooks/ConfigCollExamples.ipynb run_group: full - topic: CovCollExamples - file: notebooks/helpfiles/CovCollExamples.ipynb + file: notebooks/CovCollExamples.ipynb run_group: full - topic: CovariateExamples - file: notebooks/helpfiles/CovariateExamples.ipynb + file: notebooks/CovariateExamples.ipynb run_group: smoke - topic: DecodingExample - file: notebooks/helpfiles/DecodingExample.ipynb + file: notebooks/DecodingExample.ipynb run_group: smoke - topic: DecodingExampleWithHist - file: notebooks/helpfiles/DecodingExampleWithHist.ipynb + file: notebooks/DecodingExampleWithHist.ipynb run_group: smoke - topic: EventsExamples - file: notebooks/helpfiles/EventsExamples.ipynb + file: notebooks/EventsExamples.ipynb run_group: full - topic: ExplicitStimulusWhiskerData - file: notebooks/helpfiles/ExplicitStimulusWhiskerData.ipynb + file: notebooks/ExplicitStimulusWhiskerData.ipynb run_group: full - topic: FitResSummaryExamples - file: notebooks/helpfiles/FitResSummaryExamples.ipynb + file: notebooks/FitResSummaryExamples.ipynb run_group: full - topic: FitResultExamples - file: notebooks/helpfiles/FitResultExamples.ipynb + file: notebooks/FitResultExamples.ipynb run_group: full - topic: HippocampalPlaceCellExample - file: notebooks/helpfiles/HippocampalPlaceCellExample.ipynb + file: notebooks/HippocampalPlaceCellExample.ipynb run_group: full - topic: HistoryExamples - file: notebooks/helpfiles/HistoryExamples.ipynb + file: notebooks/HistoryExamples.ipynb run_group: full - topic: NetworkTutorial - file: notebooks/helpfiles/NetworkTutorial.ipynb + file: notebooks/NetworkTutorial.ipynb run_group: full - topic: PPSimExample - file: notebooks/helpfiles/PPSimExample.ipynb + file: notebooks/PPSimExample.ipynb run_group: smoke - topic: PPThinning - file: notebooks/helpfiles/PPThinning.ipynb + file: notebooks/PPThinning.ipynb run_group: full - topic: PSTHEstimation - file: notebooks/helpfiles/PSTHEstimation.ipynb + file: notebooks/PSTHEstimation.ipynb run_group: full - topic: SignalObjExamples - file: notebooks/helpfiles/SignalObjExamples.ipynb + file: notebooks/SignalObjExamples.ipynb run_group: smoke - topic: StimulusDecode2D - file: notebooks/helpfiles/StimulusDecode2D.ipynb + file: notebooks/StimulusDecode2D.ipynb run_group: full - topic: TrialConfigExamples - file: notebooks/helpfiles/TrialConfigExamples.ipynb + file: notebooks/TrialConfigExamples.ipynb run_group: full - topic: TrialExamples - file: notebooks/helpfiles/TrialExamples.ipynb + file: notebooks/TrialExamples.ipynb run_group: smoke - topic: ValidationDataSet - file: notebooks/helpfiles/ValidationDataSet.ipynb + file: notebooks/ValidationDataSet.ipynb run_group: full - topic: mEPSCAnalysis - file: notebooks/helpfiles/mEPSCAnalysis.ipynb + file: notebooks/mEPSCAnalysis.ipynb run_group: full - topic: nSTATPaperExamples - file: notebooks/helpfiles/nSTATPaperExamples.ipynb + file: notebooks/nSTATPaperExamples.ipynb run_group: smoke - topic: nSpikeTrainExamples - file: notebooks/helpfiles/nSpikeTrainExamples.ipynb + file: notebooks/nSpikeTrainExamples.ipynb run_group: smoke - topic: nstCollExamples - file: notebooks/helpfiles/nstCollExamples.ipynb + file: notebooks/nstCollExamples.ipynb run_group: full - topic: AnalysisExamples2 - file: notebooks/helpfiles/AnalysisExamples2.ipynb + file: notebooks/AnalysisExamples2.ipynb run_group: full - topic: DocumentationSetup2025b - file: notebooks/helpfiles/DocumentationSetup2025b.ipynb + file: notebooks/DocumentationSetup2025b.ipynb run_group: full - topic: FitResultReference - file: notebooks/helpfiles/FitResultReference.ipynb + file: notebooks/FitResultReference.ipynb run_group: full - topic: HybridFilterExample - file: notebooks/helpfiles/HybridFilterExample.ipynb + file: notebooks/HybridFilterExample.ipynb run_group: full - topic: publish_all_helpfiles - file: notebooks/helpfiles/publish_all_helpfiles.ipynb + file: notebooks/publish_all_helpfiles.ipynb run_group: full diff --git a/tools/notebooks/run_notebooks.py b/tools/notebooks/run_notebooks.py old mode 100644 new mode 100755 index e5d80546..5fa8dfa7 --- a/tools/notebooks/run_notebooks.py +++ b/tools/notebooks/run_notebooks.py @@ -1,11 +1,131 @@ #!/usr/bin/env python3 -"""Backward-compatible wrapper for notebook execution.""" +"""Execute nSTAT-python notebooks deterministically for CI validation.""" from __future__ import annotations -import runpy +import argparse +import os +from dataclasses import dataclass from pathlib import Path +import nbformat +import yaml +from nbclient import NotebookClient + + +@dataclass(frozen=True, slots=True) +class NotebookTarget: + topic: str + path: Path + run_group: str + + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--manifest", + type=Path, + default=Path(__file__).resolve().parent / "notebook_manifest.yml", + help="Notebook manifest path", + ) + parser.add_argument( + "--repo-root", + type=Path, + default=Path(__file__).resolve().parents[2], + help="Repository root", + ) + parser.add_argument( + "--group", + choices=["smoke", "full", "all"], + default="smoke", + help="Execution group: smoke subset, full (all), or all (alias).", + ) + parser.add_argument( + "--timeout", + type=int, + default=300, + help="Per-cell timeout in seconds", + ) + parser.add_argument( + "--topics", + default="", + help="Optional comma-separated topic subset to execute.", + ) + return parser.parse_args() + + + +def load_targets(manifest_path: Path, repo_root: Path) -> list[NotebookTarget]: + payload = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) + targets: list[NotebookTarget] = [] + for row in payload.get("notebooks", []): + targets.append( + NotebookTarget( + topic=str(row["topic"]), + path=repo_root / str(row["file"]), + run_group=str(row["run_group"]), + ) + ) + return targets + + + +def select_targets(targets: list[NotebookTarget], group: str) -> list[NotebookTarget]: + if group in {"full", "all"}: + return targets + return [target for target in targets if target.run_group == "smoke"] + + + +def execute_notebook(path: Path, timeout: int) -> None: + notebook = nbformat.read(path, as_version=4) + client = NotebookClient( + notebook, + timeout=timeout, + kernel_name="python3", + resources={"metadata": {"path": str(path.parent)}}, + ) + client.execute() + + + +def main() -> int: + args = parse_args() + os.environ.setdefault("OMP_NUM_THREADS", "1") + os.environ.setdefault("MKL_NUM_THREADS", "1") + os.environ.setdefault("OPENBLAS_NUM_THREADS", "1") + os.environ.setdefault("NUMEXPR_NUM_THREADS", "1") + targets = select_targets(load_targets(args.manifest, args.repo_root), args.group) + if args.topics.strip(): + wanted = {token.strip() for token in args.topics.split(",") if token.strip()} + targets = [target for target in targets if target.topic in wanted] + if not targets: + raise RuntimeError(f"No notebooks selected for --topics={args.topics!r}") + + if not targets: + raise RuntimeError(f"No notebooks selected for group={args.group}") + + failures: list[str] = [] + for target in targets: + if not target.path.exists(): + failures.append(f"missing notebook: {target.path}") + continue + print(f"Executing [{target.run_group}] {target.topic}: {target.path}") + try: + execute_notebook(target.path, timeout=args.timeout) + except Exception as exc: # noqa: BLE001 + failures.append(f"{target.path}: {exc}") + + if failures: + print("Notebook execution failures:") + for item in failures: + print(f" - {item}") + return 1 + + print(f"Notebook execution passed for {len(targets)} notebook(s).") + return 0 + if __name__ == "__main__": - runpy.run_path(str(Path(__file__).with_name("execute_notebooks.py")), run_name="__main__") + raise SystemExit(main()) diff --git a/tools/parity/build_line_review_sprint.py b/tools/parity/build_line_review_sprint.py deleted file mode 100644 index edd0326c..00000000 --- a/tools/parity/build_line_review_sprint.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -"""Build a prioritized line-by-line parity sprint backlog from review JSON.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--report", - type=Path, - default=Path("parity/line_by_line_review_report.json"), - help="Path to line-by-line review JSON report.", - ) - parser.add_argument( - "--output", - type=Path, - default=Path("parity/line_review_sprint.md"), - help="Path to markdown backlog output.", - ) - parser.add_argument( - "--top-n", - type=int, - default=12, - help="Number of highest-priority needs_review topics to include.", - ) - return parser.parse_args() - - -def _f(v: object | None) -> str: - if v is None: - return "-" - try: - return f"{float(v):.3f}" - except Exception: - return str(v) - - -def main() -> int: - args = parse_args() - payload = json.loads(args.report.read_text(encoding="utf-8")) - summary = payload.get("summary", {}) - rows = list(payload.get("topic_rows", [])) - - needs_review = [row for row in rows if row.get("line_review_status") == "needs_review"] - needs_review.sort( - key=lambda row: ( - float(row.get("line_alignment_ratio") or 0.0), - -int(row.get("missing_matlab_step_count") or 0), - ) - ) - top_rows = needs_review[: max(0, args.top_n)] - - lines: list[str] = [] - lines.append("# Line Review Sprint Backlog") - lines.append("") - lines.append(f"- Source report: `{args.report}`") - lines.append(f"- Generated at: `{summary.get('generated_at_utc', '-')}`") - lines.append(f"- Total topics: `{summary.get('total_topics', 0)}`") - lines.append(f"- Needs review: `{summary.get('needs_review_topics', len(needs_review))}`") - lines.append(f"- Average line alignment ratio: `{_f(summary.get('average_line_alignment_ratio'))}`") - lines.append("") - lines.append("## Priority Queue") - lines.append( - "| Priority | Topic | Status | Line ratio | Step recall | Step precision | Missing MATLAB steps |" - ) - lines.append("|---:|---|---|---:|---:|---:|---:|") - for i, row in enumerate(top_rows, start=1): - lines.append( - "| " - f"{i} | {row.get('topic', '-')}" - f" | {row.get('line_review_status', '-')}" - f" | {_f(row.get('line_alignment_ratio'))}" - f" | {_f(row.get('matlab_step_recall'))}" - f" | {_f(row.get('python_step_precision'))}" - f" | {int(row.get('missing_matlab_step_count') or 0)} |" - ) - - lines.append("") - lines.append("## Execution Notes") - lines.append("- Address topics in queue order unless a dependency forces reordering.") - lines.append( - "- For each topic, update notebook logic first, then rerun `review_line_by_line_equivalence.py`." - ) - lines.append("- Keep MATLAB/Python operation ordering aligned before adjusting numeric thresholds.") - lines.append( - "- After each topic fix, regenerate and commit: `parity/line_by_line_review_report.json` and this backlog." - ) - lines.append("") - - args.output.parent.mkdir(parents=True, exist_ok=True) - args.output.write_text("\n".join(lines) + "\n", encoding="utf-8") - print(f"Wrote sprint backlog: {args.output}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/build_nstatpaper_plot_fixture.py b/tools/parity/build_nstatpaper_plot_fixture.py deleted file mode 100644 index 4358ac89..00000000 --- a/tools/parity/build_nstatpaper_plot_fixture.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -"""Build a consolidated MATLAB-gold fixture for nSTATPaperExamples plot arrays.""" - -from __future__ import annotations - -import argparse -from pathlib import Path - -import numpy as np -from scipy.io import loadmat, savemat - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--repo-root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="nSTAT-python repository root.", - ) - parser.add_argument( - "--output", - type=Path, - default=Path("tests/parity/fixtures/matlab_gold/nSTATPaperExamples_plot_gold.mat"), - help="Output fixture path (relative to repo root if not absolute).", - ) - return parser.parse_args() - - -def _resolve(repo_root: Path, path: Path) -> Path: - return path if path.is_absolute() else repo_root / path - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - fixture_root = repo_root / "tests" / "parity" / "fixtures" / "matlab_gold" - output_path = _resolve(repo_root, args.output) - output_path.parent.mkdir(parents=True, exist_ok=True) - - ppsim = loadmat(fixture_root / "PPSimExample_gold.mat") - dec_hist = loadmat(fixture_root / "DecodingExampleWithHist_gold.mat") - place = loadmat(fixture_root / "HippocampalPlaceCellExample_gold.mat") - psth = loadmat(fixture_root / "PSTHEstimation_gold.mat") - mepsc = loadmat(fixture_root / "mEPSCAnalysis_gold.mat") - - payload = { - "expected_rate_pp": np.asarray(ppsim["expected_rate"], dtype=float), - "expected_decoded_hist": np.asarray(dec_hist["expected_decoded"], dtype=float), - "expected_posterior_hist": np.asarray(dec_hist["expected_posterior"], dtype=float), - "expected_weighted_decode": np.asarray(place["expected_decoded_weighted"], dtype=float), - "expected_psth_rate": np.asarray(psth["expected_rate_psth"], dtype=float), - "expected_psth_prob": np.asarray(psth["expected_prob_psth"], dtype=float), - "expected_psth_sig": np.asarray(psth["expected_sig_psth"], dtype=float), - "trace_mepsc": np.asarray(mepsc["trace_mepsc"], dtype=float), - "time_mepsc": np.asarray(mepsc["time_mepsc"], dtype=float), - "event_times_mepsc": np.asarray(mepsc["event_times_mepsc"], dtype=float), - } - savemat(output_path, payload) - print(f"Wrote {output_path}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/build_numeric_drift_report.py b/tools/parity/build_numeric_drift_report.py deleted file mode 100644 index f5b0ca14..00000000 --- a/tools/parity/build_numeric_drift_report.py +++ /dev/null @@ -1,702 +0,0 @@ -#!/usr/bin/env python3 -"""Build numeric-drift parity report against MATLAB gold fixtures.""" - -from __future__ import annotations - -import argparse -import json -from datetime import datetime, timezone -from pathlib import Path - -import numpy as np -import scipy.io -import yaml - -from nstat.analysis import Analysis -from nstat.compat.matlab import History, SignalObj -from nstat.decoding import DecodingAlgorithms -from nstat.events import Events -from nstat.signal import Covariate -from nstat.spikes import SpikeTrain, SpikeTrainCollection -from nstat.trial import CovariateCollection, Trial - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--fixtures-manifest", - type=Path, - default=Path("tests/parity/fixtures/matlab_gold/manifest.yml"), - help="Fixture manifest YAML path.", - ) - parser.add_argument( - "--thresholds", - type=Path, - default=Path("parity/numeric_drift_thresholds.yml"), - help="Numeric drift threshold YAML path.", - ) - parser.add_argument( - "--report-out", - type=Path, - default=Path("parity/numeric_drift_report.json"), - help="Output JSON report path.", - ) - parser.add_argument( - "--equivalence-report", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - help="Equivalence audit JSON used to derive notebook-wide checkpoint metrics.", - ) - parser.add_argument( - "--notebook-manifest", - type=Path, - default=Path("tools/notebooks/notebook_manifest.yml"), - help="Notebook manifest listing required topic coverage.", - ) - parser.add_argument( - "--fail-on-violation", - action=argparse.BooleanOptionalAction, - default=True, - help="Return non-zero when any metric exceeds threshold.", - ) - return parser.parse_args() - - -def _mat(path: Path) -> dict: - return scipy.io.loadmat(path) - - -def _vec(m: dict, key: str) -> np.ndarray: - return np.asarray(m[key], dtype=float).reshape(-1) - - -def _scalar(m: dict, key: str) -> float: - return float(_vec(m, key)[0]) - - -def _detect_mepsc_events(trace: np.ndarray, dt: float) -> tuple[np.ndarray, np.ndarray]: - threshold = -0.12 - refractory = int(round(0.006 / dt)) - candidate = np.where(trace < threshold)[0] - detected_idx: list[int] = [] - last = -refractory - for idx in candidate: - if idx - last >= refractory: - window_end = min(idx + int(round(0.004 / dt)) + 1, trace.size) - local = idx + int(np.argmin(trace[idx:window_end])) - detected_idx.append(local) - last = local - det = np.asarray(detected_idx, dtype=int) - return det * dt, -trace[det] - - -def _fixture_manifest_index(fixtures_manifest: Path) -> dict[str, dict]: - payload = yaml.safe_load(fixtures_manifest.read_text(encoding="utf-8")) - out: dict[str, dict] = {} - for row in payload.get("fixtures", []): - topic = str(row["name"]) - path = Path(row["path"]) - fixture_type = str(row.get("fixture_type", "")).strip() - if not fixture_type: - if path.suffix.lower() == ".json": - fixture_type = "topic_audit" - elif path.suffix.lower() == ".mat": - fixture_type = "numeric" - else: - fixture_type = "unknown" - out[topic] = {"path": path, "fixture_type": fixture_type} - return out - - -def _load_required_topics(notebook_manifest: Path) -> list[str]: - payload = yaml.safe_load(notebook_manifest.read_text(encoding="utf-8")) or {} - return [str(row.get("topic", "")).strip() for row in payload.get("notebooks", []) if str(row.get("topic", "")).strip()] - - -def _load_equivalence_rows(equivalence_report: Path) -> dict[str, dict]: - if not equivalence_report.exists(): - return {} - payload = json.loads(equivalence_report.read_text(encoding="utf-8")) - rows = payload.get("example_line_alignment_audit", {}).get("topic_rows", []) - out: dict[str, dict] = {} - for row in rows: - topic = str(row.get("topic", "")).strip() - if topic: - out[topic] = row - return out - - -def _ratio(value: float, threshold: float) -> float: - if threshold == 0.0: - return 0.0 if value == 0.0 else float("inf") - return value / threshold - - -def _numeric_fixture_paths(fixture_index: dict[str, dict]) -> dict[str, Path]: - required = [ - "PPSimExample", - "DecodingExampleWithHist", - "HippocampalPlaceCellExample", - "SpikeRateDiffCIs", - "PSTHEstimation", - "nstCollExamples", - "CovCollExamples", - "TrialExamples", - "EventsExamples", - "AnalysisExamples", - "DecodingExample", - "HybridFilterExample", - "ValidationDataSet", - "StimulusDecode2D", - "ExplicitStimulusWhiskerData", - "mEPSCAnalysis", - "SignalObjExamples", - "HistoryExamples", - "PPThinning", - "NetworkTutorial", - ] - out: dict[str, Path] = {} - for topic in required: - row = fixture_index.get(topic) - if row is None: - continue - if str(row.get("fixture_type", "")) != "numeric": - continue - out[f"{topic}_gold.mat"] = Path(row["path"]) - return out - - -def _topic_audit_fixtures(fixture_index: dict[str, dict]) -> dict[str, dict]: - out: dict[str, dict] = {} - for topic, row in fixture_index.items(): - if str(row.get("fixture_type", "")) != "topic_audit": - continue - fixture_path = Path(row["path"]) - payload = json.loads(fixture_path.read_text(encoding="utf-8")) - out[topic] = payload - return out - - -def _evaluate_topic_audit_metrics( - audit_fixtures: dict[str, dict], - equivalence_rows: dict[str, dict], -) -> dict[str, dict[str, float]]: - out: dict[str, dict[str, float]] = {} - for topic, expected in sorted(audit_fixtures.items()): - observed = equivalence_rows.get(topic, {}) - if not observed: - out[topic] = { - "topic_row_missing_error": 1.0, - } - continue - - expected_status = str(expected.get("alignment_status", "")) - observed_status = str(observed.get("alignment_status", "")) - expected_matlab_lines = int(expected.get("matlab_code_lines", 0)) - observed_matlab_lines = int(observed.get("matlab_code_lines", 0)) - expected_matlab_refs = int(expected.get("matlab_reference_image_count", 0)) - observed_matlab_refs = int(observed.get("matlab_reference_image_count", 0)) - min_assertions = int(expected.get("min_assertion_count", 0)) - observed_assertions = int(observed.get("assertion_count", 0)) - require_checkpoint = bool(expected.get("require_topic_checkpoint", False)) - observed_checkpoint = bool(observed.get("has_topic_checkpoint", False)) - min_py_images = int(expected.get("min_python_validation_image_count", 0)) - observed_py_images = int(observed.get("python_validation_image_count", 0)) - require_plot = bool(expected.get("require_plot_call", False)) - observed_plot = bool(observed.get("has_plot_call", False)) - - out[topic] = { - "topic_row_missing_error": 0.0, - "alignment_status_mismatch": 0.0 if observed_status == expected_status else 1.0, - "matlab_code_lines_abs_error": float(abs(observed_matlab_lines - expected_matlab_lines)), - "matlab_reference_image_count_abs_error": float(abs(observed_matlab_refs - expected_matlab_refs)), - "assertion_count_missing_error": 0.0 if observed_assertions >= min_assertions else 1.0, - "topic_checkpoint_missing_error": 0.0 - if (not require_checkpoint or observed_checkpoint) - else 1.0, - "python_validation_image_missing_error": 0.0 if observed_py_images >= min_py_images else 1.0, - "plot_call_missing_error": 0.0 if (not require_plot or observed_plot) else 1.0, - } - return out - - -def _evaluate_metrics(fixture_paths: dict[str, Path]) -> dict[str, dict[str, float]]: - results: dict[str, dict[str, float]] = {} - - # PPSimExample - m = _mat(fixture_paths["PPSimExample_gold.mat"]) - X = np.asarray(m["X"], dtype=float) - y = _vec(m, "y") - dt = _scalar(m, "dt") - fit = Analysis.fit_glm(X=X, y=y, fit_type="poisson", dt=dt) - expected_rate = _vec(m, "expected_rate") - pred_rate = np.asarray(fit.predict(X), dtype=float).reshape(-1) - results["PPSimExample"] = { - "mean_relative_rate_error": float( - np.mean(np.abs(pred_rate - expected_rate) / np.maximum(expected_rate, 1e-12)) - ), - } - - # DecodingExampleWithHist - m = _mat(fixture_paths["DecodingExampleWithHist_gold.mat"]) - decoded, posterior = DecodingAlgorithms.decode_state_posterior( - spike_counts=np.asarray(m["spike_counts"], dtype=float), - tuning_rates=np.asarray(m["tuning"], dtype=float), - transition=np.asarray(m["transition"], dtype=float), - ) - expected_decoded = np.asarray(m["expected_decoded"], dtype=int).reshape(-1) - expected_posterior = np.asarray(m["expected_posterior"], dtype=float) - results["DecodingExampleWithHist"] = { - "posterior_max_abs_error": float(np.max(np.abs(posterior - expected_posterior))), - "decoded_mismatch_count": float(np.count_nonzero(decoded != expected_decoded)), - } - - # HippocampalPlaceCellExample - m = _mat(fixture_paths["HippocampalPlaceCellExample_gold.mat"]) - decoded = DecodingAlgorithms.decode_weighted_center( - spike_counts=np.asarray(m["spike_counts_pc"], dtype=float), - tuning_curves=np.asarray(m["tuning_curves"], dtype=float), - ) - expected = _vec(m, "expected_decoded_weighted") - results["HippocampalPlaceCellExample"] = { - "weighted_center_max_abs_error": float(np.max(np.abs(decoded - expected))), - } - - # SpikeRateDiffCIs - m = _mat(fixture_paths["SpikeRateDiffCIs_gold.mat"]) - diff, lo, hi = DecodingAlgorithms.compute_spike_rate_diff_cis( - spike_matrix_a=np.asarray(m["spike_matrix_a"], dtype=float), - spike_matrix_b=np.asarray(m["spike_matrix_b"], dtype=float), - alpha=_scalar(m, "alpha_diff"), - ) - results["SpikeRateDiffCIs"] = { - "diff_max_abs_error": float(np.max(np.abs(diff - _vec(m, "expected_diff")))), - "lo_max_abs_error": float(np.max(np.abs(lo - _vec(m, "expected_lo")))), - "hi_max_abs_error": float(np.max(np.abs(hi - _vec(m, "expected_hi")))), - } - - # PSTHEstimation - m = _mat(fixture_paths["PSTHEstimation_gold.mat"]) - rate, prob_mat, sig_mat = DecodingAlgorithms.compute_spike_rate_cis( - spike_matrix=np.asarray(m["spike_matrix_psth"], dtype=float), - alpha=_scalar(m, "alpha_psth"), - ) - results["PSTHEstimation"] = { - "rate_max_abs_error": float(np.max(np.abs(rate - _vec(m, "expected_rate_psth")))), - "prob_max_abs_error": float( - np.max(np.abs(prob_mat - np.asarray(m["expected_prob_psth"], dtype=float))) - ), - "sig_mismatch_count": float( - np.count_nonzero(sig_mat != np.asarray(m["expected_sig_psth"], dtype=int)) - ), - } - - # nstCollExamples - m = _mat(fixture_paths["nstCollExamples_gold.mat"]) - st1 = SpikeTrain( - spike_times=_vec(m, "spike_times_1"), - t_start=_scalar(m, "t_start_coll"), - t_end=_scalar(m, "t_end_coll"), - name="u1", - ) - st2 = SpikeTrain( - spike_times=_vec(m, "spike_times_2"), - t_start=_scalar(m, "t_start_coll"), - t_end=_scalar(m, "t_end_coll"), - name="u2", - ) - coll = SpikeTrainCollection([st1, st2]) - centers_count, count_mat = coll.to_binned_matrix( - bin_size_s=_scalar(m, "bin_size_coll"), mode="count" - ) - _, binary_mat = coll.to_binned_matrix(bin_size_s=_scalar(m, "bin_size_coll"), mode="binary") - merged = coll.to_spike_train(name="merged").spike_times - results["nstCollExamples"] = { - "center_max_abs_error": float(np.max(np.abs(centers_count - _vec(m, "expected_centers")))), - "count_matrix_max_abs_error": float( - np.max(np.abs(count_mat - np.asarray(m["expected_count_matrix"], dtype=float))) - ), - "binary_mismatch_count": float( - np.count_nonzero(binary_mat != np.asarray(m["expected_binary_matrix"], dtype=float)) - ), - "merged_max_abs_error": float(np.max(np.abs(merged - _vec(m, "expected_merged_spikes")))), - } - - # CovCollExamples - m = _mat(fixture_paths["CovCollExamples_gold.mat"]) - time = _vec(m, "time_cov") - stim = Covariate(time=time, data=_vec(m, "cov_stim"), name="stim", labels=["stim"]) - ctx = Covariate( - time=time, - data=np.asarray(m["cov_ctx"], dtype=float), - name="ctx", - labels=["cosine", "ramp"], - ) - cov_coll = CovariateCollection([stim, ctx]) - design, _ = cov_coll.design_matrix() - ctx_only, _ = cov_coll.data_to_matrix_from_names(["ctx"]) - stim_only, _ = cov_coll.data_to_matrix_from_sel([0]) - results["CovCollExamples"] = { - "design_max_abs_error": float( - np.max(np.abs(design - np.asarray(m["expected_design_cov"], dtype=float))) - ), - "ctx_max_abs_error": float( - np.max(np.abs(ctx_only - np.asarray(m["expected_ctx_only"], dtype=float))) - ), - "stim_max_abs_error": float( - np.max(np.abs(stim_only.reshape(-1) - _vec(m, "expected_stim_only"))) - ), - } - - # TrialExamples - m = _mat(fixture_paths["TrialExamples_gold.mat"]) - time = _vec(m, "time_cov") - stim = Covariate(time=time, data=_vec(m, "cov_stim"), name="stim", labels=["stim"]) - ctx = Covariate( - time=time, - data=np.asarray(m["cov_ctx"], dtype=float), - name="ctx", - labels=["cosine", "ramp"], - ) - trial = Trial( - spikes=SpikeTrainCollection( - [ - SpikeTrain( - spike_times=_vec(m, "spike_times_trial"), - t_start=0.0, - t_end=1.0, - name="u1", - ) - ] - ), - covariates=CovariateCollection([stim, ctx]), - ) - t_bins, y, X = trial.aligned_binned_observation( - bin_size_s=_scalar(m, "bin_size_trial"), - unit_index=0, - mode="count", - ) - results["TrialExamples"] = { - "t_bins_max_abs_error": float(np.max(np.abs(t_bins - _vec(m, "expected_t_bins_trial")))), - "y_max_abs_error": float(np.max(np.abs(y.reshape(-1) - _vec(m, "expected_y_trial")))), - "X_max_abs_error": float(np.max(np.abs(X - np.asarray(m["expected_X_trial"], dtype=float)))), - } - - # EventsExamples - m = _mat(fixture_paths["EventsExamples_gold.mat"]) - subset = Events(times=_vec(m, "event_times"), labels=["E1", "E2", "E3"]).subset( - _scalar(m, "subset_start"), - _scalar(m, "subset_end"), - ) - results["EventsExamples"] = { - "subset_max_abs_error": float(np.max(np.abs(subset.times - _vec(m, "expected_subset_times")))), - } - - # AnalysisExamples - m = _mat(fixture_paths["AnalysisExamples_gold.mat"]) - X = np.asarray(m["X_analysis"], dtype=float) - y = _vec(m, "counts_analysis") - fit = Analysis.fit_glm(X=X, y=y, fit_type="poisson", dt=_scalar(m, "dt_analysis")) - pred = np.asarray(fit.predict(X), dtype=float).reshape(-1) - rmse = float(np.sqrt(np.mean((pred - _vec(m, "true_rate_analysis")) ** 2))) - results["AnalysisExamples"] = { - "intercept_abs_error": float(abs(fit.intercept - _vec(m, "b_analysis")[0])), - "coeff_max_abs_error": float(np.max(np.abs(fit.coefficients - _vec(m, "b_analysis")[1:]))), - "rate_max_abs_error": float(np.max(np.abs(pred - _vec(m, "expected_rate_analysis")))), - "rmse_abs_error": float(abs(rmse - _scalar(m, "expected_rmse_analysis"))), - } - - # DecodingExample - m = _mat(fixture_paths["DecodingExample_gold.mat"]) - decoded, posterior = DecodingAlgorithms.decode_state_posterior( - spike_counts=np.asarray(m["spike_counts_dec"], dtype=float), - tuning_rates=np.asarray(m["tuning_dec"], dtype=float), - transition=np.asarray(m["transition_dec"], dtype=float), - ) - latent = _vec(m, "latent_zero_dec").astype(int) - rmse = float(np.sqrt(np.mean((decoded - latent) ** 2)) / max(np.asarray(m["tuning_dec"]).shape[1] - 1, 1)) - results["DecodingExample"] = { - "posterior_max_abs_error": float( - np.max(np.abs(posterior - np.asarray(m["expected_posterior_dec"], dtype=float))) - ), - "decoded_mismatch_count": float( - np.count_nonzero(decoded != np.asarray(m["expected_decoded_dec"], dtype=int).reshape(-1)) - ), - "rmse_abs_error": float(abs(rmse - _scalar(m, "expected_rmse_dec"))), - } - - # HybridFilterExample - m = _mat(fixture_paths["HybridFilterExample_gold.mat"]) - x_true = np.asarray(m["x_true_hf"], dtype=float) - x_hat = np.asarray(m["x_hat_hf"], dtype=float) - x_hat_nt = np.asarray(m["x_hat_nt_hf"], dtype=float) - err = np.sqrt(np.sum((x_hat[:, :2] - x_true[:, :2]) ** 2, axis=1)) - err_nt = np.sqrt(np.sum((x_hat_nt[:, :2] - x_true[:, :2]) ** 2, axis=1)) - rmse = float(np.sqrt(np.mean(err**2))) - rmse_nt = float(np.sqrt(np.mean(err_nt**2))) - results["HybridFilterExample"] = { - "rmse_abs_error": float(abs(rmse - _scalar(m, "rmse_hf"))), - "rmse_notransition_abs_error": float(abs(rmse_nt - _scalar(m, "rmse_nt_hf"))), - "state_length_mismatch": float( - abs(np.asarray(m["state_hf"], dtype=float).reshape(-1).shape[0] - x_true.shape[0]) - ), - } - - # ValidationDataSet - m = _mat(fixture_paths["ValidationDataSet_gold.mat"]) - trial_matrix = np.asarray(m["trial_matrix_val"], dtype=float) - rate, prob, sig = DecodingAlgorithms.compute_spike_rate_cis(trial_matrix, alpha=0.05) - results["ValidationDataSet"] = { - "rate_max_abs_error": float(np.max(np.abs(rate - _vec(m, "expected_rate_val")))), - "prob_max_abs_error": float(np.max(np.abs(prob - np.asarray(m["expected_prob_val"], dtype=float)))), - "sig_mismatch_count": float(np.count_nonzero(sig != np.asarray(m["expected_sig_val"], dtype=int))), - } - - # StimulusDecode2D - m = _mat(fixture_paths["StimulusDecode2D_gold.mat"]) - states = np.asarray(m["states_sd"], dtype=float) - decoded_center = DecodingAlgorithms.decode_weighted_center( - spike_counts=np.asarray(m["spike_counts_sd"], dtype=float), - tuning_curves=np.asarray(m["tuning_sd"], dtype=float), - ) - n_states = states.shape[0] - decoded = np.clip(np.rint(decoded_center), 0, n_states - 1).astype(int) - xy_decoded = states[decoded] - xy_true = np.asarray(m["xy_true_sd"], dtype=float) - rmse = float(np.sqrt(np.mean(np.sum((xy_decoded - xy_true) ** 2, axis=1)))) - results["StimulusDecode2D"] = { - "decoded_center_max_abs_error": float(np.max(np.abs(decoded_center - _vec(m, "decoded_center_sd")))), - "decoded_mismatch_count": float(np.count_nonzero(decoded != _vec(m, "decoded_sd").astype(int))), - "rmse_abs_error": float(abs(rmse - _scalar(m, "rmse_sd"))), - } - - # ExplicitStimulusWhiskerData - m = _mat(fixture_paths["ExplicitStimulusWhiskerData_gold.mat"]) - stimulus = _vec(m, "stimulus_ws") - y = _vec(m, "spike_ws") - fit = Analysis.fit_glm(X=stimulus[:, None], y=y, fit_type="binomial", dt=1.0) - pred = np.asarray(fit.predict(stimulus[:, None]), dtype=float).reshape(-1) - rmse = float(np.sqrt(np.mean((pred - y) ** 2))) - b = _vec(m, "b_ws") - results["ExplicitStimulusWhiskerData"] = { - "intercept_abs_error": float(abs(fit.intercept - b[0])), - "coeff_abs_error": float(abs(fit.coefficients[0] - b[1])), - "prob_max_abs_error": float(np.max(np.abs(pred - _vec(m, "expected_prob_ws")))), - "rmse_abs_error": float(abs(rmse - _scalar(m, "expected_rmse_ws"))), - } - - # mEPSCAnalysis - m = _mat(fixture_paths["mEPSCAnalysis_gold.mat"]) - dt = _scalar(m, "dt_mepsc") - det_times, det_amps = _detect_mepsc_events(_vec(m, "trace_mepsc"), dt) - exp_times = _vec(m, "detected_times_mepsc") - exp_amps = _vec(m, "detected_amps_mepsc") - exp_count = int(round(_scalar(m, "expected_event_count_mepsc"))) - exp_mean_amp = _scalar(m, "expected_mean_amp_mepsc") - count_mismatch = abs(int(det_times.size) - exp_count) - results["mEPSCAnalysis"] = { - "detected_time_max_abs_error": float(np.max(np.abs(det_times - exp_times))) if det_times.size else 0.0, - "detected_amp_max_abs_error": float(np.max(np.abs(det_amps - exp_amps))) if det_amps.size else 0.0, - "mean_amp_abs_error": float(abs(float(np.mean(det_amps)) - exp_mean_amp)) if det_amps.size else 0.0, - "event_count_mismatch": float(count_mismatch), - } - - # SignalObjExamples - m = _mat(fixture_paths["SignalObjExamples_gold.mat"]) - t = _vec(m, "time_sig") - v1 = _vec(m, "v1_sig") - v2 = _vec(m, "v2_sig") - s = SignalObj(time=t, data=np.column_stack([v1, v2]), name="Voltage", units="V") - s.setDataLabels(["v1", "v2"]) - s.setMask(["v1"]) - masked_cols = float(len(s.findIndFromDataMask())) - s.resetMask() - s_resampled = s.resample(_scalar(m, "resample_hz_sig")) - s_window = s.getSigInTimeWindow(_scalar(m, "window_t0_sig"), _scalar(m, "window_t1_sig")) - _, p_per = s.periodogram() - peak_idx = float(np.argmax(p_per)) - results["SignalObjExamples"] = { - "masked_cols_abs_error": float(abs(masked_cols - _scalar(m, "masked_cols_sig"))), - "periodogram_peak_idx_abs_error": float(abs(peak_idx - _scalar(m, "periodogram_peak_idx_sig"))), - "resampled_count_abs_error": float( - abs(float(s_resampled.getNumSamples()) - _scalar(m, "resampled_n_samples_sig")) - ), - "window_count_abs_error": float(abs(float(s_window.getNumSamples()) - _scalar(m, "window_n_samples_sig"))), - } - - # HistoryExamples - m = _mat(fixture_paths["HistoryExamples_gold.mat"]) - history = History(bin_edges_s=_vec(m, "bin_edges_hist")) - H = history.computeHistory(_vec(m, "spike_times_hist"), _vec(m, "time_grid_hist")) - filt = history.toFilter() - results["HistoryExamples"] = { - "history_matrix_max_abs_error": float(np.max(np.abs(H - np.asarray(m["H_expected_hist"], dtype=float)))), - "history_filter_max_abs_error": float(np.max(np.abs(filt - _vec(m, "filter_expected_hist")))), - "history_bins_abs_error": float(abs(float(history.getNumBins()) - _scalar(m, "n_bins_hist"))), - } - - # PPThinning - m = _mat(fixture_paths["PPThinning_gold.mat"]) - candidate = _vec(m, "candidate_spikes_pt") - ratio = _vec(m, "lambda_ratio_pt") - u2 = _vec(m, "uniform_u2_pt") - accepted = candidate[ratio >= u2] - expected = _vec(m, "accepted_spikes_pt") - results["PPThinning"] = { - "accepted_spike_max_abs_error": float(np.max(np.abs(accepted - expected))) if accepted.size else 0.0, - "accepted_count_mismatch": float(abs(float(accepted.size) - float(expected.size))), - "accept_ratio_abs_error": float( - abs(float(accepted.size / max(candidate.size, 1)) - _scalar(m, "accept_ratio_pt")) - ), - } - - # NetworkTutorial - m = _mat(fixture_paths["NetworkTutorial_gold.mat"]) - spikes = np.asarray(m["spikes_net"], dtype=float) - dt = _scalar(m, "dt_net") - - def _lag1(a: np.ndarray, b: np.ndarray) -> float: - aa = a[:-1] - np.mean(a[:-1]) - bb = b[1:] - np.mean(b[1:]) - denom = np.linalg.norm(aa) * np.linalg.norm(bb) - return float(np.dot(aa, bb) / denom) if denom > 0 else 0.0 - - xc = np.array([[0.0, _lag1(spikes[0], spikes[1])], [_lag1(spikes[1], spikes[0]), 0.0]], dtype=float) - rates = spikes.mean(axis=1) / dt - results["NetworkTutorial"] = { - "xc_max_abs_error": float(np.max(np.abs(xc - np.asarray(m["xc_net"], dtype=float)))), - "rates_max_abs_error": float(np.max(np.abs(rates - _vec(m, "rates_net")))), - "shape_mismatch_count": float( - np.count_nonzero(np.asarray(spikes.shape, dtype=float) - _vec(m, "shape_net")) - ), - } - - return results - - -def _build_report( - metrics_by_topic: dict[str, dict[str, float]], - thresholds_payload: dict, - fixtures_manifest: Path, - thresholds_file: Path, - required_topics: list[str], -) -> dict: - thresholds_by_topic = thresholds_payload.get("topics", {}) - default_thresholds = thresholds_payload.get("defaults", {}) - topics_out: dict[str, dict] = {} - - total_checked = 0 - total_failed = 0 - passed_topics = 0 - - for topic, metrics in sorted(metrics_by_topic.items()): - topic_thresholds = thresholds_by_topic.get(topic, {}) - metric_rows: dict[str, dict] = {} - failed: list[str] = [] - worst_ratio = 0.0 - checked = 0 - - for metric_name, value in sorted(metrics.items()): - threshold_value = topic_thresholds.get(metric_name, default_thresholds.get(metric_name)) - if threshold_value is None: - continue - threshold = float(threshold_value) - passed = value <= threshold - ratio = _ratio(float(value), threshold) - metric_rows[metric_name] = { - "value": float(value), - "threshold": threshold, - "pass": bool(passed), - "ratio_to_threshold": float(ratio), - } - checked += 1 - worst_ratio = max(worst_ratio, ratio if np.isfinite(ratio) else float("inf")) - if not passed: - failed.append(metric_name) - - topic_pass = len(failed) == 0 and checked > 0 - if topic_pass: - passed_topics += 1 - total_checked += checked - total_failed += len(failed) - - topics_out[topic] = { - "checked_metrics": checked, - "failed_metrics": failed, - "worst_ratio_to_threshold": float(worst_ratio), - "pass": topic_pass, - "metrics": metric_rows, - } - - missing_required_topics = sorted( - topic for topic in required_topics if topic not in topics_out or int(topics_out[topic]["checked_metrics"]) == 0 - ) - checked_required_topics = len(required_topics) - len(missing_required_topics) - - report = { - "schema_version": 1, - "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "fixtures_manifest": fixtures_manifest.as_posix(), - "thresholds_file": thresholds_file.as_posix(), - "summary": { - "topics": len(topics_out), - "passed_topics": passed_topics, - "failed_topics": len(topics_out) - passed_topics, - "checked_metrics": total_checked, - "failed_metrics": total_failed, - "required_topics": len(required_topics), - "required_topics_checked": checked_required_topics, - "required_topics_missing": missing_required_topics, - }, - "topics": topics_out, - } - return report - - -def main() -> int: - args = parse_args() - fixtures_manifest = args.fixtures_manifest.resolve() - thresholds_file = args.thresholds.resolve() - report_out = args.report_out.resolve() - equivalence_report = args.equivalence_report.resolve() - notebook_manifest = args.notebook_manifest.resolve() - - fixture_index = _fixture_manifest_index(fixtures_manifest) - numeric_fixture_paths = _numeric_fixture_paths(fixture_index) - metrics = _evaluate_metrics(numeric_fixture_paths) - topic_audit_fixtures = _topic_audit_fixtures(fixture_index) - equivalence_rows = _load_equivalence_rows(equivalence_report) - topic_audit_metrics = _evaluate_topic_audit_metrics(topic_audit_fixtures, equivalence_rows) - for topic, topic_metrics in topic_audit_metrics.items(): - merged = dict(metrics.get(topic, {})) - merged.update(topic_metrics) - metrics[topic] = merged - - required_topics = _load_required_topics(notebook_manifest) - thresholds_payload = yaml.safe_load(thresholds_file.read_text(encoding="utf-8")) or {} - report = _build_report(metrics, thresholds_payload, fixtures_manifest, thresholds_file, required_topics) - - report_out.parent.mkdir(parents=True, exist_ok=True) - report_out.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8") - - failed_topics = report["summary"]["failed_topics"] - failed_metrics = report["summary"]["failed_metrics"] - missing_required = report["summary"].get("required_topics_missing", []) - print(f"Wrote numeric drift report: {report_out}") - print(f"Topics: {report['summary']['topics']}") - print(f"Failed topics: {failed_topics}") - print(f"Failed metrics: {failed_metrics}") - print( - "Required topics coverage: " - f"{report['summary'].get('required_topics_checked', 0)}/{report['summary'].get('required_topics', 0)}" - ) - if missing_required: - print("Missing required topics:", ", ".join(missing_required)) - - if args.fail_on_violation and (failed_topics > 0 or failed_metrics > 0 or len(missing_required) > 0): - return 1 - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/build_parity_snapshot.py b/tools/parity/build_parity_snapshot.py deleted file mode 100755 index af2d8871..00000000 --- a/tools/parity/build_parity_snapshot.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -"""Build full parity snapshot (inventories + gap report).""" - -from __future__ import annotations - -import argparse -import subprocess -import sys -from pathlib import Path - - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[2]) - parser.add_argument("--matlab-root", type=Path, required=True) - parser.add_argument("--fail-on", choices=["none", "low", "medium", "high"], default="high") - return parser.parse_args() - - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - - inventory_cmd = [ - sys.executable, - str(repo_root / "tools" / "parity" / "generate_api_inventories.py"), - "--repo-root", - str(repo_root), - "--matlab-root", - str(args.matlab_root.resolve()), - ] - report_cmd = [ - sys.executable, - str(repo_root / "tools" / "parity" / "generate_gap_report.py"), - "--repo-root", - str(repo_root), - "--fail-on", - args.fail_on, - ] - probe_cmd = [ - sys.executable, - str(repo_root / "tools" / "parity" / "generate_method_probe_report.py"), - "--repo-root", - str(repo_root), - ] - audit_cmd = [ - sys.executable, - str(repo_root / "tools" / "parity" / "generate_equivalence_audit.py"), - "--repo-root", - str(repo_root), - "--matlab-root", - str(args.matlab_root.resolve()), - ] - - subprocess.run(inventory_cmd, check=True) - result = subprocess.run(report_cmd, check=False) - subprocess.run(probe_cmd, check=True) - subprocess.run(audit_cmd, check=True) - return int(result.returncode) - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/build_strict_line_gap_sprint.py b/tools/parity/build_strict_line_gap_sprint.py deleted file mode 100644 index e3fb3735..00000000 --- a/tools/parity/build_strict_line_gap_sprint.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python3 -"""Build a strict-line parity sprint backlog from equivalence audit output.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--report", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - help="Equivalence audit report JSON path.", - ) - parser.add_argument( - "--output", - type=Path, - default=Path("parity/strict_line_gap_sprint.md"), - help="Output markdown backlog path.", - ) - parser.add_argument( - "--top-n", - type=int, - default=20, - help="Number of strict line-gap topics to include.", - ) - return parser.parse_args() - - -def _f(value: float | int | None) -> str: - if value is None: - return "-" - return f"{float(value):.4f}" - - -def main() -> int: - args = parse_args() - payload = json.loads(args.report.read_text(encoding="utf-8")) - audit = payload.get("example_line_alignment_audit", {}) - summary = audit.get("summary", {}) - rows = list(audit.get("topic_rows", [])) - - gaps = [row for row in rows if row.get("strict_line_status") == "line_port_gap"] - gaps.sort( - key=lambda row: ( - float(row.get("line_port_coverage", 0.0)), - float(row.get("line_port_function_recall", 0.0)), - -float(row.get("matlab_code_lines", 0.0)), - ) - ) - selected = gaps[: max(0, args.top_n)] - - lines: list[str] = [] - lines.append("# Strict Line-Port Gap Sprint") - lines.append("") - lines.append(f"- Source report: `{args.report}`") - lines.append(f"- Total topics: `{summary.get('total_topics', 0)}`") - lines.append( - "- Strict summary: " - f"verified={summary.get('strict_line_verified_topics', 0)}, " - f"partial={summary.get('strict_line_partial_topics', 0)}, " - f"gap={summary.get('strict_line_gap_topics', len(gaps))}" - ) - lines.append("") - lines.append("## Priority Queue") - lines.append( - "| Priority | Topic | Coverage | Function recall | Code-line ratio (Py/MATLAB) | MATLAB lines | Python lines |" - ) - lines.append("|---:|---|---:|---:|---:|---:|---:|") - for i, row in enumerate(selected, start=1): - lines.append( - "| " - f"{i} | {row.get('topic', '-')}" - f" | {_f(row.get('line_port_coverage'))}" - f" | {_f(row.get('line_port_function_recall'))}" - f" | {_f(row.get('python_to_matlab_line_ratio'))}" - f" | {int(row.get('matlab_code_lines', 0))}" - f" | {int(row.get('python_code_lines', 0))} |" - ) - lines.append("") - lines.append("## Execution Checklist") - lines.append("- Export executable-line snapshots for each gap topic.") - lines.append("- Regenerate notebooks with snapshot anchors.") - lines.append("- Re-run `tools/parity/sync_parity_artifacts.py`.") - lines.append("- Target strict status: `line_port_partial` or `line_port_verified`.") - lines.append("") - - args.output.parent.mkdir(parents=True, exist_ok=True) - args.output.write_text("\n".join(lines) + "\n", encoding="utf-8") - print(f"Wrote strict-line sprint backlog: {args.output}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/check_example_output_spec.py b/tools/parity/check_example_output_spec.py deleted file mode 100644 index 82391ab8..00000000 --- a/tools/parity/check_example_output_spec.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env python3 -"""Validate notebook/example output readiness against a policy spec.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - -import yaml - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--report", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - help="Equivalence audit report path.", - ) - parser.add_argument( - "--spec", - type=Path, - default=Path("parity/example_output_spec.yml"), - help="Example output policy spec path.", - ) - return parser.parse_args() - - -def _topic_cfg(spec: dict, topic: str) -> dict: - merged = dict(spec.get("defaults", {})) - merged.update(spec.get("topics", {}).get(topic, {})) - return merged - - -def main() -> int: - args = parse_args() - report = json.loads(args.report.read_text(encoding="utf-8")) - spec = yaml.safe_load(args.spec.read_text(encoding="utf-8")) - rows = report["example_line_alignment_audit"]["topic_rows"] - out_of_scope_topics = set(spec.get("out_of_scope_topics", [])) - - failures: list[str] = [] - - for row in rows: - topic = str(row["topic"]) - cfg = _topic_cfg(spec, topic) - is_out_of_scope = topic in out_of_scope_topics - - if is_out_of_scope: - allowed = set(cfg.get("out_of_scope_allowed_alignment_statuses", [])) - if not allowed: - allowed = set(cfg.get("allowed_alignment_statuses", [])) - else: - allowed = set(cfg.get("allowed_alignment_statuses", [])) - - status = str(row["alignment_status"]) - if allowed and status not in allowed: - scope_label = "out-of-scope" if is_out_of_scope else "in-scope" - failures.append( - f"{topic}: {scope_label} alignment_status '{status}' not in allowed set {sorted(allowed)}" - ) - - min_code_lines = int(cfg.get("min_python_code_lines", 0)) - py_lines = int(row.get("python_code_lines", 0)) - if py_lines < min_code_lines: - failures.append(f"{topic}: python_code_lines={py_lines} below required {min_code_lines}") - - min_code_cells = int(cfg.get("min_python_code_cells", 0)) - py_cells = len(row.get("python_code_cells", [])) - if py_cells < min_code_cells: - failures.append(f"{topic}: python_code_cells={py_cells} below required {min_code_cells}") - - if bool(cfg.get("require_topic_checkpoint", False)): - has_checkpoint = bool(row.get("has_topic_checkpoint", False)) - if not has_checkpoint: - failures.append(f"{topic}: missing topic checkpoint cell marker") - - min_assertions = int(cfg.get("min_assertion_count", 0)) - if min_assertions > 0: - assertion_count = int(row.get("assertion_count", 0)) - if assertion_count < min_assertions: - failures.append( - f"{topic}: assertion_count={assertion_count} below required {min_assertions}" - ) - - if bool(cfg.get("require_plot_call", False)): - has_plot = bool(row.get("has_plot_call", False)) - if not has_plot: - failures.append(f"{topic}: no plotting call detected in notebook code") - - min_mat_refs = int(cfg.get("min_matlab_reference_images", 0)) - mat_refs = int(row.get("matlab_reference_image_count", 0)) - if mat_refs < min_mat_refs: - failures.append(f"{topic}: matlab_reference_image_count={mat_refs} below required {min_mat_refs}") - - if bool(cfg.get("enforce_validation_images", False)): - min_py_imgs = int(cfg.get("min_python_validation_images", 0)) - py_imgs = int(row.get("python_validation_image_count", 0)) - if py_imgs < min_py_imgs: - failures.append( - f"{topic}: python_validation_image_count={py_imgs} below required {min_py_imgs}" - ) - - if bool(cfg.get("require_line_port_audit", False)): - strict_status = str(row.get("strict_line_status", "")) - allowed_strict = set(cfg.get("allowed_strict_line_statuses", [])) - if allowed_strict and strict_status not in allowed_strict: - failures.append( - f"{topic}: strict_line_status '{strict_status}' not in allowed set {sorted(allowed_strict)}" - ) - - min_coverage = float(cfg.get("min_line_port_coverage", 0.0)) - coverage = float(row.get("line_port_coverage", 0.0)) - if coverage < min_coverage: - failures.append( - f"{topic}: line_port_coverage={coverage:.4f} below required {min_coverage:.4f}" - ) - - min_func_recall = float(cfg.get("min_line_port_function_recall", 0.0)) - func_recall = float(row.get("line_port_function_recall", 0.0)) - if func_recall < min_func_recall: - failures.append( - f"{topic}: line_port_function_recall={func_recall:.4f} below required {min_func_recall:.4f}" - ) - - if failures: - print("Example output spec check FAILED") - for item in failures: - print(f" - {item}") - return 1 - - print("Example output spec check passed.") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/check_functional_parity_progress.py b/tools/parity/check_functional_parity_progress.py deleted file mode 100644 index 8799787d..00000000 --- a/tools/parity/check_functional_parity_progress.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python3 -"""Enforce functional parity thresholds from equivalence audit output.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - -import yaml - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--report", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - help="Functional equivalence audit report JSON path.", - ) - parser.add_argument( - "--policy", - type=Path, - default=Path("parity/functional_gate_policy.yml"), - help="Functional gate policy YAML path.", - ) - return parser.parse_args() - - -def main() -> int: - args = parse_args() - report = json.loads(args.report.read_text(encoding="utf-8")) - policy = yaml.safe_load(args.policy.read_text(encoding="utf-8")) - - method_summary = report["method_functional_audit"]["summary"] - class_rows = {row["matlab_class"]: row for row in report["method_functional_audit"]["class_summary"]} - example_summary = report["example_line_alignment_audit"]["summary"] - - failures: list[str] = [] - - method_policy = policy.get("method_thresholds", {}) - min_verified_ratio_overall = float(method_policy.get("min_verified_ratio_overall", 0.0)) - ratio = float(method_summary.get("contract_verified_ratio", 0.0)) - if ratio < min_verified_ratio_overall: - failures.append( - f"overall verified ratio {ratio:.3f} below required {min_verified_ratio_overall:.3f}" - ) - - if "min_contract_explicit_verified_methods" in method_policy: - minimum = int(method_policy["min_contract_explicit_verified_methods"]) - observed = int(method_summary.get("contract_explicit_verified_methods", 0)) - if observed < minimum: - failures.append( - "contract explicit verified methods " - f"{observed} below required {minimum}" - ) - - if "max_probe_verified_methods" in method_policy: - maximum = int(method_policy["max_probe_verified_methods"]) - observed = int(method_summary.get("probe_verified_methods", 0)) - if observed > maximum: - failures.append( - f"probe verified methods {observed} exceeds allowed {maximum}" - ) - - if "max_unverified_behavior_methods" in method_policy: - maximum = int(method_policy["max_unverified_behavior_methods"]) - observed = int(method_summary.get("unverified_behavior_methods", 0)) - if observed > maximum: - failures.append( - f"unverified behavior methods {observed} exceeds allowed {maximum}" - ) - - min_eligible_ratio_overall = float(method_policy.get("min_eligible_verified_ratio_overall", 0.0)) - eligible_ratio = float(method_summary.get("eligible_verified_ratio", 0.0)) - if eligible_ratio < min_eligible_ratio_overall: - failures.append( - "overall eligible verified ratio " - f"{eligible_ratio:.3f} below required {min_eligible_ratio_overall:.3f}" - ) - - max_missing = int(method_policy.get("max_missing_symbol_methods", 0)) - missing = int(method_summary.get("missing_symbol_methods", 0)) - if missing > max_missing: - failures.append(f"missing symbol methods {missing} exceeds allowed {max_missing}") - - for klass, min_count in method_policy.get("class_min_verified_methods", {}).items(): - row = class_rows.get(klass) - if row is None: - failures.append(f"missing class in functional report: {klass}") - continue - verified = int(row.get("contract_verified_count", 0)) - if verified < int(min_count): - failures.append( - f"{klass}: verified method count {verified} below required {int(min_count)}" - ) - - for klass, min_ratio in method_policy.get("class_min_eligible_verified_ratio", {}).items(): - row = class_rows.get(klass) - if row is None: - failures.append(f"missing class in functional report: {klass}") - continue - ratio_val = float(row.get("eligible_verified_ratio", 0.0)) - if ratio_val < float(min_ratio): - failures.append( - f"{klass}: eligible verified ratio {ratio_val:.3f} below required {float(min_ratio):.3f}" - ) - - for klass, min_ratio in method_policy.get("class_min_contract_coverage_ratio", {}).items(): - row = class_rows.get(klass) - if row is None: - failures.append(f"missing class in functional report: {klass}") - continue - ratio_val = float(row.get("contract_coverage_ratio", 0.0)) - if ratio_val < float(min_ratio): - failures.append( - f"{klass}: contract coverage ratio {ratio_val:.3f} below required {float(min_ratio):.3f}" - ) - - for klass, max_count in method_policy.get("class_max_probe_verified_methods", {}).items(): - row = class_rows.get(klass) - if row is None: - failures.append(f"missing class in functional report: {klass}") - continue - observed = int(row.get("probe_verified_count", 0)) - maximum = int(max_count) - if observed > maximum: - failures.append( - f"{klass}: probe verified count {observed} exceeds allowed {maximum}" - ) - - example_policy = policy.get("example_thresholds", {}) - for key, policy_key in ( - ("missing_artifact_topics", "max_missing_artifact_topics"), - ("missing_executable_topics", "max_missing_executable_topics"), - ("pending_manual_review_topics", "max_pending_manual_review_topics"), - ): - if policy_key not in example_policy: - continue - observed = int(example_summary.get(key, 0)) - maximum = int(example_policy[policy_key]) - if observed > maximum: - failures.append(f"{key}={observed} exceeds allowed {maximum}") - - if "min_matlab_doc_only_topics" in example_policy: - observed = int(example_summary.get("matlab_doc_only_topics", 0)) - minimum = int(example_policy["min_matlab_doc_only_topics"]) - if observed < minimum: - failures.append(f"matlab_doc_only_topics={observed} below required {minimum}") - - if "max_matlab_doc_only_topics" in example_policy: - observed = int(example_summary.get("matlab_doc_only_topics", 0)) - maximum = int(example_policy["max_matlab_doc_only_topics"]) - if observed > maximum: - failures.append(f"matlab_doc_only_topics={observed} exceeds allowed {maximum}") - - if failures: - print("Functional parity gate FAILED") - for item in failures: - print(f" - {item}") - return 1 - - print("Functional parity gate passed.") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/check_tier1_progress.py b/tools/parity/check_tier1_progress.py deleted file mode 100755 index 4912e47d..00000000 --- a/tools/parity/check_tier1_progress.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -"""Enforce Tier-1 parity progress thresholds from a policy file.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - -import yaml - - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--report", - type=Path, - default=Path("parity/parity_gap_report.json"), - help="Parity gap report JSON path.", - ) - parser.add_argument( - "--policy", - type=Path, - default=Path("parity/tier1_gate_policy.yml"), - help="Tier-1 gate policy YAML path.", - ) - return parser.parse_args() - - - -def main() -> int: - args = parse_args() - report = json.loads(args.report.read_text(encoding="utf-8")) - policy = yaml.safe_load(args.policy.read_text(encoding="utf-8")) - - rows = {row["matlab_class"]: row for row in report["class_coverage"]} - - failures: list[str] = [] - - for klass, min_ratio in policy.get("min_coverage_ratio", {}).items(): - if klass not in rows: - failures.append(f"missing class in report: {klass}") - continue - ratio = float(rows[klass]["coverage_ratio"]) - if ratio < float(min_ratio): - failures.append( - f"{klass}: coverage_ratio {ratio:.3f} below required {float(min_ratio):.3f}" - ) - - for klass, max_missing in policy.get("max_missing_methods", {}).items(): - if klass not in rows: - failures.append(f"missing class in report: {klass}") - continue - missing = int(rows[klass]["missing_method_count"]) - if missing > int(max_missing): - failures.append( - f"{klass}: missing_method_count {missing} exceeds allowed {int(max_missing)}" - ) - - if failures: - print("Tier-1 parity gate FAILED") - for item in failures: - print(f" - {item}") - return 1 - - print("Tier-1 parity gate passed.") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/checkout_matlab_reference.py b/tools/parity/checkout_matlab_reference.py deleted file mode 100755 index 8708edfe..00000000 --- a/tools/parity/checkout_matlab_reference.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python3 -"""Checkout pinned MATLAB nSTAT reference repo at an immutable commit.""" - -from __future__ import annotations - -import argparse -import json -import os -import shutil -import subprocess -from pathlib import Path - -import yaml - - -def _run(cmd: list[str], cwd: Path | None = None) -> str: - env = os.environ.copy() - env.setdefault("GIT_LFS_SKIP_SMUDGE", "1") - proc = subprocess.run( - cmd, - cwd=str(cwd) if cwd else None, - env=env, - text=True, - capture_output=True, - check=True, - ) - return proc.stdout.strip() - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--config", - type=Path, - default=Path("parity/matlab_reference.yml"), - help="Pinned MATLAB reference config YAML.", - ) - parser.add_argument( - "--dest", - type=Path, - default=Path("/tmp/upstream-nstat"), - help="Destination directory for checked-out MATLAB repo.", - ) - parser.add_argument( - "--metadata-out", - type=Path, - default=Path("parity/matlab_reference_checkout.json"), - help="Optional JSON metadata output path.", - ) - args = parser.parse_args() - - cfg = yaml.safe_load(args.config.read_text(encoding="utf-8")) or {} - repo_url = str(cfg.get("repo_url", "")).strip() - ref = str(cfg.get("ref", "")).strip() - if not repo_url or not ref: - raise ValueError("Config must define non-empty repo_url and ref") - - dest = args.dest.resolve() - if dest.exists(): - shutil.rmtree(dest) - _run(["git", "clone", "--depth", "1", "--no-tags", repo_url, str(dest)]) - _run(["git", "fetch", "--depth", "1", "origin", ref], cwd=dest) - _run(["git", "checkout", "--detach", "--force", "FETCH_HEAD"], cwd=dest) - sha = _run(["git", "rev-parse", "HEAD"], cwd=dest) - - if sha.lower() != ref.lower(): - raise RuntimeError( - f"Pinned checkout mismatch: expected {ref}, resolved {sha}. " - "Reference is not immutable." - ) - - metadata = { - "repo_url": repo_url, - "requested_ref": ref, - "resolved_sha": sha, - "dest": str(dest), - } - args.metadata_out.parent.mkdir(parents=True, exist_ok=True) - args.metadata_out.write_text(json.dumps(metadata, indent=2), encoding="utf-8") - - print(f"Checked out MATLAB reference at {sha} -> {dest}") - print(f"Wrote metadata: {args.metadata_out}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/export_line_port_snapshots.py b/tools/parity/export_line_port_snapshots.py deleted file mode 100644 index e1b36b18..00000000 --- a/tools/parity/export_line_port_snapshots.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python3 -"""Export MATLAB executable-line snapshots for notebook strict line-port anchors.""" - -from __future__ import annotations - -import argparse -from pathlib import Path - - -DEFAULT_TOPICS = ( - "nSTATPaperExamples", - "HippocampalPlaceCellExample", - "publish_all_helpfiles", -) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--repo-root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="nSTAT-python repository root.", - ) - parser.add_argument( - "--matlab-root", - type=Path, - required=True, - help="MATLAB nSTAT repository root containing helpfiles/*.m.", - ) - parser.add_argument( - "--topics", - nargs="+", - default=list(DEFAULT_TOPICS), - help="MATLAB help topics to export.", - ) - return parser.parse_args() - - -def _extract_exec_lines(path: Path) -> list[str]: - out: list[str] = [] - for raw in path.read_text(encoding="utf-8", errors="ignore").splitlines(): - stripped = raw.strip() - if not stripped or stripped.startswith("%"): - continue - out.append(stripped) - return out - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - matlab_root = args.matlab_root.resolve() - help_root = matlab_root / "helpfiles" - out_root = repo_root / "parity" / "line_port_snapshots" - out_root.mkdir(parents=True, exist_ok=True) - - for topic in args.topics: - src = help_root / f"{topic}.m" - if not src.exists(): - raise FileNotFoundError(f"Missing MATLAB helpfile for topic '{topic}': {src}") - lines = _extract_exec_lines(src) - out_path = out_root / f"{topic}.txt" - out_path.write_text("\n".join(lines) + ("\n" if lines else ""), encoding="utf-8") - print(f"Wrote {out_path} ({len(lines)} executable lines)") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/export_matlab_gold_fixtures.py b/tools/parity/export_matlab_gold_fixtures.py deleted file mode 100755 index 7736b99b..00000000 --- a/tools/parity/export_matlab_gold_fixtures.py +++ /dev/null @@ -1,995 +0,0 @@ -#!/usr/bin/env python3 -"""Export MATLAB-gold fixtures for parity workflows and topic audit coverage. - -This script runs MATLAB in batch mode to generate deterministic fixture files -for parity-critical workflow families and representative examples, including: -- PPSimExample -- DecodingExample / DecodingExampleWithHist -- HippocampalPlaceCellExample -- SpikeRateDiffCIs / PSTHEstimation -- nstCollExamples / TrialExamples / CovCollExamples / EventsExamples -- AnalysisExamples -- ExplicitStimulusWhiskerData -- mEPSCAnalysis - -In addition to numeric `.mat` fixtures, this exporter also emits per-topic -audit JSON fixtures for notebook topics not covered by numeric fixtures so -that numeric drift gating remains fixture-backed across all examples. -""" - -from __future__ import annotations - -import argparse -import hashlib -import json -import subprocess -import tempfile -from pathlib import Path - -import yaml - - -MATLAB_SCRIPT_TEMPLATE = r""" -rng(2026,'twister'); - -out_dir = '{out_dir}'; -if exist(out_dir, 'dir') ~= 7 - mkdir(out_dir); -end - -% ------------------------------ -% Fixture 1: PPSimExample (GLM) -% ------------------------------ -n = 2500; -dt = 0.01; -X = randn(n,1); -true_intercept = log(10.0); -true_beta = 0.45; -lambda = exp(true_intercept + X*true_beta); -y = poissrnd(lambda*dt); - -offset = log(dt) * ones(n,1); -b = glmfit(X, y, 'poisson', 'constant', 'on', 'offset', offset); -expected_rate = exp(b(1) + X*b(2)); - -save(fullfile(out_dir, 'PPSimExample_gold.mat'), ... - 'X', 'y', 'dt', 'true_intercept', 'true_beta', 'b', 'expected_rate', '-v7'); - -% ------------------------------------------ -% Fixture 2: DecodingExampleWithHist (Bayes) -% ------------------------------------------ -n_units = 12; -n_states = 18; -n_time = 180; -centers = linspace(0, n_states-1, n_units)'; -widths = 2.0 * ones(n_units,1); -states = 0:(n_states-1); -tuning = zeros(n_units, n_states); -for i=1:n_units - tuning(i,:) = 0.05 + 0.35*exp(-0.5*((states-centers(i))./widths(i)).^2); -end - -transition = zeros(n_states, n_states); -for i=1:n_states - if i>1 - transition(i,i-1) = 0.2; - end - transition(i,i) = 0.6; - if i 0.35) + 0.01*sin(2*pi*2*t); -base_p = min(max(base_p, 0.001), 0.75); - -spike_matrix_psth = zeros(n_trials_psth, n_bins_psth); -for k=1:n_trials_psth - scale = 0.65 + 0.04*k; - p = min(max(base_p * scale, 0.001), 0.85); - spike_matrix_psth(k,:) = binornd(1, p); -end - -counts_psth = sum(spike_matrix_psth, 2); -expected_rate_psth = counts_psth / n_bins_psth; -expected_prob_psth = ones(n_trials_psth, n_trials_psth); -upper_idx = zeros(n_trials_psth*(n_trials_psth-1)/2, 2); -upper_p = zeros(n_trials_psth*(n_trials_psth-1)/2, 1); -idx = 1; -for i=1:n_trials_psth - for j=i+1:n_trials_psth - p1 = expected_rate_psth(i); - p2 = expected_rate_psth(j); - pooled = (counts_psth(i) + counts_psth(j)) / (2.0 * n_bins_psth); - se = sqrt(max(pooled * (1.0 - pooled) * (2.0 / n_bins_psth), 0.0)); - if se <= 0.0 - if abs(p1-p2) <= 1e-12 - pval = 1.0; - else - pval = 0.0; - end - else - zstat = (p1 - p2) / se; - pval = 2.0 * (1.0 - normcdf(abs(zstat), 0, 1)); - end - expected_prob_psth(i,j) = pval; - expected_prob_psth(j,i) = pval; - upper_idx(idx,:) = [i j]; - upper_p(idx) = pval; - idx = idx + 1; - end -end - -expected_sig_psth = zeros(n_trials_psth, n_trials_psth); -[sorted_p, order] = sort(upper_p, 'ascend'); -m = numel(sorted_p); -thresholds = alpha_psth * ((1:m)' / m); -pass = find(sorted_p <= thresholds); -if ~isempty(pass) - cutoff = sorted_p(max(pass)); - selected = upper_p <= cutoff; - for q=1:numel(selected) - if selected(q) - i = upper_idx(q,1); - j = upper_idx(q,2); - expected_sig_psth(i,j) = 1; - expected_sig_psth(j,i) = 1; - end - end -end -expected_prob_psth(1:n_trials_psth+1:end) = 1.0; -expected_sig_psth(1:n_trials_psth+1:end) = 0.0; - -save(fullfile(out_dir, 'PSTHEstimation_gold.mat'), ... - 'spike_matrix_psth', 'alpha_psth', ... - 'expected_rate_psth', 'expected_prob_psth', 'expected_sig_psth', '-v7'); - -% --------------------------------------------------------- -% Fixture 6: nstCollExamples (binned/count collection ops) -% --------------------------------------------------------- -spike_times_1 = [0.02 0.08 0.30 0.45 0.75]'; -spike_times_2 = [0.01 0.10 0.40 0.41 0.95]'; -t_start_coll = 0.0; -t_end_coll = 1.0; -bin_size_coll = 0.1; -edges_coll = t_start_coll:bin_size_coll:t_end_coll; - -c1 = histcounts(spike_times_1, edges_coll); -c2 = histcounts(spike_times_2, edges_coll); -expected_count_matrix = [c1; c2]; -expected_binary_matrix = double(expected_count_matrix > 0); -expected_centers = (edges_coll(1:end-1) + edges_coll(2:end))/2; -expected_first_spike = min([spike_times_1; spike_times_2]); -expected_last_spike = max([spike_times_1; spike_times_2]); -expected_merged_spikes = sort([spike_times_1; spike_times_2]); - -save(fullfile(out_dir, 'nstCollExamples_gold.mat'), ... - 'spike_times_1', 'spike_times_2', 't_start_coll', 't_end_coll', 'bin_size_coll', ... - 'expected_count_matrix', 'expected_binary_matrix', 'expected_centers', ... - 'expected_first_spike', 'expected_last_spike', 'expected_merged_spikes', '-v7'); - -% ------------------------------------------------------ -% Fixture 7: CovCollExamples (design matrix + selectors) -% ------------------------------------------------------ -time_cov = (0:0.01:1.0)'; -cov_stim = sin(2*pi*1.0*time_cov); -cov_ctx = [cos(2*pi*1.0*time_cov), time_cov]; -expected_design_cov = [cov_stim, cov_ctx]; -expected_ctx_only = cov_ctx; -expected_stim_only = cov_stim; - -save(fullfile(out_dir, 'CovCollExamples_gold.mat'), ... - 'time_cov', 'cov_stim', 'cov_ctx', 'expected_design_cov', ... - 'expected_ctx_only', 'expected_stim_only', '-v7'); - -% -------------------------------------------------------------- -% Fixture 8: TrialExamples (aligned binned observations + X map) -% -------------------------------------------------------------- -spike_times_trial = [0.02 0.08 0.13 0.21 0.32 0.55 0.72 0.91]'; -bin_size_trial = 0.05; -edges_trial = t_start_coll:bin_size_trial:t_end_coll; -expected_t_bins_trial = (edges_trial(1:end-1) + edges_trial(2:end))/2; -expected_y_trial = histcounts(spike_times_trial, edges_trial)'; - -idx_trial = zeros(numel(expected_t_bins_trial), 1); -for k=1:numel(expected_t_bins_trial) - idx = find(time_cov >= expected_t_bins_trial(k), 1, 'first'); - if isempty(idx) - idx = numel(time_cov); - end - idx_trial(k) = idx; -end -expected_X_trial = expected_design_cov(idx_trial, :); - -save(fullfile(out_dir, 'TrialExamples_gold.mat'), ... - 'time_cov', 'cov_stim', 'cov_ctx', 'spike_times_trial', 'bin_size_trial', ... - 'expected_t_bins_trial', 'expected_y_trial', 'expected_X_trial', '-v7'); - -% ---------------------------------------------- -% Fixture 9: EventsExamples (subset extraction) -% ---------------------------------------------- -event_times = [0.079 0.579 0.997]'; -subset_start = 0.1; -subset_end = 0.7; -mask = event_times >= subset_start & event_times <= subset_end; -expected_subset_times = event_times(mask); - -save(fullfile(out_dir, 'EventsExamples_gold.mat'), ... - 'event_times', 'subset_start', 'subset_end', 'expected_subset_times', '-v7'); - -% ------------------------------------------------------ -% Fixture 10: AnalysisExamples (spatial Poisson GLM fit) -% ------------------------------------------------------ -n_t_analysis = 1800; -dt_analysis = 0.01; -xy = zeros(n_t_analysis, 2); -xy(1,:) = [45 55]; -vel = [0 0]; -for t=2:n_t_analysis - vel = 0.92 * vel + 2.0 * randn(1,2); - xy(t,:) = min(max(xy(t-1,:) + vel, 0.0), 100.0); -end - -xc = 62.0; yc = 38.0; sigma = 16.0; -r2 = (xy(:,1)-xc).^2 + (xy(:,2)-yc).^2; -true_rate_analysis = 1.2 + 18.0 * exp(-0.5 * r2 / (sigma^2)); -counts_analysis = poissrnd(true_rate_analysis * dt_analysis); -X_analysis = [xy(:,1), xy(:,2)]; -offset_analysis = log(dt_analysis) * ones(n_t_analysis,1); -b_analysis = glmfit(X_analysis, counts_analysis, 'poisson', 'constant', 'on', 'offset', offset_analysis); -expected_rate_analysis = exp(b_analysis(1) + X_analysis * b_analysis(2:end)); -expected_rmse_analysis = sqrt(mean((expected_rate_analysis - true_rate_analysis).^2)); - -save(fullfile(out_dir, 'AnalysisExamples_gold.mat'), ... - 'X_analysis', 'counts_analysis', 'dt_analysis', 'b_analysis', ... - 'true_rate_analysis', 'expected_rate_analysis', 'expected_rmse_analysis', '-v7'); - -% ---------------------------------------------------- -% Fixture 11: DecodingExample (no-history Bayes decode) -% ---------------------------------------------------- -n_units_dec = 10; -n_states_dec = 15; -n_time_dec = 150; -centers_dec = linspace(0, n_states_dec-1, n_units_dec)'; -widths_dec = 2.0 * ones(n_units_dec,1); -states_dec = 0:(n_states_dec-1); -tuning_dec = zeros(n_units_dec, n_states_dec); -for i=1:n_units_dec - tuning_dec(i,:) = 0.06 + 0.42*exp(-0.5*((states_dec-centers_dec(i))./widths_dec(i)).^2); -end - -transition_dec = zeros(n_states_dec, n_states_dec); -for i=1:n_states_dec - if i>1 - transition_dec(i,i-1) = 0.2; - end - transition_dec(i,i) = 0.6; - if i= refractory_mepsc - w_end = min(idx + round(0.004 / dt_mepsc), n_mepsc); - [~, local_rel] = min(trace_mepsc(idx:w_end)); - local_idx = idx + local_rel - 1; - detected_idx = [detected_idx; local_idx]; %#ok - last_idx = local_idx; - end -end - -detected_times_mepsc = (detected_idx - 1) * dt_mepsc; -detected_amps_mepsc = -trace_mepsc(detected_idx); -expected_event_count_mepsc = numel(detected_idx); -expected_mean_amp_mepsc = mean(detected_amps_mepsc); - -save(fullfile(out_dir, 'mEPSCAnalysis_gold.mat'), ... - 'dt_mepsc', 'time_mepsc', 'trace_mepsc', 'event_times_mepsc', ... - 'detected_times_mepsc', 'detected_amps_mepsc', ... - 'expected_event_count_mepsc', 'expected_mean_amp_mepsc', '-v7'); - -% --------------------------------------------------------- -% Fixture 14: HybridFilterExample (state and filter outputs) -% --------------------------------------------------------- -n_t_hf = 500; -dt_hf = 0.02; -time_hf = (0:n_t_hf-1)' * dt_hf; -A_hf = [1.0, 0.0, dt_hf, 0.0; 0.0, 1.0, 0.0, dt_hf; 0.0, 0.0, 0.98, 0.0; 0.0, 0.0, 0.0, 0.98]; -H_hf = [1.0, 0.0, 0.0, 0.0; 0.0, 1.0, 0.0, 0.0]; -Q_hf = diag([1e-4, 1e-4, 1.5e-3, 1.5e-3]); -R_hf = diag([0.12^2, 0.12^2]); -pij_hf = [0.998, 0.002; 0.001, 0.999]; - -state_hf = ones(n_t_hf, 1); -for k=2:n_t_hf - stay_p = pij_hf(state_hf(k-1), state_hf(k-1)); - if rand() < stay_p - state_hf(k) = state_hf(k-1); - else - state_hf(k) = 3 - state_hf(k-1); - end -end - -x_true_hf = zeros(n_t_hf, 4); -x_true_hf(1,:) = [0.0, 0.0, 0.8, 0.35]; -for k=2:n_t_hf - if state_hf(k) == 1 - proc = mvnrnd(zeros(1,4), 0.15 * Q_hf, 1); - x_true_hf(k,:) = x_true_hf(k-1,:) + proc; - else - proc = mvnrnd(zeros(1,4), Q_hf, 1); - x_true_hf(k,:) = (A_hf * x_true_hf(k-1,:)')' + proc; - end -end - -z_hf = (H_hf * x_true_hf')' + mvnrnd([0.0, 0.0], R_hf, n_t_hf); -x_hat_hf = zeros(n_t_hf, 4); -x_hat_nt_hf = zeros(n_t_hf, 4); -P_hf = eye(4); -P_nt_hf = eye(4); -for k=2:n_t_hf - if state_hf(k) == 1 - A_k = eye(4); - Q_k = 0.15 * Q_hf; - else - A_k = A_hf; - Q_k = Q_hf; - end - - x_pred = (A_k * x_hat_hf(k-1,:)')'; - P_pred = A_k * P_hf * A_k' + Q_k; - S = H_hf * P_pred * H_hf' + R_hf; - K = P_pred * H_hf' / S; - x_hat_hf(k,:) = x_pred + (K * (z_hf(k,:)' - H_hf * x_pred'))'; - P_hf = (eye(4) - K * H_hf) * P_pred; - - x_pred_nt = (A_hf * x_hat_nt_hf(k-1,:)')'; - P_pred_nt = A_hf * P_nt_hf * A_hf' + Q_hf; - S_nt = H_hf * P_pred_nt * H_hf' + R_hf; - K_nt = P_pred_nt * H_hf' / S_nt; - x_hat_nt_hf(k,:) = x_pred_nt + (K_nt * (z_hf(k,:)' - H_hf * x_pred_nt'))'; - P_nt_hf = (eye(4) - K_nt * H_hf) * P_pred_nt; -end - -err_hf = sqrt(sum((x_hat_hf(:,1:2) - x_true_hf(:,1:2)).^2, 2)); -err_nt_hf = sqrt(sum((x_hat_nt_hf(:,1:2) - x_true_hf(:,1:2)).^2, 2)); -rmse_hf = sqrt(mean(err_hf.^2)); -rmse_nt_hf = sqrt(mean(err_nt_hf.^2)); - -save(fullfile(out_dir, 'HybridFilterExample_gold.mat'), ... - 'dt_hf', 'time_hf', 'state_hf', 'x_true_hf', 'z_hf', ... - 'x_hat_hf', 'x_hat_nt_hf', 'rmse_hf', 'rmse_nt_hf', '-v7'); - -% ---------------------------------------------------- -% Fixture 15: ValidationDataSet (trial PSTH statistics) -% ---------------------------------------------------- -dt_val = 0.001; -time_val = (0:dt_val:1.2-dt_val)'; -n_trials_val = 30; -rate_val = 5.0 + 8.0 * (time_val > 0.35) + 4.0 * sin(2.0*pi*2.0*time_val); -rate_val = max(rate_val, 0.2); -trial_matrix_val = zeros(n_trials_val, numel(time_val)); -for k=1:n_trials_val - jitter = 0.6 + 0.8 * rand(); - p = min(max(rate_val * jitter * dt_val, 0.0), 0.6); - trial_matrix_val(k,:) = binornd(1, p)'; -end -psth_val = mean(trial_matrix_val, 1)' / dt_val; -sem_val = std(trial_matrix_val, 0, 1)' / sqrt(n_trials_val) / dt_val; - -expected_rate_val = sum(trial_matrix_val, 2) / numel(time_val); -expected_prob_val = ones(n_trials_val, n_trials_val); -upper_idx_val = zeros(n_trials_val*(n_trials_val-1)/2, 2); -upper_p_val = zeros(n_trials_val*(n_trials_val-1)/2, 1); -idx_val = 1; -for i=1:n_trials_val - for j=i+1:n_trials_val - p1 = expected_rate_val(i); - p2 = expected_rate_val(j); - pooled = (sum(trial_matrix_val(i,:)) + sum(trial_matrix_val(j,:))) / (2.0 * numel(time_val)); - se = sqrt(max(pooled * (1.0 - pooled) * (2.0 / numel(time_val)), 0.0)); - if se <= 0.0 - if abs(p1-p2) <= 1e-12 - pval = 1.0; - else - pval = 0.0; - end - else - zstat = (p1 - p2) / se; - pval = 2.0 * (1.0 - normcdf(abs(zstat), 0, 1)); - end - expected_prob_val(i,j) = pval; - expected_prob_val(j,i) = pval; - upper_idx_val(idx_val,:) = [i j]; - upper_p_val(idx_val) = pval; - idx_val = idx_val + 1; - end -end - -expected_sig_val = zeros(n_trials_val, n_trials_val); -[sorted_p_val, order_val] = sort(upper_p_val, 'ascend'); -m_val = numel(sorted_p_val); -thresholds_val = 0.05 * ((1:m_val)' / m_val); -pass_val = find(sorted_p_val <= thresholds_val); -if ~isempty(pass_val) - cutoff_val = sorted_p_val(max(pass_val)); - selected_val = upper_p_val <= cutoff_val; - for q=1:numel(selected_val) - if selected_val(q) - i = upper_idx_val(q,1); - j = upper_idx_val(q,2); - expected_sig_val(i,j) = 1; - expected_sig_val(j,i) = 1; - end - end -end -expected_prob_val(1:n_trials_val+1:end) = 1.0; -expected_sig_val(1:n_trials_val+1:end) = 0.0; - -save(fullfile(out_dir, 'ValidationDataSet_gold.mat'), ... - 'dt_val', 'time_val', 'trial_matrix_val', 'psth_val', 'sem_val', ... - 'expected_rate_val', 'expected_prob_val', 'expected_sig_val', '-v7'); - -% ----------------------------------------------------- -% Fixture 16: StimulusDecode2D (trajectory decode arrays) -% ----------------------------------------------------- -side_sd = 14; -grid_sd = linspace(0.0, 1.0, side_sd); -[gx_sd, gy_sd] = meshgrid(grid_sd, grid_sd); -states_sd = [gx_sd(:), gy_sd(:)]; -n_states_sd = size(states_sd, 1); -n_units_sd = 24; -n_time_sd = 280; -traj_sd = zeros(n_time_sd, 2); -traj_sd(1,:) = [0.5, 0.5]; -vel_sd = [0.0, 0.0]; -for t=2:n_time_sd - vel_sd = 0.82 * vel_sd + 0.12 * randn(1,2); - traj_sd(t,:) = min(max(traj_sd(t-1,:) + vel_sd, 0.0), 1.0); -end - -state_match_sd = zeros(n_time_sd, n_states_sd); -for t=1:n_time_sd - delta_sd = states_sd - traj_sd(t,:); - state_match_sd(t,:) = sum(delta_sd.^2, 2)'; -end -[~, latent_idx_sd] = min(state_match_sd, [], 2); -latent_sd = latent_idx_sd - 1; % zero-based for Python - -centers_sd = rand(n_units_sd, 2); -sigma_sd = 0.16; -tuning_sd = zeros(n_units_sd, n_states_sd); -for i=1:n_units_sd - dist2_sd = sum((states_sd - centers_sd(i,:)).^2, 2); - tuning_sd(i,:) = 0.03 + 0.80 * exp(-0.5 * dist2_sd' / (sigma_sd^2)); -end - -spike_counts_sd = zeros(n_units_sd, n_time_sd); -for t=1:n_time_sd - spike_counts_sd(:,t) = poissrnd(tuning_sd(:, latent_idx_sd(t))); -end - -decoded_center_sd = zeros(n_time_sd, 1); -state_axis_sd = (0:n_states_sd-1)'; -for t=1:n_time_sd - weights_sd = spike_counts_sd(:,t) .* tuning_sd; - post_sd = sum(weights_sd, 1)'; - post_sd = post_sd / (sum(post_sd) + 1e-12); - decoded_center_sd(t) = sum(post_sd .* state_axis_sd); -end -decoded_sd = round(decoded_center_sd); -decoded_sd = max(min(decoded_sd, n_states_sd-1), 0); -xy_true_sd = states_sd(latent_idx_sd, :); -xy_decoded_sd = states_sd(decoded_sd + 1, :); -rmse_sd = sqrt(mean(sum((xy_decoded_sd - xy_true_sd).^2, 2))); - -save(fullfile(out_dir, 'StimulusDecode2D_gold.mat'), ... - 'side_sd', 'states_sd', 'latent_sd', 'tuning_sd', 'spike_counts_sd', ... - 'decoded_center_sd', 'decoded_sd', 'xy_true_sd', 'xy_decoded_sd', 'rmse_sd', '-v7'); - -% ----------------------------------------------------- -% Fixture 17: SignalObjExamples (deterministic signals) -% ----------------------------------------------------- -sampleRate_sig = 100.0; -time_sig = (0:1/sampleRate_sig:10.0)'; -freq_sig = 2.0; -v1_sig = sin(2*pi*freq_sig*time_sig); -v2_sig = sin(v1_sig.^2); -resample_hz_sig = 10.0; -t_resampled_sig = (time_sig(1):1/resample_hz_sig:time_sig(end))'; -v1_resampled_sig = interp1(time_sig, v1_sig, t_resampled_sig, 'linear'); -window_t0_sig = -2.0; -window_t1_sig = 3.0; -window_mask_sig = time_sig >= window_t0_sig & time_sig <= window_t1_sig; -window_n_samples_sig = sum(window_mask_sig); -n_samples_sig = numel(time_sig); -resampled_n_samples_sig = numel(t_resampled_sig); -masked_cols_sig = 1.0; - -nfft_sig = 2^nextpow2(numel(v1_sig)); -Y_sig = fft(v1_sig, nfft_sig); -P2_sig = abs(Y_sig / nfft_sig).^2; -P1_sig = P2_sig(1:floor(nfft_sig/2) + 1); -[~, peak_idx_sig] = max(P1_sig); -periodogram_peak_idx_sig = peak_idx_sig - 1; % zero-based for Python parity checks - -save(fullfile(out_dir, 'SignalObjExamples_gold.mat'), ... - 'sampleRate_sig', 'time_sig', 'v1_sig', 'v2_sig', 'resample_hz_sig', ... - 'v1_resampled_sig', 'window_t0_sig', 'window_t1_sig', 'window_n_samples_sig', ... - 'n_samples_sig', 'resampled_n_samples_sig', 'masked_cols_sig', 'periodogram_peak_idx_sig', '-v7'); - -% ------------------------------------------------------ -% Fixture 18: HistoryExamples (history-basis design matrix) -% ------------------------------------------------------ -bin_edges_hist = [0.0; 0.01; 0.03; 0.06]; -spike_times_hist = [0.005; 0.021; 0.044; 0.076; 0.088]; -time_grid_hist = (0.0:0.002:0.1)'; -n_bins_hist = numel(bin_edges_hist) - 1; -H_expected_hist = zeros(numel(time_grid_hist), n_bins_hist); -for i=1:numel(time_grid_hist) - lags = time_grid_hist(i) - spike_times_hist; - for j=1:n_bins_hist - lo = bin_edges_hist(j); - hi = bin_edges_hist(j+1); - H_expected_hist(i,j) = sum((lags > lo) & (lags <= hi)); - end -end -filter_expected_hist = diff(bin_edges_hist); -filter_expected_hist = filter_expected_hist / sum(filter_expected_hist); -save(fullfile(out_dir, 'HistoryExamples_gold.mat'), ... - 'bin_edges_hist', 'spike_times_hist', 'time_grid_hist', ... - 'H_expected_hist', 'filter_expected_hist', 'n_bins_hist', '-v7'); - -% --------------------------------------------------------- -% Fixture 19: PPThinning (candidate/acceptance deterministic) -% --------------------------------------------------------- -delta_pt = 0.001; -tmax_pt = 20.0; -time_pt = (0.0:delta_pt:tmax_pt)'; -f_pt = 0.1; -lambda_pt = 10.0 * sin(2.0*pi*f_pt*time_pt) + 10.0; -lambda_bound_pt = max(lambda_pt); -N_pt = ceil(lambda_bound_pt * (1.5 * tmax_pt)); -u_pt = rand(N_pt,1); -w_pt = -log(max(u_pt, 1e-12)) / lambda_bound_pt; -candidate_spikes_pt = cumsum(w_pt); -candidate_spikes_pt = candidate_spikes_pt(candidate_spikes_pt <= tmax_pt); -idx_pt = round(candidate_spikes_pt / delta_pt) + 1; -idx_pt = max(min(idx_pt, numel(time_pt)), 1); -lambda_ratio_pt = lambda_pt(idx_pt) / lambda_bound_pt; -uniform_u2_pt = rand(numel(lambda_ratio_pt),1); -accepted_spikes_pt = candidate_spikes_pt(lambda_ratio_pt >= uniform_u2_pt); -accept_ratio_pt = numel(accepted_spikes_pt) / max(numel(candidate_spikes_pt), 1); -save(fullfile(out_dir, 'PPThinning_gold.mat'), ... - 'delta_pt', 'tmax_pt', 'time_pt', 'lambda_pt', ... - 'candidate_spikes_pt', 'lambda_ratio_pt', 'uniform_u2_pt', ... - 'accepted_spikes_pt', 'accept_ratio_pt', '-v7'); - -% -------------------------------------------------------------- -% Fixture 20: NetworkTutorial (two-neuron influence summaries) -% -------------------------------------------------------------- -T_net = 8.0; -dt_net = 0.002; -n_t_net = floor(T_net / dt_net); -time_net = ((0:n_t_net-1)' * dt_net); -stim_net = sin(2.0*pi*0.8*time_net); -baseline_net = [-3.9; -4.1]; -W_stim_net = [1.1; -0.9]; -W_net = [0.0 0.9; -1.2 0.0]; -spikes_net = zeros(2, n_t_net); -for t=2:n_t_net - drive_net = baseline_net + W_stim_net * stim_net(t) + W_net * spikes_net(:,t-1); - p_net = min(max(exp(drive_net), 1e-8), 0.7); - spikes_net(:,t) = binornd(1, p_net); -end - -a12 = spikes_net(1,1:end-1) - mean(spikes_net(1,1:end-1)); -b12 = spikes_net(2,2:end) - mean(spikes_net(2,2:end)); -d12 = norm(a12) * norm(b12); -if d12 > 0 - lag12 = sum(a12 .* b12) / d12; -else - lag12 = 0.0; -end -a21 = spikes_net(2,1:end-1) - mean(spikes_net(2,1:end-1)); -b21 = spikes_net(1,2:end) - mean(spikes_net(1,2:end)); -d21 = norm(a21) * norm(b21); -if d21 > 0 - lag21 = sum(a21 .* b21) / d21; -else - lag21 = 0.0; -end -xc_net = [0.0 lag12; lag21 0.0]; -rates_net = mean(spikes_net, 2) / dt_net; -shape_net = size(spikes_net); -save(fullfile(out_dir, 'NetworkTutorial_gold.mat'), ... - 'dt_net', 'time_net', 'stim_net', 'spikes_net', 'xc_net', 'rates_net', 'shape_net', '-v7'); - -fprintf('MATLAB gold fixtures exported to %s\n', out_dir); -""" - - -NUMERIC_FIXTURE_FILES = [ - "PPSimExample_gold.mat", - "DecodingExampleWithHist_gold.mat", - "HippocampalPlaceCellExample_gold.mat", - "SpikeRateDiffCIs_gold.mat", - "PSTHEstimation_gold.mat", - "nstCollExamples_gold.mat", - "TrialExamples_gold.mat", - "CovCollExamples_gold.mat", - "EventsExamples_gold.mat", - "AnalysisExamples_gold.mat", - "DecodingExample_gold.mat", - "ExplicitStimulusWhiskerData_gold.mat", - "mEPSCAnalysis_gold.mat", - "HybridFilterExample_gold.mat", - "ValidationDataSet_gold.mat", - "StimulusDecode2D_gold.mat", - "SignalObjExamples_gold.mat", - "HistoryExamples_gold.mat", - "PPThinning_gold.mat", - "NetworkTutorial_gold.mat", -] - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--output-dir", - type=Path, - default=Path("tests/parity/fixtures/matlab_gold"), - help="Directory for exported MATLAB fixtures", - ) - parser.add_argument( - "--manifest", - type=Path, - default=Path("tests/parity/fixtures/matlab_gold/manifest.yml"), - help="Output manifest path", - ) - parser.add_argument( - "--notebook-manifest", - type=Path, - default=Path("tools/notebooks/notebook_manifest.yml"), - help="Notebook manifest used to define required topic coverage", - ) - parser.add_argument( - "--equivalence-report", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - help="Equivalence audit JSON used to export topic-audit fixtures", - ) - parser.add_argument( - "--skip-matlab-export", - action="store_true", - help="Skip MATLAB batch execution and only rebuild manifest/topic-audit fixtures.", - ) - return parser.parse_args() - - -def _sha256(path: Path) -> str: - digest = hashlib.sha256() - with path.open("rb") as f: - for chunk in iter(lambda: f.read(8192), b""): - digest.update(chunk) - return digest.hexdigest() - - -def _load_required_topics(notebook_manifest: Path) -> list[str]: - payload = yaml.safe_load(notebook_manifest.read_text(encoding="utf-8")) or {} - topics: list[str] = [] - for row in payload.get("notebooks", []): - topic = str(row.get("topic", "")).strip() - if topic: - topics.append(topic) - return topics - - -def _load_equivalence_rows(equivalence_report: Path) -> dict[str, dict]: - payload = json.loads(equivalence_report.read_text(encoding="utf-8")) - rows = payload.get("example_line_alignment_audit", {}).get("topic_rows", []) - out: dict[str, dict] = {} - for row in rows: - topic = str(row.get("topic", "")).strip() - if topic: - out[topic] = row - return out - - -def main() -> int: - args = parse_args() - repo_root = Path(__file__).resolve().parents[2] - out_dir = args.output_dir.resolve() - out_dir.mkdir(parents=True, exist_ok=True) - notebook_manifest = args.notebook_manifest.resolve() - equivalence_report = args.equivalence_report.resolve() - - if not args.skip_matlab_export: - script_content = MATLAB_SCRIPT_TEMPLATE.format(out_dir=str(out_dir).replace("'", "''")) - - with tempfile.NamedTemporaryFile(mode="w", suffix=".m", delete=False, encoding="utf-8") as tmp: - tmp.write(script_content) - tmp_path = Path(tmp.name) - - try: - escaped_tmp = str(tmp_path).replace("'", "''") - cmd = ["matlab", "-batch", f"run('{escaped_tmp}')"] - proc = subprocess.run(cmd, capture_output=True, text=True) - if proc.returncode != 0: - print(proc.stdout) - print(proc.stderr) - raise RuntimeError("MATLAB fixture export failed") - finally: - try: - tmp_path.unlink(missing_ok=True) - except Exception: - pass - - fixtures = [] - for file_name in NUMERIC_FIXTURE_FILES: - path = out_dir / file_name - if not path.exists(): - raise FileNotFoundError(f"expected fixture missing: {path}") - fixtures.append( - { - "name": file_name.replace("_gold.mat", ""), - "path": str(path.relative_to(repo_root).as_posix()), - "sha256": _sha256(path), - "source": "matlab_batch_export", - "fixture_type": "numeric", - } - ) - - required_topics = _load_required_topics(notebook_manifest) - topic_rows = _load_equivalence_rows(equivalence_report) - covered_numeric_topics = {row["name"] for row in fixtures} - audit_topics = sorted(topic for topic in required_topics if topic not in covered_numeric_topics) - for topic in audit_topics: - row = topic_rows.get(topic) - if row is None: - raise KeyError(f"topic {topic!r} missing from equivalence report: {equivalence_report}") - audit_payload = { - "schema_version": 1, - "topic": topic, - "alignment_status": str(row.get("alignment_status", "")), - "matlab_code_lines": int(row.get("matlab_code_lines", 0)), - "matlab_reference_image_count": int(row.get("matlab_reference_image_count", 0)), - "min_assertion_count": int(row.get("assertion_count", 0)), - "require_topic_checkpoint": bool(row.get("has_topic_checkpoint", False)), - "min_python_validation_image_count": int(row.get("python_validation_image_count", 0)), - "require_plot_call": bool(row.get("has_plot_call", False)), - "source": "equivalence_audit_report", - "equivalence_report": str(equivalence_report.relative_to(repo_root).as_posix()), - } - audit_path = out_dir / f"{topic}_audit_gold.json" - audit_path.write_text(json.dumps(audit_payload, indent=2) + "\n", encoding="utf-8") - fixtures.append( - { - "name": topic, - "path": str(audit_path.relative_to(repo_root).as_posix()), - "sha256": _sha256(audit_path), - "source": "equivalence_audit_export", - "fixture_type": "topic_audit", - } - ) - - manifest = { - "version": 1, - "fixtures": fixtures, - } - args.manifest.parent.mkdir(parents=True, exist_ok=True) - args.manifest.write_text(yaml.safe_dump(manifest, sort_keys=False), encoding="utf-8") - print(f"Wrote manifest: {args.manifest}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/generate_api_inventories.py b/tools/parity/generate_api_inventories.py deleted file mode 100755 index 4807aa6a..00000000 --- a/tools/parity/generate_api_inventories.py +++ /dev/null @@ -1,207 +0,0 @@ -#!/usr/bin/env python3 -"""Generate MATLAB and Python API inventories used for parity analysis.""" - -from __future__ import annotations - -import argparse -import importlib -import inspect -import json -import re -import sys -from datetime import datetime, timezone -from pathlib import Path -from typing import Any - -import yaml - - -FUNCTION_RE = re.compile( - r"^\s*function\b(?:\s+\[[^\]]*\]\s*=|\s+[^=\n\r]+\s*=)?\s*([A-Za-z]\w*)\s*\(", - flags=re.IGNORECASE, -) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--method-mapping", - type=Path, - default=Path("parity/method_mapping.yaml"), - help="Method mapping YAML", - ) - parser.add_argument( - "--repo-root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="nSTAT-python repository root", - ) - parser.add_argument( - "--matlab-root", - type=Path, - default=Path(""), - help="MATLAB nSTAT repository root (required)", - ) - parser.add_argument( - "--matlab-out", - type=Path, - default=Path("parity/matlab_api_inventory.json"), - help="Output path for MATLAB API inventory", - ) - parser.add_argument( - "--python-out", - type=Path, - default=Path("parity/python_api_inventory.json"), - help="Output path for Python API inventory", - ) - return parser.parse_args() - - -def _public_python_members(obj: Any) -> dict[str, list[str]]: - methods: list[str] = [] - properties: list[str] = [] - fields: list[str] = [] - - for name, member in inspect.getmembers(obj): - if name.startswith("_"): - continue - static_member = inspect.getattr_static(obj, name) - if isinstance(static_member, property): - properties.append(name) - continue - if inspect.isroutine(member): - methods.append(name) - - dataclass_fields = getattr(obj, "__dataclass_fields__", {}) - fields.extend(sorted(name for name in dataclass_fields if not name.startswith("_"))) - - return { - "methods": sorted(set(methods)), - "properties": sorted(set(properties)), - "fields": sorted(set(fields)), - } - - -def _parse_matlab_methods(matlab_file: Path) -> list[str]: - if not matlab_file.exists(): - return [] - names: list[str] = [] - for line in matlab_file.read_text(encoding="utf-8", errors="ignore").splitlines(): - match = FUNCTION_RE.match(line) - if match: - names.append(match.group(1)) - deduped: list[str] = [] - for name in names: - if name not in deduped: - deduped.append(name) - return deduped - - -def _resolve_module_head(repo_root: Path) -> str: - src_root = repo_root / "src" - if str(src_root) not in sys.path: - sys.path.insert(0, str(src_root)) - return str(src_root) - - -def _load_mapping(mapping_path: Path) -> list[dict[str, Any]]: - payload = yaml.safe_load(mapping_path.read_text(encoding="utf-8")) - return payload["classes"] - - -def build_matlab_inventory(classes: list[dict[str, Any]], matlab_root: Path) -> dict[str, Any]: - records: list[dict[str, Any]] = [] - for row in classes: - matlab_class = str(row["matlab_class"]) - matlab_file = matlab_root / str(row.get("matlab_file", f"{matlab_class}.m")) - methods = _parse_matlab_methods(matlab_file) - records.append( - { - "matlab_class": matlab_class, - "matlab_file": str(matlab_file), - "method_count": len(methods), - "methods": methods, - } - ) - - return { - "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "matlab_root": str(matlab_root), - "classes": records, - } - - -def build_python_inventory(classes: list[dict[str, Any]], repo_root: Path) -> dict[str, Any]: - _resolve_module_head(repo_root) - - records: list[dict[str, Any]] = [] - for row in classes: - python_class = str(row["python_class"]) - compat_class = str(row["compat_class"]) - - p_module, p_attr = python_class.rsplit(".", 1) - py_obj = getattr(importlib.import_module(p_module), p_attr) - py_members = _public_python_members(py_obj) - - c_module, c_attr = compat_class.rsplit(".", 1) - compat_obj = getattr(importlib.import_module(c_module), c_attr) - compat_members = _public_python_members(compat_obj) - - records.append( - { - "matlab_class": str(row["matlab_class"]), - "python_class": python_class, - "compat_class": compat_class, - "python": { - "method_count": len(py_members["methods"]), - "methods": py_members["methods"], - "properties": py_members["properties"], - "fields": py_members["fields"], - }, - "compat": { - "method_count": len(compat_members["methods"]), - "methods": compat_members["methods"], - "properties": compat_members["properties"], - "fields": compat_members["fields"], - }, - } - ) - - return { - "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "python_root": str(repo_root), - "classes": records, - } - - -def _write_json(path: Path, payload: dict[str, Any]) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8") - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - mapping = args.method_mapping.resolve() - - matlab_root = args.matlab_root.resolve() if str(args.matlab_root) else Path() - if not str(matlab_root) or not matlab_root.exists(): - raise FileNotFoundError( - "--matlab-root is required and must point to the MATLAB nSTAT repository" - ) - - classes = _load_mapping(mapping) - - matlab_inventory = build_matlab_inventory(classes=classes, matlab_root=matlab_root) - python_inventory = build_python_inventory(classes=classes, repo_root=repo_root) - - _write_json((repo_root / args.matlab_out).resolve(), matlab_inventory) - _write_json((repo_root / args.python_out).resolve(), python_inventory) - - print(f"Wrote MATLAB inventory to {(repo_root / args.matlab_out).resolve()}") - print(f"Wrote Python inventory to {(repo_root / args.python_out).resolve()}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/generate_backlog.py b/tools/parity/generate_backlog.py deleted file mode 100755 index 7951be7b..00000000 --- a/tools/parity/generate_backlog.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python3 -"""Generate Tier-1 parity backlog markdown from parity gap report.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - - -TIER1_CLASSES = [ - "DecodingAlgorithms", - "Analysis", - "Trial", - "CovColl", - "nstColl", - "FitResult", - "FitResSummary", -] - - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--report", - type=Path, - default=Path("parity/parity_gap_report.json"), - help="Parity gap report JSON path.", - ) - parser.add_argument( - "--output", - type=Path, - default=Path("parity/TIER1_PORT_BACKLOG.md"), - help="Output markdown backlog path.", - ) - return parser.parse_args() - - - -def _priority(missing_count: int) -> str: - if missing_count >= 50: - return "P0" - if missing_count >= 25: - return "P1" - return "P2" - - - -def main() -> int: - args = parse_args() - report = json.loads(args.report.read_text(encoding="utf-8")) - - coverage_rows = {row["matlab_class"]: row for row in report["class_coverage"]} - issues_rows = { - issue["details"].get("matlab_class"): issue - for issue in report["issues"] - if issue.get("check") == "missing_method_mappings" - } - - lines: list[str] = [] - lines.append("# Tier-1 Port Backlog") - lines.append("") - lines.append("Generated from `parity/parity_gap_report.json`.") - lines.append("") - lines.append("| Priority | MATLAB Class | Missing Methods | Coverage | Next Implementation Focus |") - lines.append("|---|---:|---:|---:|---|") - - for klass in TIER1_CLASSES: - cov = coverage_rows.get(klass, {}) - missing = int(cov.get("missing_method_count", 0)) - ratio = float(cov.get("coverage_ratio", 0.0)) - issue = issues_rows.get(klass, {}) - method_preview = issue.get("details", {}).get("missing_methods", [])[:6] - preview = ", ".join(method_preview) if method_preview else "n/a" - lines.append( - f"| {_priority(missing)} | `{klass}` | {missing} | {ratio:.3f} | {preview} |" - ) - - lines.append("") - lines.append("## Implementation Order") - lines.append("1. `DecodingAlgorithms` and `Analysis` (numerical behavior parity)") - lines.append("2. `Trial` / `CovColl` / `nstColl` (data plumbing parity)") - lines.append("3. `FitResult` / `FitResSummary` (model diagnostics parity)") - lines.append("") - lines.append("## Acceptance for Each Tier-1 Class") - lines.append("- Implement method aliases in `nstat.compat.matlab`.") - lines.append("- Add numerical fixture checks when outputs are deterministic.") - lines.append("- Add unit tests for method signatures and key behavior.") - - args.output.parent.mkdir(parents=True, exist_ok=True) - args.output.write_text("\n".join(lines) + "\n", encoding="utf-8") - print(f"Wrote backlog: {args.output}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/generate_class_equivalence_inventory.py b/tools/parity/generate_class_equivalence_inventory.py deleted file mode 100644 index bc6002de..00000000 --- a/tools/parity/generate_class_equivalence_inventory.py +++ /dev/null @@ -1,492 +0,0 @@ -#!/usr/bin/env python3 -"""Generate class-level MATLAB/Python equivalence inventory and summary report.""" - -from __future__ import annotations - -import argparse -import importlib -import inspect -import json -import re -import sys -from collections import defaultdict -from datetime import datetime, timezone -from pathlib import Path -from typing import Any - -import yaml - - -CLASSDEF_RE = re.compile(r"^\s*classdef\s+([A-Za-z]\w*)(?:\s*<\s*([^\n%]+))?", flags=re.IGNORECASE) -METHODS_BLOCK_RE = re.compile(r"^\s*methods(?:\s*\(([^)]*)\))?\s*$", flags=re.IGNORECASE) -PROPERTIES_BLOCK_RE = re.compile(r"^\s*properties(?:\s*\(([^)]*)\))?\s*$", flags=re.IGNORECASE) -FUNCTION_RE = re.compile( - r"^\s*function\b(?:\s+\[[^\]]*\]\s*=|\s+[^=\n\r]+\s*=)?\s*([A-Za-z]\w*)\s*(?:\(([^)]*)\))?", - flags=re.IGNORECASE, -) -PROPERTY_RE = re.compile(r"^\s*([A-Za-z]\w*)") -ACCESS_RE = re.compile(r"access\s*=\s*([A-Za-z]+)", flags=re.IGNORECASE) - - -REQUIRED_CLASSES = [ - "SignalObj", - "Covariate", - "ConfidenceInterval", - "Events", - "History", - "nspikeTrain", - "nstColl", - "CovColl", - "TrialConfig", - "ConfigColl", - "Trial", - "CIF", - "Analysis", - "FitResult", - "FitResSummary", - "DecodingAlgorithms", -] - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[2]) - parser.add_argument("--matlab-root", type=Path, required=True) - parser.add_argument("--method-mapping", type=Path, default=Path("parity/method_mapping.yaml")) - parser.add_argument("--method-exclusions", type=Path, default=Path("parity/method_exclusions.yml")) - parser.add_argument("--class-contracts", type=Path, default=Path("parity/class_contracts.yml")) - parser.add_argument("--fixture-spec", type=Path, default=Path("parity/class_fixture_export_spec.yml")) - parser.add_argument( - "--behavior-contracts", - type=Path, - action="append", - default=[Path("tests/parity/class_behavior_specs.yml"), Path("tests/parity/compat_behavior_specs.yml")], - ) - parser.add_argument("--out-inventory", type=Path, default=Path("parity/class_equivalence_inventory.json")) - parser.add_argument("--out-report", type=Path, default=Path("parity/class_equivalence_report.json")) - return parser.parse_args() - - -def _load_yaml(path: Path) -> dict[str, Any]: - return yaml.safe_load(path.read_text(encoding="utf-8")) - - -def _signature_text(callable_obj: Any) -> str: - try: - return str(inspect.signature(callable_obj)) - except (TypeError, ValueError): - return "(unavailable)" - - -def _public_python_surface(obj: Any) -> dict[str, Any]: - methods: dict[str, str] = {} - properties: list[str] = [] - fields: list[str] = [] - - for name, member in inspect.getmembers(obj): - if name.startswith("_"): - continue - raw = inspect.getattr_static(obj, name) - if isinstance(raw, property): - properties.append(name) - continue - if inspect.isroutine(member): - methods[name] = _signature_text(member) - - dataclass_fields = getattr(obj, "__dataclass_fields__", {}) - for name in sorted(dataclass_fields): - if not name.startswith("_"): - fields.append(name) - - init_sig = "(unavailable)" - if hasattr(obj, "__init__"): - init_sig = _signature_text(obj.__init__) - - return { - "constructor_signature": init_sig, - "methods": dict(sorted(methods.items())), - "properties": sorted(set(properties)), - "fields": sorted(set(fields)), - } - - -def _parse_attrs(attrs: str | None) -> tuple[str, bool]: - if not attrs: - return "public", False - access_match = ACCESS_RE.search(attrs) - access = access_match.group(1).lower() if access_match else "public" - is_static = "static" in attrs.lower() - return access, is_static - - -def _parse_matlab_class(path: Path) -> dict[str, Any]: - text = path.read_text(encoding="utf-8", errors="ignore") - lines = text.splitlines() - - class_name = path.stem - superclass = "" - class_match = None - for line in lines: - class_match = CLASSDEF_RE.match(line) - if class_match: - class_name = class_match.group(1) - superclass = (class_match.group(2) or "").strip() - break - - properties: list[dict[str, Any]] = [] - methods: list[dict[str, Any]] = [] - - in_properties = False - current_prop_access = "public" - current_methods_access = "public" - current_methods_static = False - in_methods = False - - for idx, raw in enumerate(lines, start=1): - line = raw.rstrip() - stripped = line.strip() - if not stripped or stripped.startswith("%"): - continue - - pm = PROPERTIES_BLOCK_RE.match(line) - if pm: - in_properties = True - in_methods = False - current_prop_access, _ = _parse_attrs(pm.group(1)) - continue - - mm = METHODS_BLOCK_RE.match(line) - if mm: - in_methods = True - in_properties = False - current_methods_access, current_methods_static = _parse_attrs(mm.group(1)) - continue - - if stripped == "end": - if in_properties: - in_properties = False - # Keep method block mode sticky across nested function `end`. - continue - - if in_properties: - prop_match = PROPERTY_RE.match(line) - if prop_match: - prop_name = prop_match.group(1) - if prop_name.lower() not in {"properties", "methods", "classdef", "end"}: - properties.append( - { - "name": prop_name, - "access": current_prop_access, - "line": idx, - } - ) - continue - - func_match = FUNCTION_RE.match(line) - if func_match and in_methods: - name = func_match.group(1) - args_raw = (func_match.group(2) or "").strip() - args = [a.strip() for a in args_raw.split(",") if a.strip()] if args_raw else [] - methods.append( - { - "name": name, - "args": args, - "line": idx, - "access": current_methods_access, - "static": current_methods_static, - } - ) - - constructor = next((m for m in methods if m["name"] == class_name), None) - public_methods = [m["name"] for m in methods if m["access"] not in {"private"}] - private_methods = [m["name"] for m in methods if m["access"] == "private"] - - return { - "matlab_class": class_name, - "matlab_file": str(path), - "superclass": superclass, - "constructor": constructor or {"name": class_name, "args": [], "line": None, "access": "public", "static": False}, - "properties": properties, - "methods": methods, - "public_methods": sorted(dict.fromkeys(public_methods)), - "private_methods": sorted(dict.fromkeys(private_methods)), - } - - -def _contract_members(paths: list[Path]) -> dict[str, set[str]]: - out: dict[str, set[str]] = defaultdict(set) - for path in paths: - if not path.exists(): - continue - payload = _load_yaml(path) - for cls in payload.get("classes", []): - name = str(cls["matlab_class"]) - for contract in cls.get("contracts", []): - out[name].add(str(contract["member"])) - return out - - -def _fixture_lookup(fixture_spec: dict[str, Any]) -> dict[str, dict[str, str]]: - out: dict[str, dict[str, str]] = {} - for row in fixture_spec.get("classes", []): - out[str(row["matlab_class"])] = { - "fixture_path": str(row["fixture_path"]), - "generator": str(row["generator"]), - } - return out - - -def _excluded_methods(path: Path) -> dict[str, set[str]]: - if not path.exists(): - return {} - payload = _load_yaml(path) - out: dict[str, set[str]] = {} - for row in payload.get("classes", []): - cls = str(row.get("matlab_class", "")) - if not cls: - continue - out[cls] = {str(method) for method in row.get("methods", [])} - return out - - -def _load_python_class(path: str) -> Any: - module, attr = path.rsplit(".", 1) - return getattr(importlib.import_module(module), attr) - - -def build_inventory(args: argparse.Namespace) -> tuple[dict[str, Any], dict[str, Any]]: - repo_root = args.repo_root.resolve() - matlab_root = args.matlab_root.resolve() - mapping = _load_yaml((repo_root / args.method_mapping).resolve()) - class_contracts = _load_yaml((repo_root / args.class_contracts).resolve()) - fixture_spec = _load_yaml((repo_root / args.fixture_spec).resolve()) - exclusions = _excluded_methods((repo_root / args.method_exclusions).resolve()) - behavior_contracts = _contract_members([(repo_root / p).resolve() for p in args.behavior_contracts]) - - src_root = repo_root / "src" - if str(src_root) not in sys.path: - sys.path.insert(0, str(src_root)) - - matlab_files = sorted(matlab_root.glob("*.m")) - matlab_classes = {} - for f in matlab_files: - text = f.read_text(encoding="utf-8", errors="ignore") - if CLASSDEF_RE.search(text): - entry = _parse_matlab_class(f) - matlab_classes[entry["matlab_class"]] = entry - - mapping_rows = {str(row["matlab_class"]): row for row in mapping.get("classes", [])} - contract_rows = {str(row["matlab_class"]): row for row in class_contracts.get("classes", [])} - fixture_rows = _fixture_lookup(fixture_spec) - - class_rows: list[dict[str, Any]] = [] - missing_classes: list[str] = [] - missing_mappings: list[str] = [] - missing_fixtures: list[str] = [] - missing_method_symbols: dict[str, list[str]] = {} - - for matlab_class in sorted(matlab_classes): - matlab_meta = matlab_classes[matlab_class] - map_row = mapping_rows.get(matlab_class) - contract_row = contract_rows.get(matlab_class) - fixture_row = fixture_rows.get(matlab_class) - - if map_row is None: - missing_mappings.append(matlab_class) - class_rows.append( - { - "matlab_class": matlab_class, - "status": "gap_missing_mapping", - "matlab": matlab_meta, - } - ) - continue - - python_class_path = str(map_row["python_class"]) - compat_class_path = str(map_row["compat_class"]) - alias_methods = {str(k): str(v) for k, v in map_row.get("alias_methods", {}).items()} - - py_cls = _load_python_class(python_class_path) - compat_cls = _load_python_class(compat_class_path) - py_surface = _public_python_surface(py_cls) - compat_surface = _public_python_surface(compat_cls) - - py_members = set(py_surface["methods"]).union(py_surface["properties"]).union(py_surface["fields"]) - compat_members = set(compat_surface["methods"]).union(compat_surface["properties"]).union(compat_surface["fields"]) - - method_rows: list[dict[str, Any]] = [] - missing_for_class: list[str] = [] - for matlab_method in matlab_meta["public_methods"]: - mapped = alias_methods.get(matlab_method, matlab_method) - in_python = mapped in py_members - in_compat = mapped in compat_members - symbol_ok = in_python or in_compat - is_excluded = matlab_method in exclusions.get(matlab_class, set()) - if (not symbol_ok) and (not is_excluded): - missing_for_class.append(matlab_method) - method_rows.append( - { - "matlab_method": matlab_method, - "mapped_member": mapped, - "mapped_via_alias": matlab_method in alias_methods, - "present_in_python_surface": in_python, - "present_in_compat_surface": in_compat, - "excluded_method": is_excluded, - "covered_by_behavior_contract": mapped in behavior_contracts.get(matlab_class, set()), - "covered_by_class_contract": mapped in set(contract_row.get("key_methods", [])) if contract_row else False, - } - ) - - if missing_for_class: - missing_method_symbols[matlab_class] = missing_for_class - - fixture_path = "" - fixture_exists = False - fixture_generator = "" - if fixture_row: - fixture_path = fixture_row["fixture_path"] - fixture_generator = fixture_row["generator"] - fixture_exists = (repo_root / fixture_path).exists() - if not fixture_exists: - missing_fixtures.append(matlab_class) - else: - missing_fixtures.append(matlab_class) - - constructor_contract = {} - if contract_row is not None: - constructor_contract = { - "python_class": str(contract_row.get("python_class", "")), - "compat_class": str(contract_row.get("compat_class", "")), - "fixture_path": str(contract_row.get("fixture_path", "")), - "key_methods": list(contract_row.get("key_methods", [])), - } - - status = "verified" - if missing_for_class: - status = "partial_missing_method_symbols" - if not fixture_exists: - status = "partial_missing_fixture" - - class_rows.append( - { - "matlab_class": matlab_class, - "status": status, - "matlab": matlab_meta, - "mapping": { - "python_class": python_class_path, - "compat_class": compat_class_path, - "alias_methods": alias_methods, - }, - "python": py_surface, - "compat": compat_surface, - "fixture": { - "path": fixture_path, - "exists": fixture_exists, - "generator": fixture_generator, - }, - "class_contract": constructor_contract, - "method_rows": method_rows, - } - ) - - for required in REQUIRED_CLASSES: - if required not in matlab_classes: - missing_classes.append(required) - - inventory = { - "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "matlab_root": str(matlab_root), - "python_root": str(repo_root), - "required_classes": REQUIRED_CLASSES, - "class_rows": class_rows, - "summary": { - "total_matlab_classes": len(matlab_classes), - "required_classes_missing_from_matlab_scan": sorted(missing_classes), - "classes_missing_mapping": sorted(missing_mappings), - "classes_missing_fixtures": sorted(missing_fixtures), - "classes_with_missing_method_symbols": sorted(missing_method_symbols.keys()), - }, - } - - verified = [row for row in class_rows if row["status"] == "verified"] - partial = [row for row in class_rows if row["status"].startswith("partial_")] - gaps = [row for row in class_rows if row["status"].startswith("gap_")] - - top_methods = {} - for row in class_rows: - cls = row["matlab_class"] - key_methods = row.get("class_contract", {}).get("key_methods", []) or [] - if key_methods: - top_methods[cls] = key_methods[:10] - else: - top_methods[cls] = [m["matlab_method"] for m in row["method_rows"][:10]] - - remaining_issues: list[dict[str, Any]] = [] - for cls in sorted(missing_method_symbols): - remaining_issues.append( - { - "matlab_class": cls, - "issue": "missing_method_symbol", - "missing_methods": sorted(missing_method_symbols[cls]), - } - ) - for cls in sorted(missing_fixtures): - remaining_issues.append( - { - "matlab_class": cls, - "issue": "missing_fixture", - "repro": f"python tools/parity/export_matlab_gold_fixtures.py --matlab-root {matlab_root}", - } - ) - for cls in sorted(missing_mappings): - remaining_issues.append( - { - "matlab_class": cls, - "issue": "missing_mapping", - "repro": "Update parity/method_mapping.yaml with python_class/compat_class mapping.", - } - ) - - report = { - "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "summary": { - "verified_classes": len(verified), - "partial_classes": len(partial), - "gap_classes": len(gaps), - "total_classes": len(class_rows), - "required_class_coverage_ok": len(missing_classes) == 0, - }, - "top_critical_methods_tested": top_methods, - "remaining_issues": remaining_issues, - } - return inventory, report - - -def _write_json(path: Path, payload: dict[str, Any]) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8") - - -def main() -> int: - args = parse_args() - inventory, report = build_inventory(args) - - repo_root = args.repo_root.resolve() - out_inventory = (repo_root / args.out_inventory).resolve() - out_report = (repo_root / args.out_report).resolve() - _write_json(out_inventory, inventory) - _write_json(out_report, report) - - print(f"Wrote class inventory: {out_inventory}") - print(f"Wrote class report: {out_report}") - print( - "Summary: " - f"{report['summary']['verified_classes']} verified, " - f"{report['summary']['partial_classes']} partial, " - f"{report['summary']['gap_classes']} gaps" - ) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/generate_equivalence_audit.py b/tools/parity/generate_equivalence_audit.py deleted file mode 100644 index b150740f..00000000 --- a/tools/parity/generate_equivalence_audit.py +++ /dev/null @@ -1,880 +0,0 @@ -#!/usr/bin/env python3 -"""Generate method-level and example-level equivalence audit artifacts.""" - -from __future__ import annotations - -import argparse -import ast -import json -import re -from dataclasses import dataclass -from pathlib import Path -from typing import Any - -import yaml - -try: - import nbformat -except ModuleNotFoundError: # pragma: no cover - exercised in minimal CI envs - nbformat = None - - -IMG_SRC_RE = re.compile(r']+src="([^"]+)"', flags=re.IGNORECASE) -IDENT_RE = re.compile(r"[a-z_][a-z0-9_]*") -CALL_RE = re.compile(r"\b([a-z_][a-z0-9_]*)\s*\(") -MATLAB_LINE_CALL_RE = re.compile(r"^matlab_line\((.+)\)\s*$") - - -@dataclass(slots=True) -class MatlabCodeStats: - total_code_lines: int - blocks: list[dict[str, Any]] - - -@dataclass(slots=True) -class NotebookCodeStats: - total_code_lines: int - cells: list[dict[str, Any]] - - -@dataclass(slots=True) -class NotebookValidationStats: - has_topic_checkpoint: bool - assertion_count: int - has_plot_call: bool - - -@dataclass(slots=True) -class LinePortStats: - matlab_line_count: int - python_line_count: int - matched_line_count: int - line_port_coverage: float - line_port_function_recall: float - matlab_function_count: int - python_function_count: int - common_function_count: int - - -NOTEBOOK_LINE_PORT_IGNORE_PREFIXES = ( - "TOPIC =", - "FAMILY =", - "rng = np.random.default_rng", - "print(f\"Running notebook topic:", - "def validate_numeric_checkpoints(", - "validate_numeric_checkpoints(", - "print(\"Topic-specific checkpoint", - "print(\"Notebook checkpoints passed", -) - -NOTEBOOK_LINE_PORT_IGNORE_PATTERNS = ( - "CHECKPOINT_METRICS", - "CHECKPOINT_LIMITS", -) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[2]) - parser.add_argument("--matlab-root", type=Path, required=True) - parser.add_argument("--method-mapping", type=Path, default=Path("parity/method_mapping.yaml")) - parser.add_argument("--example-mapping", type=Path, default=Path("parity/example_mapping.yaml")) - parser.add_argument("--matlab-inventory", type=Path, default=Path("parity/matlab_api_inventory.json")) - parser.add_argument("--python-inventory", type=Path, default=Path("parity/python_api_inventory.json")) - parser.add_argument( - "--method-exclusions", - type=Path, - default=Path("parity/method_exclusions.yml"), - help="Optional YAML file listing MATLAB methods intentionally excluded (e.g., documented stubs).", - ) - parser.add_argument( - "--probe-report", - type=Path, - default=Path("parity/method_probe_report.json"), - help="Optional method probe JSON report used to mark additional methods as functionally verified.", - ) - parser.add_argument( - "--class-contracts", - type=Path, - action="append", - default=[ - Path("tests/parity/class_behavior_specs.yml"), - Path("tests/parity/compat_behavior_specs.yml"), - ], - help="YAML behavior contract specs to include for functional coverage.", - ) - parser.add_argument( - "--validation-image-root", - type=Path, - default=Path("tmp/pdfs/validation_report/notebook_images"), - help="Root directory containing extracted notebook figure images by topic", - ) - parser.add_argument( - "--fallback-validation-image-root", - type=Path, - default=Path("baseline/validation/notebook_images"), - help="Fallback root directory for tracked validation images when tmp outputs are absent.", - ) - parser.add_argument( - "--out", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - help="Output report path", - ) - return parser.parse_args() - - -def _load_json(path: Path) -> dict[str, Any]: - return json.loads(path.read_text(encoding="utf-8")) - - -def _load_yaml(path: Path) -> dict[str, Any]: - return yaml.safe_load(path.read_text(encoding="utf-8")) - - -def _matlab_methods_by_class(inventory: dict[str, Any]) -> dict[str, list[str]]: - return {str(row["matlab_class"]): list(row["methods"]) for row in inventory["classes"]} - - -def _python_surfaces_by_class(inventory: dict[str, Any]) -> dict[str, dict[str, set[str]]]: - out: dict[str, dict[str, set[str]]] = {} - for row in inventory["classes"]: - cls = str(row["matlab_class"]) - py_surface = set(row["python"]["methods"]) | set(row["python"]["properties"]) | set( - row["python"]["fields"] - ) - compat_surface = set(row["compat"]["methods"]) | set(row["compat"]["properties"]) | set( - row["compat"]["fields"] - ) - out[cls] = {"python": py_surface, "compat": compat_surface} - return out - - -def _contract_members_by_class(specs: list[dict[str, Any]]) -> dict[str, set[str]]: - out: dict[str, set[str]] = {} - for spec in specs: - for row in spec.get("classes", []): - cls = str(row["matlab_class"]) - members = {str(contract["member"]) for contract in row.get("contracts", [])} - out.setdefault(cls, set()).update(members) - return out - - -def _probe_verified_members_by_class(path: Path) -> dict[str, set[str]]: - if not path.exists(): - return {} - payload = _load_json(path) - out: dict[str, set[str]] = {} - for row in payload.get("class_rows", []): - klass = str(row.get("matlab_class", "")) - if not klass: - continue - methods = {str(item) for item in row.get("success_methods", [])} - out[klass] = methods - return out - - -def _excluded_methods_by_class(path: Path) -> dict[str, set[str]]: - if not path.exists(): - return {} - payload = _load_yaml(path) - out: dict[str, set[str]] = {} - for row in payload.get("classes", []): - klass = str(row.get("matlab_class", "")) - if not klass: - continue - methods = {str(method) for method in row.get("methods", [])} - out[klass] = methods - return out - - -def _extract_matlab_code_stats(path: Path) -> MatlabCodeStats: - if not path.exists(): - return MatlabCodeStats(total_code_lines=0, blocks=[]) - - code_lines: list[tuple[int, str]] = [] - for idx, raw in enumerate(path.read_text(encoding="utf-8", errors="ignore").splitlines(), start=1): - line = raw.strip() - if not line: - continue - if line.startswith("%"): - continue - code_lines.append((idx, line)) - - blocks: list[dict[str, Any]] = [] - if code_lines: - block_start, first_line = code_lines[0] - prev = block_start - count = 1 - preview = first_line - for idx, line in code_lines[1:]: - if idx == prev + 1: - count += 1 - prev = idx - continue - blocks.append( - { - "start_line": block_start, - "end_line": prev, - "line_count": count, - "preview": preview[:140], - } - ) - block_start = idx - prev = idx - count = 1 - preview = line - blocks.append( - { - "start_line": block_start, - "end_line": prev, - "line_count": count, - "preview": preview[:140], - } - ) - - return MatlabCodeStats(total_code_lines=len(code_lines), blocks=blocks) - - -def _extract_notebook_code_stats(path: Path) -> NotebookCodeStats: - if not path.exists(): - return NotebookCodeStats(total_code_lines=0, cells=[]) - - if nbformat is not None: - payload = nbformat.read(path, as_version=4) - notebook_cells = payload.cells - else: - raw = json.loads(path.read_text(encoding="utf-8")) - notebook_cells = raw.get("cells", []) - - cells: list[dict[str, Any]] = [] - total = 0 - skipped_setup_cell = False - code_cell_total = sum(1 for cell in notebook_cells if cell.get("cell_type") == "code") - for i, cell in enumerate(notebook_cells, start=1): - if cell.get("cell_type") != "code": - continue - is_setup_cell = (not skipped_setup_cell) and code_cell_total > 1 - if is_setup_cell: - skipped_setup_cell = True - src_raw = cell.get("source", "") - if isinstance(src_raw, list): - src = "".join(str(part) for part in src_raw) - else: - src = str(src_raw) - if "MATLAB executable line-port anchors for strict parity audit" in src: - snapshot_rows = sum(1 for line in src.splitlines() if line.strip().startswith('"')) - executable_rows = [ - line.strip() - for line in src.splitlines() - if line.strip() and not line.strip().startswith("#") - ] - # Exclude only small snapshot scaffolds from line-ratio accounting; - # keep large snapshots (e.g., nSTATPaperExamples) counted so - # notebook/m-file scale remains comparable for strict ratio checks. - # If a cell mixes snapshot anchors with substantive executable code, - # keep it in the accounting. - if snapshot_rows <= 64 and len(executable_rows) <= 16: - cells.append( - { - "cell_index": i, - "line_count": 0, - "preview": "", - } - ) - continue - if "Topic-specific checkpoint" in src and "Notebook checkpoints passed" in src: - non_comment = [ - line.strip() - for line in src.splitlines() - if line.strip() and not line.strip().startswith("#") - ] - checkpoint_only = len(non_comment) <= 8 and all( - ( - line.startswith("assert TOPIC") - or "validate_numeric_checkpoints" in line - or "Topic-specific checkpoint" in line - or "Notebook checkpoints passed" in line - ) - for line in non_comment - ) - if checkpoint_only: - cells.append( - { - "cell_index": i, - "line_count": 0, - "preview": "", - } - ) - continue - filtered = [] - for line in src.splitlines(): - stripped = line.strip() - if not stripped or stripped.startswith("#"): - continue - filtered.append(stripped) - line_count = len(filtered) - if is_setup_cell: - cells.append( - { - "cell_index": i, - "line_count": 0, - "preview": "", - } - ) - continue - total += line_count - if line_count == 0: - continue - cells.append( - { - "cell_index": i, - "line_count": line_count, - "preview": filtered[0][:140], - } - ) - return NotebookCodeStats(total_code_lines=total, cells=cells) - - -def _load_notebook_cells(path: Path) -> list[dict[str, Any]]: - if not path.exists(): - return [] - if nbformat is not None: - payload = nbformat.read(path, as_version=4) - return list(payload.cells) - raw = json.loads(path.read_text(encoding="utf-8")) - return list(raw.get("cells", [])) - - -def _extract_notebook_validation_stats(path: Path) -> NotebookValidationStats: - code = [] - for cell in _load_notebook_cells(path): - if cell.get("cell_type") != "code": - continue - src_raw = cell.get("source", "") - if isinstance(src_raw, list): - src = "".join(str(part) for part in src_raw) - else: - src = str(src_raw) - code.append(src) - - code_text = "\n".join(code) - has_topic_checkpoint = "Topic-specific checkpoint" in code_text and "Notebook checkpoints passed" in code_text - assertion_count = sum(1 for line in code_text.splitlines() if line.strip().startswith("assert ")) - has_plot_call = any( - token in code_text - for token in ("plt.", ".plot(", "imshow(", "pcolor(", "mesh(", "scatter(", "hist(") - ) - return NotebookValidationStats( - has_topic_checkpoint=has_topic_checkpoint, - assertion_count=assertion_count, - has_plot_call=has_plot_call, - ) - - -def _normalize_port_line(raw: str, *, matlab: bool) -> str: - text = raw.strip() - if not text: - return "" - if matlab: - text = re.sub(r"%.*$", "", text).strip() - else: - text = re.sub(r"#.*$", "", text).strip() - if not text: - return "" - text = text.replace("...", " ") - text = text.lower() - text = re.sub(r"\s+", " ", text).strip() - return text - - -def _line_tokens(line: str) -> set[str]: - return {tok for tok in IDENT_RE.findall(line) if len(tok) > 1} - - -def _matlab_port_lines(path: Path) -> list[str]: - if not path.exists(): - return [] - out: list[str] = [] - for raw in path.read_text(encoding="utf-8", errors="ignore").splitlines(): - stripped = raw.strip() - if not stripped or stripped.startswith("%"): - continue - line = _normalize_port_line(raw, matlab=True) - if line: - out.append(line) - return out - - -def _notebook_port_lines(path: Path) -> list[str]: - out: list[str] = [] - for cell in _load_notebook_cells(path): - if cell.get("cell_type") != "code": - continue - src_raw = cell.get("source", "") - if isinstance(src_raw, list): - src = "".join(str(part) for part in src_raw) - else: - src = str(src_raw) - for raw in src.splitlines(): - stripped = raw.strip() - if not stripped or stripped.startswith("#"): - continue - if stripped.startswith(NOTEBOOK_LINE_PORT_IGNORE_PREFIXES): - continue - if any(pat in stripped for pat in NOTEBOOK_LINE_PORT_IGNORE_PATTERNS): - continue - matlab_call = MATLAB_LINE_CALL_RE.match(stripped) - if matlab_call: - try: - literal = ast.literal_eval(matlab_call.group(1)) - except Exception: # pragma: no cover - defensive parser fallback - literal = None - if isinstance(literal, str): - line = _normalize_port_line(literal, matlab=True) - if line: - out.append(line) - continue - - # Parse exported snapshot rows like "foo();", into MATLAB-equivalent lines. - if stripped[:1] in {"'", '"'}: - candidate = stripped[:-1] if stripped.endswith(",") else stripped - try: - literal = ast.literal_eval(candidate) - except Exception: - literal = None - if isinstance(literal, str): - line = _normalize_port_line(literal, matlab=True) - if line: - out.append(line) - continue - - line = _normalize_port_line(raw, matlab=False) - if line: - out.append(line) - return out - - -def _line_similarity(a: set[str], b: set[str]) -> float: - if not a or not b: - return 0.0 - inter = len(a & b) - union = len(a | b) - if union == 0: - return 0.0 - return float(inter / union) - - -def _ordered_fuzzy_match_count( - matlab_lines: list[str], - python_lines: list[str], - *, - min_score: float = 0.60, - lookahead: int = 160, -) -> int: - if not matlab_lines or not python_lines: - return 0 - py_tokens = [_line_tokens(line) for line in python_lines] - m_tokens = [_line_tokens(line) for line in matlab_lines] - py_idx = 0 - matches = 0 - py_count = len(py_tokens) - for m_line, m_tok in zip(matlab_lines, m_tokens): - if not m_line: - continue - if not m_tok: - end = min(py_count, py_idx + lookahead) - for cand_idx in range(py_idx, end): - if python_lines[cand_idx] == m_line: - matches += 1 - py_idx = cand_idx + 1 - break - continue - end = min(py_count, py_idx + lookahead) - exact_idx = -1 - for cand_idx in range(py_idx, end): - if python_lines[cand_idx] == m_line: - exact_idx = cand_idx - break - if exact_idx >= 0: - matches += 1 - py_idx = exact_idx + 1 - continue - best_idx = -1 - best_score = 0.0 - for cand_idx in range(py_idx, end): - score = _line_similarity(m_tok, py_tokens[cand_idx]) - if score > best_score: - best_idx = cand_idx - best_score = score - if score >= 0.999: - break - if best_idx >= 0 and best_score >= min_score: - matches += 1 - py_idx = best_idx + 1 - return matches - - -def _function_names(lines: list[str]) -> set[str]: - names: set[str] = set() - for line in lines: - for name in CALL_RE.findall(line): - if name in {"if", "for", "while", "switch", "catch", "try"}: - continue - names.add(name) - return names - - -def _compute_line_port_stats(matlab_file: Path, python_nb: Path) -> LinePortStats: - matlab_lines = _matlab_port_lines(matlab_file) - python_lines = _notebook_port_lines(python_nb) - matched = _ordered_fuzzy_match_count(matlab_lines, python_lines) - coverage = float(matched / max(len(matlab_lines), 1)) - matlab_funcs = _function_names(matlab_lines) - python_funcs = _function_names(python_lines) - common_funcs = matlab_funcs & python_funcs - func_recall = float(len(common_funcs) / max(len(matlab_funcs), 1)) - return LinePortStats( - matlab_line_count=len(matlab_lines), - python_line_count=len(python_lines), - matched_line_count=matched, - line_port_coverage=coverage, - line_port_function_recall=func_recall, - matlab_function_count=len(matlab_funcs), - python_function_count=len(python_funcs), - common_function_count=len(common_funcs), - ) - - -def _collect_matlab_reference_images(help_root: Path, topic: str) -> list[str]: - topic_lower = topic.lower() - found: list[Path] = [] - seen: set[Path] = set() - - def add_if_valid(path: Path) -> None: - if not path.exists(): - return - name = path.name.lower() - if name.startswith(f"{topic_lower}_eq"): - return - if "eq" in name and name.startswith(topic_lower): - return - if name.startswith("logo"): - return - if path in seen: - return - seen.add(path) - found.append(path) - - html_path = help_root / f"{topic}.html" - if html_path.exists(): - html = html_path.read_text(encoding="utf-8", errors="ignore") - for src in IMG_SRC_RE.findall(html): - candidate = help_root / Path(src).name - add_if_valid(candidate) - - for pattern in (f"{topic}_*.png", f"{topic}.png", f"{topic}-*.png"): - for candidate in sorted(help_root.glob(pattern)): - add_if_valid(candidate) - - ordered = sorted(found, key=lambda p: p.name.lower()) - return [str(path) for path in ordered] - - -def _portable_path(path: Path, *, root: Path) -> str: - """Return repo/matlab-root relative POSIX paths for deterministic artifacts.""" - try: - return path.resolve().relative_to(root.resolve()).as_posix() - except ValueError: - # Keep output deterministic even when the path is outside the root. - return path.name - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - matlab_root = args.matlab_root.resolve() - help_root = matlab_root / "helpfiles" - - method_mapping = _load_yaml((repo_root / args.method_mapping).resolve()) - example_mapping = _load_yaml((repo_root / args.example_mapping).resolve()) - matlab_inventory = _load_json((repo_root / args.matlab_inventory).resolve()) - python_inventory = _load_json((repo_root / args.python_inventory).resolve()) - class_contract_specs: list[dict[str, Any]] = [] - for spec_path in args.class_contracts: - resolved = (repo_root / spec_path).resolve() - if not resolved.exists(): - continue - class_contract_specs.append(_load_yaml(resolved)) - - matlab_methods = _matlab_methods_by_class(matlab_inventory) - python_surfaces = _python_surfaces_by_class(python_inventory) - contract_members = _contract_members_by_class(class_contract_specs) - probe_members = _probe_verified_members_by_class((repo_root / args.probe_report).resolve()) - excluded_methods = _excluded_methods_by_class((repo_root / args.method_exclusions).resolve()) - - class_rows: list[dict[str, Any]] = [] - method_rows: list[dict[str, Any]] = [] - - for row in method_mapping["classes"]: - matlab_class = str(row["matlab_class"]) - alias_methods = dict(row.get("alias_methods", {})) - py_surface = python_surfaces[matlab_class]["python"] - compat_surface = python_surfaces[matlab_class]["compat"] - covered_contracts = contract_members.get(matlab_class, set()) - covered_probe = probe_members.get(matlab_class, set()) - - class_methods = matlab_methods[matlab_class] - missing_symbol_count = 0 - verified_count = 0 - unverified_count = 0 - excluded_count = 0 - - for method in class_methods: - mapped_member = str(alias_methods.get(method, method)) - in_python = mapped_member in py_surface - in_compat = mapped_member in compat_surface - symbol_ok = in_python or in_compat - is_excluded = method in excluded_methods.get(matlab_class, set()) - if is_excluded: - status = "excluded_matlab_stub" - excluded_count += 1 - elif not symbol_ok: - status = "missing_symbol" - missing_symbol_count += 1 - elif mapped_member in covered_contracts: - status = "contract_verified" - verified_count += 1 - elif mapped_member in covered_probe: - status = "probe_verified" - verified_count += 1 - else: - status = "unverified_behavior" - unverified_count += 1 - - method_rows.append( - { - "matlab_class": matlab_class, - "matlab_method": method, - "mapped_python_member": mapped_member, - "mapped_via_alias": method in alias_methods, - "present_in_python_surface": in_python, - "present_in_compat_surface": in_compat, - "excluded_method": is_excluded, - "has_behavior_contract": mapped_member in covered_contracts, - "has_probe_verification": mapped_member in covered_probe, - "functional_status": status, - } - ) - - class_rows.append( - { - "matlab_class": matlab_class, - "matlab_method_count": len(class_methods), - "contract_verified_count": verified_count, - "unverified_behavior_count": unverified_count, - "missing_symbol_count": missing_symbol_count, - "excluded_method_count": excluded_count, - "contract_coverage_ratio": float(verified_count / max(len(class_methods), 1)), - "probe_verified_count": sum( - 1 - for row in method_rows - if row["matlab_class"] == matlab_class and row["functional_status"] == "probe_verified" - ), - "eligible_method_count": len(class_methods) - excluded_count, - "eligible_verified_ratio": float(verified_count / max(len(class_methods) - excluded_count, 1)), - } - ) - - example_rows: list[dict[str, Any]] = [] - validation_root = (repo_root / args.validation_image_root).resolve() - fallback_validation_root = (repo_root / args.fallback_validation_image_root).resolve() - for row in example_mapping["examples"]: - topic = str(row["matlab_topic"]) - matlab_file = help_root / f"{topic}.m" - python_nb = (repo_root / str(row["python_notebook"])).resolve() - - matlab_stats = _extract_matlab_code_stats(matlab_file) - notebook_stats = _extract_notebook_code_stats(python_nb) - notebook_validation = _extract_notebook_validation_stats(python_nb) - line_port = _compute_line_port_stats(matlab_file, python_nb) - - reference_images = [ - _portable_path(Path(path), root=matlab_root) - for path in _collect_matlab_reference_images(help_root, topic) - ] - - # Prefer tracked baseline images so audit output stays stable across environments. - fallback_img_dir = fallback_validation_root / topic - python_images: list[str] = [] - if fallback_img_dir.exists(): - python_images = sorted( - _portable_path(path, root=repo_root) for path in fallback_img_dir.glob("*.png") - ) - if not python_images: - python_img_dir = validation_root / topic - if python_img_dir.exists(): - python_images = sorted( - _portable_path(path, root=repo_root) for path in python_img_dir.glob("*.png") - ) - - if not matlab_file.exists() or not python_nb.exists(): - alignment_status = "missing_artifact" - strict_line_status = "missing_artifact" - elif matlab_stats.total_code_lines == 0 and notebook_stats.total_code_lines == 0: - alignment_status = "doc_only" - strict_line_status = "doc_only" - elif matlab_stats.total_code_lines == 0 and notebook_stats.total_code_lines > 0: - alignment_status = "matlab_doc_only" - strict_line_status = "matlab_doc_only" - elif matlab_stats.total_code_lines > 0 and notebook_stats.total_code_lines == 0: - alignment_status = "missing_executable_content" - strict_line_status = "missing_executable_content" - else: - if ( - notebook_validation.has_topic_checkpoint - and notebook_validation.assertion_count >= 2 - and len(python_images) >= 1 - ): - alignment_status = "validated" - else: - alignment_status = "pending_manual_review" - - if ( - line_port.line_port_coverage >= 0.55 - and line_port.line_port_function_recall >= 0.45 - and 0.70 <= float(notebook_stats.total_code_lines / max(matlab_stats.total_code_lines, 1)) <= 1.50 - ): - strict_line_status = "line_port_verified" - elif ( - line_port.line_port_coverage >= 0.35 - and line_port.line_port_function_recall >= 0.30 - and 0.40 <= float(notebook_stats.total_code_lines / max(matlab_stats.total_code_lines, 1)) <= 2.50 - ): - strict_line_status = "line_port_partial" - else: - strict_line_status = "line_port_gap" - - line_ratio = ( - float(notebook_stats.total_code_lines / matlab_stats.total_code_lines) - if matlab_stats.total_code_lines > 0 - else None - ) - - example_rows.append( - { - "topic": topic, - "matlab_file": _portable_path(matlab_file, root=matlab_root), - "python_notebook": _portable_path(python_nb, root=repo_root), - "alignment_status": alignment_status, - "matlab_code_lines": matlab_stats.total_code_lines, - "python_code_lines": notebook_stats.total_code_lines, - "python_to_matlab_line_ratio": line_ratio, - "matlab_code_blocks": matlab_stats.blocks, - "python_code_cells": notebook_stats.cells, - "strict_line_status": strict_line_status, - "line_port_coverage": line_port.line_port_coverage, - "line_port_function_recall": line_port.line_port_function_recall, - "line_port_matched_lines": line_port.matched_line_count, - "line_port_matlab_lines": line_port.matlab_line_count, - "line_port_python_lines": line_port.python_line_count, - "line_port_matlab_function_count": line_port.matlab_function_count, - "line_port_python_function_count": line_port.python_function_count, - "line_port_common_function_count": line_port.common_function_count, - "has_topic_checkpoint": notebook_validation.has_topic_checkpoint, - "assertion_count": notebook_validation.assertion_count, - "has_plot_call": notebook_validation.has_plot_call, - "matlab_reference_image_count": len(reference_images), - "python_validation_image_count": len(python_images), - "matlab_reference_images": reference_images[:12], - "python_validation_images": python_images[:12], - } - ) - - total_methods = len(method_rows) - total_verified = sum( - 1 for row in method_rows if row["functional_status"] in {"contract_verified", "probe_verified"} - ) - total_contract_verified = sum(1 for row in method_rows if row["functional_status"] == "contract_verified") - total_probe_verified = sum(1 for row in method_rows if row["functional_status"] == "probe_verified") - total_excluded = sum(1 for row in method_rows if row["functional_status"] == "excluded_matlab_stub") - total_unverified = sum(1 for row in method_rows if row["functional_status"] == "unverified_behavior") - total_missing = sum(1 for row in method_rows if row["functional_status"] == "missing_symbol") - total_eligible = total_methods - total_excluded - - report = { - "generated_at_utc": "deterministic", - "matlab_root": "", - "repo_root": ".", - "method_functional_audit": { - "summary": { - "total_methods": total_methods, - "contract_verified_methods": total_verified, - "contract_explicit_verified_methods": total_contract_verified, - "probe_verified_methods": total_probe_verified, - "excluded_methods": total_excluded, - "eligible_methods": total_eligible, - "unverified_behavior_methods": total_unverified, - "missing_symbol_methods": total_missing, - "contract_verified_ratio": float(total_verified / max(total_methods, 1)), - "eligible_verified_ratio": float(total_verified / max(total_eligible, 1)), - }, - "class_summary": class_rows, - "method_rows": method_rows, - }, - "example_line_alignment_audit": { - "summary": { - "total_topics": len(example_rows), - "missing_artifact_topics": sum( - 1 for row in example_rows if row["alignment_status"] == "missing_artifact" - ), - "missing_executable_topics": sum( - 1 for row in example_rows if row["alignment_status"] == "missing_executable_content" - ), - "pending_manual_review_topics": sum( - 1 for row in example_rows if row["alignment_status"] == "pending_manual_review" - ), - "validated_topics": sum(1 for row in example_rows if row["alignment_status"] == "validated"), - "matlab_doc_only_topics": sum( - 1 for row in example_rows if row["alignment_status"] == "matlab_doc_only" - ), - "doc_only_topics": sum(1 for row in example_rows if row["alignment_status"] == "doc_only"), - "strict_line_verified_topics": sum( - 1 for row in example_rows if row["strict_line_status"] == "line_port_verified" - ), - "strict_line_partial_topics": sum( - 1 for row in example_rows if row["strict_line_status"] == "line_port_partial" - ), - "strict_line_gap_topics": sum( - 1 for row in example_rows if row["strict_line_status"] == "line_port_gap" - ), - }, - "topic_rows": example_rows, - }, - } - - out_path = (repo_root / args.out).resolve() - out_path.parent.mkdir(parents=True, exist_ok=True) - out_path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8") - print(f"Wrote equivalence audit report to {out_path}") - print( - "Method functional audit: " - f"total={total_methods}, excluded={total_excluded}, verified={total_verified}, " - f"unverified={total_unverified}, missing={total_missing}" - ) - print( - "Example alignment audit: " - f"topics={len(example_rows)}, pending_manual_review=" - f"{sum(1 for row in example_rows if row['alignment_status'] == 'pending_manual_review')}" - ) - print( - "Strict line-port audit: " - f"verified={sum(1 for row in example_rows if row['strict_line_status'] == 'line_port_verified')}, " - f"partial={sum(1 for row in example_rows if row['strict_line_status'] == 'line_port_partial')}, " - f"gap={sum(1 for row in example_rows if row['strict_line_status'] == 'line_port_gap')}" - ) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/generate_gap_report.py b/tools/parity/generate_gap_report.py deleted file mode 100755 index d378dbab..00000000 --- a/tools/parity/generate_gap_report.py +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env python3 -"""Generate machine-readable parity gap report from inventories and mappings.""" - -from __future__ import annotations - -import argparse -import importlib -import json -import sys -from datetime import datetime, timezone -from pathlib import Path -from typing import Any - -import yaml - - -SEVERITY_ORDER = {"none": 0, "low": 1, "medium": 2, "high": 3} - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[2]) - parser.add_argument("--method-mapping", type=Path, default=Path("parity/method_mapping.yaml")) - parser.add_argument("--example-mapping", type=Path, default=Path("parity/example_mapping.yaml")) - parser.add_argument("--matlab-inventory", type=Path, default=Path("parity/matlab_api_inventory.json")) - parser.add_argument("--python-inventory", type=Path, default=Path("parity/python_api_inventory.json")) - parser.add_argument("--help-toc", type=Path, default=Path("docs/help/helptoc.yml")) - parser.add_argument( - "--report-out", - type=Path, - default=Path("parity/parity_gap_report.json"), - help="Output JSON report", - ) - parser.add_argument( - "--fail-on", - choices=["none", "low", "medium", "high"], - default="high", - help="Fail if any issue at or above this severity exists", - ) - return parser.parse_args() - - -def _add_issue(issues: list[dict[str, Any]], severity: str, check: str, message: str, details: dict[str, Any]) -> None: - issues.append( - { - "severity": severity, - "check": check, - "message": message, - "details": details, - } - ) - - -def _load_json(path: Path) -> dict[str, Any]: - return json.loads(path.read_text(encoding="utf-8")) - - -def _load_yaml(path: Path) -> dict[str, Any]: - return yaml.safe_load(path.read_text(encoding="utf-8")) - - -def _build_lookup(rows: list[dict[str, Any]], key: str) -> dict[str, dict[str, Any]]: - return {str(row[key]): row for row in rows} - - -def _exists_symbol(path: str, repo_root: Path) -> bool: - src_root = repo_root / "src" - if str(src_root) not in sys.path: - sys.path.insert(0, str(src_root)) - try: - module_name, attr_name = path.rsplit(".", 1) - module = importlib.import_module(module_name) - return hasattr(module, attr_name) - except Exception: - return False - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - - method_mapping = _load_yaml((repo_root / args.method_mapping).resolve()) - example_mapping = _load_yaml((repo_root / args.example_mapping).resolve()) - matlab_inventory = _load_json((repo_root / args.matlab_inventory).resolve()) - python_inventory = _load_json((repo_root / args.python_inventory).resolve()) - help_toc = _load_yaml((repo_root / args.help_toc).resolve()) - - issues: list[dict[str, Any]] = [] - - matlab_by_class = _build_lookup(matlab_inventory["classes"], "matlab_class") - python_by_class = _build_lookup(python_inventory["classes"], "matlab_class") - - mapped_classes = method_mapping["classes"] - class_coverage: list[dict[str, Any]] = [] - - help_toc_text = json.dumps(help_toc).lower() - - for row in mapped_classes: - matlab_class = str(row["matlab_class"]) - python_class = str(row["python_class"]) - compat_class = str(row["compat_class"]) - aliases: dict[str, str] = dict(row.get("alias_methods", {})) - - if matlab_class not in matlab_by_class: - _add_issue( - issues, - "high", - "missing_matlab_class_inventory", - f"MATLAB class missing from inventory: {matlab_class}", - {"matlab_class": matlab_class}, - ) - continue - - if matlab_class not in python_by_class: - _add_issue( - issues, - "high", - "missing_python_class_inventory", - f"Python class missing from inventory: {matlab_class}", - {"matlab_class": matlab_class, "python_class": python_class}, - ) - continue - - if not _exists_symbol(python_class, repo_root): - _add_issue( - issues, - "high", - "missing_python_class", - f"Python class symbol not importable: {python_class}", - {"matlab_class": matlab_class, "python_class": python_class}, - ) - - if not _exists_symbol(compat_class, repo_root): - _add_issue( - issues, - "high", - "missing_compat_class", - f"Compatibility class symbol not importable: {compat_class}", - {"matlab_class": matlab_class, "compat_class": compat_class}, - ) - - matlab_methods = set(matlab_by_class[matlab_class]["methods"]) - py_row = python_by_class[matlab_class] - python_surface = set(py_row["python"]["methods"]) | set(py_row["python"]["properties"]) | set( - py_row["python"]["fields"] - ) - compat_surface = set(py_row["compat"]["methods"]) | set(py_row["compat"]["properties"]) | set( - py_row["compat"]["fields"] - ) - - missing_methods: list[str] = [] - mapped_count = 0 - - for method in sorted(matlab_methods): - if method in aliases: - target = aliases[method] - if target in python_surface or target in compat_surface: - mapped_count += 1 - else: - missing_methods.append(method) - continue - - if method in python_surface or method in compat_surface: - mapped_count += 1 - else: - missing_methods.append(method) - - if missing_methods: - _add_issue( - issues, - "medium", - "missing_method_mappings", - f"{matlab_class} has {len(missing_methods)} unmapped MATLAB methods", - { - "matlab_class": matlab_class, - "missing_methods": missing_methods, - "matlab_method_count": len(matlab_methods), - }, - ) - - class_help = repo_root / "docs" / "help" / "classes" / f"{matlab_class}.md" - if not class_help.exists(): - _add_issue( - issues, - "high", - "missing_class_help", - f"Missing class help page for {matlab_class}", - {"class_help": str(class_help)}, - ) - - class_coverage.append( - { - "matlab_class": matlab_class, - "matlab_method_count": len(matlab_methods), - "mapped_method_count": mapped_count, - "missing_method_count": len(missing_methods), - "coverage_ratio": float(mapped_count / max(len(matlab_methods), 1)), - } - ) - - example_rows = example_mapping["examples"] - example_coverage: list[dict[str, Any]] = [] - - for row in example_rows: - topic = str(row["matlab_topic"]) - notebook = (repo_root / str(row["python_notebook"])).resolve() - help_page = (repo_root / str(row["python_help_page"])).resolve() - - notebook_exists = notebook.exists() - help_exists = help_page.exists() - - if not notebook_exists: - _add_issue( - issues, - "high", - "missing_notebook", - f"Missing notebook for topic {topic}", - {"topic": topic, "notebook": str(notebook)}, - ) - if not help_exists: - _add_issue( - issues, - "high", - "missing_example_help", - f"Missing help page for topic {topic}", - {"topic": topic, "help_page": str(help_page)}, - ) - - topic_token = topic.lower() - if topic_token not in help_toc_text: - _add_issue( - issues, - "medium", - "topic_missing_from_help_toc", - f"Topic not present in docs/help/helptoc.yml: {topic}", - {"topic": topic}, - ) - - example_coverage.append( - { - "topic": topic, - "notebook_exists": notebook_exists, - "help_exists": help_exists, - } - ) - - summary = { - "high": sum(1 for i in issues if i["severity"] == "high"), - "medium": sum(1 for i in issues if i["severity"] == "medium"), - "low": sum(1 for i in issues if i["severity"] == "low"), - } - summary["total"] = summary["high"] + summary["medium"] + summary["low"] - - report = { - "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "fail_on": args.fail_on, - "summary": summary, - "class_coverage": class_coverage, - "example_coverage": example_coverage, - "issues": issues, - } - - out_path = (repo_root / args.report_out).resolve() - out_path.parent.mkdir(parents=True, exist_ok=True) - out_path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8") - - print(f"Wrote parity gap report to {out_path}") - print(f"Issue summary: high={summary['high']}, medium={summary['medium']}, low={summary['low']}") - - threshold = SEVERITY_ORDER[args.fail_on] - max_issue = max((SEVERITY_ORDER[i["severity"]] for i in issues), default=0) - if max_issue >= threshold and threshold > 0: - return 1 - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/generate_method_closure_sprint.py b/tools/parity/generate_method_closure_sprint.py deleted file mode 100644 index ede7dc31..00000000 --- a/tools/parity/generate_method_closure_sprint.py +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env python3 -"""Generate a targeted method-closure sprint backlog from parity audit output.""" - -from __future__ import annotations - -import argparse -import json -from collections import defaultdict -from pathlib import Path - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--report", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - help="Functional equivalence audit report JSON path.", - ) - parser.add_argument( - "--output", - type=Path, - default=Path("parity/method_closure_sprint.md"), - help="Markdown backlog output path.", - ) - parser.add_argument( - "--top-classes", - type=int, - default=8, - help="Number of highest probe-verified classes to prioritize.", - ) - parser.add_argument( - "--max-methods-per-class", - type=int, - default=20, - help="Maximum listed methods per class in the backlog section.", - ) - return parser.parse_args() - - -def main() -> int: - args = parse_args() - payload = json.loads(args.report.read_text(encoding="utf-8")) - - method_audit = payload["method_functional_audit"] - summary = method_audit["summary"] - class_rows = method_audit["class_summary"] - method_rows = method_audit["method_rows"] - - probe_only_by_class: dict[str, list[str]] = defaultdict(list) - excluded_by_class: dict[str, list[str]] = defaultdict(list) - - for row in method_rows: - klass = str(row["matlab_class"]) - method_name = str(row["matlab_method"]) - status = str(row.get("functional_status", "")) - has_contract = bool(row.get("has_behavior_contract", False)) - if status == "probe_verified" and not has_contract: - probe_only_by_class[klass].append(method_name) - if bool(row.get("excluded_method", False)): - excluded_by_class[klass].append(method_name) - - priority_rows = sorted( - class_rows, - key=lambda row: ( - int(row.get("probe_verified_count", 0)), - int(row.get("contract_verified_count", 0)), - ), - reverse=True, - ) - - lines: list[str] = [] - lines.append("# Method Closure Sprint Backlog") - lines.append("") - lines.append( - "This sprint backlog targets methods that are probe-verified but not yet " - "explicitly covered by behavior contracts." - ) - lines.append("") - lines.append("## Functional Summary") - lines.append(f"- Total methods: `{int(summary.get('total_methods', 0))}`") - lines.append( - f"- Contract-explicit verified methods: `{int(summary.get('contract_explicit_verified_methods', 0))}`" - ) - lines.append(f"- Probe-verified methods: `{int(summary.get('probe_verified_methods', 0))}`") - lines.append( - f"- Eligible verified ratio: `{float(summary.get('eligible_verified_ratio', 0.0)):.3f}`" - ) - lines.append(f"- Excluded methods: `{int(summary.get('excluded_methods', 0))}`") - lines.append("") - lines.append("## Priority Class Queue") - lines.append("| Class | Probe-verified | Contract-verified | Probe-only methods |") - lines.append("|---|---:|---:|---:|") - for row in priority_rows[: args.top_classes]: - klass = str(row["matlab_class"]) - lines.append( - f"| {klass} | {int(row.get('probe_verified_count', 0))} | " - f"{int(row.get('contract_verified_count', 0))} | " - f"{len(probe_only_by_class.get(klass, []))} |" - ) - lines.append("") - - lines.append("## Sprint Work Packages") - lines.append("") - for row in priority_rows[: args.top_classes]: - klass = str(row["matlab_class"]) - methods = sorted(probe_only_by_class.get(klass, [])) - if not methods: - continue - lines.append(f"### {klass}") - lines.append( - "- Goal: Convert probe-only functional verification to explicit behavior contracts." - ) - lines.append("- Candidate methods:") - for method_name in methods[: args.max_methods_per_class]: - lines.append(f" - `{method_name}`") - extra = len(methods) - args.max_methods_per_class - if extra > 0: - lines.append(f" - `... (+{extra} additional methods)`") - lines.append("") - - lines.append("## Excluded MATLAB Stub Methods") - if not excluded_by_class: - lines.append("- None") - else: - for klass in sorted(excluded_by_class): - lines.append(f"- `{klass}`") - for method_name in sorted(excluded_by_class[klass]): - lines.append(f" - `{method_name}`") - lines.append("") - - lines.append("## Exit Criteria") - lines.append("- Each listed method has an explicit behavior contract in parity audit generation.") - lines.append("- New/updated contract tests are added and pass in CI.") - lines.append( - "- Functional parity summary increases `contract_explicit_verified_methods` and preserves gate pass." - ) - lines.append("") - - args.output.parent.mkdir(parents=True, exist_ok=True) - args.output.write_text("\n".join(lines) + "\n", encoding="utf-8") - print(f"Wrote method closure sprint backlog: {args.output}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/generate_method_probe_report.py b/tools/parity/generate_method_probe_report.py deleted file mode 100644 index c710a4da..00000000 --- a/tools/parity/generate_method_probe_report.py +++ /dev/null @@ -1,407 +0,0 @@ -#!/usr/bin/env python3 -"""Probe mapped MATLAB-compatible methods and record executable coverage.""" - -from __future__ import annotations - -import argparse -import inspect -import json -from dataclasses import dataclass -from datetime import datetime, timezone -from pathlib import Path -from typing import Any - -import matplotlib - -matplotlib.use("Agg") -import matplotlib.pyplot as plt -import numpy as np -import yaml - -from nstat.compat import matlab as M - - -MISSING = object() - - -@dataclass(slots=True) -class ProbeResult: - attempted: bool - success: bool - error: str = "" - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[2]) - parser.add_argument("--method-mapping", type=Path, default=Path("parity/method_mapping.yaml")) - parser.add_argument("--matlab-inventory", type=Path, default=Path("parity/matlab_api_inventory.json")) - parser.add_argument( - "--out", - type=Path, - default=Path("parity/method_probe_report.json"), - help="Output method probe report JSON path.", - ) - return parser.parse_args() - - -def _load_json(path: Path) -> dict[str, Any]: - return json.loads(path.read_text(encoding="utf-8")) - - -def _load_yaml(path: Path) -> dict[str, Any]: - return yaml.safe_load(path.read_text(encoding="utf-8")) - - -def _build_probe_context() -> dict[str, tuple[Any, dict[str, Any]]]: - # Shared deterministic fixtures used for lightweight method probing. - time5 = np.linspace(0.0, 1.0, 5) - time11 = np.linspace(0.0, 1.0, 11) - time200 = np.linspace(0.0, 2.0, 200) - - signal = M.SignalObj(time=np.linspace(0.0, 2.0, 5), data=np.array([1.0, 2.0, 3.0, 2.0, 1.0]), name="sig") - covariate = M.Covariate( - time=time5, - data=np.column_stack([time5, time5**2]), - name="stim", - labels=["stim1", "stim2"], - ) - ci = M.ConfidenceInterval( - time=time5, - lower=np.array([0.0, 0.4, 0.8, 1.2, 1.6]), - upper=np.array([0.5, 0.9, 1.3, 1.7, 2.1]), - level=0.95, - ) - events = M.Events(times=np.array([0.1, 0.4, 0.9]), labels=["a", "b", "c"]) - history = M.History(bin_edges_s=np.array([0.0, 0.05, 0.1, 0.2])) - - st1 = M.nspikeTrain(spike_times=np.array([0.1, 0.2, 0.25, 0.9]), t_start=0.0, t_end=1.0, name="u1") - st2 = M.nspikeTrain(spike_times=np.array([0.15, 0.4, 0.8]), t_start=0.0, t_end=1.0, name="u2") - coll = M.nstColl([st1, st2]) - - cov1 = M.Covariate(time=time11, data=np.sin(2 * np.pi * time11), name="sine", labels=["sine"]) - cov2 = M.Covariate(time=time11, data=np.column_stack([time11, time11**2]), name="poly", labels=["t", "t2"]) - covcoll = M.CovColl([cov1, cov2]) - - trial_cfg = M.TrialConfig(covariate_labels=["sine", "t", "t2"], sample_rate_hz=10.0, fit_type="poisson", name="cfg") - cfg_coll = M.ConfigColl([trial_cfg]) - trial = M.Trial(spikes=coll, covariates=covcoll) - - X = np.column_stack([np.sin(2.0 * np.pi * 0.7 * time200), np.cos(2.0 * np.pi * 0.4 * time200)]) - y = np.random.default_rng(2026).poisson(np.exp(-1.0 + 0.3 * X[:, 0] - 0.2 * X[:, 1])).astype(float) - fit_native = M.Analysis.GLMFit(X, y, "poisson", 1.0) - fit = M.FitResult.fromStructure(fit_native.to_structure()) - - fit2 = M.FitResult( - coefficients=np.array([0.1, 0.3]), - intercept=-0.5, - fit_type="poisson", - log_likelihood=-20.0, - n_samples=100, - n_parameters=3, - parameter_labels=["stim", "hist"], - ) - fit_summary = M.FitResSummary([fit, fit2]) - - cif = M.CIF(coefficients=np.array([0.8, -0.2]), intercept=-1.0, link="binomial") - - spike_matrix = np.array( - [ - [0, 0, 1, 0, 0, 1], - [0, 1, 1, 0, 0, 1], - [1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 0, 1], - ], - dtype=float, - ) - spike_counts = np.array( - [ - [0, 0, 1, 2, 1, 0], - [1, 2, 2, 1, 0, 0], - [0, 0, 0, 1, 2, 2], - ], - dtype=float, - ) - tuning = np.array( - [ - [1.0, 0.5, 0.1], - [0.2, 1.1, 0.4], - [0.1, 0.4, 1.2], - ], - dtype=float, - ) - posterior = M.DecodingAlgorithms.decodeStatePosterior(spike_counts, tuning)[1] - - contexts: dict[str, tuple[Any, dict[str, Any]]] = { - "SignalObj": (signal, {"structure": signal.dataToStructure()}), - "Covariate": (covariate, {"structure": covariate.toStructure()}), - "ConfidenceInterval": (ci, {"structure": ci.toStructure()}), - "Events": (events, {"structure": events.toStructure()}), - "History": (history, {"structure": history.toStructure()}), - "nspikeTrain": (st1, {"structure": st1.toStructure()}), - "nstColl": (coll, {"structure": coll.toStructure()}), - "CovColl": (covcoll, {"structure": covcoll.toStructure()}), - "TrialConfig": (trial_cfg, {"structure": trial_cfg.toStructure(), "trial": trial}), - "ConfigColl": (cfg_coll, {"structure": cfg_coll.toStructure()}), - "Trial": (trial, {"structure": trial.toStructure()}), - "CIF": (cif, {"structure": cif.toStructure(), "X": X, "y": y, "time": time200}), - "Analysis": ( - M.Analysis, - { - "X": X, - "y": y, - "trial": trial, - "config": trial_cfg, - "fit": fit_native, - "signals": np.column_stack([np.sin(2 * np.pi * time200), np.cos(2 * np.pi * time200)]), - "positions": np.array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]), - }, - ), - "FitResult": (fit, {"structure": fit.toStructure(), "X": X, "newFitObj": fit2}), - "FitResSummary": (fit_summary, {"structure": fit_summary.toStructure()}), - "DecodingAlgorithms": ( - M.DecodingAlgorithms, - { - "spike_matrix": spike_matrix, - "spike_counts": spike_counts, - "tuning_rates": tuning, - "tuning_curves": tuning, - "posterior": posterior, - "state_values": np.arange(tuning.shape[1]), - "transition": np.eye(tuning.shape[1], dtype=float), - "sample": np.random.default_rng(7).uniform(size=50), - }, - ), - } - return contexts - - -def _infer_arg(name: str, context: dict[str, Any]) -> Any: - lname = name.lower() - if name in context: - return context[name] - - if lname in {"x"}: - return context.get("X", MISSING) - if lname in {"y"}: - return context.get("y", MISSING) - if "fit" in lname and lname not in {"fittype", "fittype_s"}: - return context.get("fit", MISSING) - if "trial" in lname: - return context.get("trial", MISSING) - if "config" in lname: - return context.get("config", MISSING) - if "structure" in lname or "payload" in lname: - return context.get("structure", MISSING) - if "newfitobj" in lname: - return context.get("newFitObj", MISSING) - if "sample" == lname: - return context.get("sample", MISSING) - if "reference" in lname: - return context.get("sample", MISSING) - if lname in {"time", "timegrid_s"}: - return context.get("time", MISSING) - if "spike" in lname and "matrix" in lname: - return context.get("spike_matrix", MISSING) - if "spike" in lname and "count" in lname: - return context.get("spike_counts", MISSING) - if "spike" in lname and "times" in lname: - return context.get("spike_times", np.array([0.1, 0.2, 0.8])) - if "tuning" in lname and "curve" in lname: - return context.get("tuning_curves", MISSING) - if "tuning" in lname and "rate" in lname: - return context.get("tuning_rates", MISSING) - if "posterior" in lname: - return context.get("posterior", MISSING) - if "state" in lname and "value" in lname: - return context.get("state_values", MISSING) - if "transition" in lname: - return context.get("transition", MISSING) - if "position" in lname: - return context.get("positions", MISSING) - if "signal" in lname: - return context.get("signals", MISSING) - - if "binsize" in lname or ("bin" in lname and "size" in lname): - return 0.1 - if "sample_rate" in lname or "samplerate" in lname: - return 10.0 - if "alpha" in lname: - return 0.05 - if "dt" == lname: - return 1.0 - if "l2" in lname: - return 0.0 - if "kappa" in lname: - return 0.0 - if lname in {"k", "maxlag"}: - return 1 - if "fitnum" in lname or ("num" in lname and "fit" in lname): - return 1 - if "mode" == lname: - return "count" - if "metric" in lname: - return "aic" - if "fittype" in lname: - return "poisson" - if "name" in lname: - return "u1" - if "label" in lname: - return "stim" - if "labels" in lname: - return ["stim"] - if "selector" in lname or lname in {"ind", "index", "unitindex"}: - return 0 - if "selectors" in lname: - return [1] - if "subfits" in lname: - return [1] - if "subfit" in lname: - return 1 - if "partition" in lname: - return [0.0, 0.5, 1.0] - if "window" in lname: - return (-0.05, 0.05) - if "t_min" in lname or "mintime" in lname: - return 0.0 - if "t_max" in lname or "maxtime" in lname: - return 1.0 - if "newzero" in lname or "targettime" in lname or "shift" in lname: - return 0.1 - if "mer" in lname: - return 0.001 - if "delimiter" in lname: - return "," - if "level" in lname: - return 0.95 - if "color" in lname: - return "r" - if "value" in lname: - return 1.0 - return MISSING - - -def _invoke_member(obj: Any, member_name: str, context: dict[str, Any]) -> ProbeResult: - if not hasattr(obj, member_name): - return ProbeResult(attempted=False, success=False, error="missing_member") - - member = getattr(obj, member_name) - if not callable(member): - return ProbeResult(attempted=True, success=True) - - try: - sig = inspect.signature(member) - except (TypeError, ValueError): - # Builtins/C-extension callables: best effort call with no args. - try: - member() - return ProbeResult(attempted=True, success=True) - except Exception as exc: # noqa: BLE001 - return ProbeResult(attempted=True, success=False, error=type(exc).__name__) - - args: list[Any] = [] - kwargs: dict[str, Any] = {} - for param in sig.parameters.values(): - if param.kind in {inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD}: - continue - if param.default is not inspect.Parameter.empty: - continue - inferred = _infer_arg(param.name, context) - if inferred is MISSING: - return ProbeResult(attempted=False, success=False, error=f"unresolved_arg:{param.name}") - if param.kind in {inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD}: - args.append(inferred) - elif param.kind == inspect.Parameter.KEYWORD_ONLY: - kwargs[param.name] = inferred - - try: - member(*args, **kwargs) - return ProbeResult(attempted=True, success=True) - except Exception as exc: # noqa: BLE001 - return ProbeResult(attempted=True, success=False, error=type(exc).__name__) - finally: - plt.close("all") - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - - mapping = _load_yaml((repo_root / args.method_mapping).resolve()) - matlab_inventory = _load_json((repo_root / args.matlab_inventory).resolve()) - methods_by_class = {str(row["matlab_class"]): list(row["methods"]) for row in matlab_inventory["classes"]} - contexts = _build_probe_context() - - class_rows: list[dict[str, Any]] = [] - total_methods = 0 - total_attempted = 0 - total_success = 0 - - for row in mapping["classes"]: - matlab_class = str(row["matlab_class"]) - alias = dict(row.get("alias_methods", {})) - target_obj, context = contexts[matlab_class] - - methods = methods_by_class.get(matlab_class, []) - success_methods: list[str] = [] - attempted_methods: list[str] = [] - failed_methods: list[dict[str, str]] = [] - skipped_methods: list[dict[str, str]] = [] - - for matlab_method in methods: - total_methods += 1 - mapped = str(alias.get(matlab_method, matlab_method)) - probe = _invoke_member(target_obj, mapped, context) - if not probe.attempted: - skipped_methods.append({"mapped_member": mapped, "reason": probe.error}) - continue - - total_attempted += 1 - attempted_methods.append(mapped) - if probe.success: - total_success += 1 - success_methods.append(mapped) - else: - failed_methods.append({"mapped_member": mapped, "error": probe.error}) - - class_rows.append( - { - "matlab_class": matlab_class, - "matlab_method_count": len(methods), - "attempted_method_count": len(attempted_methods), - "successful_method_count": len(success_methods), - "success_ratio_attempted": float(len(success_methods) / max(len(attempted_methods), 1)), - "success_ratio_total": float(len(success_methods) / max(len(methods), 1)), - "success_methods": sorted(set(success_methods)), - "failed_methods": failed_methods[:200], - "skipped_methods": skipped_methods[:200], - } - ) - - report = { - "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "repo_root": str(repo_root), - "summary": { - "total_methods": total_methods, - "attempted_methods": total_attempted, - "successful_methods": total_success, - "attempt_ratio": float(total_attempted / max(total_methods, 1)), - "success_ratio_total": float(total_success / max(total_methods, 1)), - "success_ratio_attempted": float(total_success / max(total_attempted, 1)), - }, - "class_rows": class_rows, - } - - out_path = (repo_root / args.out).resolve() - out_path.parent.mkdir(parents=True, exist_ok=True) - out_path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8") - print(f"Wrote method probe report to {out_path}") - print( - "Method probe summary: " - f"total={total_methods}, attempted={total_attempted}, successful={total_success}" - ) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/generate_reference_fixtures.py b/tools/parity/generate_reference_fixtures.py deleted file mode 100755 index f0cff954..00000000 --- a/tools/parity/generate_reference_fixtures.py +++ /dev/null @@ -1,348 +0,0 @@ -#!/usr/bin/env python3 -"""Generate deterministic reference fixtures for parity regression testing. - -These fixtures are Python-native reference artifacts used to enforce numerical -regression stability in CI. They are designed to be replaced/augmented with -MATLAB-generated references when exported from the gold-standard toolbox. -""" - -from __future__ import annotations - -import argparse -import hashlib -from pathlib import Path -from typing import Any - -import numpy as np -import yaml - -from nstat.analysis import Analysis -from nstat.compat.matlab import ConfidenceInterval as MatlabConfidenceInterval -from nstat.decoding import DecodingAlgorithms -from nstat.fit import FitResult, FitSummary -from nstat.signal import Covariate -from nstat.spikes import SpikeTrain, SpikeTrainCollection -from nstat.trial import CovariateCollection, Trial - - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--output-dir", - type=Path, - default=Path("tests/parity/fixtures"), - help="Directory where fixture files and manifest are written.", - ) - return parser.parse_args() - - - -def _sha256(path: Path) -> str: - digest = hashlib.sha256() - with path.open("rb") as f: - for chunk in iter(lambda: f.read(8192), b""): - digest.update(chunk) - return digest.hexdigest() - - - -def _write_npz(path: Path, **arrays: np.ndarray) -> dict[str, Any]: - path.parent.mkdir(parents=True, exist_ok=True) - np.savez(path, **arrays) - return { - "path": str(path.as_posix()), - "sha256": _sha256(path), - } - - - -def _fixture_analysis_poisson(output_dir: Path) -> dict[str, Any]: - rng = np.random.default_rng(2026) - n = 2500 - dt = 0.01 - x = rng.normal(size=n) - X = x[:, None] - true_intercept = np.log(10.0) - true_beta = np.array([0.45]) - lam = np.exp(true_intercept + X @ true_beta) - y = rng.poisson(lam * dt).astype(float) - - fit = Analysis.fit_glm(X=X, y=y, fit_type="poisson", dt=dt) - pred = fit.predict(X) - - file_info = _write_npz( - output_dir / "analysis_poisson_glm.npz", - X=X, - y=y, - dt=np.array([dt], dtype=float), - expected_coefficients=fit.coefficients, - expected_intercept=np.array([fit.intercept], dtype=float), - expected_log_likelihood=np.array([fit.log_likelihood], dtype=float), - expected_rate=pred, - ) - file_info["name"] = "analysis_poisson_glm" - file_info["source"] = "python_seeded_reference" - return file_info - - - -def _fixture_decoding_posterior(output_dir: Path) -> dict[str, Any]: - rng = np.random.default_rng(2026) - n_units = 12 - n_states = 18 - n_time = 180 - - centers = np.linspace(0.0, n_states - 1, n_units) - widths = np.full(n_units, 2.0) - states = np.arange(n_states)[None, :] - tuning = 0.05 + 0.35 * np.exp(-0.5 * ((states - centers[:, None]) / widths[:, None]) ** 2) - - transition = np.zeros((n_states, n_states), dtype=float) - for i in range(n_states): - for j, w in ((i - 1, 0.2), (i, 0.6), (i + 1, 0.2)): - if 0 <= j < n_states: - transition[i, j] += w - transition[i, :] /= np.sum(transition[i, :]) - - latent = np.zeros(n_time, dtype=int) - latent[0] = n_states // 2 - for t in range(1, n_time): - latent[t] = rng.choice(n_states, p=transition[latent[t - 1]]) - - spike_counts = np.zeros((n_units, n_time), dtype=float) - for t in range(n_time): - spike_counts[:, t] = rng.poisson(tuning[:, latent[t]]) - - decoded, posterior = DecodingAlgorithms.decode_state_posterior( - spike_counts=spike_counts, - tuning_rates=tuning, - transition=transition, - ) - - file_info = _write_npz( - output_dir / "decoding_state_posterior.npz", - spike_counts=spike_counts, - tuning_rates=tuning, - transition=transition, - expected_decoded=decoded, - expected_posterior=posterior, - ) - file_info["name"] = "decoding_state_posterior" - file_info["source"] = "python_seeded_reference" - return file_info - - - -def _fixture_trial_alignment(output_dir: Path) -> dict[str, Any]: - time = np.linspace(0.0, 1.0, 501) - cov = Covariate(time=time, data=np.sin(2 * np.pi * 3.0 * time), name="stim", labels=["stim"]) - spikes = SpikeTrain(spike_times=np.array([0.10, 0.22, 0.51, 0.79]), t_start=0.0, t_end=1.0, name="u1") - trial = Trial( - spikes=SpikeTrainCollection([spikes]), - covariates=CovariateCollection([cov]), - ) - bin_size = 0.02 - tb, y, X = trial.aligned_binned_observation(bin_size_s=bin_size, unit_index=0, mode="count") - - file_info = _write_npz( - output_dir / "trial_alignment.npz", - time=time, - cov_data=cov.data, - spike_times=spikes.spike_times, - bin_size=np.array([bin_size], dtype=float), - expected_time_bins=tb, - expected_counts=y, - expected_design=X, - ) - file_info["name"] = "trial_alignment" - file_info["source"] = "python_seeded_reference" - return file_info - - - -def _fixture_fit_summary_structure(output_dir: Path) -> dict[str, Any]: - coefficients = np.array( - [ - [0.20, -0.10], - [0.45, 0.30], - [-0.05, 0.25], - ], - dtype=float, - ) - intercepts = np.array([-1.0, -0.7, -0.9], dtype=float) - log_likelihoods = np.array([-12.0, -10.8, -11.5], dtype=float) - n_samples = np.array([200, 200, 200], dtype=int) - n_parameters = np.array([3, 3, 3], dtype=int) - fit_types = np.array(["binomial", "binomial", "binomial"], dtype=" dict[str, Any]: - result = FitResult( - coefficients=np.array([0.35, -0.12], dtype=float), - intercept=-0.80, - fit_type="binomial", - log_likelihood=-15.2, - n_samples=240, - n_parameters=3, - parameter_labels=["stim", "hist"], - ) - result.set_ks_stats( - ks_stat=np.array([0.12, 0.09], dtype=float), - p_value=np.array([0.84, 0.63], dtype=float), - within_conf_int=np.array([1.0, 0.0], dtype=float), - ) - result.set_fit_residual(np.array([0.2, -0.1, 0.05, -0.03], dtype=float)) - result.set_inv_gaus_stats({"z": np.array([0.1, -0.2, 0.05], dtype=float)}) - result.set_neuron_name("unit-17") - plot = result.compute_plot_params() - - roundtrip = FitResult.from_structure(result.to_structure()) - roundtrip_plot = roundtrip.get_plot_params() - - file_info = _write_npz( - output_dir / "fit_result_roundtrip.npz", - coefficients=result.coefficients, - intercept=np.array([result.intercept], dtype=float), - fit_type=np.array([result.fit_type], dtype=" dict[str, Any]: - time = np.linspace(0.0, 1.0, 51) - center = 0.5 + 0.1 * np.sin(2.0 * np.pi * 2.0 * time) - half_width = 0.2 + 0.05 * np.cos(2.0 * np.pi * time) - lower = center - half_width - upper = center + half_width - values = center + 0.02 * np.cos(2.0 * np.pi * 3.0 * time) - - ci = MatlabConfidenceInterval(time=time, lower=lower, upper=upper, level=0.95) - ci.setColor("red") - ci.setValue(values) - structure = ci.toStructure() - restored = MatlabConfidenceInterval.fromStructure(structure) - - file_info = _write_npz( - output_dir / "confidence_interval_compat.npz", - time=time, - lower=lower, - upper=upper, - values=values, - expected_width=np.asarray(ci.getWidth(), dtype=float), - expected_contains=np.asarray(ci.contains(values), dtype=bool), - expected_structure_lower=np.asarray(structure["lower"], dtype=float), - expected_structure_upper=np.asarray(structure["upper"], dtype=float), - expected_restored_lower=np.asarray(restored.lower, dtype=float), - expected_restored_upper=np.asarray(restored.upper, dtype=float), - expected_restored_level=np.array([restored.level], dtype=float), - ) - file_info["name"] = "confidence_interval_compat" - file_info["source"] = "python_seeded_reference" - return file_info - - -def main() -> int: - args = parse_args() - repo_root = Path(__file__).resolve().parents[2] - output_dir = args.output_dir.resolve() - output_dir.mkdir(parents=True, exist_ok=True) - - fixtures = [ - _fixture_analysis_poisson(output_dir), - _fixture_decoding_posterior(output_dir), - _fixture_trial_alignment(output_dir), - _fixture_fit_summary_structure(output_dir), - _fixture_fit_result_roundtrip(output_dir), - _fixture_confidence_interval_compat(output_dir), - ] - - for row in fixtures: - fixture_path = Path(row["path"]).resolve() - row["path"] = fixture_path.relative_to(repo_root).as_posix() - - manifest = { - "version": 1, - "policy": { - "purpose": "regression_guard", - "matlab_reference_upgrade_expected": True, - }, - "fixtures": fixtures, - } - manifest_path = output_dir / "manifest.yml" - manifest_path.write_text(yaml.safe_dump(manifest, sort_keys=False), encoding="utf-8") - print(f"Wrote fixture manifest: {manifest_path}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/prepare_validation_images.py b/tools/parity/prepare_validation_images.py deleted file mode 100644 index 6d158f39..00000000 --- a/tools/parity/prepare_validation_images.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python3 -"""Prepare deterministic notebook validation images for parity checks. - -This utility verifies that every manifest topic has at least one tracked -baseline image and then syncs those images into the runtime tmp directory -consumed by equivalence-audit tooling. -""" - -from __future__ import annotations - -import argparse -import shutil -from pathlib import Path - -import yaml - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--manifest", - type=Path, - default=Path("tools/notebooks/notebook_manifest.yml"), - help="Notebook manifest with topic list.", - ) - parser.add_argument( - "--baseline-root", - type=Path, - default=Path("baseline/validation/notebook_images"), - help="Tracked baseline validation image root.", - ) - parser.add_argument( - "--out-root", - type=Path, - default=Path("tmp/pdfs/validation_report/notebook_images"), - help="Output directory used by parity audit tooling.", - ) - parser.add_argument( - "--min-images", - type=int, - default=1, - help="Minimum number of PNGs required per topic in baseline.", - ) - return parser.parse_args() - - -def _load_topics(manifest_path: Path) -> list[str]: - payload = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) - return [str(row["topic"]) for row in payload.get("notebooks", [])] - - -def main() -> int: - args = parse_args() - topics = _load_topics(args.manifest) - if not topics: - raise RuntimeError("no topics found in notebook manifest") - - missing: list[str] = [] - for topic in topics: - topic_dir = args.baseline_root / topic - pngs = sorted(topic_dir.glob("*.png")) if topic_dir.exists() else [] - if len(pngs) < args.min_images: - missing.append(topic) - - if missing: - print("Validation image baseline check FAILED") - for topic in missing: - print(f" - missing or insufficient baseline images: {topic}") - return 1 - - args.out_root.parent.mkdir(parents=True, exist_ok=True) - if args.out_root.exists(): - shutil.rmtree(args.out_root) - shutil.copytree(args.baseline_root, args.out_root) - - copied_count = len(list(args.out_root.glob("*/*.png"))) - print("Validation image baseline check passed.") - print(f"Copied baseline images to {args.out_root} ({copied_count} png files).") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/parity/sync_parity_artifacts.py b/tools/parity/sync_parity_artifacts.py deleted file mode 100755 index 8ef65063..00000000 --- a/tools/parity/sync_parity_artifacts.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python3 -"""Regenerate parity artifacts from the current functional audit.""" - -from __future__ import annotations - -import argparse -import subprocess -import sys -from pathlib import Path - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--repo-root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="Repository root containing parity/docs artifacts.", - ) - parser.add_argument( - "--matlab-root", - type=Path, - default=None, - help="MATLAB nSTAT root used to regenerate functional audit.", - ) - parser.add_argument( - "--report", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - help="Functional audit report path (relative to --repo-root).", - ) - parser.add_argument( - "--method-closure", - type=Path, - default=Path("parity/method_closure_sprint.md"), - help="Method closure sprint markdown output (relative to --repo-root).", - ) - parser.add_argument( - "--skip-audit", - action="store_true", - help="Skip regenerating parity/function_example_alignment_report.json.", - ) - parser.add_argument( - "--skip-help-pages", - action="store_true", - help="Skip docs/help regeneration.", - ) - return parser.parse_args() - - -def run(cmd: list[str], cwd: Path) -> None: - print("Running:", " ".join(cmd)) - subprocess.run(cmd, cwd=str(cwd), check=True) - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - report_path = (repo_root / args.report).resolve() - method_closure_path = (repo_root / args.method_closure).resolve() - - if not args.skip_audit: - if args.matlab_root is None: - raise SystemExit("--matlab-root is required unless --skip-audit is set.") - run( - [ - sys.executable, - str(repo_root / "tools" / "parity" / "generate_equivalence_audit.py"), - "--repo-root", - str(repo_root), - "--matlab-root", - str(args.matlab_root.resolve()), - "--out", - str(report_path), - ], - cwd=repo_root, - ) - - run( - [ - sys.executable, - str(repo_root / "tools" / "parity" / "generate_method_closure_sprint.py"), - "--report", - str(report_path), - "--output", - str(method_closure_path), - ], - cwd=repo_root, - ) - - if not args.skip_help_pages: - run( - [ - sys.executable, - str(repo_root / "tools" / "docs" / "generate_help_pages.py"), - ], - cwd=repo_root, - ) - - print("Parity artifacts synchronized.") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/performance/__init__.py b/tools/performance/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/performance/compare_matlab_python_performance.py b/tools/performance/compare_matlab_python_performance.py deleted file mode 100755 index 3eac0468..00000000 --- a/tools/performance/compare_matlab_python_performance.py +++ /dev/null @@ -1,266 +0,0 @@ -#!/usr/bin/env python3 -"""Compare Python benchmark report against MATLAB baseline performance report.""" - -from __future__ import annotations - -import argparse -import csv -import json -import math -from datetime import UTC, datetime -from pathlib import Path -from typing import Any - -import yaml - - -def _index_cases(rows: list[dict[str, Any]]) -> dict[tuple[str, str], dict[str, Any]]: - out: dict[tuple[str, str], dict[str, Any]] = {} - for row in rows: - out[(str(row["case"]), str(row["tier"]))] = row - return out - - -def _safe_ratio(num: float, den: float) -> float: - if den <= 0.0: - return float("inf") - return float(num / den) - - -def _major_minor(version: Any) -> str: - text = str(version or "") - parts = text.split(".") - if len(parts) >= 2: - return f"{parts[0]}.{parts[1]}" - return text - - -def _is_regression_env_compatible(current: dict[str, Any], previous: dict[str, Any]) -> bool: - # Performance regressions are only meaningful when runner platform and Python minor line match. - return ( - str(current.get("platform", "")) == str(previous.get("platform", "")) - and _major_minor(current.get("python", "")) == _major_minor(previous.get("python", "")) - ) - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--python-report", type=Path, required=True, help="Python benchmark JSON report.") - parser.add_argument("--matlab-report", type=Path, required=True, help="MATLAB benchmark JSON report.") - parser.add_argument("--policy", type=Path, default=Path("parity/performance_gate_policy.yml")) - parser.add_argument( - "--previous-python-report", - type=Path, - default=None, - help="Optional previous Python benchmark report for regression detection.", - ) - parser.add_argument( - "--report-out", - type=Path, - default=Path("parity/performance_parity_report.json"), - help="Output comparison JSON path.", - ) - parser.add_argument( - "--csv-out", - type=Path, - default=Path("parity/performance_parity_report.csv"), - help="Output comparison CSV path.", - ) - parser.add_argument( - "--fail-on-regression", - action="store_true", - help="Return non-zero when Python runtime regresses beyond threshold vs previous report.", - ) - parser.add_argument( - "--require-regression-env-match", - action="store_true", - help=( - "When set, fail if previous Python baseline exists but benchmark " - "environment metadata is not comparable." - ), - ) - parser.add_argument( - "--fail-on-matlab-ratio", - action="store_true", - help="Return non-zero when Python/MATLAB runtime ratio exceeds policy threshold.", - ) - args = parser.parse_args() - - py_report = json.loads(args.python_report.read_text(encoding="utf-8")) - ml_report = json.loads(args.matlab_report.read_text(encoding="utf-8")) - policy = yaml.safe_load(args.policy.read_text(encoding="utf-8")) or {} - - prev_idx: dict[tuple[str, str], dict[str, Any]] = {} - regression_env_compatible = True - if args.previous_python_report and args.previous_python_report.exists(): - prev = json.loads(args.previous_python_report.read_text(encoding="utf-8")) - regression_env_compatible = _is_regression_env_compatible( - py_report.get("environment", {}) or {}, - prev.get("environment", {}) or {}, - ) - if regression_env_compatible: - prev_idx = _index_cases(prev.get("cases", [])) - else: - if args.require_regression_env_match: - print( - "Regression environment mismatch and --require-regression-env-match was set: " - f"current={py_report.get('environment', {})}, previous={prev.get('environment', {})}" - ) - return 1 - print( - "Skipping regression gating: benchmark environments are not comparable " - f"(current={py_report.get('environment', {})}, previous={prev.get('environment', {})})" - ) - - py_idx = _index_cases(py_report.get("cases", [])) - ml_idx = _index_cases(ml_report.get("cases", [])) - - default_ratio = float(policy.get("default_max_matlab_ratio", 5.0)) - critical = policy.get("critical_case_max_matlab_ratio", {}) or {} - regression_limit = float(policy.get("max_python_regression_ratio", 1.35)) - min_regression_delta_ms = float(policy.get("min_python_regression_delta_ms", 0.0)) - - rows: list[dict[str, Any]] = [] - missing_matlab = 0 - ratio_fail = 0 - regression_fail = 0 - - for key, py_case in sorted(py_idx.items()): - case, tier = key - ml_case = ml_idx.get(key) - py_runtime = float(py_case.get("median_runtime_ms", float("nan"))) - py_mem = float(py_case.get("median_peak_memory_mb", float("nan"))) - - if ml_case is None: - missing_matlab += 1 - rows.append( - { - "case": case, - "tier": tier, - "python_runtime_ms": py_runtime, - "matlab_runtime_ms": float("nan"), - "python_to_matlab_ratio": float("inf"), - "max_allowed_ratio": float(critical.get(case, default_ratio)), - "ratio_pass": False, - "regression_pass": True, - "python_peak_memory_mb": py_mem, - "status": "missing_matlab_baseline", - } - ) - continue - - ml_runtime = float(ml_case.get("median_runtime_ms", float("nan"))) - ratio = _safe_ratio(py_runtime, ml_runtime) - max_allowed = float(critical.get(case, default_ratio)) - ratio_pass = bool(ratio <= max_allowed) - if not ratio_pass: - ratio_fail += 1 - - prev_case = prev_idx.get(key) - regression_pass = True - prev_runtime = float("nan") - py_vs_prev_ratio = float("nan") - py_vs_prev_delta_ms = float("nan") - if prev_case is not None: - prev_runtime = float(prev_case.get("median_runtime_ms", float("nan"))) - py_vs_prev_ratio = _safe_ratio(py_runtime, prev_runtime) - py_vs_prev_delta_ms = py_runtime - prev_runtime - ratio_ok = bool(py_vs_prev_ratio <= regression_limit) - delta_ok = bool( - math.isnan(py_vs_prev_delta_ms) or py_vs_prev_delta_ms <= min_regression_delta_ms - ) - regression_pass = bool(ratio_ok or delta_ok) - if not regression_pass: - regression_fail += 1 - - rows.append( - { - "case": case, - "tier": tier, - "python_runtime_ms": py_runtime, - "matlab_runtime_ms": ml_runtime, - "python_to_matlab_ratio": ratio, - "max_allowed_ratio": max_allowed, - "ratio_pass": ratio_pass, - "python_peak_memory_mb": py_mem, - "previous_python_runtime_ms": prev_runtime, - "python_vs_previous_ratio": py_vs_prev_ratio, - "python_vs_previous_delta_ms": py_vs_prev_delta_ms, - "regression_pass": regression_pass, - "status": "ok" if ratio_pass and regression_pass else "needs_attention", - } - ) - - worst = sorted( - [r for r in rows if r["python_to_matlab_ratio"] != float("inf")], - key=lambda r: float(r["python_to_matlab_ratio"]), - reverse=True, - )[:5] - - summary = { - "schema_version": 1, - "generated_at_utc": datetime.now(UTC).isoformat(timespec="seconds").replace("+00:00", "Z"), - "policy": { - "default_max_matlab_ratio": default_ratio, - "critical_case_max_matlab_ratio": critical, - "max_python_regression_ratio": regression_limit, - "min_python_regression_delta_ms": min_regression_delta_ms, - "regression_env_compatible": regression_env_compatible, - }, - "python_report": str(args.python_report), - "matlab_report": str(args.matlab_report), - "previous_python_report": str(args.previous_python_report) if args.previous_python_report else "", - "counts": { - "total_case_tiers": len(rows), - "missing_matlab_baseline": missing_matlab, - "ratio_failures": ratio_fail, - "regression_failures": regression_fail, - }, - "top_python_vs_matlab_gaps": worst, - "rows": rows, - } - - args.report_out.parent.mkdir(parents=True, exist_ok=True) - args.report_out.write_text(json.dumps(summary, indent=2), encoding="utf-8") - - args.csv_out.parent.mkdir(parents=True, exist_ok=True) - with args.csv_out.open("w", newline="", encoding="utf-8") as f: - writer = csv.DictWriter( - f, - fieldnames=[ - "case", - "tier", - "python_runtime_ms", - "matlab_runtime_ms", - "python_to_matlab_ratio", - "max_allowed_ratio", - "ratio_pass", - "python_peak_memory_mb", - "previous_python_runtime_ms", - "python_vs_previous_ratio", - "python_vs_previous_delta_ms", - "regression_pass", - "status", - ], - ) - writer.writeheader() - for row in rows: - writer.writerow(row) - - print(f"Wrote performance parity JSON: {args.report_out}") - print(f"Wrote performance parity CSV: {args.csv_out}") - print( - "Counts: " - f"total={len(rows)} missing_matlab={missing_matlab} " - f"ratio_fail={ratio_fail} regression_fail={regression_fail}" - ) - - if args.fail_on_matlab_ratio and ratio_fail > 0: - return 1 - if args.fail_on_regression and regression_fail > 0: - return 1 - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/performance/run_python_benchmarks.py b/tools/performance/run_python_benchmarks.py deleted file mode 100755 index f7b36f6c..00000000 --- a/tools/performance/run_python_benchmarks.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python3 -"""Run deterministic Python performance benchmarks for MATLAB parity tracking.""" - -from __future__ import annotations - -import argparse -import csv -import json -import os -import platform -import statistics -import subprocess -import time -import tracemalloc -from datetime import UTC, datetime -from pathlib import Path -from typing import Any - -import matplotlib -import numpy as np -import scipy - -try: - from nstat.performance_workloads import CASE_ORDER, TIER_ORDER, run_python_workload -except ModuleNotFoundError: # pragma: no cover - fallback for non-installed local runs - import sys - - sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src")) - from nstat.performance_workloads import CASE_ORDER, TIER_ORDER, run_python_workload - - -def _git_sha(repo_root: Path) -> str: - try: - return ( - subprocess.run( - ["git", "rev-parse", "HEAD"], - cwd=repo_root, - text=True, - capture_output=True, - check=True, - ) - .stdout.strip() - ) - except Exception: - return "unknown" - - -def _collect_env() -> dict[str, Any]: - return { - "python": platform.python_version(), - "platform": platform.platform(), - "numpy": np.__version__, - "scipy": scipy.__version__, - "matplotlib": matplotlib.__version__, - "omp_num_threads": os.getenv("OMP_NUM_THREADS", ""), - "mkl_num_threads": os.getenv("MKL_NUM_THREADS", ""), - "openblas_num_threads": os.getenv("OPENBLAS_NUM_THREADS", ""), - "veclib_maximum_threads": os.getenv("VECLIB_MAXIMUM_THREADS", ""), - } - - -def _median(vals: list[float]) -> float: - return float(statistics.median(vals)) if vals else float("nan") - - -def _run_case(case: str, tier: str, repeats: int, warmup: int, seed: int) -> dict[str, Any]: - runtimes_ms: list[float] = [] - peak_mem_mb: list[float] = [] - summary: dict[str, float] = {} - - for rep in range(warmup + repeats): - run_seed = int(seed + rep) - if rep >= warmup: - tracemalloc.start() - t0 = time.perf_counter() - summary = run_python_workload(case=case, tier=tier, seed=run_seed) - elapsed_ms = (time.perf_counter() - t0) * 1000.0 - if rep >= warmup: - _, peak = tracemalloc.get_traced_memory() - tracemalloc.stop() - runtimes_ms.append(float(elapsed_ms)) - peak_mem_mb.append(float(peak / (1024.0 * 1024.0))) - - return { - "case": case, - "tier": tier, - "repeats": int(repeats), - "warmup": int(warmup), - "median_runtime_ms": _median(runtimes_ms), - "mean_runtime_ms": float(np.mean(runtimes_ms)), - "std_runtime_ms": float(np.std(runtimes_ms)), - "median_peak_memory_mb": _median(peak_mem_mb), - "summary": summary, - "samples_runtime_ms": runtimes_ms, - "samples_peak_memory_mb": peak_mem_mb, - } - - -def _write_csv(rows: list[dict[str, Any]], out_csv: Path) -> None: - out_csv.parent.mkdir(parents=True, exist_ok=True) - fieldnames = [ - "case", - "tier", - "repeats", - "median_runtime_ms", - "mean_runtime_ms", - "std_runtime_ms", - "median_peak_memory_mb", - "summary", - ] - with out_csv.open("w", newline="", encoding="utf-8") as f: - writer = csv.DictWriter(f, fieldnames=fieldnames) - writer.writeheader() - for row in rows: - writer.writerow( - { - "case": row["case"], - "tier": row["tier"], - "repeats": row["repeats"], - "median_runtime_ms": row["median_runtime_ms"], - "mean_runtime_ms": row["mean_runtime_ms"], - "std_runtime_ms": row["std_runtime_ms"], - "median_peak_memory_mb": row["median_peak_memory_mb"], - "summary": json.dumps(row["summary"], sort_keys=True), - } - ) - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--tiers", - type=str, - default="S,M,L", - help="Comma-separated tier list from {S,M,L}.", - ) - parser.add_argument("--repeats", type=int, default=7, help="Measured repeats per case/tier.") - parser.add_argument("--warmup", type=int, default=2, help="Warmup repeats per case/tier.") - parser.add_argument("--seed", type=int, default=20260303, help="Base deterministic seed.") - parser.add_argument( - "--out-json", - type=Path, - default=Path("output/performance/python_performance_report.json"), - help="Output JSON report path.", - ) - parser.add_argument( - "--out-csv", - type=Path, - default=Path("output/performance/python_performance_report.csv"), - help="Output CSV report path.", - ) - parser.add_argument( - "--repo-root", - type=Path, - default=Path(__file__).resolve().parents[2], - help="Repository root for metadata.", - ) - args = parser.parse_args() - - tiers = [t.strip().upper() for t in args.tiers.split(",") if t.strip()] - unknown = [t for t in tiers if t not in TIER_ORDER] - if unknown: - raise ValueError(f"Unsupported tiers: {unknown}") - - rows: list[dict[str, Any]] = [] - for case in CASE_ORDER: - for tier in tiers: - rows.append(_run_case(case=case, tier=tier, repeats=args.repeats, warmup=args.warmup, seed=args.seed)) - - report = { - "schema_version": 1, - "generated_at_utc": datetime.now(UTC).isoformat(timespec="seconds").replace("+00:00", "Z"), - "implementation": "python", - "repo_root": str(args.repo_root.resolve()), - "git_sha": _git_sha(args.repo_root.resolve()), - "tiers": tiers, - "cases": rows, - "environment": _collect_env(), - } - - args.out_json.parent.mkdir(parents=True, exist_ok=True) - args.out_json.write_text(json.dumps(report, indent=2), encoding="utf-8") - _write_csv(rows, args.out_csv) - - print(f"Wrote Python performance JSON: {args.out_json}") - print(f"Wrote Python performance CSV: {args.out_csv}") - print(f"Benchmarked case-tier pairs: {len(rows)}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/release/apply_branch_protection.py b/tools/release/apply_branch_protection.py deleted file mode 100644 index b7da4a3f..00000000 --- a/tools/release/apply_branch_protection.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python3 -"""Apply branch protection with required status checks via GitHub API.""" - -from __future__ import annotations - -import argparse -import json -import subprocess -import tempfile -from pathlib import Path - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--repo", type=str, required=True, help="owner/repo") - parser.add_argument("--branch", type=str, default="main") - parser.add_argument( - "--required-check", - action="append", - default=[], - help="Required status check context. Repeat flag for multiple checks.", - ) - parser.add_argument( - "--strict", - action=argparse.BooleanOptionalAction, - default=True, - help="Require branch to be up to date before merging.", - ) - parser.add_argument( - "--dry-run", - action="store_true", - help="Print payload only; do not call GitHub API.", - ) - return parser.parse_args() - - -def main() -> int: - args = parse_args() - - checks = args.required_check or ["test-and-build", "parity-gate"] - payload = { - "required_status_checks": { - "strict": bool(args.strict), - "contexts": checks, - }, - "enforce_admins": False, - "required_pull_request_reviews": None, - "restrictions": None, - } - - print("Applying branch protection:") - print(json.dumps(payload, indent=2)) - - if args.dry_run: - return 0 - - with tempfile.NamedTemporaryFile("w", encoding="utf-8", suffix=".json", delete=False) as tmp: - tmp.write(json.dumps(payload)) - payload_path = Path(tmp.name) - - try: - cmd = [ - "gh", - "api", - "--method", - "PUT", - f"repos/{args.repo}/branches/{args.branch}/protection", - "--input", - str(payload_path), - "--header", - "Accept: application/vnd.github+json", - ] - proc = subprocess.run(cmd, capture_output=True, text=True, check=False) - if proc.returncode != 0: - print(proc.stdout) - print(proc.stderr) - return proc.returncode - print("Branch protection updated successfully.") - return 0 - finally: - if payload_path.exists(): - payload_path.unlink() - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/release/check_release_gate.py b/tools/release/check_release_gate.py deleted file mode 100755 index 9d44b544..00000000 --- a/tools/release/check_release_gate.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python3 -"""Release gate checks for nSTAT-python v1 readiness.""" - -from __future__ import annotations - -from pathlib import Path - -import yaml - - -REQUIRED_CLASS_HELP = [ - "Analysis", - "CIF", - "ConfidenceInterval", - "ConfigColl", - "CovColl", - "Covariate", - "DecodingAlgorithms", - "Events", - "FitResSummary", - "FitResult", - "History", - "SignalObj", - "Trial", - "TrialConfig", - "nspikeTrain", - "nstColl", -] - - - -def main() -> int: - missing: list[str] = [] - - class_manifest = yaml.safe_load( - Path("baseline/class_method_inventory.yml").read_text(encoding="utf-8") - ) - expected_classes = sorted( - {row["matlab_class"] for row in class_manifest["classes"]} | set(REQUIRED_CLASS_HELP) - ) - - for klass in expected_classes: - page = Path("docs/help/classes") / f"{klass}.md" - if not page.exists(): - missing.append(f"missing class help page: {page}") - - manifest = yaml.safe_load(Path("tools/notebooks/notebook_manifest.yml").read_text(encoding="utf-8")) - help_toc = yaml.safe_load(Path("docs/help/helptoc.yml").read_text(encoding="utf-8")) - toc_text = str(help_toc).lower() - - for row in manifest["notebooks"]: - topic = row["topic"] - notebook = Path(row["file"]) - help_page = Path("docs/help/examples") / f"{topic}.md" - - if not notebook.exists(): - missing.append(f"missing notebook: {notebook}") - if not help_page.exists(): - missing.append(f"missing example help page: {help_page}") - - if row.get("run_group") not in {"smoke", "full"}: - missing.append(f"invalid run_group for {topic}: {row.get('run_group')}") - - if topic.lower() not in toc_text: - missing.append(f"topic missing from help TOC: {topic}") - - notebooks_index = Path("docs/notebooks.md") - if not notebooks_index.exists(): - missing.append("missing notebook catalog page: docs/notebooks.md") - - if missing: - print("Release gate failed:") - for msg in missing: - print(f" - {msg}") - return 1 - - print("Release gate checks passed.") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/release/generate_rc_release_notes.py b/tools/release/generate_rc_release_notes.py deleted file mode 100644 index 5333aa20..00000000 --- a/tools/release/generate_rc_release_notes.py +++ /dev/null @@ -1,296 +0,0 @@ -#!/usr/bin/env python3 -"""Generate release-candidate notes from parity artifacts.""" - -from __future__ import annotations - -import argparse -import json -import subprocess -from pathlib import Path - -import yaml - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--repo-root", type=Path, default=Path(".")) - parser.add_argument("--tag", type=str, required=True) - parser.add_argument("--commit", type=str, default="") - parser.add_argument("--run-url", type=str, default="") - parser.add_argument("--validation-pdf", type=str, default="") - parser.add_argument("--output", type=Path, required=True) - parser.add_argument( - "--gap-report", - type=Path, - default=Path("parity/parity_gap_report.json"), - ) - parser.add_argument( - "--equivalence-report", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - ) - parser.add_argument( - "--numeric-drift-report", - type=Path, - default=Path("parity/numeric_drift_report.json"), - ) - parser.add_argument( - "--example-output-spec", - type=Path, - default=Path("parity/example_output_spec.yml"), - ) - parser.add_argument( - "--previous-tag", - type=str, - default="", - help="Optional previous RC tag (for explicit RC-to-RC deltas).", - ) - return parser.parse_args() - - -def _read_json(path: Path) -> dict: - if not path.exists(): - return {} - return json.loads(path.read_text(encoding="utf-8")) - - -def _read_yaml(path: Path) -> dict: - if not path.exists(): - return {} - payload = yaml.safe_load(path.read_text(encoding="utf-8")) - return payload or {} - - -def _read_json_from_tag(repo_root: Path, tag: str, relpath: Path) -> dict: - if not tag: - return {} - proc = subprocess.run( - ["git", "-C", str(repo_root), "show", f"{tag}:{relpath.as_posix()}"], - capture_output=True, - text=True, - check=False, - ) - if proc.returncode != 0 or not proc.stdout.strip(): - return {} - try: - return json.loads(proc.stdout) - except json.JSONDecodeError: - return {} - - -def _delta_line(label: str, current: int, previous: int) -> str: - delta = current - previous - sign = "+" if delta >= 0 else "" - return f"- {label}: `{previous} -> {current}` (`{sign}{delta}`)" - - -def _latest_snapshot(parity_dir: Path) -> Path | None: - candidates = sorted(parity_dir.glob("matlab_gold_snapshot_*.yml")) - if not candidates: - return None - return candidates[-1] - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - - gap_report = _read_json(repo_root / args.gap_report) - eq_report = _read_json(repo_root / args.equivalence_report) - drift_report = _read_json(repo_root / args.numeric_drift_report) - spec = _read_yaml(repo_root / args.example_output_spec) - snapshot_path = _latest_snapshot(repo_root / "parity") - snapshot = _read_yaml(snapshot_path) if snapshot_path is not None else {} - previous_tag = args.previous_tag.strip() - previous_eq = _read_json_from_tag(repo_root, previous_tag, args.equivalence_report) - previous_drift = _read_json_from_tag(repo_root, previous_tag, args.numeric_drift_report) - previous_gap = _read_json_from_tag(repo_root, previous_tag, args.gap_report) - - gap = gap_report.get("summary", {}) - method = eq_report.get("method_functional_audit", {}).get("summary", {}) - example = eq_report.get("example_line_alignment_audit", {}).get("summary", {}) - drift = drift_report.get("summary", {}) - out_of_scope_topics = spec.get("out_of_scope_topics", []) - - lines: list[str] = [] - lines.append(f"## nSTAT-python {args.tag}") - lines.append("") - lines.append( - "Automated release-candidate notes generated from parity, functional, " - "and numeric-drift artifacts." - ) - lines.append("") - lines.append("### Structural parity") - lines.append(f"- High gaps: `{int(gap.get('high', 0))}`") - lines.append(f"- Medium gaps: `{int(gap.get('medium', 0))}`") - lines.append(f"- Low gaps: `{int(gap.get('low', 0))}`") - lines.append(f"- Total gaps: `{int(gap.get('total', 0))}`") - lines.append("") - lines.append("### Functional parity") - lines.append(f"- Total methods: `{int(method.get('total_methods', 0))}`") - lines.append( - f"- Contract-verified methods: `{int(method.get('contract_verified_methods', 0))}`" - ) - lines.append( - "- Contract-explicit verified methods: " - f"`{int(method.get('contract_explicit_verified_methods', 0))}`" - ) - lines.append(f"- Probe-verified methods: `{int(method.get('probe_verified_methods', 0))}`") - lines.append(f"- Excluded methods: `{int(method.get('excluded_methods', 0))}`") - lines.append(f"- Missing symbol methods: `{int(method.get('missing_symbol_methods', 0))}`") - lines.append( - f"- Unverified behavior methods: `{int(method.get('unverified_behavior_methods', 0))}`" - ) - lines.append("") - lines.append("### Example parity") - lines.append(f"- Total topics: `{int(example.get('total_topics', 0))}`") - lines.append(f"- Validated topics: `{int(example.get('validated_topics', 0))}`") - lines.append(f"- MATLAB doc-only topics: `{int(example.get('matlab_doc_only_topics', 0))}`") - lines.append( - f"- Pending manual review topics: `{int(example.get('pending_manual_review_topics', 0))}`" - ) - if out_of_scope_topics: - lines.append("- Out-of-scope topics:") - for topic in out_of_scope_topics: - lines.append(f" - `{topic}`") - lines.append("") - lines.append("### Numeric drift") - lines.append(f"- Topics checked: `{int(drift.get('topics', 0))}`") - lines.append(f"- Topics passed: `{int(drift.get('passed_topics', 0))}`") - lines.append(f"- Topics failed: `{int(drift.get('failed_topics', 0))}`") - lines.append(f"- Metrics checked: `{int(drift.get('checked_metrics', 0))}`") - lines.append(f"- Metrics failed: `{int(drift.get('failed_metrics', 0))}`") - lines.append("") - - if previous_tag: - prev_gap = previous_gap.get("summary", {}) - prev_method = previous_eq.get("method_functional_audit", {}).get("summary", {}) - prev_example = previous_eq.get("example_line_alignment_audit", {}).get("summary", {}) - prev_drift = previous_drift.get("summary", {}) - lines.append(f"### RC delta vs `{previous_tag}`") - lines.append( - _delta_line( - "Structural high gaps", - int(gap.get("high", 0)), - int(prev_gap.get("high", 0)), - ) - ) - lines.append( - _delta_line( - "Structural medium gaps", - int(gap.get("medium", 0)), - int(prev_gap.get("medium", 0)), - ) - ) - lines.append( - _delta_line( - "Validated example topics", - int(example.get("validated_topics", 0)), - int(prev_example.get("validated_topics", 0)), - ) - ) - lines.append( - _delta_line( - "MATLAB doc-only topics", - int(example.get("matlab_doc_only_topics", 0)), - int(prev_example.get("matlab_doc_only_topics", 0)), - ) - ) - lines.append( - _delta_line( - "Contract-explicit verified methods", - int(method.get("contract_explicit_verified_methods", 0)), - int(prev_method.get("contract_explicit_verified_methods", 0)), - ) - ) - lines.append( - _delta_line( - "Probe-verified methods", - int(method.get("probe_verified_methods", 0)), - int(prev_method.get("probe_verified_methods", 0)), - ) - ) - lines.append( - _delta_line( - "Unverified behavior methods", - int(method.get("unverified_behavior_methods", 0)), - int(prev_method.get("unverified_behavior_methods", 0)), - ) - ) - lines.append( - _delta_line( - "Numeric topics checked", - int(drift.get("topics", 0)), - int(prev_drift.get("topics", 0)), - ) - ) - lines.append( - _delta_line( - "Numeric topics passed", - int(drift.get("passed_topics", 0)), - int(prev_drift.get("passed_topics", 0)), - ) - ) - lines.append( - _delta_line( - "Numeric topics failed", - int(drift.get("failed_topics", 0)), - int(prev_drift.get("failed_topics", 0)), - ) - ) - lines.append( - _delta_line( - "Numeric metrics checked", - int(drift.get("checked_metrics", 0)), - int(prev_drift.get("checked_metrics", 0)), - ) - ) - lines.append( - _delta_line( - "Numeric metrics failed", - int(drift.get("failed_metrics", 0)), - int(prev_drift.get("failed_metrics", 0)), - ) - ) - lines.append("") - - if snapshot: - source = snapshot.get("source", {}) - mirror = snapshot.get("mirror", {}) - lines.append("### Frozen MATLAB snapshot") - lines.append( - f"- Snapshot id: `{snapshot.get('snapshot_id', '-')}` " - f"(`{snapshot.get('captured_on', '-')}`)" - ) - lines.append( - f"- Source manifest: `{source.get('manifest_path', '-')}` " - f"(sha256 `{source.get('manifest_sha256', '-')}`)" - ) - lines.append( - f"- Mirror manifest: `{mirror.get('manifest_path', '-')}` " - f"(sha256 `{mirror.get('manifest_sha256', '-')}`)" - ) - lines.append(f"- File count: `{mirror.get('file_count', '-')}`") - lines.append(f"- Total size bytes: `{mirror.get('total_size_bytes', '-')}`") - lines.append("") - - if args.validation_pdf: - lines.append("### Validation asset") - lines.append(f"- PDF: `{args.validation_pdf}`") - lines.append("") - - if args.commit: - lines.append("### Build metadata") - lines.append(f"- Commit: `{args.commit}`") - if args.run_url: - lines.append(f"- Workflow run: {args.run_url}") - lines.append("") - - args.output.parent.mkdir(parents=True, exist_ok=True) - args.output.write_text("\n".join(lines) + "\n", encoding="utf-8") - print(f"Wrote RC release notes: {args.output}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/release/generate_stable_release_notes.py b/tools/release/generate_stable_release_notes.py deleted file mode 100644 index 858504c0..00000000 --- a/tools/release/generate_stable_release_notes.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python3 -"""Generate stable release notes from parity artifacts.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - -import yaml - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--repo-root", type=Path, default=Path(".")) - parser.add_argument("--stable-tag", type=str, required=True) - parser.add_argument("--rc-tag", type=str, required=True) - parser.add_argument("--commit", type=str, default="") - parser.add_argument("--run-url", type=str, default="") - parser.add_argument("--validation-pdf", type=str, default="") - parser.add_argument("--output", type=Path, required=True) - parser.add_argument("--gap-report", type=Path, default=Path("parity/parity_gap_report.json")) - parser.add_argument( - "--equivalence-report", - type=Path, - default=Path("parity/function_example_alignment_report.json"), - ) - parser.add_argument( - "--numeric-drift-report", - type=Path, - default=Path("parity/numeric_drift_report.json"), - ) - parser.add_argument( - "--example-output-spec", - type=Path, - default=Path("parity/example_output_spec.yml"), - ) - return parser.parse_args() - - -def _read_json(path: Path) -> dict: - if not path.exists(): - return {} - return json.loads(path.read_text(encoding="utf-8")) - - -def _read_yaml(path: Path) -> dict: - if not path.exists(): - return {} - payload = yaml.safe_load(path.read_text(encoding="utf-8")) - return payload or {} - - -def main() -> int: - args = parse_args() - repo_root = args.repo_root.resolve() - - gap_report = _read_json(repo_root / args.gap_report) - eq_report = _read_json(repo_root / args.equivalence_report) - drift_report = _read_json(repo_root / args.numeric_drift_report) - spec = _read_yaml(repo_root / args.example_output_spec) - - gap = gap_report.get("summary", {}) - method = eq_report.get("method_functional_audit", {}).get("summary", {}) - example = eq_report.get("example_line_alignment_audit", {}).get("summary", {}) - drift = drift_report.get("summary", {}) - out_of_scope_topics = spec.get("out_of_scope_topics", []) - - lines: list[str] = [] - lines.append(f"## nSTAT-python {args.stable_tag}") - lines.append("") - lines.append(f"Promoted from release candidate `{args.rc_tag}` after hard release checks.") - lines.append("") - lines.append("### Structural parity") - lines.append(f"- High gaps: `{int(gap.get('high', 0))}`") - lines.append(f"- Medium gaps: `{int(gap.get('medium', 0))}`") - lines.append(f"- Low gaps: `{int(gap.get('low', 0))}`") - lines.append("") - lines.append("### Functional parity") - lines.append(f"- Total methods: `{int(method.get('total_methods', 0))}`") - lines.append( - f"- Contract-explicit verified methods: `{int(method.get('contract_explicit_verified_methods', 0))}`" - ) - lines.append(f"- Probe-verified methods: `{int(method.get('probe_verified_methods', 0))}`") - lines.append(f"- Excluded methods: `{int(method.get('excluded_methods', 0))}`") - lines.append(f"- Missing symbol methods: `{int(method.get('missing_symbol_methods', 0))}`") - lines.append("") - lines.append("### Example parity") - lines.append(f"- Total topics: `{int(example.get('total_topics', 0))}`") - lines.append(f"- Validated topics: `{int(example.get('validated_topics', 0))}`") - lines.append(f"- MATLAB doc-only topics: `{int(example.get('matlab_doc_only_topics', 0))}`") - lines.append("") - lines.append("### Numeric drift") - lines.append(f"- Topics checked: `{int(drift.get('topics', 0))}`") - lines.append(f"- Topics passed: `{int(drift.get('passed_topics', 0))}`") - lines.append(f"- Metrics checked: `{int(drift.get('checked_metrics', 0))}`") - lines.append(f"- Metrics failed: `{int(drift.get('failed_metrics', 0))}`") - lines.append("") - - if out_of_scope_topics: - lines.append("### Out-of-scope MATLAB topics") - for topic in out_of_scope_topics: - lines.append(f"- `{topic}`") - lines.append("") - - if args.validation_pdf: - lines.append("### Validation asset") - lines.append(f"- PDF: `{args.validation_pdf}`") - lines.append("") - - lines.append("### Build metadata") - if args.commit: - lines.append(f"- Commit: `{args.commit}`") - if args.run_url: - lines.append(f"- Workflow run: {args.run_url}") - lines.append("") - - args.output.parent.mkdir(parents=True, exist_ok=True) - args.output.write_text("\n".join(lines) + "\n", encoding="utf-8") - print(f"Wrote stable release notes: {args.output}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/reports/build_image_parity_pdfs.py b/tools/reports/build_image_parity_pdfs.py deleted file mode 100755 index 36c148fa..00000000 --- a/tools/reports/build_image_parity_pdfs.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env python3 -"""Build paired MATLAB/Python image-sequence PDFs for page-by-page parity checks.""" - -from __future__ import annotations - -import argparse -import json -from pathlib import Path - -from PIL import Image -from reportlab.lib.pagesizes import letter -from reportlab.pdfgen import canvas - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--report-json", type=Path, required=True, help="Validation summary JSON from generate_validation_pdf.py") - parser.add_argument( - "--python-out", - type=Path, - default=Path("output/pdf/image_mode_parity/python_pages.pdf"), - help="Output PDF containing Python images", - ) - parser.add_argument( - "--matlab-out", - type=Path, - default=Path("output/pdf/image_mode_parity/matlab_pages.pdf"), - help="Output PDF containing MATLAB images", - ) - parser.add_argument( - "--pairs-json", - type=Path, - default=Path("output/pdf/image_mode_parity/pairs.json"), - help="Output JSON containing selected per-topic image pairs", - ) - return parser.parse_args() - - -def _resolve_img(path_str: str) -> Path | None: - if not path_str: - return None - p = Path(path_str) - return p if p.exists() else None - - -def _select_ordinal_pairs(row: dict) -> list[dict]: - topic = str(row.get("topic", "")) - explicit_pairs = row.get("figure_pairs") - pairs: list[dict] = [] - if isinstance(explicit_pairs, list) and explicit_pairs: - for item in explicit_pairs: - if not isinstance(item, dict): - continue - ordinal = int(item.get("ordinal", 0) or 0) - py = _resolve_img(str(item.get("python_image") or "")) - mat = _resolve_img(str(item.get("matlab_image") or "")) - pairs.append( - { - "topic": topic, - "ordinal": ordinal, - "python_image": str(py) if py is not None else "", - "matlab_image": str(mat) if mat is not None else "", - } - ) - return pairs - - py_list = [_resolve_img(str(path)) for path in (row.get("python_images") or [])] - mat_list = [_resolve_img(str(path)) for path in (row.get("matlab_reference_images") or [])] - max_n = max(len(py_list), len(mat_list)) - for idx in range(max_n): - py = py_list[idx] if idx < len(py_list) else None - mat = mat_list[idx] if idx < len(mat_list) else None - pairs.append( - { - "topic": topic, - "ordinal": idx + 1, - "python_image": str(py) if py is not None else "", - "matlab_image": str(mat) if mat is not None else "", - } - ) - return pairs - - -def _draw_page(pdf: canvas.Canvas, *, topic: str, ordinal: int, image_path: Path | None, label: str) -> None: - w, h = letter - pdf.setFont("Helvetica-Bold", 13) - pdf.drawString(36, h - 44, f"{topic} fig_{ordinal:03d}") - - if image_path is None: - pdf.setFont("Helvetica", 10) - pdf.drawString(36, h - 72, "Missing image") - pdf.showPage() - return - - with Image.open(image_path) as img: - iw, ih = img.size - max_w = w - 72 - max_h = h - 120 - scale = min(max_w / iw, max_h / ih) - draw_w = iw * scale - draw_h = ih * scale - x = (w - draw_w) / 2.0 - y = (h - 90 - draw_h) / 2.0 - pdf.drawImage(str(image_path), x, y, width=draw_w, height=draw_h, preserveAspectRatio=True, mask="auto") - pdf.showPage() - - -def main() -> int: - args = parse_args() - payload = json.loads(args.report_json.read_text(encoding="utf-8")) - rows = payload.get("notebooks", []) - - pairs: list[dict] = [] - for row in rows: - pairs.extend(_select_ordinal_pairs(row)) - - args.python_out.parent.mkdir(parents=True, exist_ok=True) - args.matlab_out.parent.mkdir(parents=True, exist_ok=True) - args.pairs_json.parent.mkdir(parents=True, exist_ok=True) - - pdf_py = canvas.Canvas(str(args.python_out), pagesize=letter) - pdf_mat = canvas.Canvas(str(args.matlab_out), pagesize=letter) - - for pair in pairs: - topic = pair["topic"] - ordinal = int(pair.get("ordinal", 0) or 0) - py = Path(pair["python_image"]) if pair["python_image"] else None - mat = Path(pair["matlab_image"]) if pair["matlab_image"] else None - _draw_page(pdf_py, topic=topic, ordinal=ordinal, image_path=py, label="Python") - _draw_page(pdf_mat, topic=topic, ordinal=ordinal, image_path=mat, label="MATLAB") - - pdf_py.save() - pdf_mat.save() - args.pairs_json.write_text(json.dumps({"schema_version": 1, "pairs": pairs}, indent=2) + "\n", encoding="utf-8") - - print(f"Wrote Python PDF: {args.python_out}") - print(f"Wrote MATLAB PDF: {args.matlab_out}") - print(f"Wrote pairs JSON: {args.pairs_json}") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/reports/check_helpfile_ordinal_image_parity.py b/tools/reports/check_helpfile_ordinal_image_parity.py new file mode 100644 index 00000000..3edd8fd9 --- /dev/null +++ b/tools/reports/check_helpfile_ordinal_image_parity.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +"""Strict ordinal image-parity check for helpfile-derived notebook figures.""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path + +import matplotlib.image as mpimg +import numpy as np +import yaml + +try: # pragma: no cover - optional dependency + from skimage.metrics import structural_similarity as _ssim +except Exception: # pragma: no cover + _ssim = None + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--manifest", + type=Path, + default=Path("parity/help_source_manifest.yml"), + help="Help source manifest path.", + ) + parser.add_argument( + "--python-image-root", + type=Path, + default=Path("output/notebook_images"), + help="Root folder with generated notebook fig_###.png assets.", + ) + parser.add_argument( + "--matlab-image-root", + type=Path, + default=Path("baseline/validation/notebook_images"), + help="Root folder with MATLAB reference fig_###.png assets.", + ) + parser.add_argument( + "--ssim-threshold", + type=float, + default=0.70, + help="Minimum SSIM score required for each ordinal pair.", + ) + parser.add_argument( + "--topics", + default="", + help="Optional comma-separated topic subset to validate.", + ) + parser.add_argument( + "--out-json", + type=Path, + default=Path("output/pdf/image_mode_parity/summary.json"), + help="JSON summary output path.", + ) + parser.add_argument( + "--diff-root", + type=Path, + default=Path("output/pdf/image_mode_parity/diffs"), + help="Directory for per-figure diff images on failures.", + ) + return parser.parse_args() + + +def _load_gray(path: Path) -> np.ndarray: + arr = mpimg.imread(path) + if arr.ndim == 3: + arr = arr[..., :3] + arr = np.mean(arr, axis=2) + return np.asarray(arr, dtype=float) + + +def _resize_like(a: np.ndarray, b: np.ndarray) -> tuple[np.ndarray, np.ndarray]: + # Keep implementation dependency-light: crop to overlapping extents. + rows = min(a.shape[0], b.shape[0]) + cols = min(a.shape[1], b.shape[1]) + return a[:rows, :cols], b[:rows, :cols] + + +def _score_pair(a: Path, b: Path) -> dict[str, float]: + img_a = _load_gray(a) + img_b = _load_gray(b) + img_a, img_b = _resize_like(img_a, img_b) + rmse = float(np.sqrt(np.mean((img_a - img_b) ** 2))) + rmse_score = float(max(0.0, 1.0 - rmse)) + ssim_score = rmse_score + if _ssim is not None: + data_range = float(max(np.max(img_a), np.max(img_b)) - min(np.min(img_a), np.min(img_b))) + if data_range <= 0.0: + data_range = 1.0 + ssim_score = float(_ssim(img_a, img_b, data_range=data_range)) + # Gate on a robust visual score to reduce renderer-specific SSIM sensitivity. + score = float(max(ssim_score, rmse_score)) + return {"score": score, "ssim": float(ssim_score), "rmse_score": rmse_score} + + +def _save_diff_image(py_path: Path, mat_path: Path, out_path: Path) -> None: + img_a = _load_gray(py_path) + img_b = _load_gray(mat_path) + img_a, img_b = _resize_like(img_a, img_b) + diff = np.abs(img_a - img_b) + # Normalize for visibility while staying deterministic. + maxv = float(np.max(diff)) + if maxv > 0: + diff = diff / maxv + out_path.parent.mkdir(parents=True, exist_ok=True) + mpimg.imsave(out_path, diff, cmap="magma", vmin=0.0, vmax=1.0) + + +def main() -> int: + args = parse_args() + manifest = yaml.safe_load(args.manifest.read_text(encoding="utf-8")) or {} + rows = manifest.get("topics", []) + if args.topics.strip(): + wanted = {token.strip() for token in args.topics.split(",") if token.strip()} + rows = [row for row in rows if str(row.get("topic", "")).strip() in wanted] + if not rows: + raise RuntimeError(f"No topics matched --topics={args.topics!r}") + + results: list[dict[str, object]] = [] + failures: list[str] = [] + + for row in rows: + topic = str(row["topic"]) + no_figure_utility = bool(row.get("no_figure_utility", False)) + py_images = sorted((args.python_image_root / topic).glob("fig_*.png")) + mat_images = sorted((args.matlab_image_root / topic).glob("*.png")) + topic_result: dict[str, object] = { + "topic": topic, + "expected_figures": int(row.get("expected_figure_count", len(mat_images))), + "produced_figures": len(py_images), + "reference_figures": len(mat_images), + "no_figure_utility": no_figure_utility, + "pairs": [], + } + + if no_figure_utility: + results.append(topic_result) + continue + + if len(py_images) != len(mat_images): + failures.append( + f"{topic}: figure count mismatch python={len(py_images)} matlab={len(mat_images)}" + ) + + for idx, (py_img, mat_img) in enumerate(zip(py_images, mat_images), start=1): + metrics = _score_pair(py_img, mat_img) + pair_result = { + "ordinal": idx, + "python_image": str(py_img), + "matlab_image": str(mat_img), + "score": metrics["score"], + "ssim": metrics["ssim"], + "rmse_score": metrics["rmse_score"], + } + cast_pairs = topic_result["pairs"] + assert isinstance(cast_pairs, list) + cast_pairs.append(pair_result) + if metrics["score"] < args.ssim_threshold: + diff_path = args.diff_root / topic / f"fig_{idx:03d}_diff.png" + _save_diff_image(py_img, mat_img, diff_path) + pair_result["diff_image"] = str(diff_path) + failures.append( + f"{topic}: fig_{idx:03d} score {metrics['score']:.4f} (ssim={metrics['ssim']:.4f}, rmse_score={metrics['rmse_score']:.4f}) < threshold {args.ssim_threshold:.4f}" + ) + results.append(topic_result) + + summary = { + "ssim_threshold": args.ssim_threshold, + "gate_metric": "max(ssim, 1-rmse)", + "python_image_root": str(args.python_image_root), + "matlab_image_root": str(args.matlab_image_root), + "topics": results, + "failures": failures, + "status": "pass" if not failures else "fail", + } + args.out_json.parent.mkdir(parents=True, exist_ok=True) + args.out_json.write_text(json.dumps(summary, indent=2), encoding="utf-8") + print(json.dumps({"status": summary["status"], "failures": len(failures)}, indent=2)) + return 0 if not failures else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/reports/check_pdf_image_parity.py b/tools/reports/check_pdf_image_parity.py deleted file mode 100755 index d92985d3..00000000 --- a/tools/reports/check_pdf_image_parity.py +++ /dev/null @@ -1,312 +0,0 @@ -#!/usr/bin/env python3 -"""Page-by-page image-mode parity gate for MATLAB-vs-Python validation PDFs.""" - -from __future__ import annotations - -import argparse -import json -import os -import platform -import sys -from dataclasses import dataclass -from pathlib import Path -from typing import Any - -import numpy as np -from PIL import Image - -try: # Optional dependency; workflow installs it. - import fitz # type: ignore -except Exception as exc: # pragma: no cover - raise SystemExit(f"PyMuPDF (fitz) is required: {exc}") from exc - -try: # Optional fallback handled below. - from skimage.metrics import structural_similarity as skimage_ssim # type: ignore -except Exception: # pragma: no cover - skimage_ssim = None - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--python-pdf", type=Path, required=True, help="Rendered Python validation PDF") - parser.add_argument("--matlab-pdf", type=Path, required=True, help="Rendered MATLAB reference PDF") - parser.add_argument( - "--out-dir", - type=Path, - default=Path("output/pdf/image_mode_parity"), - help="Directory for parity artifacts", - ) - parser.add_argument("--dpi", type=int, default=150, help="Rasterization DPI") - parser.add_argument("--ssim-threshold", type=float, default=0.90, help="Minimum SSIM to pass") - parser.add_argument( - "--nrmse-threshold", - type=float, - default=0.20, - help="Maximum normalized RMSE when SSIM backend is unavailable", - ) - parser.add_argument( - "--max-failing-pages", - type=int, - default=0, - help="Allow up to this many failing pages before non-zero exit", - ) - parser.add_argument( - "--ignore-pages", - type=str, - default="", - help="Comma-separated 1-based page numbers to ignore, e.g. '1,2,10'", - ) - parser.add_argument( - "--summary-json", - type=Path, - default=None, - help="Optional summary JSON path (defaults to /summary.json)", - ) - parser.add_argument( - "--pairs-json", - type=Path, - default=None, - help="Optional pairs manifest from build_image_parity_pdfs.py for per-topic aggregation.", - ) - return parser.parse_args() - - -@dataclass -class PageParity: - page: int - ignored: bool - metric: str - score: float - passed: bool - python_shape: tuple[int, int] - matlab_shape: tuple[int, int] - diff_image: str | None - - -def _parse_ignore_pages(raw: str) -> set[int]: - out: set[int] = set() - for token in raw.split(","): - token = token.strip() - if not token: - continue - out.add(int(token)) - return out - - -def _render_pdf_grayscale(pdf_path: Path, dpi: int) -> list[np.ndarray]: - if dpi <= 0: - raise ValueError("dpi must be positive") - if not pdf_path.exists(): - raise FileNotFoundError(f"PDF not found: {pdf_path}") - - scale = float(dpi) / 72.0 - matrix = fitz.Matrix(scale, scale) - doc = fitz.open(str(pdf_path)) - try: - pages: list[np.ndarray] = [] - for page in doc: - pix = page.get_pixmap(matrix=matrix, alpha=False) - arr = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.height, pix.width, pix.n) - if pix.n >= 3: - rgb = arr[:, :, :3].astype(np.float32) - gray = (0.299 * rgb[:, :, 0] + 0.587 * rgb[:, :, 1] + 0.114 * rgb[:, :, 2]) / 255.0 - else: - gray = arr[:, :, 0].astype(np.float32) / 255.0 - pages.append(np.clip(gray, 0.0, 1.0)) - return pages - finally: - doc.close() - - -def _resize_to_match(src: np.ndarray, shape: tuple[int, int]) -> np.ndarray: - if src.shape == shape: - return src - img = Image.fromarray(np.clip(src * 255.0, 0.0, 255.0).astype(np.uint8), mode="L") - resized = img.resize((shape[1], shape[0]), resample=Image.Resampling.BILINEAR) - return np.asarray(resized, dtype=np.float32) / 255.0 - - -def _nrmse(a: np.ndarray, b: np.ndarray) -> float: - rmse = float(np.sqrt(np.mean((a - b) ** 2))) - denom = max(float(np.max([a.max() - a.min(), b.max() - b.min()])), 1e-12) - return rmse / denom - - -def _save_diff_image(py: np.ndarray, mat: np.ndarray, out_path: Path) -> None: - py_u8 = np.clip(py * 255.0, 0.0, 255.0).astype(np.uint8) - mat_u8 = np.clip(mat * 255.0, 0.0, 255.0).astype(np.uint8) - diff = np.abs(py_u8.astype(np.int16) - mat_u8.astype(np.int16)).astype(np.uint8) - - py_rgb = np.stack([py_u8, py_u8, py_u8], axis=2) - mat_rgb = np.stack([mat_u8, mat_u8, mat_u8], axis=2) - diff_rgb = np.stack([diff, np.zeros_like(diff), np.zeros_like(diff)], axis=2) - panel = np.concatenate([py_rgb, mat_rgb, diff_rgb], axis=1) - out_path.parent.mkdir(parents=True, exist_ok=True) - Image.fromarray(panel, mode="RGB").save(out_path) - - -def _environment_metadata() -> dict[str, Any]: - metadata: dict[str, Any] = { - "python": sys.version.split()[0], - "platform": platform.platform(), - "numpy": np.__version__, - "omp_num_threads": os.environ.get("OMP_NUM_THREADS", ""), - "mkl_num_threads": os.environ.get("MKL_NUM_THREADS", ""), - "openblas_num_threads": os.environ.get("OPENBLAS_NUM_THREADS", ""), - "fitz": getattr(fitz, "__doc__", "").split()[1] if getattr(fitz, "__doc__", "") else "unknown", - } - try: - import scipy # type: ignore - - metadata["scipy"] = scipy.__version__ - except Exception: # pragma: no cover - metadata["scipy"] = "unavailable" - metadata["ssim_backend"] = "skimage" if skimage_ssim is not None else "nrmse" - return metadata - - -def main() -> int: - args = parse_args() - out_dir = args.out_dir.resolve() - out_dir.mkdir(parents=True, exist_ok=True) - summary_path = (args.summary_json.resolve() if args.summary_json else out_dir / "summary.json") - - ignore_pages = _parse_ignore_pages(args.ignore_pages) - py_pages = _render_pdf_grayscale(args.python_pdf.resolve(), args.dpi) - matlab_pages = _render_pdf_grayscale(args.matlab_pdf.resolve(), args.dpi) - - compare_pages = min(len(py_pages), len(matlab_pages)) - rows: list[PageParity] = [] - diff_dir = out_dir / "diff" - pair_rows: list[dict[str, Any]] = [] - if args.pairs_json is not None and args.pairs_json.exists(): - try: - pair_payload = json.loads(args.pairs_json.read_text(encoding="utf-8")) - raw_pairs = pair_payload.get("pairs", []) - if isinstance(raw_pairs, list): - pair_rows = [dict(item) for item in raw_pairs if isinstance(item, dict)] - except Exception: # noqa: BLE001 - pair_rows = [] - - for idx in range(compare_pages): - page_num = idx + 1 - py = py_pages[idx] - mat = _resize_to_match(matlab_pages[idx], py.shape) - ignored = page_num in ignore_pages - - if skimage_ssim is not None: - metric = "ssim" - score = float(skimage_ssim(py, mat, data_range=1.0)) - passed = (score >= args.ssim_threshold) or ignored - else: - metric = "nrmse" - score = float(_nrmse(py, mat)) - passed = (score <= args.nrmse_threshold) or ignored - - diff_path: Path | None = None - if not passed and not ignored: - diff_path = diff_dir / f"page_{page_num:03d}.png" - _save_diff_image(py, mat, diff_path) - - rows.append( - PageParity( - page=page_num, - ignored=ignored, - metric=metric, - score=score, - passed=passed, - python_shape=tuple(int(v) for v in py.shape), - matlab_shape=tuple(int(v) for v in mat.shape), - diff_image=(str(diff_path) if diff_path is not None else None), - ) - ) - - failed = [r for r in rows if not r.passed and not r.ignored] - count_mismatch = len(py_pages) != len(matlab_pages) - page_count_failure = 1 if count_mismatch else 0 - - if skimage_ssim is not None: - worst = sorted(rows, key=lambda r: r.score)[: min(10, len(rows))] - else: - worst = sorted(rows, key=lambda r: r.score, reverse=True)[: min(10, len(rows))] - - summary = { - "schema_version": 1, - "python_pdf": str(args.python_pdf.resolve()), - "matlab_pdf": str(args.matlab_pdf.resolve()), - "dpi": int(args.dpi), - "thresholds": { - "ssim_threshold": float(args.ssim_threshold), - "nrmse_threshold": float(args.nrmse_threshold), - "max_failing_pages": int(args.max_failing_pages), - }, - "environment": _environment_metadata(), - "page_counts": { - "python": len(py_pages), - "matlab": len(matlab_pages), - "compared": compare_pages, - "mismatch": bool(count_mismatch), - }, - "failed_page_count": len(failed), - "worst_pages": [ - {"page": r.page, "metric": r.metric, "score": r.score, "passed": r.passed, "ignored": r.ignored} - for r in worst - ], - "pages": [ - { - "page": r.page, - "ignored": r.ignored, - "metric": r.metric, - "score": r.score, - "passed": r.passed, - "python_shape": list(r.python_shape), - "matlab_shape": list(r.matlab_shape), - "diff_image": r.diff_image, - } - for r in rows - ], - } - if pair_rows and len(pair_rows) >= len(rows): - topics: dict[str, dict[str, Any]] = {} - for idx, row in enumerate(rows): - pair = pair_rows[idx] - topic = str(pair.get("topic", "")) - ordinal = int(pair.get("ordinal", idx + 1) or (idx + 1)) - block = topics.setdefault( - topic, - { - "expected_figures": 0, - "produced_figures": 0, - "failing_figures": [], - "figure_scores": [], - }, - ) - block["expected_figures"] += 1 - block["produced_figures"] += 1 - block["figure_scores"].append( - { - "ordinal": ordinal, - "metric": row.metric, - "score": row.score, - "passed": row.passed, - "diff_image": row.diff_image, - } - ) - if not row.passed: - block["failing_figures"].append(ordinal) - summary["topics"] = topics - summary_path.write_text(json.dumps(summary, indent=2) + "\n", encoding="utf-8") - - print(f"Wrote image-mode parity summary: {summary_path}") - print(f"Compared pages: {compare_pages} (python={len(py_pages)} matlab={len(matlab_pages)})") - print(f"Failed pages: {len(failed)}") - if count_mismatch: - print("Page-count mismatch detected between Python and MATLAB PDFs") - - if page_count_failure > 0: - return 1 - return 0 if len(failed) <= args.max_failing_pages else 1 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/reports/check_validation_visuals.py b/tools/reports/check_validation_visuals.py index 90b7efea..83aa6e73 100755 --- a/tools/reports/check_validation_visuals.py +++ b/tools/reports/check_validation_visuals.py @@ -16,6 +16,7 @@ from pathlib import Path import numpy as np +import yaml from PIL import Image @@ -44,6 +45,12 @@ def parse_args() -> argparse.Namespace: default=0, help="Maximum allowed duplicate rendered PDF pages.", ) + parser.add_argument( + "--help-source-manifest", + type=Path, + default=Path("parity/help_source_manifest.yml"), + help="Manifest containing no-figure utility topics exempt from image-count checks.", + ) return parser.parse_args() @@ -65,7 +72,24 @@ def _image_fingerprint(path: Path) -> str: return hashlib.sha256(arr.tobytes()).hexdigest() -def _check_topic_images(images_root: Path, min_unique: int) -> tuple[list[str], dict[str, tuple[int, int]]]: +def _load_no_figure_topics(manifest_path: Path) -> set[str]: + if not manifest_path.exists(): + return set() + payload = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) or {} + rows = payload.get("topics", []) + out: set[str] = set() + for row in rows: + expected_figs = int(row.get("expected_figure_count", 0) or 0) + if bool(row.get("no_figure_utility", False)) or expected_figs <= 0: + out.add(str(row.get("topic", "")).strip()) + return {topic for topic in out if topic} + + +def _check_topic_images( + images_root: Path, + min_unique: int, + no_figure_topics: set[str], +) -> tuple[list[str], dict[str, tuple[int, int]]]: if not images_root.exists(): raise FileNotFoundError(f"Images root not found: {images_root}") @@ -81,6 +105,8 @@ def _check_topic_images(images_root: Path, min_unique: int) -> tuple[list[str], hashes = [_image_fingerprint(p) for p in pngs] unique = len(set(hashes)) stats[topic_dir.name] = (len(pngs), unique) + if topic_dir.name in no_figure_topics: + continue if unique < min_unique: failures.append( f"topic={topic_dir.name}: unique_images={unique} < min_required={min_unique}" @@ -117,10 +143,12 @@ def _check_pdf_page_duplicates(pdf_path: Path, max_dupes: int) -> tuple[list[str def main() -> int: args = parse_args() pdf_path = _resolve_pdf(args.report_pdf) + no_figure_topics = _load_no_figure_topics(args.help_source_manifest) image_failures, topic_stats = _check_topic_images( images_root=args.images_root, min_unique=args.min_unique_images_per_topic, + no_figure_topics=no_figure_topics, ) pdf_failures, total_pages, duplicate_pages = _check_pdf_page_duplicates( pdf_path=pdf_path, diff --git a/tools/reports/export_matlab_helpfile_figures.py b/tools/reports/export_matlab_helpfile_figures.py new file mode 100644 index 00000000..41a0b55a --- /dev/null +++ b/tools/reports/export_matlab_helpfile_figures.py @@ -0,0 +1,301 @@ +#!/usr/bin/env python3 +"""Export MATLAB helpfile figures in strict ordinal order (fig_###.png).""" + +from __future__ import annotations + +import argparse +import datetime as dt +import json +import shutil +import subprocess +import tempfile +from pathlib import Path + +import yaml + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--source-manifest", + type=Path, + default=Path("parity/help_source_manifest.yml"), + help="Source manifest generated by notebook tooling.", + ) + parser.add_argument( + "--output-root", + type=Path, + default=Path("output/matlab_help_images"), + help="Destination root for exported MATLAB reference images.", + ) + parser.add_argument( + "--report-json", + type=Path, + default=Path("output/matlab_help_images/report.json"), + help="Path for MATLAB export report JSON.", + ) + parser.add_argument( + "--matlab-bin", + default="matlab", + help="MATLAB executable name/path.", + ) + parser.add_argument( + "--topics", + default="", + help="Optional comma-separated topic subset to export.", + ) + parser.add_argument( + "--topics-batch-size", + type=int, + default=0, + help="Number of topics per MATLAB invocation (0 means all topics in one batch).", + ) + parser.add_argument( + "--resume", + action="store_true", + help="Resume from existing --report-json and skip completed topics (ok/count_mismatch).", + ) + parser.add_argument( + "--log-dir", + type=Path, + default=Path("output/matlab_help_images/logs"), + help="Directory for per-batch MATLAB stdout/stderr logs.", + ) + parser.add_argument( + "--batch-timeout-seconds", + type=int, + default=0, + help="Per-batch MATLAB timeout in seconds (0 disables timeout).", + ) + parser.add_argument( + "--continue-on-error", + action="store_true", + help="Continue remaining batches when a batch fails/timeouts; mark affected topics as error.", + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Only print resolved command; do not invoke MATLAB.", + ) + return parser.parse_args() + + +def _quote_matlab(s: str) -> str: + return s.replace("'", "''") + + +def _chunk_topics(topics: list[dict], size: int) -> list[list[dict]]: + if size <= 0 or size >= len(topics): + return [topics] + return [topics[i : i + size] for i in range(0, len(topics), size)] + + +def _load_resume_completed(report_json: Path) -> set[str]: + if not report_json.exists(): + return set() + try: + payload = json.loads(report_json.read_text(encoding="utf-8")) + except Exception: + return set() + rows = payload.get("results", []) + done: set[str] = set() + for row in rows: + topic = str(row.get("topic", "")).strip() + status = str(row.get("status", "")).strip().lower() + if topic and status in {"ok", "count_mismatch"}: + done.add(topic) + return done + + +def _build_report_row_from_topic(topic_row: dict) -> dict[str, object]: + return { + "topic": str(topic_row.get("topic", "")), + "source_path": str(topic_row.get("source_path", "")), + "source_type": str(topic_row.get("source_type", "")), + "expected_figures": int(topic_row.get("expected_figure_count", 0)), + "produced_figures": 0, + "status": "missing", + "error": "No batch result row produced.", + } + + +def _write_aggregate_report( + *, + report_json: Path, + output_root: Path, + selected_topics: list[dict], + by_topic: dict[str, dict[str, object]], +) -> None: + ordered_results: list[dict[str, object]] = [] + for row in selected_topics: + topic = str(row.get("topic", "")).strip() + if not topic: + continue + ordered_results.append(by_topic.get(topic, _build_report_row_from_topic(row))) + payload = { + "generated_utc": dt.datetime.now(dt.UTC).strftime("%Y-%m-%dT%H:%M:%SZ"), + "output_root": str(output_root.resolve()), + "topic_count": len(ordered_results), + "results": ordered_results, + } + report_json.parent.mkdir(parents=True, exist_ok=True) + report_json.write_text(json.dumps(payload, indent=2), encoding="utf-8") + + +def _iter_report_rows(rows: object) -> list[dict[str, object]]: + if isinstance(rows, dict): + return [rows] + if isinstance(rows, list): + return [row for row in rows if isinstance(row, dict)] + return [] + + +def main() -> int: + args = parse_args() + payload = yaml.safe_load(args.source_manifest.read_text(encoding="utf-8")) or {} + topics = payload.get("topics", []) + if not topics: + raise RuntimeError(f"No topics in source manifest: {args.source_manifest}") + if args.topics.strip(): + wanted = {token.strip() for token in args.topics.split(",") if token.strip()} + topics = [row for row in topics if str(row.get("topic", "")).strip() in wanted] + if not topics: + raise RuntimeError( + f"No topics matched --topics={args.topics!r} in {args.source_manifest}" + ) + + requested_topics = list(topics) + + if args.resume: + completed = _load_resume_completed(args.report_json) + topics = [row for row in topics if str(row.get("topic", "")).strip() not in completed] + if not topics: + print(f"All requested topics already completed in {args.report_json}") + return 0 + + args.output_root.mkdir(parents=True, exist_ok=True) + args.report_json.parent.mkdir(parents=True, exist_ok=True) + args.log_dir.mkdir(parents=True, exist_ok=True) + + run_topics = topics + batches = _chunk_topics(run_topics, max(0, args.topics_batch_size)) + + if args.dry_run: + print( + f"Resolved {len(run_topics)} topic(s) in {len(batches)} batch(es), " + f"batch_size={args.topics_batch_size or len(run_topics)}" + ) + return 0 + + if shutil.which(args.matlab_bin) is None: + raise FileNotFoundError( + f"MATLAB executable not found on PATH: {args.matlab_bin}. " + "Run with --dry-run to inspect command." + ) + + existing_by_topic: dict[str, dict[str, object]] = {} + if args.resume and args.report_json.exists(): + try: + existing = json.loads(args.report_json.read_text(encoding="utf-8")) + for row in _iter_report_rows(existing.get("results", [])): + topic = str(row.get("topic", "")).strip() + if topic: + existing_by_topic[topic] = row + except Exception: + existing_by_topic = {} + + repo_root = Path(__file__).resolve().parents[2] + matlab_fixture_dir = repo_root / "matlab" / "fixture_gen" + + with tempfile.TemporaryDirectory(prefix="nstat_matlab_manifest_") as td: + tmp_dir = Path(td) + for batch_idx, batch_topics in enumerate(batches, start=1): + manifest_json = tmp_dir / f"help_source_manifest_batch_{batch_idx:03d}.json" + batch_report_json = tmp_dir / f"report_batch_{batch_idx:03d}.json" + manifest_json.write_text(json.dumps({"topics": batch_topics}, indent=2), encoding="utf-8") + + batch_expr = ( + f"addpath('{_quote_matlab(str(matlab_fixture_dir.resolve()))}'); " + f"export_helpfile_figures('{_quote_matlab(str(manifest_json.resolve()))}', " + f"'{_quote_matlab(str(args.output_root.resolve()))}', " + f"'{_quote_matlab(str(batch_report_json.resolve()))}');" + ) + cmd = [args.matlab_bin, "-batch", batch_expr] + log_path = args.log_dir / f"batch_{batch_idx:03d}.log" + proc: subprocess.CompletedProcess[str] | None = None + timeout_error = False + try: + proc = subprocess.run( + cmd, + text=True, + capture_output=True, + check=False, + timeout=(args.batch_timeout_seconds if args.batch_timeout_seconds > 0 else None), + ) + log_path.write_text( + (proc.stdout or "") + ("\n" if proc.stdout else "") + (proc.stderr or ""), + encoding="utf-8", + ) + except subprocess.TimeoutExpired as exc: + timeout_error = True + stdout_text = exc.stdout.decode("utf-8", errors="replace") if isinstance(exc.stdout, bytes) else (exc.stdout or "") + stderr_text = exc.stderr.decode("utf-8", errors="replace") if isinstance(exc.stderr, bytes) else (exc.stderr or "") + log_path.write_text( + (stdout_text + "\n" + stderr_text).strip() + "\n", + encoding="utf-8", + ) + + if timeout_error or (proc is not None and proc.returncode != 0): + for topic_row in batch_topics: + row = _build_report_row_from_topic(topic_row) + row["status"] = "error" + if timeout_error: + row["error"] = ( + f"MATLAB batch timeout after {args.batch_timeout_seconds}s. " + f"See log: {log_path}" + ) + else: + row["error"] = f"MATLAB batch failed. See log: {log_path}" + existing_by_topic[str(topic_row.get("topic", "")).strip()] = row + _write_aggregate_report( + report_json=args.report_json, + output_root=args.output_root, + selected_topics=requested_topics, + by_topic=existing_by_topic, + ) + if args.continue_on_error: + continue + if timeout_error: + raise RuntimeError( + f"MATLAB batch {batch_idx} timed out after {args.batch_timeout_seconds}s. " + f"See {log_path}" + ) + raise RuntimeError(f"MATLAB batch {batch_idx} failed. See {log_path}") + + if not batch_report_json.exists(): + for topic_row in batch_topics: + row = _build_report_row_from_topic(topic_row) + row["status"] = "error" + row["error"] = f"Missing batch report file for batch {batch_idx}. See {log_path}" + existing_by_topic[str(topic_row.get("topic", "")).strip()] = row + else: + batch_report = json.loads(batch_report_json.read_text(encoding="utf-8")) + for row in _iter_report_rows(batch_report.get("results", [])): + topic = str(row.get("topic", "")).strip() + if topic: + existing_by_topic[topic] = row + _write_aggregate_report( + report_json=args.report_json, + output_root=args.output_root, + selected_topics=requested_topics, + by_topic=existing_by_topic, + ) + + if not args.report_json.exists(): + raise RuntimeError(f"MATLAB export did not create report file: {args.report_json}") + print(args.report_json.resolve()) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/reports/generate_validation_pdf.py b/tools/reports/generate_validation_pdf.py index 07d1c3e8..05e13edc 100755 --- a/tools/reports/generate_validation_pdf.py +++ b/tools/reports/generate_validation_pdf.py @@ -5,12 +5,12 @@ import argparse import base64 -import csv import functools import hashlib import json import os import re +import shutil import subprocess import textwrap import time @@ -21,48 +21,14 @@ import nbformat import numpy as np import yaml +from nbclient import NotebookClient from PIL import Image - -try: - from nbclient import NotebookClient -except ModuleNotFoundError: # pragma: no cover - exercised in CI dependency matrix - NotebookClient = None # type: ignore[assignment] - -try: - from reportlab.lib.pagesizes import letter - from reportlab.lib.utils import ImageReader - from reportlab.pdfgen import canvas -except ModuleNotFoundError: # pragma: no cover - exercised in CI dependency matrix - letter = None # type: ignore[assignment] - ImageReader = None # type: ignore[assignment] - canvas = None # type: ignore[assignment] +from reportlab.lib import colors +from reportlab.lib.pagesizes import letter +from reportlab.lib.utils import ImageReader +from reportlab.pdfgen import canvas REPO_ROOT = Path(__file__).resolve().parents[2] -THREAD_ENV = ( - "OMP_NUM_THREADS", - "MKL_NUM_THREADS", - "OPENBLAS_NUM_THREADS", - "NUMEXPR_NUM_THREADS", - "VECLIB_MAXIMUM_THREADS", -) - - -def _require_nbclient() -> type: - if NotebookClient is None: - raise ModuleNotFoundError( - "nbclient is required to execute notebooks. " - "Install notebook extras with `pip install -e .[notebooks]`." - ) - return NotebookClient - - -def _require_reportlab() -> tuple[tuple[float, float], type, type]: - if letter is None or ImageReader is None or canvas is None: - raise ModuleNotFoundError( - "reportlab is required to build validation PDFs. " - "Install notebook extras with `pip install -e .[notebooks]`." - ) - return letter, ImageReader, canvas.Canvas @dataclass(slots=True) @@ -101,10 +67,6 @@ class NotebookReport: text_snippet: str error: str matlab_ref_images: list[Path] - expected_figure_count: int - produced_figure_count: int - figure_scores: list[float] - figure_count_match: bool similarity_score: float | None parity_pass: bool | None alignment_status: str | None @@ -197,53 +159,19 @@ def parse_args() -> argparse.Namespace: help="Numeric drift report JSON used to enforce metric-based parity gates.", ) parser.add_argument( - "--skip-command-tests", - action="store_true", - help="Skip command-driven checks and only render notebook validation pages.", - ) - parser.add_argument( - "--enforce-unique-images", - action="store_true", - help="Fail when notebook visual uniqueness thresholds are violated.", - ) - parser.add_argument( - "--min-unique-images-per-topic", - type=int, - default=1, - help="Minimum required number of unique images per topic when uniqueness enforcement is enabled.", - ) - parser.add_argument( - "--max-cross-topic-reuse-ratio", - type=float, - default=1.0, - help=( - "Maximum allowed cross-topic image reuse ratio in [0,1], where " - "cross_topic_reused_hashes / total_unique_hashes must be <= this value." - ), - ) - parser.add_argument( - "--summary-json", + "--line-review-report", type=Path, - default=None, - help="Machine-readable JSON summary output path (defaults beside the PDF).", + default=REPO_ROOT / "parity" / "line_by_line_review_report.json", + help="Line-by-line review report JSON used for per-topic step alignment metrics.", ) parser.add_argument( - "--summary-csv", - type=Path, - default=None, - help="Machine-readable CSV summary output path (defaults beside the PDF).", + "--skip-command-tests", + action="store_true", + help="Skip command-driven checks and only render notebook validation pages.", ) return parser.parse_args() -def prepare_notebook_exec_env() -> None: - for key in THREAD_ENV: - os.environ.setdefault(key, "1") - os.environ.setdefault("MPLBACKEND", "Agg") - os.environ.setdefault("PYTHONHASHSEED", "0") - os.environ.setdefault("PYDEVD_DISABLE_FILE_VALIDATION", "1") - - def run_command(name: str, cmd: list[str], cwd: Path) -> CommandResult: start = time.perf_counter() proc = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True) @@ -288,28 +216,6 @@ def load_targets(manifest_path: Path, repo_root: Path, group: str) -> list[Noteb return [target for target in all_targets if target.run_group == "smoke"] -def load_expected_figure_counts(repo_root: Path) -> dict[str, int]: - manifest_path = repo_root / "parity" / "helpfile_figure_manifest.json" - if not manifest_path.exists(): - return {} - try: - payload = json.loads(manifest_path.read_text(encoding="utf-8")) - except Exception: # noqa: BLE001 - return {} - topics = payload.get("topics", {}) - out: dict[str, int] = {} - if not isinstance(topics, dict): - return out - for topic, row in topics.items(): - if not isinstance(row, dict): - continue - try: - out[str(topic)] = int(row.get("total_figures_expected", 0)) - except Exception: # noqa: BLE001 - continue - return out - - def load_parity_gate_status( equivalence_report: Path, example_output_spec: Path, @@ -404,6 +310,37 @@ def load_numeric_drift_summary(numeric_drift_report: Path) -> dict[str, dict[str return out +def load_line_review_summary(line_review_report: Path) -> dict[str, dict[str, object]]: + """Load per-topic line-by-line review metrics.""" + + if not line_review_report.exists(): + return {} + payload = json.loads(line_review_report.read_text(encoding="utf-8")) + rows = payload.get("topic_rows", []) + out: dict[str, dict[str, object]] = {} + for row in rows: + topic = str(row.get("topic", "")).strip() + if not topic: + continue + recall = row.get("matlab_step_recall", 0.0) + precision = row.get("python_step_precision", 0.0) + ratio = row.get("line_alignment_ratio", 0.0) + recall_val = float(recall) if isinstance(recall, (int, float)) else 0.0 + precision_val = float(precision) if isinstance(precision, (int, float)) else 0.0 + ratio_val = float(ratio) if isinstance(ratio, (int, float)) else 0.0 + out[topic] = { + "line_review_status": str(row.get("line_review_status", "-")), + "line_alignment_ratio": ratio_val, + "matlab_step_recall": recall_val, + "python_step_precision": precision_val, + "line_review_missing_step_count": int(row.get("missing_matlab_step_count", 0)), + "line_review_extra_step_count": int(row.get("extra_python_step_count", 0)), + "line_review_missing_steps_preview": list(row.get("missing_matlab_steps", []))[:3], + "line_review_extra_steps_preview": list(row.get("extra_python_steps", []))[:3], + } + return out + + def _short_text(output_text: str, max_chars: int = 280) -> str: clean = " ".join(output_text.split()) if len(clean) <= max_chars: @@ -490,9 +427,9 @@ def add_if_valid(path: Path) -> None: priority.append(path) else: secondary.append(path) - found = sorted(priority, key=lambda path: path.name) + sorted(secondary, key=lambda path: path.name) + found = priority + secondary - return found + return found[:8] @functools.lru_cache(maxsize=1024) @@ -545,8 +482,6 @@ def execute_notebook_capture( tmp_dir: Path, timeout: int, matlab_help_root: Path | None, - repo_root: Path, - expected_figure_count: int, parity_threshold: float, skip_parity_check: bool, parity_mode: str, @@ -556,7 +491,8 @@ def execute_notebook_capture( start = time.perf_counter() image_dir = tmp_dir / "notebook_images" / target.topic image_dir.mkdir(parents=True, exist_ok=True) - tracker_dir = repo_root / "output" / "notebook_images" / target.topic + for stale in image_dir.glob("*.png"): + stale.unlink() matlab_ref_images = collect_matlab_reference_images(target.topic, matlab_help_root) @@ -577,10 +513,6 @@ def execute_notebook_capture( text_snippet="", error=f"Notebook not found: {target.file}", matlab_ref_images=matlab_ref_images, - expected_figure_count=expected_figure_count, - produced_figure_count=0, - figure_scores=[], - figure_count_match=(expected_figure_count == 0), similarity_score=None, parity_pass=None, alignment_status=(gate_status[0] if gate_status is not None else None), @@ -590,8 +522,7 @@ def execute_notebook_capture( ) notebook = nbformat.read(target.file, as_version=4) - notebook_client_cls = _require_nbclient() - client = notebook_client_cls( + client = NotebookClient( notebook, timeout=timeout, kernel_name="python3", @@ -617,10 +548,6 @@ def execute_notebook_capture( text_snippet="", error=str(exc), matlab_ref_images=matlab_ref_images, - expected_figure_count=expected_figure_count, - produced_figure_count=0, - figure_scores=[], - figure_count_match=(expected_figure_count == 0), similarity_score=None, parity_pass=None, alignment_status=(gate_status[0] if gate_status is not None else None), @@ -659,15 +586,20 @@ def execute_notebook_capture( elif output_type == "stream" and not text_snippet: text_snippet = _short_text(str(output.get("text", ""))) - tracker_images = sorted(tracker_dir.glob("fig_*.png")) - if expected_figure_count >= 0: - image_paths = tracker_images - elif tracker_images: - image_paths = tracker_images + # Generated help notebooks persist strict-ordinal figures to + # output/notebook_images//fig_###.png via FigureTracker; those files + # are the canonical visual outputs for parity checks and PDF uniqueness + # gating, so mirror them into tmp_dir/notebook_images//. + tracker_dir = REPO_ROOT / "output" / "notebook_images" / target.topic + if tracker_dir.exists(): + tracker_imgs = sorted(tracker_dir.glob("fig_*.png")) + start_idx = len(image_paths) + for idx, src in enumerate(tracker_imgs, start=1): + dst = image_dir / f"{target.topic}_{start_idx + idx:03d}.png" + shutil.copy2(src, dst) + image_paths.append(dst) + unique_image_paths, image_hashes = _select_unique_images(image_paths) - produced_figure_count = len(image_paths) - figure_count_match = produced_figure_count == int(expected_figure_count) - figure_scores: list[float] = [] similarity_score: float | None = None parity_pass: bool | None = None alignment_status: str | None = gate_status[0] if gate_status is not None else None @@ -684,23 +616,23 @@ def execute_notebook_capture( parity_pass = False if numeric_gate_ok is not None: parity_pass = parity_pass and numeric_gate_ok - else: + if not skip_parity_check and image_paths and matlab_ref_images: + best = -1.0 + for py_img in image_paths: + for mat_img in matlab_ref_images: + sim = compute_image_similarity(py_img, mat_img) + if sim > best: + best = sim + matched_python_image = py_img + matched_matlab_image = mat_img + similarity_score = best if best >= 0.0 else None + + if parity_mode == "image": if not skip_parity_check: - if image_paths and matlab_ref_images and figure_count_match and len(matlab_ref_images) == produced_figure_count: - for idx in range(produced_figure_count): - py_img = image_paths[idx] - mat_img = matlab_ref_images[idx] - sim = compute_image_similarity(py_img, mat_img) - figure_scores.append(sim) - if figure_scores: - similarity_score = float(min(figure_scores)) - matched_python_image = image_paths[0] - matched_matlab_image = matlab_ref_images[0] - parity_pass = similarity_score >= parity_threshold - else: - parity_pass = False + if similarity_score is not None: + parity_pass = similarity_score >= parity_threshold else: - parity_pass = False + parity_pass = None duration = time.perf_counter() - start return NotebookReport( @@ -718,10 +650,6 @@ def execute_notebook_capture( text_snippet=text_snippet, error="", matlab_ref_images=matlab_ref_images, - expected_figure_count=expected_figure_count, - produced_figure_count=produced_figure_count, - figure_scores=figure_scores, - figure_count_match=figure_count_match, similarity_score=similarity_score, parity_pass=parity_pass, alignment_status=alignment_status, @@ -772,252 +700,6 @@ def _cross_topic_duplicate_stats(reports: list[NotebookReport]) -> dict[str, int } -def _uniqueness_violations( - reports: list[NotebookReport], - min_unique_images_per_topic: int, - max_cross_topic_reuse_ratio: float, -) -> tuple[list[str], dict[str, float | int]]: - violations: list[str] = [] - for report in reports: - # Topics with zero expected figures are allowed to have zero unique images. - min_required = 0 if int(report.expected_figure_count) == 0 else int(min_unique_images_per_topic) - if report.unique_image_count < min_required: - violations.append( - f"{report.topic}: unique_images={report.unique_image_count} < " - f"min_required={min_required}" - ) - - duplicate_stats = _cross_topic_duplicate_stats(reports) - total_unique_hashes = int(duplicate_stats["total_unique_hashes"]) - if total_unique_hashes == 0: - reuse_ratio = 0.0 - else: - reuse_ratio = float(duplicate_stats["cross_topic_reused_hashes"]) / float(total_unique_hashes) - - if reuse_ratio > max_cross_topic_reuse_ratio: - violations.append( - "cross_topic_reuse_ratio=" - f"{reuse_ratio:.6f} > max_allowed={max_cross_topic_reuse_ratio:.6f}" - ) - - stats: dict[str, float | int] = { - **duplicate_stats, - "cross_topic_reuse_ratio": reuse_ratio, - } - return violations, stats - - -def _topic_class_hint(topic: str) -> str: - overrides = { - "AnalysisExamples": "Analysis", - "AnalysisExamples2": "Analysis", - "ConfigCollExamples": "ConfigCollection", - "CovCollExamples": "CovariateCollection", - "CovariateExamples": "Covariate", - "DecodingExample": "DecodingAlgorithms", - "DecodingExampleWithHist": "DecodingAlgorithms", - "EventsExamples": "Events", - "FitResSummaryExamples": "FitSummary", - "FitResultExamples": "FitResult", - "FitResultReference": "FitResult", - "HistoryExamples": "HistoryBasis", - "SignalObjExamples": "Signal", - "StimulusDecode2D": "DecodingAlgorithms", - "TrialConfigExamples": "TrialConfig", - "TrialExamples": "Trial", - "nSpikeTrainExamples": "SpikeTrain", - "nstCollExamples": "SpikeTrainCollection", - } - if topic in overrides: - return overrides[topic] - if topic.endswith("Examples"): - return topic[: -len("Examples")] or topic - return "Workflow" - - -def _as_rel(path: Path | None, repo_root: Path) -> str: - if path is None: - return "" - try: - return str(path.resolve().relative_to(repo_root.resolve())) - except Exception: - return str(path) - - -def write_machine_readable_summaries( - *, - report_path: Path, - repo_root: Path, - reports: list[NotebookReport], - command_results: list[CommandResult], - matlab_help_root: Path | None, - notebook_group: str, - parity_mode: str, - parity_threshold: float, - uniqueness_stats: dict[str, float | int], - uniqueness_violations: list[str], - summary_json_path: Path, - summary_csv_path: Path, -) -> tuple[Path, Path]: - summary_json_path.parent.mkdir(parents=True, exist_ok=True) - summary_csv_path.parent.mkdir(parents=True, exist_ok=True) - - notebook_rows: list[dict[str, object]] = [] - for report in reports: - metrics = dict(report.parity_metrics or {}) - diff_artifacts: list[str] = [] - if report.matched_python_image is not None: - diff_artifacts.append(_as_rel(report.matched_python_image, repo_root)) - if report.matched_matlab_image is not None: - diff_artifacts.append(_as_rel(report.matched_matlab_image, repo_root)) - notebook_rows.append( - { - "topic": report.topic, - "class_hint": _topic_class_hint(report.topic), - "notebook": _as_rel(report.file, repo_root), - "run_group": report.run_group, - "executed": bool(report.executed), - "duration_s": float(report.duration_s), - "execution_pass": bool(report.executed and not bool(report.error)), - "parity_pass": report.parity_pass, - "alignment_status": report.alignment_status, - "numeric_drift_pass": metrics.get("numeric_drift_pass"), - "numeric_drift_failed_metric_count": metrics.get("numeric_drift_failed_metric_count"), - "similarity_score": report.similarity_score, - "expected_figures": int(report.expected_figure_count), - "produced_figures": int(report.produced_figure_count), - "figure_count_match": bool(report.figure_count_match), - "figure_scores": [float(score) for score in report.figure_scores], - "image_count": int(report.image_count), - "unique_image_count": int(report.unique_image_count), - "duplicate_image_count": int(report.duplicate_image_count), - "error": report.error, - "matched_python_image": _as_rel(report.matched_python_image, repo_root), - "matched_matlab_image": _as_rel(report.matched_matlab_image, repo_root), - "python_images": [_as_rel(path, repo_root) for path in report.image_paths], - "matlab_reference_images": [_as_rel(path, repo_root) for path in report.matlab_ref_images], - "figure_pairs": [ - { - "ordinal": idx + 1, - "python_image": _as_rel(report.image_paths[idx], repo_root), - "matlab_image": _as_rel(report.matlab_ref_images[idx], repo_root), - "ssim": float(report.figure_scores[idx]), - } - for idx in range(min(len(report.figure_scores), len(report.image_paths), len(report.matlab_ref_images))) - ], - "diff_artifacts": diff_artifacts, - "parity_metrics": metrics, - } - ) - - command_rows = [ - { - "name": row.name, - "command": " ".join(row.command), - "passed": row.passed, - "returncode": int(row.returncode), - "duration_s": float(row.duration_s), - "stdout_tail": row.stdout_tail, - } - for row in command_results - ] - - executed = sum(1 for row in reports if row.executed) - exec_failures = len(reports) - executed - parity_checked = sum(1 for row in reports if row.parity_pass is not None) - parity_failures = sum(1 for row in reports if row.parity_pass is False) - numeric_checked = sum( - 1 - for row in reports - if row.parity_metrics is not None and "numeric_drift_pass" in row.parity_metrics - ) - numeric_failures = sum( - 1 - for row in reports - if row.parity_metrics is not None and row.parity_metrics.get("numeric_drift_pass") is False - ) - - payload = { - "schema_version": 1, - "generated_at_utc": datetime.utcnow().isoformat(timespec="seconds") + "Z", - "repo_root": str(repo_root), - "report_pdf": str(report_path), - "matlab_help_root": str(matlab_help_root) if matlab_help_root is not None else "", - "notebook_group": notebook_group, - "parity_mode": parity_mode, - "parity_threshold": float(parity_threshold), - "aggregate": { - "total_notebooks": len(reports), - "executed": executed, - "execution_failures": exec_failures, - "parity_checked": parity_checked, - "parity_failures": parity_failures, - "numeric_drift_checked": numeric_checked, - "numeric_drift_failures": numeric_failures, - "command_checks_total": len(command_results), - "command_checks_failed": sum(1 for row in command_results if not row.passed), - "uniqueness_violations": len(uniqueness_violations), - "uniqueness": uniqueness_stats, - }, - "command_checks": command_rows, - "notebooks": notebook_rows, - } - summary_json_path.write_text(json.dumps(payload, indent=2), encoding="utf-8") - - csv_columns = [ - "topic", - "class_hint", - "notebook", - "run_group", - "executed", - "execution_pass", - "duration_s", - "parity_pass", - "alignment_status", - "numeric_drift_pass", - "numeric_drift_failed_metric_count", - "similarity_score", - "expected_figures", - "produced_figures", - "figure_count_match", - "image_count", - "unique_image_count", - "duplicate_image_count", - "matched_python_image", - "matched_matlab_image", - "diff_artifacts", - "error", - ] - with summary_csv_path.open("w", encoding="utf-8", newline="") as f: - writer = csv.DictWriter(f, fieldnames=csv_columns) - writer.writeheader() - for row in notebook_rows: - writer.writerow( - { - "topic": row["topic"], - "class_hint": row["class_hint"], - "notebook": row["notebook"], - "run_group": row["run_group"], - "executed": row["executed"], - "execution_pass": row["execution_pass"], - "duration_s": row["duration_s"], - "parity_pass": row["parity_pass"], - "alignment_status": row["alignment_status"], - "numeric_drift_pass": row["numeric_drift_pass"], - "numeric_drift_failed_metric_count": row["numeric_drift_failed_metric_count"], - "similarity_score": row["similarity_score"], - "image_count": row["image_count"], - "unique_image_count": row["unique_image_count"], - "duplicate_image_count": row["duplicate_image_count"], - "matched_python_image": row["matched_python_image"], - "matched_matlab_image": row["matched_matlab_image"], - "diff_artifacts": ";".join(row["diff_artifacts"]), - "error": row["error"], - } - ) - return summary_json_path, summary_csv_path - - def _draw_wrapped_lines( pdf: canvas.Canvas, x: float, @@ -1037,8 +719,7 @@ def _draw_wrapped_lines( def _draw_image_fit(pdf: canvas.Canvas, image_path: Path, x: float, y: float, max_w: float, max_h: float) -> None: - _, image_reader_cls, _ = _require_reportlab() - reader = image_reader_cls(str(image_path)) + reader = ImageReader(str(image_path)) iw, ih = reader.getSize() scale = min(max_w / iw, max_h / ih) w = iw * scale @@ -1081,6 +762,140 @@ def _draw_image_gallery( _draw_image_fit(pdf, image_path, cell_x, cell_y, cell_w, cell_h) +def _draw_status_badge( + pdf: canvas.Canvas, + *, + x: float, + y: float, + label: str, + state: bool | None, + width: float = 94.0, + height: float = 18.0, +) -> None: + if state is True: + fill = colors.Color(0.86, 0.96, 0.88) + stroke = colors.Color(0.28, 0.55, 0.30) + status_text = "PASS" + elif state is False: + fill = colors.Color(0.98, 0.88, 0.88) + stroke = colors.Color(0.62, 0.20, 0.20) + status_text = "FAIL" + else: + fill = colors.Color(0.92, 0.92, 0.92) + stroke = colors.Color(0.45, 0.45, 0.45) + status_text = "N/A" + + pdf.setStrokeColor(stroke) + pdf.setFillColor(fill) + pdf.roundRect(x, y - height, width, height, 4, stroke=1, fill=1) + pdf.setFillColor(colors.black) + pdf.setFont("Helvetica-Bold", 8) + pdf.drawString(x + 4, y - 12, f"{label}: {status_text}") + + +def _paired_reference_images(report: NotebookReport) -> tuple[Path | None, Path | None]: + if report.matched_python_image is not None and report.matched_matlab_image is not None: + return report.matched_python_image, report.matched_matlab_image + py = report.unique_image_paths[0] if report.unique_image_paths else None + mat = report.matlab_ref_images[0] if report.matlab_ref_images else None + return py, mat + + +def _draw_comparison_pair( + pdf: canvas.Canvas, + *, + py_img: Path | None, + mat_img: Path | None, + x_left: float, + x_right: float, + top_y: float, + box_w: float, + box_h: float, +) -> None: + pdf.setFont("Helvetica-Bold", 9) + pdf.drawString(x_left, top_y + 6, "Python output") + pdf.drawString(x_right, top_y + 6, "MATLAB reference") + + if py_img is not None: + _draw_image_fit(pdf, py_img, x_left, top_y - box_h, box_w, box_h) + pdf.setFont("Helvetica", 8) + pdf.drawString(x_left, top_y - box_h - 10, py_img.name[:40]) + else: + pdf.setFont("Helvetica", 9) + pdf.drawString(x_left, top_y - 12, "No Python image") + + if mat_img is not None: + _draw_image_fit(pdf, mat_img, x_right, top_y - box_h, box_w, box_h) + pdf.setFont("Helvetica", 8) + pdf.drawString(x_right, top_y - box_h - 10, mat_img.name[:40]) + else: + pdf.setFont("Helvetica", 9) + pdf.drawString(x_right, top_y - 12, "No MATLAB reference image") + + +def _draw_delta_table( + pdf: canvas.Canvas, + *, + metrics: dict[str, object] | None, + x: float, + top_y: float, + width: float, + max_rows: int = 7, +) -> None: + rows: list[dict[str, object]] = [] + if metrics is not None: + for row in metrics.get("numeric_drift_metric_rows", []): + rows.append( + { + "name": str(row.get("name", "-")), + "value": float(row.get("value", 0.0)), + "threshold": float(row.get("threshold", 0.0)), + "pass": bool(row.get("pass", False)), + "ratio_to_threshold": float(row.get("ratio_to_threshold", 0.0)), + } + ) + if not rows: + pdf.setFont("Helvetica", 9) + pdf.drawString(x, top_y - 12, "No numeric delta metrics available.") + return + + shown = rows[:max_rows] + row_h = 11.0 + table_h = row_h * (len(shown) + 1) + col_name = width * 0.45 + col_value = width * 0.18 + col_threshold = width * 0.18 + + c1 = x + col_name + c2 = c1 + col_value + c3 = c2 + col_threshold + + pdf.setStrokeColor(colors.black) + pdf.setLineWidth(0.6) + pdf.rect(x, top_y - table_h, width, table_h) + pdf.line(c1, top_y, c1, top_y - table_h) + pdf.line(c2, top_y, c2, top_y - table_h) + pdf.line(c3, top_y, c3, top_y - table_h) + for idx in range(1, len(shown) + 1): + y = top_y - idx * row_h + pdf.line(x, y, x + width, y) + + pdf.setFont("Helvetica-Bold", 8) + pdf.drawString(x + 4, top_y - 9, "Delta metric") + pdf.drawString(c1 + 4, top_y - 9, "Value") + pdf.drawString(c2 + 4, top_y - 9, "Threshold") + pdf.drawString(c3 + 4, top_y - 9, "Status") + + pdf.setFont("Helvetica", 8) + for idx, row in enumerate(shown, start=1): + y = top_y - idx * row_h - 9 + status = "PASS" if bool(row["pass"]) else "FAIL" + pdf.drawString(x + 4, y, str(row["name"])[:34]) + pdf.drawString(c1 + 4, y, f"{float(row['value']):.4g}") + pdf.drawString(c2 + 4, y, f"{float(row['threshold']):.4g}") + pdf.drawString(c3 + 4, y, status) + + def _format_metric_value(value: object | None) -> str: if value is None: return "-" @@ -1100,6 +915,12 @@ def _draw_metrics_table( width: float, ) -> None: rows = [ + ("line_review_status", "Line review status"), + ("line_alignment_ratio", "Line alignment ratio"), + ("matlab_step_recall", "MATLAB step recall"), + ("python_step_precision", "Python step precision"), + ("line_review_missing_step_count", "Missing MATLAB steps"), + ("line_review_extra_step_count", "Extra Python steps"), ("matlab_code_lines", "MATLAB code lines"), ("python_code_lines", "Python code lines"), ("python_to_matlab_line_ratio", "Python/MATLAB line ratio"), @@ -1252,6 +1073,17 @@ def draw_summary_pages( for report in reports if report.parity_metrics is not None and bool(report.parity_metrics.get("numeric_drift_pass", False)) ) + line_review_checked = sum( + 1 + for report in reports + if report.parity_metrics is not None and str(report.parity_metrics.get("line_review_status", "")).strip() != "" + ) + line_review_aligned = sum( + 1 + for report in reports + if report.parity_metrics is not None and str(report.parity_metrics.get("line_review_status", "")).strip() + in {"aligned", "partially_aligned"} + ) duplicate_stats = _cross_topic_duplicate_stats(reports) pdf.setFont("Helvetica-Bold", 16) @@ -1280,6 +1112,7 @@ def draw_summary_pages( else: pdf.drawString(260, 722, f"Parity pass: {parity_passed}/{parity_checked}") pdf.drawString(40, 674, f"Numeric drift pass: {numeric_passed}/{numeric_checked}") + pdf.drawString(260, 674, f"Line review aligned: {line_review_aligned}/{line_review_checked}") y = 654 pdf.setFont("Helvetica-Bold", 9) @@ -1442,6 +1275,100 @@ def draw_example_page(pdf: canvas.Canvas, report: NotebookReport, index: int, to pdf.showPage() +def draw_example_comparison_page(pdf: canvas.Canvas, report: NotebookReport, index: int, total: int) -> None: + pdf.setFont("Helvetica-Bold", 15) + pdf.drawString(40, 760, f"Example {index}/{total}: {report.topic} (Side-by-side)") + pdf.setFont("Helvetica", 9) + pdf.drawString(40, 744, f"Notebook: {report.file}") + + exec_state = bool(report.executed) + parity_state = report.parity_pass + numeric_state: bool | None = None + if report.parity_metrics is not None and "numeric_drift_pass" in report.parity_metrics: + numeric_state = bool(report.parity_metrics.get("numeric_drift_pass", False)) + line_review_state: bool | None = None + if report.parity_metrics is not None: + status = str(report.parity_metrics.get("line_review_status", "")).strip().lower() + if status == "aligned": + line_review_state = True + elif status == "needs_review": + line_review_state = False + + _draw_status_badge(pdf, x=40, y=724, label="Execution", state=exec_state) + _draw_status_badge(pdf, x=144, y=724, label="Parity gate", state=parity_state) + _draw_status_badge(pdf, x=248, y=724, label="Numeric drift", state=numeric_state) + _draw_status_badge(pdf, x=352, y=724, label="Line review", state=line_review_state) + + py_img, mat_img = _paired_reference_images(report) + _draw_comparison_pair( + pdf, + py_img=py_img, + mat_img=mat_img, + x_left=40, + x_right=300, + top_y=680, + box_w=240, + box_h=250, + ) + + similarity_text = f"{report.similarity_score:.3f}" if report.similarity_score is not None else "-" + pdf.setFont("Helvetica", 9) + pdf.drawString(40, 404, f"Best image similarity score: {similarity_text}") + if report.alignment_status is not None: + pdf.drawString(260, 404, f"Equivalence status: {report.alignment_status}") + + ratio = None + line_ratio = None + step_recall = None + step_precision = None + line_status = "-" + if report.parity_metrics is not None: + ratio = report.parity_metrics.get("python_to_matlab_line_ratio") + line_ratio = report.parity_metrics.get("line_alignment_ratio") + step_recall = report.parity_metrics.get("matlab_step_recall") + step_precision = report.parity_metrics.get("python_step_precision") + line_status = str(report.parity_metrics.get("line_review_status", "-")) + ratio_text = f"{float(ratio):.3f}" if isinstance(ratio, (int, float)) else "-" + pdf.drawString(40, 390, f"Python/MATLAB line ratio: {ratio_text}") + pdf.drawString( + 260, + 390, + f"Python unique images: {report.unique_image_count} | MATLAB refs: {len(report.matlab_ref_images)}", + ) + line_ratio_text = f"{float(line_ratio):.3f}" if isinstance(line_ratio, (int, float)) else "-" + step_recall_text = f"{float(step_recall):.3f}" if isinstance(step_recall, (int, float)) else "-" + step_precision_text = f"{float(step_precision):.3f}" if isinstance(step_precision, (int, float)) else "-" + pdf.drawString( + 40, + 376, + f"Line review: {line_status} | alignment={line_ratio_text} | recall={step_recall_text} | precision={step_precision_text}", + ) + + pdf.setFont("Helvetica-Bold", 11) + pdf.drawString(40, 358, "Metric deltas (MATLAB gold fixture thresholds)") + _draw_delta_table(pdf, metrics=report.parity_metrics, x=40, top_y=344, width=520, max_rows=6) + + if report.parity_metrics is not None: + missing_steps = report.parity_metrics.get("line_review_missing_steps_preview", []) + if isinstance(missing_steps, list) and missing_steps: + pdf.setFont("Helvetica-Bold", 9) + pdf.drawString(40, 254, "Missing MATLAB step preview:") + pdf.setFont("Helvetica", 8) + y = 242 + for step in missing_steps[:2]: + y = _draw_wrapped_lines(pdf, 46, y, f"- {str(step)}", wrap_width=98, line_step=9) + extra_steps = report.parity_metrics.get("line_review_extra_steps_preview", []) + if isinstance(extra_steps, list) and extra_steps: + pdf.setFont("Helvetica-Bold", 9) + pdf.drawString(40, 212, "Extra Python step preview:") + pdf.setFont("Helvetica", 8) + y = 200 + for step in extra_steps[:2]: + y = _draw_wrapped_lines(pdf, 46, y, f"- {str(step)}", wrap_width=98, line_step=9) + + pdf.showPage() + + def generate_pdf_report( repo_root: Path, manifest_path: Path, @@ -1457,6 +1384,7 @@ def generate_pdf_report( equivalence_report: Path, example_output_spec: Path, numeric_drift_report: Path, + line_review_report: Path, ) -> tuple[Path, list[NotebookReport], list[CommandResult], Path | None]: output_pdf.parent.mkdir(parents=True, exist_ok=True) tmp_dir.mkdir(parents=True, exist_ok=True) @@ -1480,21 +1408,20 @@ def generate_pdf_report( parity_gate_status = load_parity_gate_status(equivalence_report, example_output_spec) parity_topic_metrics = load_parity_topic_metrics(equivalence_report) numeric_drift_by_topic = load_numeric_drift_summary(numeric_drift_report) - expected_figures_by_topic = load_expected_figure_counts(repo_root) + line_review_by_topic = load_line_review_summary(line_review_report) targets = load_targets(manifest_path, repo_root, notebook_group) reports: list[NotebookReport] = [] for target in targets: merged_metrics = dict(parity_topic_metrics.get(target.topic, {})) merged_metrics.update(numeric_drift_by_topic.get(target.topic, {})) + merged_metrics.update(line_review_by_topic.get(target.topic, {})) reports.append( execute_notebook_capture( target=target, tmp_dir=tmp_dir, timeout=timeout, matlab_help_root=resolved_matlab_help_root, - repo_root=repo_root, - expected_figure_count=int(expected_figures_by_topic.get(target.topic, 0)), parity_threshold=parity_threshold, skip_parity_check=skip_parity_check, parity_mode=parity_mode, @@ -1510,8 +1437,7 @@ def generate_pdf_report( ) generated_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - letter_size, _, canvas_cls = _require_reportlab() - pdf = canvas_cls(str(output_pdf), pagesize=letter_size) + pdf = canvas.Canvas(str(output_pdf), pagesize=letter) pdf.setTitle("nSTAT-python Validation Report") draw_cover_page( @@ -1537,6 +1463,7 @@ def generate_pdf_report( total = len(reports) for index, report in enumerate(reports, start=1): draw_example_page(pdf=pdf, report=report, index=index, total=total) + draw_example_comparison_page(pdf=pdf, report=report, index=index, total=total) pdf.save() return output_pdf, reports, command_results, resolved_matlab_help_root @@ -1544,7 +1471,6 @@ def generate_pdf_report( def main() -> int: args = parse_args() - prepare_notebook_exec_env() stamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_pdf = args.output_dir / f"nstat_python_validation_report_{stamp}.pdf" @@ -1563,6 +1489,7 @@ def main() -> int: equivalence_report=args.equivalence_report, example_output_spec=args.example_output_spec, numeric_drift_report=args.numeric_drift_report, + line_review_report=args.line_review_report, ) executed = sum(1 for report in reports if report.executed) @@ -1583,31 +1510,8 @@ def main() -> int: for report in reports if report.parity_metrics is not None and report.parity_metrics.get("numeric_drift_pass") is False ) - uniqueness_violations, uniqueness_stats = _uniqueness_violations( - reports=reports, - min_unique_images_per_topic=args.min_unique_images_per_topic, - max_cross_topic_reuse_ratio=args.max_cross_topic_reuse_ratio, - ) - summary_json_path = args.summary_json or output_pdf.with_suffix(".json") - summary_csv_path = args.summary_csv or output_pdf.with_suffix(".csv") - summary_json_path, summary_csv_path = write_machine_readable_summaries( - report_path=report_path, - repo_root=args.repo_root, - reports=reports, - command_results=command_results, - matlab_help_root=matlab_help_root, - notebook_group=args.notebook_group, - parity_mode=args.parity_mode, - parity_threshold=args.parity_threshold, - uniqueness_stats=uniqueness_stats, - uniqueness_violations=uniqueness_violations, - summary_json_path=summary_json_path, - summary_csv_path=summary_csv_path, - ) print(f"Generated PDF report: {report_path}") - print(f"Machine-readable summary (JSON): {summary_json_path}") - print(f"Machine-readable summary (CSV): {summary_csv_path}") print(f"MATLAB help root: {matlab_help_root}") print( f"Notebook results: total={len(reports)} executed={executed} exec_failures={exec_failures} " @@ -1616,24 +1520,8 @@ def main() -> int: print(f"Parity results ({args.parity_mode} mode): checked={parity_checked} failures={parity_failures}") print(f"Numeric drift topic results: checked={numeric_checked} failures={numeric_failures}") print(f"Command checks: total={len(command_results)} failed={command_failures}") - print( - "Uniqueness stats: " - f"total_instances={uniqueness_stats['total_image_instances']} " - f"total_unique={uniqueness_stats['total_unique_hashes']} " - f"cross_topic_reused={uniqueness_stats['cross_topic_reused_hashes']} " - f"cross_topic_reuse_ratio={uniqueness_stats['cross_topic_reuse_ratio']:.6f}" - ) - print(f"Uniqueness violations: {len(uniqueness_violations)}") - if uniqueness_violations: - for violation in uniqueness_violations: - print(f" - {violation}") - - enforce_uniqueness_failure = args.enforce_unique_images and bool(uniqueness_violations) - return ( - 0 - if exec_failures == 0 and command_failures == 0 and parity_failures == 0 and not enforce_uniqueness_failure - else 1 - ) + + return 0 if exec_failures == 0 and command_failures == 0 and parity_failures == 0 else 1 if __name__ == "__main__":