├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── confusing-documentation.md │ └── feature_request.md └── workflows │ ├── black-formatting.yml │ ├── caches_cron_job.yml │ ├── core-test.yml │ ├── ebrains.yml │ ├── io-test.yml │ ├── io-test_dispatch.yml │ ├── io-test_trigger.yml │ ├── plexon2-testing.yml │ ├── publish-to-pypi-test.yml │ └── publish-to-pypi.yml ├── .gitignore ├── .pep8speaks.yml ├── .readthedocs.yaml ├── AUTHORS ├── CITATION.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── MANIFEST.in ├── README.rst ├── codemeta.json ├── doc ├── Makefile ├── example_data.txt ├── example_data_about.json ├── make.bat ├── old_stuffs │ ├── core.rst │ ├── developers_guide.rst │ ├── examples.rst │ ├── gif2011workshop.rst │ ├── grouping.rst │ ├── index.rst │ ├── install.rst │ ├── io.rst │ ├── io_developers_guide.rst │ ├── rawio.rst │ ├── specific_annotations.rst │ └── usecases.rst ├── requirements_docs.txt └── source │ ├── _static │ └── css │ │ └── custom.css │ ├── add_file_format.rst │ ├── api_reference.rst │ ├── authors.rst │ ├── bug_reports.rst │ ├── conf.py │ ├── contributing.rst │ ├── example_data.txt │ ├── example_data_about.json │ ├── example_plot.png │ ├── governance.rst │ ├── images │ ├── IODiagram.eps │ ├── IODiagram.png │ ├── IODiagram.svg │ ├── base_schematic.png │ ├── base_schematic.svg │ ├── generate_diagram.py │ ├── generate_io_overview.py │ ├── incf_endorsed_with_spacing.png │ ├── multi_segment_diagram.png │ ├── multi_segment_diagram.svg │ ├── multi_segment_diagram_spiketrain.png │ ├── multi_segment_diagram_spiketrain.svg │ ├── neo_ecosystem.drawio │ ├── neo_ecosystem.svg │ ├── neologo.png │ ├── neologo.svg │ ├── neologo_darkmode.png │ ├── neologo_favicon.png │ ├── neologo_light.png │ ├── neologo_small.png │ ├── neologo_small_darkmode.png │ ├── simple_generated_diagram.png │ └── simple_generated_diagram.svg │ ├── index.rst │ ├── install.rst │ ├── iolist.rst │ ├── neo_users.rst │ ├── rawio.rst │ ├── rawiolist.rst │ ├── read_and_analyze.rst │ ├── releases.rst │ ├── releases │ ├── 0.10.0.rst │ ├── 0.10.1.rst │ ├── 0.10.2.rst │ ├── 0.11.0.rst │ ├── 0.11.1.rst │ ├── 0.12.0.rst │ ├── 0.13.0.rst │ ├── 0.13.1.rst │ ├── 0.13.2.rst │ ├── 0.13.3.rst │ ├── 0.13.4.rst │ ├── 0.14.0.rst │ ├── 0.14.1.rst │ ├── 0.5.0.rst │ ├── 0.5.1.rst │ ├── 0.5.2.rst │ ├── 0.6.0.rst │ ├── 0.7.0.rst │ ├── 0.7.1.rst │ ├── 0.7.2.rst │ ├── 0.8.0.rst │ └── 0.9.0.rst │ ├── scripts │ ├── multi_tetrode_example.py │ └── spike_sorting_example.py │ ├── share_data.rst │ └── use_neo_as_dependency.rst ├── environment_testing.yml ├── examples ├── README.rst ├── convert_to_nwb.py ├── plot_igorio.py ├── plot_imageseq.py ├── plot_multi_tetrode_example.py ├── plot_read_files_neo_io.py ├── plot_read_files_neo_rawio.py ├── plot_read_proxy_with_lazy_load.py ├── plot_roi_demo.py └── plot_with_matplotlib.py ├── neo ├── __init__.py ├── core │ ├── __init__.py │ ├── analogsignal.py │ ├── baseneo.py │ ├── basesignal.py │ ├── block.py │ ├── container.py │ ├── dataobject.py │ ├── epoch.py │ ├── event.py │ ├── filters.py │ ├── group.py │ ├── imagesequence.py │ ├── irregularlysampledsignal.py │ ├── objectlist.py │ ├── regionofinterest.py │ ├── segment.py │ ├── spiketrain.py │ ├── spiketrainlist.py │ └── view.py ├── io │ ├── __init__.py │ ├── alphaomegaio.py │ ├── asciiimageio.py │ ├── asciisignalio.py │ ├── asciispiketrainio.py │ ├── axographio.py │ ├── axonaio.py │ ├── axonio.py │ ├── basefromrawio.py │ ├── baseio.py │ ├── bci2000io.py │ ├── biocamio.py │ ├── blackrockio.py │ ├── blkio.py │ ├── brainvisionio.py │ ├── brainwaredamio.py │ ├── brainwaref32io.py │ ├── brainwaresrcio.py │ ├── cedio.py │ ├── edfio.py │ ├── elanio.py │ ├── elphyio.py │ ├── exampleio.py │ ├── igorproio.py │ ├── intanio.py │ ├── klustakwikio.py │ ├── kwikio.py │ ├── maxwellio.py │ ├── mearecio.py │ ├── medio.py │ ├── micromedio.py │ ├── neomatlabio.py │ ├── nestio.py │ ├── neuralynxio.py │ ├── neuroexplorerio.py │ ├── neuronexusio.py │ ├── neuroscopeio.py │ ├── neuroshareapiio.py │ ├── neurosharectypesio.py │ ├── nixio.py │ ├── nixio_fr.py │ ├── nwbio.py │ ├── openephysbinaryio.py │ ├── openephysio.py │ ├── phyio.py │ ├── pickleio.py │ ├── plexon2io.py │ ├── plexonio.py │ ├── proxyobjects.py │ ├── rawbinarysignalio.py │ ├── rawmcsio.py │ ├── spike2io.py │ ├── spikegadgetsio.py │ ├── spikeglxio.py │ ├── stimfitio.py │ ├── tdtio.py │ ├── tiffio.py │ ├── tools.py │ ├── winedrio.py │ └── winwcpio.py ├── rawio │ ├── __init__.py │ ├── alphaomegarawio.py │ ├── axographrawio.py │ ├── axonarawio.py │ ├── axonrawio.py │ ├── baserawio.py │ ├── bci2000rawio.py │ ├── biocamrawio.py │ ├── blackrockrawio.py │ ├── brainvisionrawio.py │ ├── cedrawio.py │ ├── edfrawio.py │ ├── elanrawio.py │ ├── examplerawio.py │ ├── intanrawio.py │ ├── maxwellrawio.py │ ├── mearecrawio.py │ ├── medrawio.py │ ├── micromedrawio.py │ ├── neuralynxrawio │ │ ├── __init__.py │ │ ├── ncssections.py │ │ ├── neuralynxrawio.py │ │ └── nlxheader.py │ ├── neuroexplorerrawio.py │ ├── neuronexusrawio.py │ ├── neuroscoperawio.py │ ├── nixrawio.py │ ├── openephysbinaryrawio.py │ ├── openephysrawio.py │ ├── phyrawio.py │ ├── plexon2rawio │ │ ├── __init__.py │ │ ├── plexon2rawio.py │ │ └── pypl2 │ │ │ ├── __init__.py │ │ │ └── pypl2lib.py │ ├── plexonrawio.py │ ├── rawbinarysignalrawio.py │ ├── rawmcsrawio.py │ ├── spike2rawio.py │ ├── spikegadgetsrawio.py │ ├── spikeglxrawio.py │ ├── tdtrawio.py │ ├── utils.py │ ├── winedrrawio.py │ ├── winwcprawio.py │ └── xarray_utils.py ├── test │ ├── README.txt │ ├── __init__.py │ ├── coretest │ │ ├── __init__.py │ │ ├── test_analogsignal.py │ │ ├── test_base.py │ │ ├── test_block.py │ │ ├── test_container.py │ │ ├── test_dataobject.py │ │ ├── test_epoch.py │ │ ├── test_event.py │ │ ├── test_generate_datasets.py │ │ ├── test_group.py │ │ ├── test_imagesequence.py │ │ ├── test_irregularysampledsignal.py │ │ ├── test_regionofinterest.py │ │ ├── test_segment.py │ │ ├── test_spiketrain.py │ │ ├── test_spiketrainlist.py │ │ └── test_view.py │ ├── generate_datasets.py │ ├── iotest │ │ ├── __init__.py │ │ ├── common_io_test.py │ │ ├── test_alphaomegaio.py │ │ ├── test_asciiimageio.py │ │ ├── test_asciisignalio.py │ │ ├── test_asciispiketrainio.py │ │ ├── test_axographio.py │ │ ├── test_axonaio.py │ │ ├── test_axonio.py │ │ ├── test_baseio.py │ │ ├── test_bci2000io.py │ │ ├── test_biocamio.py │ │ ├── test_blackrockio.py │ │ ├── test_brainvisionio.py │ │ ├── test_brainwaredamio.py │ │ ├── test_brainwaref32io.py │ │ ├── test_brainwaresrcio.py │ │ ├── test_cedio.py │ │ ├── test_edfio.py │ │ ├── test_elanio.py │ │ ├── test_elphyio.py │ │ ├── test_exampleio.py │ │ ├── test_get_io.py │ │ ├── test_igorio.py │ │ ├── test_intanio.py │ │ ├── test_klustakwikio.py │ │ ├── test_kwikio.py │ │ ├── test_maxwellio.py │ │ ├── test_mearecio.py │ │ ├── test_medio.py │ │ ├── test_micromedio.py │ │ ├── test_neomatlabio.py │ │ ├── test_nestio.py │ │ ├── test_neuralynxio.py │ │ ├── test_neuroexplorerio.py │ │ ├── test_neuronexusio.py │ │ ├── test_neuroscopeio.py │ │ ├── test_neuroshareio.py │ │ ├── test_nixio.py │ │ ├── test_nixio_fr.py │ │ ├── test_nwbio.py │ │ ├── test_openephysbinaryio.py │ │ ├── test_openephysio.py │ │ ├── test_phyio.py │ │ ├── test_pickleio.py │ │ ├── test_plexon2io.py │ │ ├── test_plexonio.py │ │ ├── test_proxyobjects.py │ │ ├── test_rawbinarysignalio.py │ │ ├── test_rawmcsio.py │ │ ├── test_spike2io.py │ │ ├── test_spikegadgetsio.py │ │ ├── test_spikeglxio.py │ │ ├── test_stimfitio.py │ │ ├── test_tdtio.py │ │ ├── test_tiffio.py │ │ ├── test_winedrio.py │ │ ├── test_winwcpio.py │ │ └── tools.py │ ├── rawiotest │ │ ├── __init__.py │ │ ├── common_rawio_test.py │ │ ├── rawio_compliance.py │ │ ├── test_alphaomegarawio.py │ │ ├── test_axographrawio.py │ │ ├── test_axonarawio.py │ │ ├── test_axonrawio.py │ │ ├── test_bci2000rawio.py │ │ ├── test_biocamrawio.py │ │ ├── test_blackrockrawio.py │ │ ├── test_brainvisionrawio.py │ │ ├── test_cedrawio.py │ │ ├── test_edfrawio.py │ │ ├── test_elanrawio.py │ │ ├── test_examplerawio.py │ │ ├── test_get_rawio.py │ │ ├── test_intanrawio.py │ │ ├── test_maxwellrawio.py │ │ ├── test_mearecrawio.py │ │ ├── test_medrawio.py │ │ ├── test_micromedrawio.py │ │ ├── test_neuralynxrawio.py │ │ ├── test_neuroexplorerrawio.py │ │ ├── test_neuronexusrawio.py │ │ ├── test_neuroscoperawio.py │ │ ├── test_nixrawio.py │ │ ├── test_openephysbinaryrawio.py │ │ ├── test_openephysrawio.py │ │ ├── test_phyrawio.py │ │ ├── test_plexon2rawio.py │ │ ├── test_plexonrawio.py │ │ ├── test_rawbinarysignalrawio.py │ │ ├── test_rawmcsrawio.py │ │ ├── test_spike2rawio.py │ │ ├── test_spikegadgetsrawio.py │ │ ├── test_spikeglxrawio.py │ │ ├── test_tdtrawio.py │ │ ├── test_winedrrawio.py │ │ ├── test_winwcprawio.py │ │ └── tools.py │ ├── tools.py │ └── utils │ │ ├── test_datasets.py │ │ └── test_misc.py └── utils │ ├── __init__.py │ ├── datasets.py │ └── misc.py ├── pyproject.toml └── setup.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us fix problems 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behaviour, preferably providing a simple code example (if the error happens in the middle of some complex code, please try to find a simpler, minimal example that demonstrates the error), and showing the full traceback. 15 | 16 | If the error occurs when reading a file that you can't share publicly, please let us know, and we'll get in touch to discuss sharing it privately. 17 | 18 | **Expected behaviour** 19 | If the bug is incorrect behaviour, rather than an unexpected Exception, please give a clear and concise description of what you expected to happen. 20 | 21 | **Environment:** 22 | - OS: [e.g. macOS, Linux, Windows] 23 | - Python version 24 | - Neo version 25 | - NumPy version 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/confusing-documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Confusing documentation 3 | about: Let us know if the documentation is confusing or incorrect 4 | title: '' 5 | labels: Documentation 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Which page is the problem on?** 11 | The URL of the documentation page where the problem is, and either copy-paste the confusing text (for a short section of text), or give the first few and last few words (for a long section). 12 | 13 | **What is the problem?** 14 | Is the documentation (a) confusing or (b) incorrect? In what way? 15 | 16 | **Suggestions for fixing the problem** 17 | If the documentation is confusing, can you suggest an improvement? If the documentation is incorrect, what should it say instead? 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea to improve Neo 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/black-formatting.yml: -------------------------------------------------------------------------------- 1 | name: Black formatting 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: "0 12 * * 0" # Weekly at noon UTC on Sundays 7 | 8 | jobs: 9 | lint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Check black formatting 16 | id: black-check 17 | uses: psf/black@stable 18 | with: 19 | options: "--check --verbose" 20 | continue-on-error: true 21 | 22 | - name: Apply black formatting 23 | id: black-apply 24 | uses: psf/black@stable 25 | if : ${{ steps.black-check.outcome == 'failure' }} 26 | with: 27 | options: "--verbose" 28 | 29 | - name: Create PR 30 | uses: peter-evans/create-pull-request@v5 31 | if : ${{ steps.black-check.outcome == 'failure' }} 32 | with: 33 | commit-message: black formatting 34 | title: Black formatting 35 | body: Reformatting code with black style 36 | branch: black-formatting 37 | -------------------------------------------------------------------------------- /.github/workflows/core-test.yml: -------------------------------------------------------------------------------- 1 | name: NeoCoreTest 2 | 3 | on: 4 | pull_request: 5 | branches: [master] 6 | types: [synchronize, opened, reopened, ready_for_review] 7 | paths: 8 | - 'neo/core/**' 9 | - 'pyproject.toml' 10 | - '.github/workflows/*.yml' 11 | 12 | # run checks on any change of master, including merge of PRs 13 | push: 14 | branches: [master] 15 | 16 | concurrency: # Cancel previous workflows on the same pull request 17 | group: ${{ github.workflow }}-${{ github.ref }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | multi-os-python-numpy: 22 | runs-on: ${{ matrix.os }} 23 | 24 | strategy: 25 | fail-fast: true 26 | matrix: 27 | os: ["ubuntu-latest", "windows-latest", "macos-latest"] 28 | python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] 29 | numpy-version: ['1.24.4', '1.25.1', '1.26.4', '2.0.2','2.1.3', '2.2.4'] 30 | # 1.24: 3.11, 1.25: 3.11, 1.26: 3.12 31 | exclude: 32 | - python-version: '3.9' 33 | numpy-version: '2.1.3' 34 | - python-version: '3.9' 35 | numpy-version: '2.2.4' 36 | - python-version: '3.12' 37 | numpy-version: '1.24.4' 38 | - python-version: '3.12' 39 | numpy-version: '1.25.1' 40 | - python-version: '3.13' 41 | numpy-version: '1.22.4' 42 | - python-version: '3.13' 43 | numpy-version: '1.23.5' 44 | - python-version: '3.13' 45 | numpy-version: '1.24.4' 46 | - python-version: '3.13' 47 | numpy-version: '1.25.1' 48 | - python-version: '3.13' 49 | numpy-version: '1.26.4' 50 | - python-version: '3.13' 51 | numpy-version: '2.0.2' 52 | 53 | steps: 54 | - name: Set up Python ${{ matrix.python-version }} 55 | uses: actions/setup-python@v5 56 | with: 57 | python-version: ${{ matrix.python-version }} 58 | 59 | - name: Checkout repository 60 | uses: actions/checkout@v4 61 | 62 | - name: Install numpy ${{ matrix.numpy-version }} 63 | run: | 64 | python -m pip install --upgrade pip 65 | pip install numpy==${{ matrix.numpy-version }} 66 | pip install pytest pytest-cov 67 | pip install . 68 | 69 | - name: List pip packages 70 | run: | 71 | pip -V 72 | pip list 73 | 74 | - name: Run tests 75 | run: | 76 | pytest --cov=neo neo/test/coretest 77 | -------------------------------------------------------------------------------- /.github/workflows/ebrains.yml: -------------------------------------------------------------------------------- 1 | name: Mirror to EBRAINS 2 | 3 | # Configure the events that are going to trigger tha automated update of the mirror 4 | on: 5 | push: 6 | branches: [ master ] 7 | 8 | # Configure what will be updated 9 | jobs: 10 | # set the job name 11 | to_ebrains: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # this task will push the master branch of the source_repo (github) to the 15 | # destination_repo (ebrains gitlab) 16 | - name: syncmaster 17 | uses: wei/git-sync@v3 18 | with: 19 | source_repo: https://github.com/NeuralEnsemble/python-neo 20 | source_branch: "master" 21 | destination_repo: "https://ghpusher:${{ secrets.EBRAINS_GITLAB_ACCESS_TOKEN }}@gitlab.ebrains.eu/NeuralEnsemble/neo.git" 22 | destination_branch: "main" 23 | # this task will push all tags from the source_repo to the destination_repo 24 | - name: synctags 25 | uses: wei/git-sync@v3 26 | with: 27 | source_repo: https://github.com/NeuralEnsemble/python-neo 28 | source_branch: "refs/tags/*" 29 | destination_repo: "https://ghpusher:${{ secrets.EBRAINS_GITLAB_ACCESS_TOKEN }}@gitlab.ebrains.eu/NeuralEnsemble/neo.git" 30 | destination_branch: "refs/tags/*" 31 | -------------------------------------------------------------------------------- /.github/workflows/io-test_dispatch.yml: -------------------------------------------------------------------------------- 1 | name: NeoIoTest-manual-trigger 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | os: 7 | description: 'The operating system to run the tests on' 8 | required: True 9 | default: 'ubuntu-latest' 10 | type: choice 11 | options: 12 | - macos-latest 13 | - windows-latest 14 | 15 | jobs: 16 | call-iotests: 17 | uses: ./.github/workflows/io-test.yml 18 | with: 19 | os: ${{ inputs.os }} -------------------------------------------------------------------------------- /.github/workflows/io-test_trigger.yml: -------------------------------------------------------------------------------- 1 | name: NeoIoTest-automatic-trigger 2 | 3 | on: 4 | pull_request: 5 | branches: [master] 6 | types: [synchronize, opened, reopened, ready_for_review] 7 | 8 | # run checks on any change of master, including merge of PRs 9 | push: 10 | branches: [master] 11 | 12 | jobs: 13 | call-iotests: 14 | uses: ./.github/workflows/io-test.yml 15 | with: 16 | os: ubuntu-latest 17 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-pypi-test.yml: -------------------------------------------------------------------------------- 1 | name: Release to Test PyPI 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | jobs: 8 | release: 9 | environment: TEST_PYPI_API_TOKEN 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up Python 3.10 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: "3.10" 18 | - name: Install Tools 19 | run: | 20 | python -m pip install --upgrade pip 21 | pip install setuptools wheel twine build 22 | pip install . 23 | - name: Get the tag version 24 | id: get-version 25 | run: | 26 | echo ${GITHUB_REF#refs/tags/} 27 | echo ::set-output name=TAG::${GITHUB_REF#refs/tags/} 28 | - name: Test version/tag correspondence 29 | id: version-check 30 | run: | 31 | neo_version=$(python -c "import neo; print(neo.__version__)") 32 | tag_version=${{ steps.get-version.outputs.TAG }} 33 | echo $neo_version 34 | echo $tag_version 35 | if [[ $tag_version == $neo_version ]]; then 36 | echo "VERSION_TAG_MATCH=true" >> $GITHUB_OUTPUT 37 | echo "Version matches tag, proceeding with release to Test PyPI" 38 | else 39 | echo "VERSION_TAG_MATCH=false" >> $GITHUB_OUTPUT 40 | echo "Version does not match tag! Fix this before proceeding." 41 | exit 1 42 | fi 43 | - name: Package and Upload 44 | env: 45 | STACKMANAGER_VERSION: ${{ github.event.release.tag_name }} 46 | TWINE_USERNAME: __token__ 47 | TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }} 48 | if: ${{ steps.version-check.outputs.VERSION_TAG_MATCH == 'true' }} 49 | run: | 50 | python -m build --sdist --wheel 51 | twine upload --repository testpypi dist/* 52 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-pypi.yml: -------------------------------------------------------------------------------- 1 | name: Release to PyPI 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | release: 8 | environment: PYPI_API_TOKEN 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Set up Python 3.10 14 | uses: actions/setup-python@v4 15 | with: 16 | python-version: "3.10" 17 | - name: Install Tools 18 | run: | 19 | python -m pip install --upgrade pip 20 | pip install setuptools wheel twine build 21 | - name: Package and Upload 22 | env: 23 | STACKMANAGER_VERSION: ${{ github.event.release.tag_name }} 24 | TWINE_USERNAME: __token__ 25 | TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} 26 | run: | 27 | python -m build --sdist --wheel 28 | twine upload dist/* 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ######################################### 2 | # Editor temporary/working/backup files # 3 | .#* 4 | [#]*# 5 | *~ 6 | *$ 7 | *.bak 8 | *.kdev4 9 | *.komodoproject 10 | *.orig 11 | .project 12 | .pydevproject 13 | .settings 14 | *.tmp* 15 | .idea 16 | *.swp 17 | *.swo 18 | .vscode 19 | 20 | 21 | # Compiled source # 22 | ################### 23 | *.a 24 | *.com 25 | *.class 26 | *.dll 27 | *.exe 28 | *.mo 29 | *.o 30 | *.py[ocd] 31 | *.so 32 | 33 | # Python files # 34 | ################ 35 | # setup.py working directory 36 | build 37 | # other build directories 38 | bin 39 | dist 40 | # sphinx build directory 41 | doc/_build 42 | # setup.py dist directory 43 | dist 44 | # Egg metadata 45 | *.egg-info 46 | *.egg 47 | *.EGG 48 | *.EGG-INFO 49 | # tox testing tool 50 | .tox 51 | # coverage 52 | .coverage 53 | cover 54 | *.ipynb_checkpoints 55 | 56 | # OS generated files # 57 | ###################### 58 | .directory 59 | .gdb_history 60 | .DS_Store? 61 | .DS_Store 62 | ehthumbs.db 63 | Icon? 64 | Thumbs.db 65 | 66 | # Things specific to this project # 67 | ################################### 68 | neo/test/io/neurosharemergeio.py 69 | files_for_testing_neo 70 | /venv 71 | /neo/test/resources 72 | doc/examples 73 | doc/*.abf 74 | doc/*.png 75 | doc/*.plx 76 | doc/*.nev 77 | doc/*.ns5 78 | doc/*.nix 79 | doc/*.nwb 80 | *.plx 81 | *.smr 82 | B95.zip 83 | grouped_ephys -------------------------------------------------------------------------------- /.pep8speaks.yml: -------------------------------------------------------------------------------- 1 | pycodestyle: 2 | max-line-length: 99 # Default is 79 in PEP8 3 | ignore: 4 | - W503 # Change in PEP8, this warning is replaced by W504 5 | - E127 6 | - E128 7 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.11" 7 | 8 | sphinx: 9 | configuration: doc/source/conf.py 10 | 11 | python: 12 | install: 13 | - method: pip 14 | path: . 15 | extra_requirements: 16 | - docs 17 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | See doc/source/authors.rst 2 | -------------------------------------------------------------------------------- /CITATION.txt: -------------------------------------------------------------------------------- 1 | To cite Neo in publications, please use: 2 | 3 | Garcia S., Guarino D., Jaillet F., Jennings T.R., Pröpper R., Rautenberg P.L., 4 | Rodgers C., Sobolev A.,Wachtler T., Yger P. and Davison A.P. (2014) 5 | Neo: an object model for handling electrophysiology data in multiple formats. 6 | Frontiers in Neuroinformatics 8:10: doi:10.3389/fninf.2014.00010 7 | 8 | A BibTeX entry for LaTeX users is:: 9 | 10 | @article{neo14, 11 | author = {Garcia S. and Guarino D. and Jaillet F. and Jennings T.R. and Pröpper R. and 12 | Rautenberg P.L. and Rodgers C. and Sobolev A. and Wachtler T. and Yger P. 13 | and Davison A.P.}, 14 | doi = {10.3389/fninf.2014.00010}, 15 | full_text = {http://www.frontiersin.org/Journal/10.3389/fninf.2014.00010/abstract}, 16 | journal = {Frontiers in Neuroinformatics}, 17 | month = {February}, 18 | title = {Neo: an object model for handling electrophysiology data in multiple formats}, 19 | volume = {8:10}, 20 | year = {2014} 21 | } 22 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at neo-maintainers@protonmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | See https://neo.readthedocs.io/en/latest/contributing.html 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2025, Neo authors and contributors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | * 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. 8 | * Neither the names of the copyright holders nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | 10 | 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 HOLDER 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. 11 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include LICENSE.txt 3 | include CITATION.rst 4 | prune drafts 5 | include examples/*.py 6 | recursive-include doc * 7 | prune doc/build 8 | exclude doc/source/images/*.svg 9 | exclude doc/source/images/*.dia 10 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | 15 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " pickle to make pickle files" 22 | @echo " json to make JSON files" 23 | @echo " htmlhelp to make HTML files and a HTML help project" 24 | @echo " qthelp to make HTML files and a qthelp project" 25 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 26 | @echo " changes to make an overview of all changed/added/deprecated items" 27 | @echo " linkcheck to check all external links for integrity" 28 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 29 | 30 | clean: 31 | -rm -rf $(BUILDDIR)/* 32 | -rm -rf source/examples 33 | 34 | html: 35 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 36 | @echo 37 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 38 | 39 | dirhtml: 40 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 41 | @echo 42 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 43 | 44 | pickle: 45 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 46 | @echo 47 | @echo "Build finished; now you can process the pickle files." 48 | 49 | json: 50 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 51 | @echo 52 | @echo "Build finished; now you can process the JSON files." 53 | 54 | htmlhelp: 55 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 56 | @echo 57 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 58 | ".hhp project file in $(BUILDDIR)/htmlhelp." 59 | 60 | qthelp: 61 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 62 | @echo 63 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 64 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 65 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/neo.qhcp" 66 | @echo "To view the help file:" 67 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/neo.qhc" 68 | 69 | latex: 70 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 71 | @echo 72 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 73 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 74 | "run these through (pdf)latex." 75 | 76 | changes: 77 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 78 | @echo 79 | @echo "The overview file is in $(BUILDDIR)/changes." 80 | 81 | linkcheck: 82 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 83 | @echo 84 | @echo "Link check complete; look for any errors in the above output " \ 85 | "or in $(BUILDDIR)/linkcheck/output.txt." 86 | 87 | doctest: 88 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 89 | @echo "Testing of doctests in the sources finished, look at the " \ 90 | "results in $(BUILDDIR)/doctest/output.txt." 91 | -------------------------------------------------------------------------------- /doc/example_data_about.json: -------------------------------------------------------------------------------- 1 | { 2 | "filename": "example_data.txt", 3 | "delimiter": " ", 4 | "timecolumn": null, 5 | "units": "mV", 6 | "time_units": "ms", 7 | "sampling_rate": { 8 | "value": 1.0, 9 | "units": "kHz" 10 | }, 11 | "method": "genfromtxt", 12 | "signal_group_mode": "all-in-one" 13 | } -------------------------------------------------------------------------------- /doc/old_stuffs/examples.rst: -------------------------------------------------------------------------------- 1 | **************** 2 | Examples 3 | **************** 4 | 5 | .. currentmodule:: neo 6 | 7 | Introduction 8 | ============= 9 | 10 | A set of examples in :file:`neo/examples/` illustrates the use of Neo classes. 11 | 12 | 13 | 14 | .. literalinclude:: ../../examples/read_files_neo_io.py 15 | 16 | .. literalinclude:: ../../examples/read_files_neo_rawio.py 17 | 18 | .. literalinclude:: ../../examples/plot_with_matplotlib.py 19 | -------------------------------------------------------------------------------- /doc/old_stuffs/index.rst: -------------------------------------------------------------------------------- 1 | .. module:: neo 2 | 3 | .. image:: images/neologo.png 4 | :width: 600 px 5 | 6 | Neo is a Python package for working with electrophysiology data in Python, together 7 | with support for reading a wide range of neurophysiology file formats, including 8 | Spike2, NeuroExplorer, AlphaOmega, Axon, Blackrock, Plexon, Tdt, Igor Pro, and support for 9 | writing to a subset of these formats plus non-proprietary formats including Kwik and HDF5. 10 | 11 | The goal of Neo is to improve interoperability between Python tools for 12 | analyzing, visualizing and generating electrophysiology data, by providing a common, 13 | shared object model. In order to be as lightweight a dependency as possible, 14 | Neo is deliberately limited to representation of data, with no functions for data 15 | analysis or visualization. 16 | 17 | Neo is used by a number of other software tools, including 18 | SpykeViewer_ (data analysis and visualization), Elephant_ (data analysis), 19 | the G-node_ suite (databasing), PyNN_ (simulations), tridesclous_ (spike sorting) 20 | and ephyviewer_ (data visualization). 21 | OpenElectrophy_ (data analysis and visualization) used an older version of Neo. 22 | 23 | 24 | Neo implements a hierarchical data model well adapted to intracellular and 25 | extracellular electrophysiology and EEG data with support for multi-electrodes 26 | (for example tetrodes). Neo's data objects build on the quantities_ package, 27 | which in turn builds on NumPy by adding support for physical dimensions. Thus 28 | Neo objects behave just like normal NumPy arrays, but with additional metadata, 29 | checks for dimensional consistency and automatic unit conversion. 30 | 31 | A project with similar aims but for neuroimaging file formats is `NiBabel`_. 32 | 33 | 34 | Documentation 35 | ------------- 36 | 37 | .. toctree:: 38 | :maxdepth: 1 39 | 40 | install 41 | core 42 | usecases 43 | io 44 | rawio 45 | examples 46 | api_reference 47 | whatisnew 48 | developers_guide 49 | io_developers_guide 50 | authors 51 | 52 | 53 | License 54 | ------- 55 | 56 | Neo is free software, distributed under a 3-clause Revised BSD license (BSD-3-Clause). 57 | 58 | 59 | Support 60 | ------- 61 | 62 | If you have problems installing the software or questions about usage, documentation or anything 63 | else related to Neo, you can post to the `NeuralEnsemble mailing list`_. If you find a bug, 64 | please create a ticket in our `issue tracker`_. 65 | 66 | 67 | Contributing 68 | ------------ 69 | 70 | Any feedback is gladly received and highly appreciated! Neo is a community project, 71 | and all contributions are welcomed - see the :doc:`developers_guide` for more information. 72 | `Source code `_ is on GitHub. 73 | 74 | 75 | Citation 76 | -------- 77 | 78 | .. include:: ../../CITATION.txt 79 | 80 | 81 | .. _OpenElectrophy: https://github.com/OpenElectrophy/OpenElectrophy 82 | .. _Elephant: http://neuralensemble.org/elephant 83 | .. _G-node: http://www.g-node.org/ 84 | .. _Neuroshare: http://neuroshare.org/ 85 | .. _SpykeViewer: https://spyke-viewer.readthedocs.io/en/latest/ 86 | .. _NiBabel: https://nipy.org/nibabel/ 87 | .. _PyNN: http://neuralensemble.org/PyNN 88 | .. _quantities: https://pypi.org/project/quantities/ 89 | .. _`NeuralEnsemble mailing list`: https://groups.google.com/forum/#!forum/neuralensemble 90 | .. _`issue tracker`: https://github.com/NeuralEnsemble/python-neo/issues 91 | .. _tridesclous: https://github.com/tridesclous/tridesclous 92 | .. _ephyviewer: https://github.com/NeuralEnsemble/ephyviewer 93 | -------------------------------------------------------------------------------- /doc/old_stuffs/install.rst: -------------------------------------------------------------------------------- 1 | ************ 2 | Installation 3 | ************ 4 | 5 | Neo is a pure Python package, so it should be easy to get it running on any 6 | system. 7 | 8 | Installing from the Python Package Index 9 | ======================================== 10 | 11 | Dependencies 12 | ------------ 13 | 14 | * Python_ >= 3.7 15 | * numpy_ >= 1.18.5 16 | * quantities_ >= 0.12.1 17 | 18 | You can install the latest published version of Neo and its dependencies using:: 19 | 20 | $ pip install neo 21 | 22 | Certain IO modules have additional dependencies. If these are not satisfied, 23 | Neo will still install but the IO module that uses them will fail on loading: 24 | 25 | * scipy >= 1.0.0 for NeoMatlabIO 26 | * h5py >= 2.5 for KwikIO 27 | * klusta for KwikIO 28 | * igor >= 0.2 for IgorIO 29 | * nixio >= 1.5 for NixIO 30 | * stfio for StimfitIO 31 | * pillow for TiffIO 32 | 33 | These dependencies can be installed by specifying a comma-separated list with the 34 | ``pip install`` command:: 35 | 36 | $ pip install neo[nixio,tiffio] 37 | 38 | Or when installing a specific version of neo:: 39 | 40 | $ pip install neo[nixio,tiffio]==0.9.0 41 | 42 | These additional dependencies for IO modules are available:: 43 | 44 | * igorproio 45 | * kwikio 46 | * neomatlabio 47 | * nixio 48 | * stimfitio 49 | * tiffio 50 | 51 | 52 | To download and install the package manually, download: 53 | 54 | |neo_github_url| 55 | 56 | 57 | Then: 58 | 59 | .. parsed-literal:: 60 | 61 | $ unzip neo-|release|.zip 62 | $ cd neo-|release| 63 | $ python setup.py install 64 | 65 | 66 | Installing from source 67 | ====================== 68 | 69 | To install the latest version of Neo from the Git repository:: 70 | 71 | $ git clone git://github.com/NeuralEnsemble/python-neo.git 72 | $ cd python-neo 73 | $ python setup.py install 74 | 75 | 76 | .. _`Python`: https://www.python.org/ 77 | .. _`numpy`: https://numpy.org/ 78 | .. _`quantities`: https://pypi.org/project/quantities/ 79 | .. _`pip`: https://pypi.org/project/pip/ 80 | .. _`setuptools`: http://pypi.python.org/pypi/setuptools 81 | .. _Anaconda: https://www.anaconda.com/distribution/ 82 | -------------------------------------------------------------------------------- /doc/old_stuffs/specific_annotations.rst: -------------------------------------------------------------------------------- 1 | .. _specific_annotations: 2 | 3 | ******************** 4 | Specific annotations 5 | ******************** 6 | 7 | Introduction 8 | ------------ 9 | 10 | Neo imposes and recommends some attributes for all objects, and also provides 11 | the *annotations* dict for all objects to deal with any kind of extensions. 12 | This flexible feature allow Neo objects to be customized for many use cases. 13 | 14 | While any names can be used for annotations, interoperability will be improved 15 | if there is some consistency in naming. Here we suggest some conventions for 16 | annotation names. 17 | 18 | 19 | Patch clamp 20 | ----------- 21 | 22 | .. todo: TODO 23 | 24 | 25 | Network simultaion 26 | ------------------ 27 | 28 | 29 | Spike sorting 30 | ------------- 31 | 32 | **SpikeTrain.annotations['waveform_features']** : when spike sorting the 33 | waveform is reduced to a smaller dimensional space with PCA or wavelets. This 34 | attribute is the projected matrice. NxM (N spike number, M features number. 35 | KlustakwikIO supports this feature. 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /doc/requirements_docs.txt: -------------------------------------------------------------------------------- 1 | docutils<0.18 2 | numpy>=1.16.1 3 | quantities>=0.12.1 4 | sphinx-inline-tabs 5 | sphinx-gallery 6 | ipython 7 | matplotlib 8 | nixio 9 | pynwb 10 | -------------------------------------------------------------------------------- /doc/source/_static/css/custom.css: -------------------------------------------------------------------------------- 1 | 2 | .navbar-header-items li.nav-item { 3 | text-align: center; 4 | } 5 | 6 | html[data-theme="light"] { 7 | --pst-color-inline-code: rgb(11, 96, 38); 8 | } 9 | 10 | html[data-theme="dark"] { 11 | --pst-color-inline-code: rgb(15, 127, 51); 12 | } 13 | -------------------------------------------------------------------------------- /doc/source/api_reference.rst: -------------------------------------------------------------------------------- 1 | ====================== 2 | Neo core API Reference 3 | ====================== 4 | 5 | Relationships between Neo objects 6 | ================================= 7 | 8 | Object: 9 | * With a star = inherits from :class:`Quantity` 10 | Attributes: 11 | * In red = required 12 | * In white = recommended 13 | Relationships: 14 | * In cyan = one to many 15 | 16 | 17 | .. image:: images/simple_generated_diagram.png 18 | :width: 750 px 19 | 20 | :download:`Click here for a better quality SVG diagram <./images/simple_generated_diagram.svg>` 21 | 22 | .. note:: This figure does not include :class:`ChannelView` and :class:`RegionOfInterest`. 23 | 24 | 25 | 26 | .. automodule:: neo.core 27 | 28 | .. testsetup:: * 29 | 30 | from neo import SpikeTrain 31 | import quantities as pq 32 | -------------------------------------------------------------------------------- /doc/source/bug_reports.rst: -------------------------------------------------------------------------------- 1 | ======================================= 2 | Reporting bugs, requesting new features 3 | ======================================= 4 | 5 | If you find a bug, unclear documentation, or would like to add a new feature to Neo, 6 | please go to https://github.com/NeuralEnsemble/python-neo/issues/. 7 | 8 | 9 | Searching the issue tracker 10 | =========================== 11 | 12 | Before creating a new issue, please read through the existing list of issues 13 | to check whether someone else has already created a similar one. 14 | You can also use Github's search capabilities for this. 15 | 16 | If you do find an existing issue, then please add a comment to say that you 17 | have also encountered this bug, or would like this feature to be added. 18 | 19 | If your issue is similar, but not identical, to one or more existing issues, 20 | then create a new issue making reference to the existing one, 21 | and explaining how your issue differs. 22 | 23 | 24 | Creating a new issue 25 | ==================== 26 | 27 | To create a new issue, click on "New issue", then click "Get started" next to the appropriate template: 28 | 29 | - "Bug report" 30 | - "Confusing documentation" 31 | - "Feature request" 32 | 33 | Please fill in all the information requested in the template. 34 | If you'd like to open an issue that isn't covered by these three options, click "Open a blank issue". 35 | -------------------------------------------------------------------------------- /doc/source/example_data_about.json: -------------------------------------------------------------------------------- 1 | { 2 | "filename": "example_data.txt", 3 | "delimiter": " ", 4 | "timecolumn": null, 5 | "units": "mV", 6 | "time_units": "ms", 7 | "sampling_rate": { 8 | "value": 1.0, 9 | "units": "kHz" 10 | }, 11 | "method": "genfromtxt", 12 | "signal_group_mode": "all-in-one" 13 | } -------------------------------------------------------------------------------- /doc/source/example_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/example_plot.png -------------------------------------------------------------------------------- /doc/source/governance.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | Governance 3 | ========== 4 | 5 | Neo is a community-developed project, 6 | we welcome contributions from anyone who is interested in the project. 7 | The project maintainers are the members of the `Neo maintainers team`_. 8 | All contributors agree to abide by the Code of Conduct, see the file `CODE_OF_CONDUCT.md`_. 9 | 10 | Contributions 11 | ============= 12 | 13 | All contributions must be by pull request, 14 | with the exception of quick bug fixes affecting fewer than ten lines of code. 15 | Normally, pull requests may be approved and merged by any maintainer, 16 | although anyone is welcome to join in the discussion. 17 | In case of disagreement with a decision, we will try to reach a consensus between maintainers, 18 | taking account of any input from the wider community. 19 | If consensus cannot be reached, decisions will be based on a majority vote among the maintainers, 20 | with the caveats that (i) only one vote per institution is allowed (i.e. in the case where several 21 | maintainers belong to the same institution they will have to agree among themselves how to vote) 22 | and (ii) a quorum of three maintainers must be achieved. 23 | 24 | .. _section-maintainers: 25 | 26 | Maintainers 27 | =========== 28 | 29 | Any contributor who has had at least three pull requests accepted may be nominated as a maintainer. 30 | Nominations must be approved by at least two existing maintainers, with no dissenting maintainer. 31 | In case of disagreement, decisions on accepting new maintainers will be based on a majority vote 32 | as above. Decisions on removing maintainers from the list are based on majority vote. 33 | 34 | The current maintainers are: 35 | 36 | - Andrew Davison (`@apdavison`_) 37 | - Samuel Garcia (`@samuelgarcia`_) 38 | - Julia Sprenger (`@JuliaSprenger`_) 39 | - Michael Denker (`@mdenker`_) 40 | - Alessio Buccino (`@alejoe91`_) 41 | - Zach McKenzie (`@zm711`_) 42 | 43 | 44 | .. _`Neo maintainers team`: https://github.com/orgs/NeuralEnsemble/teams/neo-maintainers 45 | .. _`CODE_OF_CONDUCT.md`: https://github.com/NeuralEnsemble/python-neo/blob/master/CODE_OF_CONDUCT.md 46 | .. _`@apdavison`: https://github.com/apdavison 47 | .. _`@samuelgarcia`: https://github.com/samuelgarcia 48 | .. _`@JuliaSprenger`: https://github.com/JuliaSprenger 49 | .. _`@mdenker`: https://github.com/mdenker 50 | .. _`@alejoe91`: https://github.com/alejoe91 51 | .. _`@zm711`: https://github.com/zm711 52 | -------------------------------------------------------------------------------- /doc/source/images/IODiagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/IODiagram.png -------------------------------------------------------------------------------- /doc/source/images/base_schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/base_schematic.png -------------------------------------------------------------------------------- /doc/source/images/incf_endorsed_with_spacing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/incf_endorsed_with_spacing.png -------------------------------------------------------------------------------- /doc/source/images/multi_segment_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/multi_segment_diagram.png -------------------------------------------------------------------------------- /doc/source/images/multi_segment_diagram_spiketrain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/multi_segment_diagram_spiketrain.png -------------------------------------------------------------------------------- /doc/source/images/neologo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/neologo.png -------------------------------------------------------------------------------- /doc/source/images/neologo_darkmode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/neologo_darkmode.png -------------------------------------------------------------------------------- /doc/source/images/neologo_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/neologo_favicon.png -------------------------------------------------------------------------------- /doc/source/images/neologo_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/neologo_light.png -------------------------------------------------------------------------------- /doc/source/images/neologo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/neologo_small.png -------------------------------------------------------------------------------- /doc/source/images/neologo_small_darkmode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/neologo_small_darkmode.png -------------------------------------------------------------------------------- /doc/source/images/simple_generated_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/doc/source/images/simple_generated_diagram.png -------------------------------------------------------------------------------- /doc/source/install.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Download and install Neo 3 | ======================== 4 | 5 | Neo is a pure Python package, so it should be easy to get it running on any 6 | system. 7 | 8 | Installing with pip 9 | =================== 10 | 11 | You can install the latest published version of Neo and its dependencies using:: 12 | 13 | $ pip install neo 14 | 15 | 16 | Dependencies 17 | ------------ 18 | 19 | * Python_ >= 3.8 20 | * numpy_ >= 1.19.5 21 | * quantities_ >= 0.12.1 22 | 23 | Certain IO modules have additional dependencies. If these are not satisfied, 24 | Neo will still install but the IO module that uses them will fail on loading: 25 | 26 | * scipy >= 1.0.0 for NeoMatlabIO 27 | * h5py >= 2.5 for KwikIO 28 | * klusta for KwikIO 29 | * igor2 >= 0.5.2 for IgorIO 30 | * nixio >= 1.5 for NixIO 31 | * stfio for StimfitIO 32 | * pillow for TiffIO 33 | 34 | These dependencies can be installed by specifying a comma-separated list with the 35 | ``pip install`` command, e.g.:: 36 | 37 | $ pip install neo[nixio,tiffio] 38 | 39 | Or when installing a specific version of neo:: 40 | 41 | $ pip install neo[nixio,tiffio]==0.9.0 42 | 43 | The following IO modules have additional dependencies: 44 | 45 | * igorproio 46 | * kwikio 47 | * neomatlabio 48 | * nixio 49 | * stimfitio 50 | * tiffio 51 | 52 | 53 | Installing from source 54 | ====================== 55 | 56 | To download and install the package manually, download: 57 | 58 | |neo_github_url| 59 | 60 | 61 | Then: 62 | 63 | .. parsed-literal:: 64 | 65 | $ unzip neo-|release|.zip 66 | $ cd neo-|release| 67 | $ pip install . 68 | 69 | Alternatively, to install the latest version of Neo from the Git repository:: 70 | 71 | $ git clone git://github.com/NeuralEnsemble/python-neo.git 72 | $ cd python-neo 73 | $ pip install . 74 | 75 | 76 | Installing with Conda 77 | ===================== 78 | 79 | :: 80 | 81 | $ conda config --add channels conda-forge 82 | $ conda config --set channel_priority strict 83 | $ conda install -c conda-forge python-neo 84 | 85 | 86 | Installing from a package repository 87 | ==================================== 88 | 89 | To install Neo if you're using Fedora_ Linux:: 90 | 91 | $ sudo dnf install python-neo 92 | 93 | .. NeuroDebian seems out of date - still has Trac as homepage - how to update? 94 | 95 | To install Neo if you're using the Spack_ package manager:: 96 | 97 | $ spack install py-neo 98 | 99 | 100 | .. _`Python`: https://www.python.org/ 101 | .. _`numpy`: https://numpy.org/ 102 | .. _`quantities`: https://pypi.org/project/quantities/ 103 | .. _`pip`: https://pypi.org/project/pip/ 104 | .. _`setuptools`: http://pypi.python.org/pypi/setuptools 105 | .. _Anaconda: https://www.anaconda.com/distribution/ 106 | .. _Fedora: https://src.fedoraproject.org/rpms/python-neo 107 | .. _Spack: https://spack.readthedocs.io/en/latest/package_list.html#py-neo 108 | -------------------------------------------------------------------------------- /doc/source/iolist.rst: -------------------------------------------------------------------------------- 1 | List of implemented IO modules 2 | ============================== 3 | 4 | .. automodule:: neo.io 5 | -------------------------------------------------------------------------------- /doc/source/neo_users.rst: -------------------------------------------------------------------------------- 1 | ================= 2 | Who is using Neo? 3 | ================= 4 | 5 | .. note:: This page has not yet been written. 6 | It will highlight some of the projects that are using Neo, 7 | such as Elephant_, ephyviewer_, PyNN_, 8 | Neurotic_, SpikeInterface_, MEArec_, tridesclous_, 9 | uncertainpy_ and eFEL_. 10 | 11 | .. note:: We also plan to maintain a list of publications that mention use of Neo and/or cite the Neo article. 12 | For now, you can view mentions on SciCrunch_ and on `Google Scholar`_, 13 | and read `comments from Neo users`_ from the INCF review of Neo as a community standard. 14 | 15 | 16 | .. _Elephant: https://github.com/NeuralEnsemble/elephant 17 | .. _ephyviewer: https://github.com/NeuralEnsemble/ephyviewer 18 | .. _PyNN: https://github.com/NeuralEnsemble/PyNN 19 | .. _Neurotic: https://github.com/jpgill86/neurotic 20 | .. _SpikeInterface: https://github.com/SpikeInterface 21 | .. _MEArec: https://github.com/alejoe91/MEArec 22 | .. _tridesclous: https://github.com/tridesclous/tridesclous 23 | .. _uncertainpy: https://github.com/simetenn/uncertainpy 24 | .. _eFEL: https://github.com/BlueBrain/eFEL 25 | .. _SciCrunch: https://scicrunch.org/resolver/SCR_000634/mentions?q=&i=rrid:scr_000634 26 | .. _`Google Scholar`: https://scholar.google.com/scholar?hl=en&as_sdt=0%2C5&q=%22RRID%3ASCR_000634%22+OR+%22SCR_000634%22+OR+%22neuralensemble.org%2Fneo%2F%22+OR+%22github.com%2FNeuralEnsemble%2Fpython-neo%22&btnG= 27 | .. _`comments from Neo users`: https://f1000research.com/documents/11-658 28 | -------------------------------------------------------------------------------- /doc/source/rawiolist.rst: -------------------------------------------------------------------------------- 1 | List of implemented RawIO modules 2 | ================================= 3 | 4 | .. automodule:: neo.rawio 5 | -------------------------------------------------------------------------------- /doc/source/releases.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Release notes 3 | ============= 4 | 5 | 6 | .. toctree:: 7 | :maxdepth: 1 8 | 9 | releases/0.14.1.rst 10 | releases/0.14.0.rst 11 | releases/0.13.4.rst 12 | releases/0.13.3.rst 13 | releases/0.13.2.rst 14 | releases/0.13.1.rst 15 | releases/0.13.0.rst 16 | releases/0.12.0.rst 17 | releases/0.11.1.rst 18 | releases/0.11.0.rst 19 | releases/0.10.2.rst 20 | releases/0.10.1.rst 21 | releases/0.10.0.rst 22 | releases/0.9.0.rst 23 | releases/0.8.0.rst 24 | releases/0.7.2.rst 25 | releases/0.7.1.rst 26 | releases/0.7.0.rst 27 | releases/0.6.0.rst 28 | releases/0.5.2.rst 29 | releases/0.5.1.rst 30 | releases/0.5.0.rst 31 | 32 | 33 | 34 | .. releases/0.2.0.rst 35 | .. releases/0.2.1.rst 36 | .. releases/0.3.0.rst 37 | .. releases/0.3.1.rst 38 | .. releases/0.3.2.rst 39 | .. releases/0.3.3.rst 40 | 41 | 42 | Version 0.4.0 43 | ------------- 44 | 45 | * added StimfitIO 46 | * added KwikIO 47 | * significant improvements to AxonIO, BlackrockIO, BrainwareSrcIO, NeuroshareIO, PlexonIO, Spike2IO, TdtIO, 48 | * many test suite improvements 49 | * Container base class 50 | 51 | 52 | Version 0.3.3 53 | ------------- 54 | 55 | * fix a bug in PlexonIO where some EventArrays only load 1 element. 56 | * fix a bug in BrainwareSrcIo for segments with no spikes. 57 | 58 | 59 | Version 0.3.2 60 | ------------- 61 | 62 | * cleanup of io test code, with additional helper functions and methods 63 | * added BrainwareDamIo 64 | * added BrainwareF32Io 65 | * added BrainwareSrcIo 66 | 67 | 68 | Version 0.3.1 69 | ------------- 70 | 71 | * lazy/cascading improvement 72 | * load_lazy_olbject() in neo.io added 73 | * added NeuroscopeIO 74 | 75 | 76 | Version 0.3.0 77 | ------------- 78 | 79 | * various bug fixes in neo.io 80 | * added ElphyIO 81 | * SpikeTrain performance improved 82 | * An IO class now can return a list of Block (see read_all_blocks in IOs) 83 | * python3 compatibility improved 84 | 85 | 86 | Version 0.2.1 87 | ------------- 88 | 89 | * assorted bug fixes 90 | * added :func:`time_slice()` method to the :class:`SpikeTrain` and :class:`AnalogSignalArray` classes. 91 | * improvements to annotation data type handling 92 | * added PickleIO, allowing saving Neo objects in the Python pickle format. 93 | * added ElphyIO (see http://neuro-psi.cnrs.fr/spip.php?article943) 94 | * added BrainVisionIO (see https://brainvision.com/) 95 | * improvements to PlexonIO 96 | * added :func:`merge()` method to the :class:`Block` and :class:`Segment` classes 97 | * development was mostly moved to GitHub, although the issue tracker is still at neuralensemble.org/neo 98 | 99 | 100 | Version 0.2.0 101 | ------------- 102 | 103 | New features compared to Neo 0.1: 104 | 105 | * new schema more consistent. 106 | * new objects: RecordingChannelGroup, EventArray, AnalogSignalArray, EpochArray 107 | * Neuron is now Unit 108 | * use the quantities_ module for everything that can have units. 109 | * Some objects directly inherit from Quantity: SpikeTrain, AnalogSignal, AnalogSignalArray, instead of having an attribute for data. 110 | * Attributes are classified in 3 categories: necessary, recommended, free. 111 | * lazy and cascade keywords are added to all IOs 112 | * Python 3 support 113 | * better tests 114 | 115 | 116 | 117 | .. _quantities: https://pypi.org/project/quantities/ 118 | -------------------------------------------------------------------------------- /doc/source/releases/0.10.0.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.10.0 release notes 3 | ======================== 4 | 5 | 27th July 2021 6 | 7 | 8 | New IO modules 9 | -------------- 10 | 11 | .. currentmodule:: neo.io 12 | 13 | * :class:`CedIO` - an alternative to :class:`Spike2IO` 14 | * :class:`AxonaIO` 15 | * :class:`OpenEphysIO` - handle the binary format 16 | * :class:`PhyIO` 17 | * :class:`SpikeGLXIO` 18 | * :class:`NWBIO` - support for a subset of the `NWB:N`_ format 19 | * :class:`MaxwellIO` 20 | 21 | 22 | Bug fixes and improvements in IO modules 23 | ---------------------------------------- 24 | 25 | * :class:`NeuralynxIO` was refactored and now supports new file versions (neuraview) and single file loading. 26 | * Legacy versions of old IOs were removed for NeuralynxIO (neuralynxio_v1), BlackrockIO, NeoHdf5IO. 27 | * :class:`NixIOfr` now supports array annotations of :class:`AnalogSignal` objects. 28 | * :class:`NSDFIO` was removed because we can no longer maintain it. 29 | * all IOs now accept :class:`pathlib.Path` objects. 30 | * The IO modules of this release have been tested with version 0.1.0 of the `ephy_testing_data`_. 31 | 32 | 33 | Removal of Unit and ChannelIndex 34 | -------------------------------- 35 | 36 | .. currentmodule:: neo.core 37 | 38 | In version 0.9.0 :class:`Group` and :class:`ChannelView` were introduced, replacing :class:`Unit` and :class:`ChannelIndex`, which were deprecated. 39 | In this version the deprecated :class:`Unit` and :class:`ChannelIndex` are removed and only the new :class:`Group` and :class:`ChannelView` objects are available. 40 | 41 | Supported Python and NumPy versions 42 | ----------------------------------- 43 | 44 | We no longer support Python 3.6, nor versions of NumPy older than 1.16. 45 | 46 | Other new or modified features 47 | ------------------------------ 48 | 49 | * Lists of :class:`SpikeTrain` objects can now also be created from two arrays: one containing spike times 50 | and the other unit identities of the times (:class:`SpikeTrainList`). 51 | * Object identity is now preserved when using utility :func:`time_slice()` methods. 52 | 53 | See all `pull requests`_ included in this release and the `list of closed issues`_. 54 | 55 | RawIO modules 56 | ------------- 57 | 58 | Internal refactoring of the neo.rawio module regarding channel grouping. 59 | Now the concept of a signal stream is used to handle channel groups for signals. 60 | This enhances the way the :attr:`annotation` and :attr:`array_annotation` attributes are rendered at neo.io level. 61 | 62 | Acknowledgements 63 | ---------------- 64 | 65 | Thanks to Samuel Garcia, Julia Sprenger, Peter N. Steinmetz, Andrew Davison, Steffen Bürgers, 66 | Regimantas Jurkus, Alessio Buccino, Shashwat Sridhar, Jeffrey Gill, Etienne Combrisson, 67 | Ben Dichter and Elodie Legouée for their contributions to this release. 68 | 69 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+milestone%3A0.10.0+is%3Aclosed 70 | .. _`pull requests`: https://github.com/NeuralEnsemble/python-neo/pulls?q=is%3Apr+is%3Aclosed+merged%3A%3E2020-11-10+milestone%3A0.10.0 71 | .. _`ephy_testing_data`: https://gin.g-node.org/NeuralEnsemble/ephy_testing_data/src/v0.1.0 72 | .. _`NWB:N`: https://www.nwb.org/nwb-neurophysiology/ 73 | -------------------------------------------------------------------------------- /doc/source/releases/0.10.1.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.10.1 release notes 3 | ======================== 4 | 5 | 2nd March 2022 6 | 7 | 8 | Bug fixes and improvements in IO modules 9 | ---------------------------------------- 10 | 11 | * :class:`NeuralynxIO` memory performace was improved during initialization [#998](https://github.com/NeuralEnsemble/python-neo/pull/990) and new arguments for file selection were added [#1023](https://github.com/NeuralEnsemble/python-neo/pull/1023) [#1043](https://github.com/NeuralEnsemble/python-neo/pull/1043) 12 | * :class:`TdtIO` can load single block tdt datasets [#1057](https://github.com/NeuralEnsemble/python-neo/pull/1057) 13 | * :class:`SpikeGLXIO` supports neuropixel 2.0 format [#1045](https://github.com/NeuralEnsemble/python-neo/pull/1045) and uses corrected gain values [#1069](https://github.com/NeuralEnsemble/python-neo/pull/1069) 14 | * :class:`NixIO` some bug fix related to nixio module 15 | * :class:`NwbIO` various improvement [#1052](https://github.com/NeuralEnsemble/python-neo/pull/1052) [#1054](https://github.com/NeuralEnsemble/python-neo/pull/1054) 16 | * :class:`OpenEphysIO` small bug fix [#1062](https://github.com/NeuralEnsemble/python-neo/pull/1062) 17 | * :class:`MaxwellIO` bug fix [#1074](https://github.com/NeuralEnsemble/python-neo/pull/1074) 18 | * :class:`NeuroscopeIO` bug fix [#1078](https://github.com/NeuralEnsemble/python-neo/pull/1078) 19 | * The IO modules of this release have been tested with version 0.1.1 of the `ephy_testing_data`_. 20 | 21 | Documentation 22 | ------------- 23 | A project governance guide has been added [#1048](https://github.com/NeuralEnsemble/python-neo/pull/1048) 24 | 25 | 26 | Acknowledgements 27 | ---------------- 28 | 29 | Thanks to Samuel Garcia, Julia Sprenger, Andrew Davison, Alessio Buccino, Ben Dichter, 30 | Elodie Legouée, Eric Larson and Heberto Mayorquin for their contributions to this release. 31 | 32 | .. _`ephy_testing_data`: https://gin.g-node.org/NeuralEnsemble/ephy_testing_data/src/v0.1.1 33 | 34 | -------------------------------------------------------------------------------- /doc/source/releases/0.10.2.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.10.2 release notes 3 | ======================== 4 | 5 | 8th March 2022 6 | 7 | This release fixes the following bugs introduced in 0.10.1: 8 | 9 | 1. Remove broken imports in `spike2rawio.py `_ 10 | 2. Fix the compilation of the documentation on `readthedoc `_ 11 | -------------------------------------------------------------------------------- /doc/source/releases/0.11.0.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.11.0 release notes 3 | ======================== 4 | 5 | 1st September 2022 6 | 7 | .. currentmodule:: neo.io 8 | 9 | Bug fixes and improvements in IO modules 10 | ---------------------------------------- 11 | 12 | Bug fixes and/or improvements have been made to :class:`NWBIO`, :class:`NeoMatlabIO`, :class:`NixIO`, 13 | :class:`AxonIO`, :class:`SpikeGLXIO`, :class:`NeuroshareIO`, :class:`NeuroScopeIO`, 14 | :class:`NeuralynxIO`, :class:`OpenEphysIO`, :class:`AsciiSignalIO`, :class:`AlphaOmegaIO`, 15 | and :class:`TdtIO`. 16 | 17 | New IO modules 18 | -------------- 19 | 20 | Modules :class:`BiocamIO` and :class:`EDFIO` have been added. 21 | 22 | Supported NumPy versions 23 | ------------------------ 24 | 25 | We no longer support versions of NumPy older than 1.18.5. 26 | 27 | 28 | Other changes 29 | ------------- 30 | 31 | .. currentmodule:: neo.io.spiketrainlist 32 | 33 | - documentation fixes and updates 34 | - improvements to :class:`SpikeTrainList` 35 | 36 | See all `pull requests`_ included in this release and the `list of closed issues`_. 37 | 38 | Acknowledgements 39 | ---------------- 40 | 41 | Thanks to Julia Sprenger, Samuel Garcia, Heberto Mayorquin, Andrew Davison, Tom Donoghue, 42 | Alessio Buccino, Thomas Perret, Saksham Sharda, Ben Dichter and Elodie Legouée 43 | for their contributions to this release. 44 | 45 | .. generated with git shortlog --since=2022-03-08 -sne then checking Github for PRs merged since the last release but with commits before then 46 | 47 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+milestone%3A0.11.0+is%3Aclosed 48 | .. _`pull requests`: https://github.com/NeuralEnsemble/python-neo/pulls?q=is%3Apr+is%3Aclosed+merged%3A%3E2022-03-08+milestone%3A0.11.0 49 | -------------------------------------------------------------------------------- /doc/source/releases/0.11.1.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.11.1 release notes 3 | ======================== 4 | 5 | 21st October 2022 6 | 7 | .. currentmodule:: neo.io 8 | 9 | Bug fixes and improvements in IO modules 10 | ---------------------------------------- 11 | 12 | Bug fixes and/or improvements have been made to 13 | :class:`OpenEphysBinaryIO`, :class:`BlackrockIO`, :class:`NWBIO`, :class:`PhyIO`, :class:`NeuralynxIO` 14 | 15 | 16 | Supported format versions 17 | ------------------------- 18 | 19 | :class:`BlackrockIO` now supports file version 3.0 20 | 21 | 22 | Other changes 23 | ------------- 24 | 25 | New installation mode 26 | 27 | - Neo can now be installed including all optional dependencies via *pip install neo[all]* 28 | 29 | Faster import 30 | 31 | - Dependency imports have been optimized for faster import of Neo 32 | 33 | Epoch durations 34 | 35 | - Epoch durations of epochs can now be of type float 36 | 37 | See all `pull requests`_ included in this release and the `list of closed issues`_. 38 | 39 | Acknowledgements 40 | ---------------- 41 | 42 | Thanks to Andrew Davison, Julia Sprenger, Chadwick Boulay, Alessio Buccino, Elodie Legouée, Samuel Garcia for their contributions to this release. 43 | 44 | .. generated with git shortlog --since=2022-09-01 -sne then checking Github for PRs merged since the last release but with commits before then 45 | 46 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+milestone%3A0.11.1+is%3Aclosed 47 | .. _`pull requests`: https://github.com/NeuralEnsemble/python-neo/pulls?q=is%3Apr+is%3Aclosed+merged%3A%3E2022-09-01+milestone%3A0.11.1 48 | -------------------------------------------------------------------------------- /doc/source/releases/0.12.0.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.12.0 release notes 3 | ======================== 4 | 5 | 17th February 2023 6 | 7 | .. currentmodule:: neo.io 8 | 9 | Change of packaging system 10 | -------------------------- 11 | 12 | We have updated our tooling for building and installing Neo to follow the 13 | `latest recommendations`_ of the Python community (using pyproject.toml, etc.) 14 | 15 | For users, this means you should always use `pip` to install Neo, 16 | unless you're using another package manager such as `conda`, `spack`, 17 | or a Linux package manager. 18 | 19 | 20 | Improved file format detection 21 | ------------------------------ 22 | 23 | In addition to the existing :func:`get_io()` function, there is now an additional utility function 24 | for finding a suitable IO for a given dataset. 25 | 26 | :func:`list_candidate_ios()` provides a list of all IOs supporting the formats detected in a given path. 27 | This list is generated based on the file extension of the file 28 | or the extensions of the matching files in a given folder, 29 | potentially also scanning subfolders if required. 30 | 31 | 32 | Bug fixes and improvements in IO modules 33 | ---------------------------------------- 34 | 35 | Bug fixes and/or improvements have been made to 36 | :class:`OpenEphysBinaryIO` and :class:`NWBIO`. 37 | 38 | 39 | Other changes 40 | ------------- 41 | 42 | - The IO test suite has been greatly improved, with a substantial speed-up. 43 | 44 | 45 | See all `pull requests`_ included in this release and the `list of closed issues`_. 46 | 47 | Updated dependencies 48 | -------------------- 49 | 50 | We have dropped support for Python 3.7 and added support for 3.11. 51 | Neo now requires NumPy version >=1.19.5 and Quantities >=v0.14.1. 52 | 53 | 54 | Acknowledgements 55 | ---------------- 56 | 57 | Thanks to Julia Sprenger, Andrew Davison, and Samuel Garcia for their contributions to this release. 58 | 59 | .. generated with git shortlog --since=2022-10-21 -sne then checking Github for PRs merged since the last release but with commits before then 60 | 61 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+milestone%3A0.12.0+is%3Aclosed 62 | .. _`pull requests`: https://github.com/NeuralEnsemble/python-neo/pulls?q=is%3Apr+is%3Aclosed+merged%3A%3E2022-10-21+milestone%3A0.12.0 63 | .. _`latest recommendations`: https://packaging.python.org/en/latest/ -------------------------------------------------------------------------------- /doc/source/releases/0.13.1.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.13.1 release notes 3 | ======================== 4 | 5 | 7th May 2024 6 | 7 | 8 | This release of Neo contains a lot of improvements to code quality and documentation, 9 | still with a focus on the planned 1.0 release, 10 | together with, as usual, bug fixes and performance improvements in IO modules. 11 | 12 | See all `pull requests`_ included in this release and the `list of closed issues`_. 13 | 14 | Code and documentation quality 15 | ------------------------------ 16 | 17 | Particular thanks go to Zach McKenzie, who has checked, and rewritten if necessary, every docstring in the project, 18 | to ensure they all have a consistent style. 19 | Zach has also updated and improved the :doc:`../examples/index` in the Sphinx documentation. 20 | 21 | The Neo code base contained a lot of ``assert``\s that should be exceptions. 22 | These have all been replaced with appropriate exceptions (again by Zach McKenzie). 23 | A new exception class, :class:`NeoReadWriteError` has been introduced. 24 | 25 | Bug fixes and improvements in IO modules 26 | ---------------------------------------- 27 | 28 | Bug fixes and/or improvements have been made to :class:`SpikeGLXIO`, :class:`OpenEphysIO`, :class:`SpikeGadgetsIO`, 29 | :class:`MaxwellIO`, :class:`AxonIO`, :class:`IntanIO`, :class:`TDTIO`, :class:`NeuralynxIO` and :class:`BlackrockIO`. 30 | 31 | 32 | Acknowledgements 33 | ---------------- 34 | 35 | Thanks to Zach McKenzie, Andrew Davison, Heberto Mayorquin, Alessio Buccino, Samuel Garcia, Peter N. Steinmetz, 36 | Aitor Morales-Gregorio, Greg Knoll, Chris Halcrow and Szonja Weigl for their contributions to this release. 37 | 38 | .. generated with git shortlog --since=2024-02-02 -sne then checking Github for PRs merged since the last release but with commits before then 39 | 40 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+milestone%3A0.13.1+is%3Aclosed 41 | .. _`pull requests`: https://github.com/NeuralEnsemble/python-neo/pulls?q=is%3Apr+is%3Aclosed+merged%3A%3E2024-02-02+milestone%3A0.13.1 42 | .. _`examples gallery`: https://neo.readthedocs.io/en/latest/examples/ 43 | -------------------------------------------------------------------------------- /doc/source/releases/0.13.2.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.13.2 release notes 3 | ======================== 4 | 5 | 1st August 2024 6 | 7 | This release of Neo contains bug fixes, still with a focus on the planned 1.0 release, 8 | along with some performance improvements in IO modules and updates to the CI. 9 | 10 | See all `pull requests`_ included in this release and the `list of closed issues`_. 11 | 12 | 13 | Continuous Integration 14 | ---------------------- 15 | 16 | Core tests now run on python 3.12. 17 | 18 | IO tests now run on python 3.9 and python 3.11. 19 | 20 | 21 | Performance Improvements & Code quality 22 | --------------------------------------- 23 | 24 | The imports across the code base were standardized to standard library, 3rd party, 25 | and then 1st party for top level imports. 26 | 27 | Additionally, :code:`neo` import time was improved. 28 | 29 | 30 | Bug fixes and improvements in IO modules 31 | ---------------------------------------- 32 | 33 | Bug fixes and/or improvements have been made to :class:`IntanIO`, :class:`PlexonIO`, :class:`SpikeGadgetsIO`, 34 | :class:`NeuralynxIO`, :class:`SpikeGLXIO`, :class:`BlackrockIO`, and :class:`RawBinarySignalRawIO`. 35 | 36 | Acknowledgements 37 | ---------------- 38 | 39 | Thanks to Heberto Mayorquin, Zach McKenzie, Alessio Buccino, Andrew Davison, Chris Heydrick, 40 | Anthony Pinto, Kyu Hun Lee, Téo Lohrer, Tom Donoghue, Xin Niu, and Samuel Garcia for their 41 | contributions to this release. 42 | 43 | .. _`pull requests`: https://github.com/NeuralEnsemble/python-neo/pulls?q=is%3Apr+is%3Aclosed+milestone%3A0.13.2 44 | 45 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+is%3Aclosed+milestone%3A0.13.2 -------------------------------------------------------------------------------- /doc/source/releases/0.13.3.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.13.3 release notes 3 | ======================== 4 | 5 | 28 August 2024 6 | 7 | This release of Neo contains bug fixes, still with a focus on the planned 1.0 release, 8 | and will be the last release not to support NumPy 2.0. 9 | 10 | See all `pull requests`_ included in this release and the `list of closed issues`_. 11 | 12 | 13 | Updated dependencies 14 | -------------------- 15 | 16 | Neo has a limit of NumPy >= 1.19.5, < 2.0.0 and Quantities >= 14.0.1, < 0.16.0 17 | 18 | 19 | Bug fixes and improvements in IO modules 20 | ---------------------------------------- 21 | 22 | Bug fixes and/or improvements have been made to :class:`PlexonIO`, :class:`SpikeGLXIO`, 23 | :class:`BiocamIO`. 24 | 25 | Acknowledgements 26 | ---------------- 27 | 28 | Thanks to Zach McKenzie, Heberto Mayorquin, and Alessio Buccino for their contributions to this release. 29 | 30 | 31 | .. _`pull requests`: https://github.com/NeuralEnsemble/python-neo/pulls?q=is%3Apr+is%3Aclosed+milestone%3A0.13.3 32 | 33 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+is%3Aclosed+milestone%3A0.13.3 -------------------------------------------------------------------------------- /doc/source/releases/0.14.0.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.14.0 release notes 3 | ======================== 4 | 5 | 17 January 2025 6 | 7 | This release of Neo is now compatible with NumPy 2.0 for core and IOs (with the exception of :class:`MedIO`) as well as Python 3.13, 8 | and includes IO bug fixes with an eye toward a 1.0 release. 9 | 10 | See all `pull requests`_ included in this release and the `list of closed issues`_. 11 | 12 | Updated dependencies 13 | -------------------- 14 | 15 | Neo now has a limit of NumPy >= 1.22.4 16 | 17 | CI Improvements 18 | --------------- 19 | 20 | To ensure compatiblility between pre- and post- NumPy 2.0 the CI was changed to test on the lowest supported Python (3.9) and 21 | the highest supported Python (3.13) each with NumPy 1.26 as well as NumPy 2.0 for all :code:`RawIO` and :code:`IO` tests. 22 | 23 | We also no longer use a cached conda env for testing as we see that there is no speed benefit to caching and we had some issues 24 | with the caches getting corrupted. 25 | 26 | Testing of additional Python-NumPy combinations for core tests were added (NumPy 2.0 and 2.1 with their respective Python versions). 27 | 28 | Bug fixes and improvements in IO modules 29 | ---------------------------------------- 30 | 31 | Bug fixes and/or improvements have been made to :class:`NeuroNexusIO`, :class:`OpenEphysBinaryIO`, :class:`MicromedIO`, :class:`IntanIO` and :class:`SpikeGLX`. 32 | 33 | Acknowledgements 34 | ---------------- 35 | 36 | Thanks to Zach McKenzie, Heberto Mayorquin, Andrew Davison, Luigi Petrucco, Alessio Buccino, and Samuel Garcia. 37 | 38 | .. _`pull requests` : https://github.com/NeuralEnsemble/python-neo/pulls?q=is%3Apr+is%3Aclosed+milestone%3A0.14.0 39 | 40 | .. _`list of closed issues` : https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue%20state%3Aclosed%20milestone%3A0.14.0 -------------------------------------------------------------------------------- /doc/source/releases/0.14.1.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Neo 0.14.1 release notes 3 | ======================== 4 | 5 | 14 April 25 6 | 7 | This release of Neo includes many bug fixes in various IOs, a new HTML based repr, and fixes to the CI all with an eye toward our 1.0 release. 8 | 9 | See all `pull requests`_ included in this release and the `list of closed issues`_. 10 | 11 | 12 | Updated dependencies 13 | -------------------- 14 | 15 | setuptools >= 78.0.2 16 | numpy >= 1.24.4 17 | 18 | Import improvements 19 | ------------------- 20 | 21 | As part of our ongoing effort to improve the speed of importing Neo we have moved the library over to using :code:`importlib.util.find_spec` 22 | rather than eagerly importing packages in :code:`try-except` blocks. 23 | 24 | CI Improvements 25 | --------------- 26 | 27 | The install for datalad/git-annex in the CI was fixed for our Python 3.12 tests allowing for all IOs to be tested on Python 3.9 and Python 3.12. 28 | The buidling of documentation was improved by fixing code style errors. 29 | 30 | 31 | HTML repr 32 | --------- 33 | 34 | Thanks to the work of Heberto Mayorquin Neo now supports an html based repr. To see an example check out `html repr`_. 35 | 36 | 37 | Bug fixes and improvements in IO modules 38 | ---------------------------------------- 39 | 40 | Bug fixes and/or improvements have been made to :code:`BlackRockIO`, :code:`SpikeGLXIO`, :code:`MaxwellIO`, :code:`IntanIO`, :code:`TdtIO`, 41 | :code:`OpenEphysBinaryIO`, :code:`NeoMatlabIO`, :code:`EdfIO`, :code:`Neuralynx`, and :code:`SpikeGadgetsIO`. 42 | 43 | 44 | Acknowledgements 45 | ---------------- 46 | 47 | Thanks to Heberto Mayorquin, Zach McKenzie, Andrew Davison, Alessio Buccino, Rémi Proville, Paul Adkisson, Baptiste Grimaud, 48 | Robert Wolff, Tommaso Lambresa, and Nina Kudryashova. 49 | 50 | 51 | 52 | .. _`html repr` : https://github.com/NeuralEnsemble/python-neo/pull/1651 53 | 54 | .. _`pull requests` : https://github.com/NeuralEnsemble/python-neo/pulls?q=is%3Apr+is%3Aclosed+milestone%3A0.14.1 55 | 56 | .. _`list of closed issues` : https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue%20state%3Aclosed%20milestone%3A0.14.1 -------------------------------------------------------------------------------- /doc/source/releases/0.5.1.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | Neo 0.5.1 release notes 3 | ======================= 4 | 5 | 4th May 2017 6 | 7 | * Fixes to :class:`AxonIO` (thanks to @erikli and @cjfraz) and :class:`NeuroExplorerIO` (thanks to Mark Hollenbeck) 8 | * Fixes to pickling of :class:`Epoch` and :class:`Event` objects (thanks to Hélissande Fragnaud) 9 | * Added methods :meth:`as_array()` and :meth:`as_quantity()` to Neo data objects to simplify the common tasks of turning a Neo data object back into a plain Numpy array 10 | * Added :class:`NeuralynxIO`, which reads standard Neuralynx output files in ncs, nev, nse and ntt format (thanks to Julia Sprenger and Carlos Canova). 11 | * Added the :attr:`extras_require` field to setup.py, to clearly document the requirements for different io modules. For example, this allows you to run :command:`pip install neo[neomatlabio]` and have the extra dependency needed for the :mod:`neomatlabio` module (scipy in this case) be automatically installed. 12 | * Fixed a bug where slicing an :class:`AnalogSignal` did not modify the linked :class:`ChannelIndex`. 13 | 14 | (Full `list of closed issues`_) 15 | 16 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+milestone%3A0.5.1+is%3Aclosed 17 | 18 | 19 | -------------------------------------------------------------------------------- /doc/source/releases/0.5.2.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | Neo 0.5.2 release notes 3 | ======================= 4 | 5 | 27th September 2017 6 | 7 | 8 | * Removed support for Python 2.6 9 | * Pickling :class:`AnalogSignal` and :class:`SpikeTrain` now preserves parent objects 10 | * Added NSDFIO, which reads and writes NSDF files 11 | * Fixes and improvements to PlexonIO, NixIO, BlackrockIO, NeuralynxIO, IgorIO, ElanIO, MicromedIO, TdtIO and others. 12 | 13 | Thanks to Michael Denker, Achilleas Koutsou, Mieszko Grodzicki, Samuel Garcia, Julia Sprenger, Andrew Davison, 14 | Rohan Shah, Richard C Gerkin, Mieszko Grodzicki, Mikkel Elle Lepperød, Joffrey Gonin, Hélissande Fragnaud, 15 | Elodie Legouée and Matthieu Sénoville for their contributions to this release. 16 | 17 | (Full `list of closed issues`_) 18 | 19 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+milestone%3A0.5.2+is%3Aclosed 20 | 21 | 22 | -------------------------------------------------------------------------------- /doc/source/releases/0.6.0.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | Neo 0.6.0 release notes 3 | ======================= 4 | 5 | 23rd March 2018 6 | 7 | Major changes: 8 | * Introduced :mod:`neo.rawio`: a low-level reader for various data formats 9 | * Added continuous integration for all IOs using CircleCI 10 | (previously only :mod:`neo.core` was tested, using Travis CI) 11 | * Moved the test file repository to https://gin.g-node.org/NeuralEnsemble/ephy_testing_data 12 | - this makes it easier for people to contribute new files for testing. 13 | 14 | Other important changes: 15 | * Added :func:`time_index()` and :func:`splice()` methods to :class:`AnalogSignal` 16 | * IO fixes and improvements: Blackrock, TDT, Axon, Spike2, Brainvision, Neuralynx 17 | * Implemented `__deepcopy__` for all data classes 18 | * New IO: BCI2000 19 | * Lots of PEP8 fixes! 20 | * Implemented `__getitem__` for :class:`Epoch` 21 | * Removed "cascade" support from all IOs 22 | * Removed lazy loading except for IOs based on rawio 23 | * Marked lazy option as deprecated 24 | * Added :func:`time_slice` in read_segment() for IOs based on rawio 25 | * Made :attr:`SpikeTrain.times` return a :class:`Quantity` instead of a :class:`SpikeTrain` 26 | * Raise a :class:`ValueError` if ``t_stop`` is earlier than ``t_start`` when creating an empty :class:`SpikeTrain` 27 | * Changed filter behaviour to return all objects if no filter parameters are specified 28 | * Fix pickling/unpickling of :class:`Events` 29 | 30 | Deprecated IO classes: 31 | * :class:`KlustaKwikIO` (use :class:`KwikIO` instead) 32 | * :class:`PyNNTextIO`, :class:`PyNNNumpyIO` 33 | 34 | (Full `list of closed issues`_) 35 | 36 | Thanks to Björn Müller, Andrew Davison, Achilleas Koutsou, Chadwick Boulay, Julia Sprenger, 37 | Matthieu Senoville, Michael Denker and especially Samuel Garcia for their contributions to this release. 38 | 39 | 40 | .. note:: version 0.6.1 was released immediately following 0.6.0 to fix a minor problem with the documentation. 41 | 42 | 43 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+milestone%3A0.6.0+is%3Aclosed 44 | -------------------------------------------------------------------------------- /doc/source/releases/0.7.0.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | Neo 0.7.0 release notes 3 | ======================= 4 | 5 | 26th November 2018 6 | 7 | 8 | Main added features: 9 | * array annotations 10 | 11 | Other features: 12 | * `Event.to_epoch()` 13 | * Change the behaviour of `SpikeTrain.__add__` and `SpikeTrain.__sub__` 14 | * bug fix for `Epoch.time_slice()` 15 | 16 | New IO classes: 17 | * RawMCSRawIO (raw multi channel system file format) 18 | * OpenEphys format 19 | * Intanrawio (both RHD and RHS) 20 | * AxographIO 21 | 22 | Many bug fixes and improvements in IO: 23 | * AxonIO 24 | * WinWCPIO 25 | * NixIO 26 | * ElphyIO 27 | * Spike2IO 28 | * NeoMatlab 29 | * NeuralynxIO 30 | * BlackrockIO (V2.3) 31 | * NixIO (rewritten) 32 | 33 | Removed: 34 | * PyNNIO 35 | 36 | (Full `list of closed issues`_) 37 | 38 | Thanks to Achilleas Koutsou, Andrew Davison, Björn Müller, Chadwick Boulay, erikli, Jeffrey Gill, Julia Sprenger, Lucas (lkoelman), 39 | Mark Histed, Michael Denker, Mike Sintsov, Samuel Garcia, Scott W Harden and William Hart for their contributions to this release. 40 | 41 | .. _`list of closed issues`: https://github.com/NeuralEnsemble/python-neo/issues?q=is%3Aissue+milestone%3A0.7.0+is%3Aclosed 42 | -------------------------------------------------------------------------------- /doc/source/releases/0.7.1.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | Neo 0.7.1 release notes 3 | ======================= 4 | 5 | 13th December 2019 6 | 7 | 8 | * Add alias `duplicate_with_new_array` for `duplicate_with_new_data`, for 9 | backwards compatibility 10 | * Update `NeuroshareapiIO` and `NeurosharectypesIO` to Neo 0.6 11 | * Create basic and compatibility test for `nixio_fr` 12 | 13 | Thanks to Chek Yin Choi, Andrew Davison and Julia Sprenger for their 14 | contributions to this release. 15 | -------------------------------------------------------------------------------- /doc/source/releases/0.7.2.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | Neo 0.7.2 release notes 3 | ======================= 4 | 5 | 10th July 2019 6 | 7 | 8 | New RawIO class: 9 | * AxographRawIO 10 | 11 | Bug fixes: 12 | * Various CI fixes 13 | 14 | Thanks to Andrew Davison, Samuel Garcia, Jeffrey Gill and Julia Sprenger for 15 | their contributions to this release. 16 | -------------------------------------------------------------------------------- /doc/source/scripts/spike_sorting_example.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example for usecases.rst 3 | """ 4 | 5 | import numpy as np 6 | from neo import Segment, AnalogSignal, SpikeTrain, Group, ChannelView 7 | from quantities import Hz 8 | 9 | # generate some fake data 10 | seg = Segment() 11 | seg.analogsignals.append( 12 | AnalogSignal( 13 | [ 14 | [0.1, 0.1, 0.1, 0.1], 15 | [-2.0, -2.0, -2.0, -2.0], 16 | [0.1, 0.1, 0.1, 0.1], 17 | [-0.1, -0.1, -0.1, -0.1], 18 | [-0.1, -0.1, -0.1, -0.1], 19 | [-3.0, -3.0, -3.0, -3.0], 20 | [0.1, 0.1, 0.1, 0.1], 21 | [0.1, 0.1, 0.1, 0.1], 22 | ], 23 | sampling_rate=1000 * Hz, 24 | units="V", 25 | ) 26 | ) 27 | 28 | # extract spike trains from all channels 29 | st_list = [] 30 | for signal in seg.analogsignals: 31 | # use a simple threshhold detector 32 | spike_mask = np.where(np.min(signal.magnitude, axis=1) < -1.0)[0] 33 | 34 | # create a spike train 35 | spike_times = signal.times[spike_mask] 36 | st = SpikeTrain(spike_times, t_start=signal.t_start, t_stop=signal.t_stop) 37 | 38 | # remember the spike waveforms 39 | wf_list = [] 40 | for spike_idx in np.nonzero(spike_mask)[0]: 41 | wf_list.append(signal[spike_idx - 1 : spike_idx + 2, :]) 42 | st.waveforms = np.array(wf_list) 43 | 44 | st_list.append(st) 45 | 46 | unit = Group() 47 | unit.spiketrains = st_list 48 | unit.analogsignals.extend(seg.analogsignals) 49 | -------------------------------------------------------------------------------- /environment_testing.yml: -------------------------------------------------------------------------------- 1 | name: neo-test-env 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - datalad 6 | - pip 7 | -------------------------------------------------------------------------------- /examples/README.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Examples 3 | ======== 4 | 5 | A set of examples in :file:`neo/examples/` illustrates the use of Neo classes. 6 | -------------------------------------------------------------------------------- /examples/convert_to_nwb.py: -------------------------------------------------------------------------------- 1 | """ 2 | Converting to NWB using Neo 3 | =========================== 4 | 5 | """ 6 | 7 | from urllib.request import urlretrieve 8 | from urllib.parse import quote 9 | from neo.io import get_io 10 | 11 | 12 | dataset_url = "https://object.cscs.ch/v1/AUTH_63ea6845b1d34ad7a43c8158d9572867/hbp-d000017_PatchClamp-GranuleCells_pub" 13 | 14 | folder = "GrC_Subject15_180116" 15 | 16 | # filenames = ["180116_0004 IV -70.abf", "180116_0005 CC step.abf", "180116_0006 EPSP.abf"] 17 | filenames = ["180116_0005 CC step.abf"] 18 | 19 | for filename in filenames: 20 | datafile_url = f"{dataset_url}/{folder}/{quote(filename)}" 21 | local_file = urlretrieve(datafile_url, filename) 22 | 23 | 24 | reader = get_io("180116_0005 CC step.abf") 25 | data = reader.read() 26 | 27 | global_metadata = { 28 | "session_start_time": data[0].rec_datetime, 29 | "identifier": data[0].file_origin, 30 | "session_id": "180116_0005", 31 | "institution": "University of Pavia", 32 | "lab": "D'Angelo Lab", 33 | "related_publications": "https://doi.org/10.1038/s42003-020-0953-x", 34 | } 35 | 36 | # data[0].annotate(**global_metadata) 37 | 38 | signal_metadata = { 39 | "nwb_group": "acquisition", 40 | "nwb_neurodata_type": ("pynwb.icephys", "PatchClampSeries"), 41 | "nwb_electrode": { 42 | "name": "patch clamp electrode", 43 | "description": "The patch-clamp pipettes were pulled from borosilicate glass capillaries " 44 | "(Hilgenberg, Malsfeld, Germany) and filled with intracellular solution " 45 | "(K-gluconate based solution)", 46 | "device": {"name": "patch clamp electrode"}, 47 | }, 48 | "nwb:gain": 1.0, 49 | } 50 | 51 | for segment in data[0].segments: 52 | signal = segment.analogsignals[0] 53 | signal.annotate(**signal_metadata) 54 | 55 | from neo.io import NWBIO 56 | 57 | writer = NWBIO("GrC_Subject15_180116.nwb", mode="w", **global_metadata) 58 | writer.write(data) 59 | -------------------------------------------------------------------------------- /examples/plot_igorio.py: -------------------------------------------------------------------------------- 1 | """ 2 | IgorProIO Demo (BROKEN) 3 | ======================= 4 | 5 | """ 6 | 7 | ########################################################### 8 | # Import our packages 9 | import os 10 | from urllib.request import urlretrieve 11 | import zipfile 12 | import matplotlib.pyplot as plt 13 | from neo.io import get_io 14 | 15 | ############################################################# 16 | # Then download some data 17 | # Downloaded from Human Brain Project Collaboratory 18 | # Digital Reconstruction of Neocortical Microcircuitry (nmc-portal) 19 | # http://microcircuits.epfl.ch/#/animal/8ecde7d1-b2d2-11e4-b949-6003088da632 20 | # NOTE: this dataset is not found as the link is broken. 21 | 22 | # datafile_url = "https://microcircuits.epfl.ch/data/released_data/B95.zip" 23 | # filename_zip = "B95.zip" 24 | # filename = "grouped_ephys/B95/B95_Ch0_IDRest_107.ibw" 25 | # urlretrieve(datafile_url, filename_zip) 26 | 27 | # zip_ref = zipfile.ZipFile(filename_zip) # create zipfile object 28 | # zip_ref.extract(path=".", member=filename) # extract file to dir 29 | # zip_ref.close() 30 | 31 | # ###################################################### 32 | # # Once we have our data we can use `get_io` to find an 33 | # # io (Igor in this case). Then we read the analogsignals 34 | # # Finally we will make some nice plots 35 | # reader = get_io(filename) 36 | # signal = reader.read_analogsignal() 37 | # plt.plot(signal.times, signal) 38 | # plt.xlabel(signal.sampling_period.dimensionality) 39 | # plt.ylabel(signal.dimensionality) 40 | 41 | # plt.show() 42 | -------------------------------------------------------------------------------- /examples/plot_imageseq.py: -------------------------------------------------------------------------------- 1 | """ 2 | ImageSequences 3 | ============== 4 | 5 | """ 6 | 7 | ########################################################## 8 | # Let's import some packages 9 | 10 | from neo.core import ImageSequence 11 | from neo.core import RectangularRegionOfInterest, CircularRegionOfInterest, PolygonRegionOfInterest 12 | import matplotlib.pyplot as plt 13 | import quantities as pq 14 | 15 | import random 16 | 17 | 18 | ############################################################ 19 | # Now we need to generate some data 20 | # We will just make a nice box and then we can attach this 21 | # ImageSequence to a variety of ROIs 22 | # our ImageSequence will be 50 frames of 100x100 pixel images 23 | 24 | l = [] 25 | for frame in range(50): 26 | l.append([]) 27 | for y in range(100): 28 | l[frame].append([]) 29 | for x in range(100): 30 | l[frame][y].append(random.randint(0, 50)) 31 | 32 | ##################################################################### 33 | # we then make our image sequence and pull out our results from the 34 | # image_seq 35 | 36 | image_seq = ImageSequence(l, sampling_rate=500 * pq.Hz, spatial_scale="m", units="V") 37 | 38 | result = image_seq.signal_from_region( 39 | CircularRegionOfInterest(image_seq, 50, 50, 25), 40 | CircularRegionOfInterest(image_seq, 10, 10, 5), 41 | PolygonRegionOfInterest(image_seq, (50, 25), (50, 45), (14, 65), (90, 80)), 42 | ) 43 | 44 | ############################################################### 45 | # It is easy to plot our results using matplotlib 46 | 47 | for i in range(len(result)): 48 | plt.figure() 49 | plt.plot(result[i].times, result[i]) 50 | plt.xlabel("seconde") 51 | plt.ylabel("valeur") 52 | plt.tight_layout() 53 | plt.show() 54 | -------------------------------------------------------------------------------- /examples/plot_read_files_neo_io.py: -------------------------------------------------------------------------------- 1 | """ 2 | Reading files with neo.io 3 | ========================= 4 | 5 | """ 6 | 7 | #################################################### 8 | # Start with package import and getting a datafile 9 | 10 | import urllib 11 | 12 | import neo 13 | 14 | url_repo = "https://web.gin.g-node.org/NeuralEnsemble/ephy_testing_data/raw/master/" 15 | 16 | # Plexon files 17 | distantfile = url_repo + "plexon/File_plexon_3.plx" 18 | localfile = "File_plexon_3.plx" 19 | urllib.request.urlretrieve(distantfile, localfile) 20 | 21 | 22 | ################################################### 23 | # Now we can create our reader and read some data 24 | 25 | # create a reader 26 | reader = neo.io.PlexonIO(filename="File_plexon_3.plx") 27 | # read the blocks 28 | blks = reader.read(lazy=False) 29 | print(blks) 30 | 31 | ###################################################### 32 | # Once we have our blocks we can iterate through each 33 | # block of data and see the contents of all parts of 34 | # that data 35 | 36 | # access to segments 37 | for blk in blks: 38 | for seg in blk.segments: 39 | print(seg) 40 | for asig in seg.analogsignals: 41 | print(asig) 42 | for st in seg.spiketrains: 43 | print(st) 44 | 45 | ####################################################### 46 | # Let's look at another file type 47 | 48 | # CED Spike2 files 49 | distantfile = url_repo + "spike2/File_spike2_1.smr" 50 | localfile = "./File_spike2_1.smr" 51 | urllib.request.urlretrieve(distantfile, localfile) 52 | # create a reader 53 | reader = neo.io.Spike2IO(filename="File_spike2_1.smr") 54 | 55 | ######################################################### 56 | # Despite being a different raw file format we can access 57 | # the data in the same way 58 | 59 | # read the block 60 | bl = reader.read(lazy=False)[0] 61 | print(bl) 62 | 63 | ########################################################## 64 | # Similarly we can view the different types of data within 65 | # the block (AnalogSignals and SpikeTrains) 66 | 67 | # access to segments 68 | for seg in bl.segments: 69 | print(seg) 70 | for asig in seg.analogsignals: 71 | print(asig) 72 | for st in seg.spiketrains: 73 | print(st) 74 | -------------------------------------------------------------------------------- /examples/plot_roi_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Working with RegionOfInterest objects 3 | ===================================== 4 | 5 | """ 6 | 7 | ################################################################# 8 | # Import our packages 9 | # We can import a variety of neo objects from neo.core and since an ImageSquence 10 | # also uses units let's import quantities which is the "units" library 11 | # that neo uses under the hood 12 | 13 | import matplotlib.pyplot as plt 14 | import numpy as np 15 | from neo.core import CircularRegionOfInterest, RectangularRegionOfInterest, PolygonRegionOfInterest, ImageSequence 16 | from numpy.random import rand 17 | import random 18 | import quantities as pq 19 | 20 | ################################################################## 21 | # First we create our image_sequence. Let's generate some data 22 | # In this simulated dataset we will just make an image that is 23 | # 100x100 pixels and then we will make 50 frames of this image 24 | # finally we will fill with random values for the data 25 | 26 | l = [] 27 | for frame in range(50): 28 | l.append([]) 29 | for y in range(100): 30 | l[frame].append([]) 31 | for x in range(100): 32 | l[frame][y].append(random.randint(0, 50)) 33 | 34 | # make an ImageSquence in Neo 35 | image_seq = ImageSequence(l, sampling_rate=500 * pq.Hz, spatial_scale="m", units="V") 36 | 37 | 38 | ################################################################# 39 | # Now we will write a function for plotting an roi 40 | def plot_roi(roi, shape): 41 | img = rand(120, 100) 42 | pir = np.array(roi.pixels_in_region()).T 43 | img[pir[1], pir[0]] = 5 44 | 45 | plt.imshow(img, cmap="gray_r") 46 | plt.clim(0, 5) 47 | 48 | ax = plt.gca() 49 | ax.add_artist(shape) 50 | 51 | 52 | ################################################################################ 53 | # Finally we will plot each roi to demonstrate how we could high regions of interest 54 | 55 | # First a nice circle 56 | roi = CircularRegionOfInterest(image_sequence=image_seq, x=50.3, y=50.8, radius=30.2) 57 | shape = plt.Circle(roi.centre, roi.radius, color="r", fill=False) 58 | plt.subplot(1, 3, 1) 59 | plot_roi(roi, shape) 60 | 61 | # Next a rectangle 62 | roi = RectangularRegionOfInterest(image_sequence=image_seq, x=50.3, y=40.2, width=40.1, height=50.3) 63 | shape = plt.Rectangle((roi.x - roi.width / 2.0, roi.y - roi.height / 2.0), roi.width, roi.height, color="r", fill=False) 64 | plt.subplot(1, 3, 2) 65 | plot_roi(roi, shape) 66 | 67 | # Finally we can make a polygon (in this case a triangle) 68 | roi = PolygonRegionOfInterest(image_seq, (20.3, 30.2), (80.7, 30.1), (55.2, 59.4)) 69 | shape = plt.Polygon(np.array(roi.vertices), closed=True, color="r", fill=False) 70 | plt.subplot(1, 3, 3) 71 | plot_roi(roi, shape) 72 | 73 | plt.tight_layout() 74 | plt.show() 75 | -------------------------------------------------------------------------------- /examples/plot_with_matplotlib.py: -------------------------------------------------------------------------------- 1 | """ 2 | Plotting a Neo object with matplotlib 3 | ===================================== 4 | 5 | """ 6 | 7 | import urllib 8 | 9 | import numpy as np 10 | import quantities as pq 11 | from matplotlib import pyplot 12 | 13 | import neo 14 | 15 | distantfile = "https://web.gin.g-node.org/NeuralEnsemble/ephy_testing_data/raw/master/plexon/File_plexon_3.plx" 16 | localfile = "File_plexon_3.plx" 17 | 18 | urllib.request.urlretrieve(distantfile, localfile) 19 | 20 | # reader = neo.io.NeuroExplorerIO(filename='File_neuroexplorer_2.nex') 21 | reader = neo.io.PlexonIO(filename="File_plexon_3.plx") 22 | 23 | bl = reader.read(lazy=False)[0] 24 | for seg in bl.segments: 25 | print("SEG: " + str(seg.file_origin)) 26 | fig = pyplot.figure() 27 | ax1 = fig.add_subplot(2, 1, 1) 28 | ax2 = fig.add_subplot(2, 1, 2) 29 | ax1.set_title(seg.file_origin) 30 | ax1.set_ylabel("arbitrary units") 31 | mint = 0 * pq.s 32 | maxt = np.inf * pq.s 33 | for i, asig in enumerate(seg.analogsignals): 34 | times = asig.times.rescale("s").magnitude 35 | asig = asig.magnitude 36 | ax1.plot(times, asig) 37 | 38 | trains = [st.rescale("s").magnitude for st in seg.spiketrains] 39 | colors = pyplot.cm.jet(np.linspace(0, 1, len(seg.spiketrains))) 40 | ax2.eventplot(trains, colors=colors) 41 | 42 | pyplot.show() 43 | -------------------------------------------------------------------------------- /neo/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Neo is a package for representing electrophysiology data in Python, 3 | together with support for reading a wide range of neurophysiology file formats 4 | """ 5 | 6 | import importlib.metadata 7 | 8 | # this need to be at the begining because some sub module will need the version 9 | __version__ = importlib.metadata.version("neo") 10 | 11 | import logging 12 | 13 | logging_handler = logging.StreamHandler() 14 | 15 | from neo.core import * 16 | from neo.io import * 17 | -------------------------------------------------------------------------------- /neo/core/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | :mod:`neo.core` provides classes for storing common electrophysiological data 3 | types. Some of these classes contain raw data, such as spike trains or 4 | analog signals, while others are containers to organize other classes 5 | (including both data classes and other container classes). 6 | 7 | Classes from :mod:`neo.io` return nested data structures containing one 8 | or more classes from this module. 9 | 10 | Classes: 11 | 12 | .. autoclass:: Block 13 | .. automethod:: Block.filter 14 | .. autoclass:: Segment 15 | .. automethod:: Segment.filter 16 | .. autoclass:: Group 17 | 18 | .. autoclass:: AnalogSignal 19 | .. autoclass:: IrregularlySampledSignal 20 | 21 | .. autoclass:: ChannelView 22 | 23 | .. autoclass:: Event 24 | .. autoclass:: Epoch 25 | 26 | .. autoclass:: SpikeTrain 27 | .. autoclass:: ImageSequence 28 | 29 | .. autoclass:: RectangularRegionOfInterest 30 | .. autoclass:: CircularRegionOfInterest 31 | .. autoclass:: PolygonRegionOfInterest 32 | 33 | """ 34 | 35 | from neo.core.block import Block 36 | from neo.core.segment import Segment 37 | from neo.core.analogsignal import AnalogSignal 38 | from neo.core.irregularlysampledsignal import IrregularlySampledSignal 39 | 40 | # Import FilterClasses 41 | from neo.core import filters 42 | 43 | from neo.core.event import Event 44 | from neo.core.epoch import Epoch 45 | 46 | from neo.core.spiketrain import SpikeTrain 47 | 48 | from neo.core.imagesequence import ImageSequence 49 | from neo.core.regionofinterest import RectangularRegionOfInterest, CircularRegionOfInterest, PolygonRegionOfInterest 50 | 51 | from neo.core.view import ChannelView 52 | from neo.core.group import Group 53 | 54 | from neo.core.baseneo import NeoReadWriteError 55 | 56 | # Block should always be first in this list 57 | objectlist = [ 58 | Block, 59 | Segment, 60 | AnalogSignal, 61 | IrregularlySampledSignal, 62 | Event, 63 | Epoch, 64 | SpikeTrain, 65 | ImageSequence, 66 | RectangularRegionOfInterest, 67 | CircularRegionOfInterest, 68 | PolygonRegionOfInterest, 69 | ChannelView, 70 | Group, 71 | ] 72 | 73 | objectnames = [ob.__name__ for ob in objectlist] 74 | class_by_name = dict(zip(objectnames, objectlist)) 75 | -------------------------------------------------------------------------------- /neo/io/alphaomegaio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.alphaomegarawio import AlphaOmegaRawIO 3 | 4 | 5 | class AlphaOmegaIO(AlphaOmegaRawIO, BaseFromRaw): 6 | """Class for reading data from AlphaOmega MPX file""" 7 | 8 | __doc__ = AlphaOmegaRawIO.__doc__ 9 | 10 | def __init__(self, filename, lsx_files=None, prune_channels=True): 11 | AlphaOmegaRawIO.__init__( 12 | self, 13 | dirname=filename, 14 | lsx_files=lsx_files, 15 | prune_channels=prune_channels, 16 | ) 17 | BaseFromRaw.__init__(self, filename) 18 | -------------------------------------------------------------------------------- /neo/io/asciiimageio.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from .baseio import BaseIO 4 | from neo.core import ImageSequence, Segment, Block 5 | 6 | 7 | class AsciiImageIO(BaseIO): 8 | """ 9 | IO class for reading ImageSequence in a text file 10 | 11 | *Usage*: 12 | >>> from neo import io 13 | >>> import quantities as pq 14 | >>> r = io.AsciiImageIO(file_name='File_asciiimage_1.txt',nb_frame=511, nb_row=100, 15 | ... nb_column=100,units='mm', sampling_rate=1.0*pq.Hz, 16 | ... spatial_scale=1.0*pq.mm) 17 | >>> block = r.read_block() 18 | read block 19 | creating segment 20 | returning block 21 | >>> block 22 | Block with 1 segments 23 | file_origin: 'File_asciiimage_1.txt 24 | # segments (N=1) 25 | 0: Segment with 1 imagesequences # analogsignals (N=0) 26 | 27 | """ 28 | 29 | name = "AsciiImage IO" 30 | description = "Neo IO module for optical imaging data stored as a folder of TIFF images." 31 | 32 | _prefered_signal_group_mode = "group-by-same-units" 33 | is_readable = True 34 | is_writable = False 35 | 36 | supported_objects = [Block, Segment, ImageSequence] 37 | readable_objects = supported_objects 38 | writeable_object = [] 39 | 40 | support_lazy = False 41 | 42 | read_params = {} 43 | write_params = {} 44 | 45 | extensions = [] 46 | 47 | mode = "file" 48 | 49 | def __init__( 50 | self, 51 | file_name=None, 52 | nb_frame=None, 53 | nb_row=None, 54 | nb_column=None, 55 | units=None, 56 | sampling_rate=None, 57 | spatial_scale=None, 58 | **kwargs, 59 | ): 60 | 61 | BaseIO.__init__(self, file_name, **kwargs) 62 | self.nb_frame = nb_frame 63 | self.nb_row = nb_row 64 | self.nb_column = nb_column 65 | self.units = units 66 | self.sampling_rate = sampling_rate 67 | self.spatial_scale = spatial_scale 68 | 69 | def read_block(self, lazy=False, **kwargs): 70 | 71 | file = open(self.filename, "r") 72 | data = file.read() 73 | print("read block") 74 | liste_value = [] 75 | record = [] 76 | for i in range(len(data)): 77 | 78 | if data[i] == "\n" or data[i] == "\t": 79 | t = "".join(str(e) for e in record) 80 | liste_value.append(t) 81 | record = [] 82 | else: 83 | record.append(data[i]) 84 | 85 | data = [] 86 | nb = 0 87 | for i in range(self.nb_frame): 88 | data.append([]) 89 | for y in range(self.nb_row): 90 | data[i].append([]) 91 | for x in range(self.nb_column): 92 | data[i][y].append(liste_value[nb]) 93 | nb += 1 94 | 95 | image_sequence = ImageSequence( 96 | np.array(data, dtype="float"), 97 | units=self.units, 98 | sampling_rate=self.sampling_rate, 99 | spatial_scale=self.spatial_scale, 100 | ) 101 | file.close() 102 | print("creating segment") 103 | segment = Segment(file_origin=self.filename) 104 | segment.imagesequences = [image_sequence] 105 | 106 | block = Block(file_origin=self.filename) 107 | block.segments.append(segment) 108 | print("returning block") 109 | 110 | return block 111 | -------------------------------------------------------------------------------- /neo/io/axographio.py: -------------------------------------------------------------------------------- 1 | """ 2 | AxographIO 3 | ========== 4 | 5 | IO class for reading AxoGraph files (.axgd, .axgx) 6 | """ 7 | 8 | from neo.io.basefromrawio import BaseFromRaw 9 | from neo.rawio.axographrawio import AxographRawIO 10 | 11 | 12 | class AxographIO(AxographRawIO, BaseFromRaw): 13 | """ 14 | IO class for reading AxoGraph files (.axgd, .axgx) 15 | 16 | Args: 17 | filename (string): 18 | File name of the AxoGraph file to read. 19 | force_single_segment (bool): 20 | Episodic files are normally read as multi-Segment Neo objects. This 21 | parameter can force AxographIO to put all signals into a single 22 | Segment. Default: False. 23 | 24 | Example: 25 | >>> import neo 26 | >>> r = neo.io.AxographIO(filename=filename) 27 | >>> blk = r.read_block(signal_group_mode='split-all') 28 | >>> display(blk) 29 | 30 | >>> # get signals 31 | >>> seg_index = 0 # episode number 32 | >>> sigs = [sig for sig in blk.segments[seg_index].analogsignals 33 | ... if sig.name in channel_names] 34 | >>> display(sigs) 35 | 36 | >>> # get event markers (same for all segments/episodes) 37 | >>> ev = blk.segments[0].events[0] 38 | >>> print([ev for ev in zip(ev.times, ev.labels)]) 39 | 40 | >>> # get interval bars (same for all segments/episodes) 41 | >>> ep = blk.segments[0].epochs[0] 42 | >>> print([ep for ep in zip(ep.times, ep.durations, ep.labels)]) 43 | 44 | >>> # get notes 45 | >>> print(blk.annotations['notes']) 46 | """ 47 | 48 | name = "AxographIO" 49 | description = "This IO reads .axgd/.axgx files created with AxoGraph" 50 | 51 | _prefered_signal_group_mode = "group-by-same-units" 52 | 53 | def __init__(self, filename="", force_single_segment=False): 54 | AxographRawIO.__init__(self, filename, force_single_segment) 55 | BaseFromRaw.__init__(self, filename) 56 | -------------------------------------------------------------------------------- /neo/io/axonaio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.axonarawio import AxonaRawIO 3 | 4 | 5 | class AxonaIO(AxonaRawIO, BaseFromRaw): 6 | name = "Axona IO" 7 | description = "Read raw continuous data (.bin and .set files)" 8 | 9 | def __init__(self, filename): 10 | AxonaRawIO.__init__(self, filename=filename) 11 | BaseFromRaw.__init__(self, filename) 12 | -------------------------------------------------------------------------------- /neo/io/bci2000io.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.bci2000rawio import BCI2000RawIO 3 | 4 | 5 | class BCI2000IO(BCI2000RawIO, BaseFromRaw): 6 | """Class for reading data from a BCI2000 .dat file, either version 1.0 or 1.1""" 7 | 8 | _prefered_signal_group_mode = "group-by-same-units" 9 | 10 | def __init__(self, filename): 11 | BCI2000RawIO.__init__(self, filename=filename) 12 | BaseFromRaw.__init__(self, filename) 13 | -------------------------------------------------------------------------------- /neo/io/biocamio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.biocamrawio import BiocamRawIO 3 | 4 | 5 | class BiocamIO(BiocamRawIO, BaseFromRaw): 6 | __doc__ = BiocamRawIO.__doc__ 7 | mode = "file" 8 | 9 | def __init__(self, filename, fill_gaps_strategy=None): 10 | BiocamRawIO.__init__(self, filename=filename, fill_gaps_strategy=fill_gaps_strategy) 11 | BaseFromRaw.__init__(self, filename) 12 | -------------------------------------------------------------------------------- /neo/io/blackrockio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.blackrockrawio import BlackrockRawIO 3 | 4 | 5 | class BlackrockIO(BlackrockRawIO, BaseFromRaw): 6 | """ 7 | Supplementary class for reading BlackRock data using only a single nsx file. 8 | """ 9 | 10 | name = "Blackrock IO for single nsx" 11 | description = ( 12 | "This IO reads a pair of corresponding nev and nsX files of the Blackrock " "" + "(Cerebus) recording system." 13 | ) 14 | 15 | _prefered_signal_group_mode = "group-by-same-units" 16 | 17 | def __init__(self, filename, **kargs): 18 | BlackrockRawIO.__init__(self, filename=filename, **kargs) 19 | BaseFromRaw.__init__(self, filename) 20 | -------------------------------------------------------------------------------- /neo/io/brainvisionio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.brainvisionrawio import BrainVisionRawIO 3 | 4 | 5 | class BrainVisionIO(BrainVisionRawIO, BaseFromRaw): 6 | """Class for reading data from the BrainVision product.""" 7 | 8 | _prefered_signal_group_mode = "group-by-same-units" 9 | 10 | def __init__(self, filename): 11 | BrainVisionRawIO.__init__(self, filename=filename) 12 | BaseFromRaw.__init__(self, filename) 13 | -------------------------------------------------------------------------------- /neo/io/cedio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.cedrawio import CedRawIO 3 | 4 | 5 | class CedIO(CedRawIO, BaseFromRaw): 6 | __doc__ = CedRawIO.__doc__ 7 | 8 | def __init__(self, filename, entfile=None, posfile=None): 9 | CedRawIO.__init__(self, filename=filename) 10 | BaseFromRaw.__init__(self, filename) 11 | -------------------------------------------------------------------------------- /neo/io/edfio.py: -------------------------------------------------------------------------------- 1 | """ 2 | IO for reading edf and edf+ files using pyedflib 3 | 4 | PyEDFLib 5 | https://pyedflib.readthedocs.io 6 | https://github.com/holgern/pyedflib 7 | 8 | EDF Format Specifications: https://www.edfplus.info/ 9 | 10 | Author: Julia Sprenger 11 | """ 12 | 13 | from neo.io.basefromrawio import BaseFromRaw 14 | from neo.rawio.edfrawio import EDFRawIO 15 | 16 | 17 | class EDFIO(EDFRawIO, BaseFromRaw): 18 | """ 19 | IO for reading edf and edf+ files. 20 | """ 21 | 22 | name = "EDF IO" 23 | description = "IO for reading EDF and EDF+ files" 24 | 25 | _prefered_signal_group_mode = "group-by-same-units" 26 | 27 | def __init__(self, filename=""): 28 | EDFRawIO.__init__(self, filename=filename) 29 | BaseFromRaw.__init__(self, filename) 30 | -------------------------------------------------------------------------------- /neo/io/elanio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.elanrawio import ElanRawIO 3 | 4 | 5 | class ElanIO(ElanRawIO, BaseFromRaw): 6 | """ 7 | Class for reading data from Elan. 8 | 9 | Elan is software for studying time-frequency maps of EEG data. 10 | 11 | Elan is developed in Lyon, France, at INSERM U821 12 | 13 | https://elan.lyon.inserm.fr 14 | 15 | Args: 16 | filename (string) : 17 | Full path to the .eeg file 18 | entfile (string) : 19 | Full path to the .ent file (optional). If None, the path to the ent 20 | file is inferred from the filename by adding the ".ent" extension 21 | to it 22 | posfile (string) : 23 | Full path to the .pos file (optional). If None, the path to the pos 24 | file is inferred from the filename by adding the ".pos" extension 25 | to it 26 | """ 27 | 28 | _prefered_signal_group_mode = "group-by-same-units" 29 | 30 | def __init__(self, filename, entfile=None, posfile=None): 31 | ElanRawIO.__init__(self, filename=filename, entfile=entfile, posfile=posfile) 32 | BaseFromRaw.__init__(self, filename) 33 | -------------------------------------------------------------------------------- /neo/io/exampleio.py: -------------------------------------------------------------------------------- 1 | """ 2 | neo.io has been split into a 2-level API: 3 | * neo.io: this API gives Neo objects 4 | * neo.rawio: this API gives raw data as they are in files. 5 | 6 | Developers are encourage to use neo.rawio. 7 | 8 | When this is done the neo.io can be implemented trivially 9 | using code like shown in this file. 10 | 11 | Author: sgarcia 12 | 13 | """ 14 | 15 | from neo.io.basefromrawio import BaseFromRaw 16 | from neo.rawio.examplerawio import ExampleRawIO 17 | 18 | 19 | class ExampleIO(ExampleRawIO, BaseFromRaw): 20 | name = "example IO" 21 | description = "Fake IO" 22 | 23 | # This is an inportant choice when there are several channels. 24 | # 'split-all' : 1 AnalogSignal each 1 channel 25 | # 'group-by-same-units' : one 2D AnalogSignal for each group of channel with same units 26 | _prefered_signal_group_mode = "group-by-same-units" 27 | 28 | def __init__(self, filename=""): 29 | ExampleRawIO.__init__(self, filename=filename) 30 | BaseFromRaw.__init__(self, filename) 31 | -------------------------------------------------------------------------------- /neo/io/intanio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.intanrawio import IntanRawIO 3 | 4 | 5 | class IntanIO(IntanRawIO, BaseFromRaw): 6 | __doc__ = IntanRawIO.__doc__ 7 | _prefered_signal_group_mode = "group-by-same-units" 8 | 9 | def __init__(self, filename): 10 | IntanRawIO.__init__(self, filename=filename) 11 | BaseFromRaw.__init__(self, filename) 12 | -------------------------------------------------------------------------------- /neo/io/maxwellio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.maxwellrawio import MaxwellRawIO 3 | 4 | 5 | class MaxwellIO(MaxwellRawIO, BaseFromRaw): 6 | mode = "file" 7 | 8 | def __init__(self, filename): 9 | MaxwellRawIO.__init__(self, filename=filename) 10 | BaseFromRaw.__init__(self, filename) 11 | -------------------------------------------------------------------------------- /neo/io/mearecio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.mearecrawio import MEArecRawIO 3 | 4 | 5 | class MEArecIO(MEArecRawIO, BaseFromRaw): 6 | __doc__ = MEArecRawIO.__doc__ 7 | mode = "file" 8 | 9 | def __init__(self, filename, load_spiketrains=True, load_analogsignal=True): 10 | MEArecRawIO.__init__( 11 | self, filename=filename, load_spiketrains=load_spiketrains, load_analogsignal=load_analogsignal 12 | ) 13 | BaseFromRaw.__init__(self, filename) 14 | -------------------------------------------------------------------------------- /neo/io/medio.py: -------------------------------------------------------------------------------- 1 | """ 2 | IO for reading MED datasets using dhn-med-py library. 3 | 4 | dhn-med-py 5 | https://medformat.org 6 | https://pypi.org/project/dhn-med-py/ 7 | 8 | MED Format Specifications: https://medformat.org 9 | 10 | Author: Dan Crepeau, Matt Stead 11 | """ 12 | 13 | from neo.io.basefromrawio import BaseFromRaw 14 | from neo.rawio.medrawio import MedRawIO 15 | 16 | 17 | class MedIO(MedRawIO, BaseFromRaw): 18 | """ 19 | IO for reading MED datasets. 20 | """ 21 | 22 | name = "MED IO" 23 | description = "IO for reading MED datasets" 24 | 25 | _prefered_signal_group_mode = "group-by-same-units" 26 | mode = "dir" 27 | 28 | def __init__(self, dirname=None, password=None, keep_original_times=False): 29 | MedRawIO.__init__(self, dirname=dirname, password=password, keep_original_times=keep_original_times) 30 | """ 31 | Initialise IO instance 32 | 33 | Parameters 34 | ---------- 35 | dirname : str 36 | Directory containing data files 37 | password : str 38 | MED sessions can be optionally encrypted with a password. 39 | Default: None 40 | keep_original_times : bool 41 | Preserve original time stamps as in data files. By default datasets are 42 | shifted to begin at t_start = 0. When set to True, timestamps will be 43 | returned as UTC (seconds since midnight 1 Jan 1970). 44 | Default: False 45 | """ 46 | BaseFromRaw.__init__(self, dirname) 47 | 48 | def close(self): 49 | MedRawIO.close(self) 50 | 51 | def __del__(self): 52 | MedRawIO.__del__(self) 53 | -------------------------------------------------------------------------------- /neo/io/micromedio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.micromedrawio import MicromedRawIO 3 | from neo.core import Segment, AnalogSignal, Epoch, Event 4 | 5 | 6 | class MicromedIO(MicromedRawIO, BaseFromRaw): 7 | """Class for reading/writing data from Micromed files (.trc).""" 8 | 9 | _prefered_signal_group_mode = "group-by-same-units" 10 | 11 | def __init__(self, filename): 12 | MicromedRawIO.__init__(self, filename=filename) 13 | BaseFromRaw.__init__(self, filename) 14 | -------------------------------------------------------------------------------- /neo/io/neuralynxio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Class for reading data from Neuralynx files. 3 | This IO supports NCS, NEV and NSE file formats. 4 | 5 | Depends on: numpy 6 | 7 | Supported: Read 8 | 9 | Author: Julia Sprenger, Carlos Canova 10 | """ 11 | 12 | import warnings 13 | from neo.io.basefromrawio import BaseFromRaw 14 | from neo.rawio.neuralynxrawio.neuralynxrawio import NeuralynxRawIO 15 | 16 | 17 | class NeuralynxIO(NeuralynxRawIO, BaseFromRaw): 18 | """ 19 | Class for reading data from Neuralynx files. 20 | This IO supports NCS, NEV, NSE and NTT file formats. 21 | 22 | NCS contains signals for one channel 23 | NEV contains events 24 | NSE contains spikes and waveforms for mono electrodes 25 | NTT contains spikes and waveforms for tetrodes 26 | """ 27 | 28 | _prefered_signal_group_mode = "group-by-same-units" 29 | mode = "dir" 30 | 31 | def __init__( 32 | self, 33 | dirname, 34 | use_cache=False, 35 | cache_path="same_as_resource", 36 | include_filenames=None, 37 | exclude_filenames=None, 38 | keep_original_times=False, 39 | filename=None, 40 | exclude_filename=None, 41 | ): 42 | """ 43 | Initialise IO instance 44 | 45 | Parameters 46 | ---------- 47 | dirname : str 48 | Directory containing data files 49 | filename : str 50 | Deprecated and will be removed. Please use `include_filenames` instead 51 | Name of a single ncs, nse, nev, or ntt file to include in dataset. Will be ignored, 52 | if dirname is provided. 53 | use_cache : bool, optional 54 | Cache results of initial file scans for faster loading in subsequent runs. 55 | Default: False 56 | cache_path : str, optional 57 | Folder path to use for cache files. 58 | Default: 'same_as_resource' 59 | exclude_filename: None, 60 | Deprecated and will be removed. Please use `exclude_filenames` instead 61 | include_filenames: str or list 62 | Filename or list of filenames to be included. This can be absolute path or path relative to dirname. 63 | exclude_filenames: str or list 64 | Filename or list of filenames to be excluded. Expects base filenames without 65 | directory path. 66 | keep_original_times : bool 67 | Preserve original time stamps as in data files. By default datasets are 68 | shifted to begin at t_start = 0*pq.second. 69 | Default: False 70 | """ 71 | 72 | if filename is not None: 73 | warnings.warn("Deprecated and will be removed. Please use `include_filenames` instead") 74 | include_filenames = [filename] 75 | 76 | if exclude_filename is not None: 77 | warnings.warn("Deprecated and will be removed. Please use `exclude_filenames` instead") 78 | exclude_filenames = exclude_filename 79 | 80 | NeuralynxRawIO.__init__( 81 | self, 82 | dirname=dirname, 83 | include_filenames=include_filenames, 84 | exclude_filenames=exclude_filenames, 85 | keep_original_times=keep_original_times, 86 | use_cache=use_cache, 87 | cache_path=cache_path, 88 | ) 89 | 90 | if self.rawmode == "one-dir": 91 | BaseFromRaw.__init__(self, dirname) 92 | elif self.rawmode == "multiple-files": 93 | BaseFromRaw.__init__(self, include_filenames=include_filenames) 94 | -------------------------------------------------------------------------------- /neo/io/neuroexplorerio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.neuroexplorerrawio import NeuroExplorerRawIO 3 | 4 | 5 | class NeuroExplorerIO(NeuroExplorerRawIO, BaseFromRaw): 6 | """Class for reading data from NeuroExplorer (.nex)""" 7 | 8 | _prefered_signal_group_mode = "group-by-same-units" 9 | 10 | def __init__(self, filename): 11 | NeuroExplorerRawIO.__init__(self, filename=filename) 12 | BaseFromRaw.__init__(self, filename) 13 | -------------------------------------------------------------------------------- /neo/io/neuronexusio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.neuronexusrawio import NeuroNexusRawIO 3 | 4 | 5 | class NeuroNexusIO(NeuroNexusRawIO, BaseFromRaw): 6 | __doc__ = NeuroNexusRawIO.__doc__ 7 | _prefered_signal_group_mode = "group-by-same-units" 8 | 9 | def __init__(self, filename): 10 | NeuroNexusRawIO.__init__(self, filename=filename) 11 | BaseFromRaw.__init__(self, filename) 12 | -------------------------------------------------------------------------------- /neo/io/neuroscopeio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.neuroscoperawio import NeuroScopeRawIO 3 | 4 | 5 | class NeuroScopeIO(NeuroScopeRawIO, BaseFromRaw): 6 | """ 7 | Reading from Neuroscope format files. 8 | 9 | Ref: http://neuroscope.sourceforge.net/ 10 | """ 11 | 12 | _prefered_signal_group_mode = "group-by-same-units" 13 | 14 | def __init__(self, filename): 15 | NeuroScopeRawIO.__init__(self, filename=filename) 16 | BaseFromRaw.__init__(self, filename) 17 | -------------------------------------------------------------------------------- /neo/io/nixio_fr.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.nixrawio import NIXRawIO 3 | 4 | # This class subjects to limitations when there are multiple asymmetric blocks 5 | 6 | 7 | class NixIO(NIXRawIO, BaseFromRaw): 8 | 9 | name = "NIX IO" 10 | 11 | _prefered_signal_group_mode = "group-by-same-units" 12 | _prefered_units_group_mode = "all-in-one" 13 | 14 | def __init__(self, filename): 15 | NIXRawIO.__init__(self, filename) 16 | BaseFromRaw.__init__(self, filename) 17 | 18 | def __enter__(self): 19 | return self 20 | 21 | def __exit__(self, *args): 22 | self.header = None 23 | self.file.close() 24 | -------------------------------------------------------------------------------- /neo/io/openephysbinaryio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.openephysbinaryrawio import OpenEphysBinaryRawIO 3 | 4 | 5 | class OpenEphysBinaryIO(OpenEphysBinaryRawIO, BaseFromRaw): 6 | _prefered_signal_group_mode = "group-by-same-units" 7 | mode = "dir" 8 | 9 | def __init__(self, dirname): 10 | OpenEphysBinaryRawIO.__init__(self, dirname=dirname) 11 | BaseFromRaw.__init__(self, dirname) 12 | -------------------------------------------------------------------------------- /neo/io/openephysio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.openephysrawio import OpenEphysRawIO 3 | 4 | 5 | class OpenEphysIO(OpenEphysRawIO, BaseFromRaw): 6 | _prefered_signal_group_mode = "group-by-same-units" 7 | mode = "dir" 8 | 9 | def __init__(self, dirname): 10 | OpenEphysRawIO.__init__(self, dirname=dirname) 11 | BaseFromRaw.__init__(self, dirname) 12 | -------------------------------------------------------------------------------- /neo/io/phyio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.phyrawio import PhyRawIO 3 | 4 | 5 | class PhyIO(PhyRawIO, BaseFromRaw): 6 | name = "Phy IO" 7 | description = "Phy IO" 8 | mode = "dir" 9 | 10 | def __init__(self, dirname, load_amplitudes=False, load_pcs=False): 11 | PhyRawIO.__init__(self, dirname=dirname, load_amplitudes=load_amplitudes, load_pcs=load_pcs) 12 | BaseFromRaw.__init__(self, dirname) 13 | -------------------------------------------------------------------------------- /neo/io/pickleio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for reading/writing data from/to Python pickle format. 3 | 4 | 5 | Class: 6 | PickleIO 7 | 8 | Supported: Read/Write 9 | 10 | Authors: Andrew Davison 11 | """ 12 | 13 | import pickle 14 | 15 | from neo.io.baseio import BaseIO 16 | from neo.core import Block, Segment, AnalogSignal, SpikeTrain, NeoReadWriteError 17 | 18 | 19 | class PickleIO(BaseIO): 20 | """ 21 | A class for reading and writing Neo data from/to the Python "pickle" format. 22 | 23 | Note that files in this format may not be readable if using a different version 24 | of Neo to that used to create the file. It should therefore not be used for 25 | long-term storage, but rather for intermediate results in a pipeline. 26 | """ 27 | 28 | is_readable = True 29 | is_writable = True 30 | has_header = False 31 | is_streameable = False # TODO - correct spelling to "is_streamable" 32 | # should extend to other classes. 33 | supported_objects = [Block, Segment, AnalogSignal, SpikeTrain] 34 | readable_objects = supported_objects 35 | writeable_objects = supported_objects 36 | mode = "file" 37 | name = "Python pickle file" 38 | extensions = ["pkl", "pickle"] 39 | 40 | def read_block(self, lazy=False): 41 | if lazy: 42 | raise NeoReadWriteError("This IO does not support lazy reading") 43 | with open(self.filename, "rb") as fp: 44 | block = pickle.load(fp) 45 | return block 46 | 47 | def write_block(self, block): 48 | with open(self.filename, "wb") as fp: 49 | pickle.dump(block, fp) 50 | -------------------------------------------------------------------------------- /neo/io/plexon2io.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.plexon2rawio import Plexon2RawIO 3 | 4 | 5 | class Plexon2IO(Plexon2RawIO, BaseFromRaw): 6 | """ 7 | Class for reading data from Plexon PL2 files 8 | 9 | The IO is based on the Plexon2RawIO, see comments for memory optimization 10 | in neo.rawio.plexon2rawio.Plexon2RawIO 11 | 12 | """ 13 | 14 | def __init__(self, filename): 15 | Plexon2RawIO.__init__(self, filename=filename) 16 | BaseFromRaw.__init__(self, filename) 17 | -------------------------------------------------------------------------------- /neo/io/plexonio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.plexonrawio import PlexonRawIO 3 | 4 | 5 | class PlexonIO(PlexonRawIO, BaseFromRaw): 6 | """ 7 | Class for reading the old data format from Plexon 8 | acquisition system (.plx) 9 | 10 | Note that Plexon now use a new format PL2 which is NOT 11 | supported by this IO. 12 | 13 | Compatible with versions 100 to 106. 14 | Other versions have not been tested. 15 | """ 16 | 17 | _prefered_signal_group_mode = "group-by-same-units" 18 | 19 | def __init__(self, filename): 20 | PlexonRawIO.__init__(self, filename) 21 | BaseFromRaw.__init__(self, filename) 22 | -------------------------------------------------------------------------------- /neo/io/rawmcsio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.rawmcsrawio import RawMCSRawIO 3 | 4 | 5 | class RawMCSIO(RawMCSRawIO, BaseFromRaw): 6 | _prefered_signal_group_mode = "group-by-same-units" 7 | 8 | def __init__(self, filename): 9 | RawMCSRawIO.__init__(self, filename=filename) 10 | BaseFromRaw.__init__(self, filename) 11 | -------------------------------------------------------------------------------- /neo/io/spike2io.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.spike2rawio import Spike2RawIO 3 | 4 | 5 | class Spike2IO(Spike2RawIO, BaseFromRaw): 6 | _prefered_signal_group_mode = "group-by-same-units" 7 | 8 | def __init__(self, filename, **kargs): 9 | Spike2RawIO.__init__(self, filename=filename, **kargs) 10 | BaseFromRaw.__init__(self, filename) 11 | -------------------------------------------------------------------------------- /neo/io/spikegadgetsio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.spikegadgetsrawio import SpikeGadgetsRawIO 3 | 4 | 5 | class SpikeGadgetsIO(SpikeGadgetsRawIO, BaseFromRaw): 6 | __doc__ = SpikeGadgetsRawIO.__doc__ 7 | 8 | def __init__(self, filename): 9 | SpikeGadgetsRawIO.__init__(self, filename=filename) 10 | BaseFromRaw.__init__(self, filename) 11 | -------------------------------------------------------------------------------- /neo/io/spikeglxio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.spikeglxrawio import SpikeGLXRawIO 3 | 4 | 5 | class SpikeGLXIO(SpikeGLXRawIO, BaseFromRaw): 6 | __doc__ = SpikeGLXRawIO.__doc__ 7 | mode = "dir" 8 | 9 | def __init__(self, dirname, load_sync_channel=False, load_channel_location=False): 10 | SpikeGLXRawIO.__init__( 11 | self, dirname=dirname, load_sync_channel=load_sync_channel, load_channel_location=load_channel_location 12 | ) 13 | BaseFromRaw.__init__(self, dirname) 14 | -------------------------------------------------------------------------------- /neo/io/tdtio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.tdtrawio import TdtRawIO 3 | 4 | 5 | class TdtIO(TdtRawIO, BaseFromRaw): 6 | """ 7 | Class for reading data from from Tucker Davis TTank format. 8 | 9 | Terminology: 10 | TDT holds data with tanks (actually a directory). And tanks hold sub blocks 11 | (sub directories). 12 | Tanks correspond to Neo Blocks and TDT blocks correspond to Neo Segments. 13 | """ 14 | 15 | _prefered_signal_group_mode = "group-by-same-units" 16 | mode = "dir" 17 | 18 | def __init__(self, dirname): 19 | TdtRawIO.__init__(self, dirname=dirname) 20 | BaseFromRaw.__init__(self, dirname) 21 | -------------------------------------------------------------------------------- /neo/io/tools.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tools for IO coder: 3 | * Creating RecordingChannel and making links with AnalogSignals and 4 | SPikeTrains 5 | """ 6 | 7 | from collections.abc import MutableSequence 8 | 9 | from neo.core import ( 10 | AnalogSignal, 11 | Block, 12 | Epoch, 13 | Event, 14 | IrregularlySampledSignal, 15 | Group, 16 | ChannelView, 17 | Segment, 18 | SpikeTrain, 19 | ) 20 | 21 | 22 | class LazyList(MutableSequence): 23 | """An enhanced list that can load its members on demand. Behaves exactly 24 | like a regular list for members that are Neo objects. Each item should 25 | contain the information that ``load_lazy_cascade`` needs to load the 26 | respective object. 27 | """ 28 | 29 | _container_objects = {Block, Segment, Group} 30 | _neo_objects = _container_objects.union( 31 | [AnalogSignal, Epoch, Event, ChannelView, IrregularlySampledSignal, SpikeTrain] 32 | ) 33 | 34 | def __init__(self, io, lazy, items=None): 35 | """ 36 | :param io: IO instance that can load items. 37 | :param lazy: Lazy parameter with which the container object 38 | using the list was loaded. 39 | :param items: Optional, initial list of items. 40 | """ 41 | if items is None: 42 | self._data = [] 43 | else: 44 | self._data = items 45 | self._lazy = lazy 46 | self._io = io 47 | 48 | def __getitem__(self, index): 49 | item = self._data.__getitem__(index) 50 | if isinstance(index, slice): 51 | return LazyList(self._io, item) 52 | 53 | if type(item) in self._neo_objects: 54 | return item 55 | 56 | loaded = self._io.load_lazy_cascade(item, self._lazy) 57 | self._data[index] = loaded 58 | return loaded 59 | 60 | def __delitem__(self, index): 61 | self._data.__delitem__(index) 62 | 63 | def __len__(self): 64 | return self._data.__len__() 65 | 66 | def __setitem__(self, index, value): 67 | self._data.__setitem__(index, value) 68 | 69 | def insert(self, index, value): 70 | self._data.insert(index, value) 71 | 72 | def append(self, value): 73 | self._data.append(value) 74 | 75 | def reverse(self): 76 | self._data.reverse() 77 | 78 | def extend(self, values): 79 | self._data.extend(values) 80 | 81 | def remove(self, value): 82 | self._data.remove(value) 83 | 84 | def __str__(self): 85 | return "<" + self.__class__.__name__ + ">" + self._data.__str__() 86 | 87 | def __repr__(self): 88 | return "<" + self.__class__.__name__ + ">" + self._data.__repr__() 89 | -------------------------------------------------------------------------------- /neo/io/winedrio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.winedrrawio import WinEdrRawIO 3 | 4 | 5 | class WinEdrIO(WinEdrRawIO, BaseFromRaw): 6 | """ 7 | Class for reading data from WinEdr, a software tool written by 8 | John Dempster. 9 | 10 | WinEdr is free: 11 | http://spider.science.strath.ac.uk/sipbs/software.htm 12 | """ 13 | 14 | _prefered_signal_group_mode = "group-by-same-units" 15 | 16 | def __init__(self, filename): 17 | WinEdrRawIO.__init__(self, filename=filename) 18 | BaseFromRaw.__init__(self, filename) 19 | -------------------------------------------------------------------------------- /neo/io/winwcpio.py: -------------------------------------------------------------------------------- 1 | from neo.io.basefromrawio import BaseFromRaw 2 | from neo.rawio.winwcprawio import WinWcpRawIO 3 | 4 | 5 | class WinWcpIO(WinWcpRawIO, BaseFromRaw): 6 | """ 7 | Class for reading data from WinWCP, a software tool written by 8 | John Dempster. 9 | 10 | WinWCP is free: 11 | http://spider.science.strath.ac.uk/sipbs/software.htm 12 | """ 13 | 14 | _prefered_signal_group_mode = "group-by-same-units" 15 | 16 | def __init__(self, filename): 17 | WinWcpRawIO.__init__(self, filename=filename) 18 | BaseFromRaw.__init__(self, filename) 19 | -------------------------------------------------------------------------------- /neo/rawio/neuralynxrawio/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | RawIO for reading data from Neuralynx files. 3 | This IO supports NCS, NEV, NSE and NTT file formats. 4 | 5 | 6 | NCS contains the sampled signal for one channel 7 | NEV contains events 8 | NSE contains spikes and waveforms for mono electrodes 9 | NTT contains spikes and waveforms for tetrodes 10 | """ 11 | 12 | from neo.rawio.neuralynxrawio.neuralynxrawio import NeuralynxRawIO 13 | -------------------------------------------------------------------------------- /neo/rawio/plexon2rawio/__init__.py: -------------------------------------------------------------------------------- 1 | from neo.rawio.plexon2rawio.plexon2rawio import Plexon2RawIO 2 | -------------------------------------------------------------------------------- /neo/rawio/plexon2rawio/pypl2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/neo/rawio/plexon2rawio/pypl2/__init__.py -------------------------------------------------------------------------------- /neo/rawio/utils.py: -------------------------------------------------------------------------------- 1 | import mmap 2 | import numpy as np 3 | 4 | 5 | def get_memmap_shape(filename, dtype, num_channels=None, offset=0): 6 | dtype = np.dtype(dtype) 7 | with open(filename, mode="rb") as f: 8 | f.seek(0, 2) 9 | flen = f.tell() 10 | bytes = flen - offset 11 | if bytes % dtype.itemsize != 0: 12 | raise ValueError("Size of available data is not a multiple of the data-type size.") 13 | size = bytes // dtype.itemsize 14 | if num_channels is None: 15 | shape = (size,) 16 | else: 17 | shape = (size // num_channels, num_channels) 18 | return shape 19 | 20 | 21 | def get_memmap_chunk_from_opened_file(fid, num_channels, start, stop, dtype, file_offset=0): 22 | """ 23 | Utility function to get a chunk as a memmap array directly from an opened file. 24 | Using this instead memmap can avoid memmory consumption when multiprocessing. 25 | 26 | Similar mechanism is used in spikeinterface. 27 | 28 | """ 29 | bytes_per_sample = num_channels * dtype.itemsize 30 | 31 | # Calculate byte offsets 32 | start_byte = file_offset + start * bytes_per_sample 33 | end_byte = file_offset + stop * bytes_per_sample 34 | 35 | # Calculate the length of the data chunk to load into memory 36 | length = end_byte - start_byte 37 | 38 | # The mmap offset must be a multiple of mmap.ALLOCATIONGRANULARITY 39 | memmap_offset, start_offset = divmod(start_byte, mmap.ALLOCATIONGRANULARITY) 40 | memmap_offset *= mmap.ALLOCATIONGRANULARITY 41 | 42 | # Adjust the length so it includes the extra data from rounding down 43 | # the memmap offset to a multiple of ALLOCATIONGRANULARITY 44 | length += start_offset 45 | 46 | memmap_obj = mmap.mmap(fid.fileno(), length=length, access=mmap.ACCESS_READ, offset=memmap_offset) 47 | 48 | arr = np.ndarray( 49 | shape=((stop - start), num_channels), 50 | dtype=dtype, 51 | buffer=memmap_obj, 52 | offset=start_offset, 53 | ) 54 | 55 | return arr 56 | -------------------------------------------------------------------------------- /neo/test/README.txt: -------------------------------------------------------------------------------- 1 | To run all tests: 2 | 3 | $ python -m unittest discover 4 | 5 | If you have pytest installed: 6 | 7 | $ pytest 8 | 9 | 10 | To run tests from an individual file: 11 | 12 | $ python test_analogsignal.py 13 | 14 | (in all Python versions) 15 | 16 | For coverage: 17 | 18 | $ pytest --cov=neo 19 | -------------------------------------------------------------------------------- /neo/test/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The subdirectory coretest contains tests for neo.core 3 | 4 | The subdirectory iotest contains tests for neo.io 5 | """ 6 | -------------------------------------------------------------------------------- /neo/test/coretest/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Contains tests for neo.core 3 | """ 4 | -------------------------------------------------------------------------------- /neo/test/coretest/test_regionofinterest.py: -------------------------------------------------------------------------------- 1 | import quantities as pq 2 | from neo.core.regionofinterest import RectangularRegionOfInterest, CircularRegionOfInterest, PolygonRegionOfInterest 3 | from neo.core.imagesequence import ImageSequence 4 | import unittest 5 | 6 | 7 | class Test_CircularRegionOfInterest(unittest.TestCase): 8 | 9 | def test_result(self): 10 | seq = ImageSequence([[[]]], spatial_scale=1, frame_duration=20 * pq.ms) 11 | self.assertEqual((CircularRegionOfInterest(seq, 6, 6, 1).pixels_in_region()), [[6, 5], [5, 6], [6, 6]]) 12 | self.assertEqual( 13 | (CircularRegionOfInterest(seq, 6, 6, 1.01).pixels_in_region()), [[6, 5], [5, 6], [6, 6], [7, 6], [6, 7]] 14 | ) 15 | 16 | 17 | class Test_RectangularRegionOfInterest(unittest.TestCase): 18 | 19 | def test_result(self): 20 | seq = ImageSequence([[[]]], spatial_scale=1, frame_duration=20 * pq.ms) 21 | self.assertEqual( 22 | RectangularRegionOfInterest(seq, 5, 5, 2, 2).pixels_in_region(), [[4, 4], [5, 4], [4, 5], [5, 5]] 23 | ) 24 | 25 | 26 | class Test_PolygonRegionOfInterest(unittest.TestCase): 27 | 28 | def test_result(self): 29 | seq = ImageSequence([[[]]], spatial_scale=1, frame_duration=20 * pq.ms) 30 | self.assertEqual( 31 | PolygonRegionOfInterest(seq, (3, 3), (2, 5), (5, 5), (5, 1), (1, 1)).pixels_in_region(), 32 | [(1, 1), (2, 1), (3, 1), (4, 1), (2, 2), (3, 2), (4, 2), (3, 3), (4, 3), (3, 4), (4, 4)], 33 | ) 34 | 35 | 36 | if __name__ == "__main__": 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /neo/test/coretest/test_view.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of the neo.core.view.ChannelView class and related functions 3 | """ 4 | 5 | import unittest 6 | 7 | import numpy as np 8 | import quantities as pq 9 | from numpy.testing import assert_array_equal 10 | 11 | from neo.core.analogsignal import AnalogSignal 12 | from neo.core.irregularlysampledsignal import IrregularlySampledSignal 13 | from neo.core.view import ChannelView 14 | 15 | 16 | class TestView(unittest.TestCase): 17 | 18 | def setUp(self): 19 | self.test_data = np.random.rand(100, 8) * pq.mV 20 | channel_names = np.array(["a", "b", "c", "d", "e", "f", "g", "h"]) 21 | self.test_signal = AnalogSignal( 22 | self.test_data, 23 | sampling_period=0.1 * pq.ms, 24 | name="test signal", 25 | description="this is a test signal", 26 | array_annotations={"channel_names": channel_names}, 27 | attUQoLtUaE=42, 28 | ) 29 | 30 | def test_create_integer_index(self): 31 | view = ChannelView( 32 | self.test_signal, 33 | [1, 2, 5, 7], 34 | name="view of test signal", 35 | description="this is a view of a test signal", 36 | array_annotations={"something": np.array(["A", "B", "C", "D"])}, 37 | sLaTfat="fish", 38 | ) 39 | 40 | assert view.obj is self.test_signal 41 | assert_array_equal(view.index, np.array([1, 2, 5, 7])) 42 | self.assertEqual(view.shape, (100, 4)) 43 | self.assertEqual(view.name, "view of test signal") 44 | self.assertEqual(view.annotations["sLaTfat"], "fish") 45 | 46 | def test_create_boolean_index(self): 47 | view1 = ChannelView(self.test_signal, [1, 2, 5, 7]) 48 | view2 = ChannelView(self.test_signal, np.array([0, 1, 1, 0, 0, 1, 0, 1], dtype=bool)) 49 | assert_array_equal(view1.index, view2.index) 50 | self.assertEqual(view1.shape, view2.shape) 51 | 52 | def test_resolve(self): 53 | view = ChannelView( 54 | self.test_signal, 55 | [1, 2, 5, 7], 56 | name="view of test signal", 57 | description="this is a view of a test signal", 58 | array_annotations={"something": np.array(["A", "B", "C", "D"])}, 59 | sLaTfat="fish", 60 | ) 61 | signal2 = view.resolve() 62 | self.assertIsInstance(signal2, AnalogSignal) 63 | self.assertEqual(signal2.shape, (100, 4)) 64 | for attr in ("name", "description", "sampling_period", "units"): 65 | self.assertEqual(getattr(self.test_signal, attr), getattr(signal2, attr)) 66 | assert_array_equal(signal2.array_annotations["channel_names"], np.array(["b", "c", "f", "h"])) 67 | assert_array_equal(self.test_data[:, [1, 2, 5, 7]], signal2.magnitude) 68 | -------------------------------------------------------------------------------- /neo/test/iotest/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Contains tests for neo.io 3 | """ 4 | -------------------------------------------------------------------------------- /neo/test/iotest/test_alphaomegaio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.alphaomegaio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import AlphaOmegaIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestAlphaOmegaIO(BaseTestIO, unittest.TestCase): 12 | entities_to_download = ["alphaomega"] 13 | entities_to_test = [ 14 | "alphaomega/mpx_map_version4", 15 | ] 16 | ioclass = AlphaOmegaIO 17 | 18 | 19 | if __name__ == "__main__": 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /neo/test/iotest/test_asciiimageio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test of neo.io.asciiimageio 3 | """ 4 | 5 | import os 6 | import unittest 7 | import quantities as pq 8 | from neo.io import AsciiImageIO 9 | import numpy as np 10 | 11 | 12 | class TestAsciiImageIO(unittest.TestCase): 13 | 14 | def test_read_txt(self): 15 | img = "" 16 | img_list = [] 17 | for frame in range(20): 18 | img_list.append([]) 19 | for y in range(50): 20 | img_list[frame].append([]) 21 | for x in range(50): 22 | img += str(x) 23 | img += "\t" 24 | img_list[frame][y].append(x) 25 | img_list = np.array(img_list) 26 | file_name = "txt_test_file.txt" 27 | file = open(file_name, mode="w") 28 | file.write(str(img)) 29 | file.close() 30 | 31 | object = AsciiImageIO( 32 | file_name="txt_test_file.txt", 33 | nb_frame=20, 34 | nb_row=50, 35 | nb_column=50, 36 | units="V", 37 | sampling_rate=1 * pq.Hz, 38 | spatial_scale=1 * pq.micrometer, 39 | ) 40 | block = object.read_block() 41 | self.assertEqual(len(block.segments), 1) 42 | self.assertEqual(len(block.segments[0].imagesequences), 1) 43 | self.assertEqual(block.segments[0].imagesequences[0].shape, (20, 50, 50)) 44 | self.assertEqual(block.segments[0].imagesequences[0].any(), img_list.any()) 45 | 46 | file.close() 47 | os.remove(file_name) 48 | 49 | 50 | if __name__ == "__main__": 51 | unittest.main() 52 | -------------------------------------------------------------------------------- /neo/test/iotest/test_asciispiketrainio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.asciispiketrainio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import AsciiSpikeTrainIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestAsciiSpikeTrainIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = AsciiSpikeTrainIO 16 | entities_to_download = ["asciispiketrain"] 17 | entities_to_test = [ 18 | "asciispiketrain/File_ascii_spiketrain_1.txt", 19 | ] 20 | 21 | 22 | if __name__ == "__main__": 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /neo/test/iotest/test_axonaio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.axonaio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io.axonaio import AxonaIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | from neo.test.rawiotest.test_axonarawio import TestAxonaRawIO 10 | 11 | 12 | class TestAxonaIO( 13 | BaseTestIO, 14 | unittest.TestCase, 15 | ): 16 | ioclass = AxonaIO 17 | entities_to_download = ["axona"] 18 | 19 | entities_to_test = TestAxonaRawIO.entities_to_test 20 | 21 | 22 | if __name__ == "__main__": 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /neo/test/iotest/test_axonio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.axonio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import AxonIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | from neo.test.rawiotest.test_axonrawio import TestAxonRawIO 11 | 12 | 13 | class TestAxonIO(BaseTestIO, unittest.TestCase): 14 | entities_to_download = TestAxonRawIO.entities_to_download 15 | entities_to_test = TestAxonRawIO.entities_to_test 16 | ioclass = AxonIO 17 | 18 | def test_annotations(self): 19 | reader = AxonIO(filename=self.get_local_path("axon/File_axon_2.abf")) 20 | bl = reader.read_block() 21 | ev = bl.segments[0].events[0] 22 | assert "comments" in ev.annotations 23 | 24 | def test_read_protocol(self): 25 | for f in self.entities_to_test: 26 | filename = self.get_local_path(f) 27 | reader = AxonIO(filename=filename) 28 | bl = reader.read_block(lazy=True) 29 | if bl.annotations["abf_version"] >= 2.0: 30 | reader.read_protocol() 31 | 32 | 33 | if __name__ == "__main__": 34 | unittest.main() 35 | -------------------------------------------------------------------------------- /neo/test/iotest/test_baseio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.baseio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.core import objectlist 8 | from neo.io.baseio import BaseIO 9 | from neo.core import NeoReadWriteError 10 | 11 | 12 | class TestIOObjects(unittest.TestCase): 13 | def test__raise_error_when_not_readable_or_writable(self): 14 | reader = BaseIO() 15 | for ob in objectlist: 16 | if ob not in BaseIO.readable_objects: 17 | meth = getattr(reader, "read_" + ob.__name__.lower()) 18 | self.assertRaises( 19 | NeoReadWriteError, 20 | meth, 21 | ) 22 | 23 | if ob not in BaseIO.writeable_objects: 24 | meth = getattr(reader, "write_" + ob.__name__.lower()) 25 | self.assertRaises(NeoReadWriteError, meth, ()) 26 | 27 | 28 | if __name__ == "__main__": 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /neo/test/iotest/test_bci2000io.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.bci2000io 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import BCI2000IO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestBCI2000IO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = BCI2000IO 16 | entities_to_download = ["bci2000"] 17 | entities_to_test = [ 18 | "bci2000/eeg1_1.dat", 19 | "bci2000/eeg1_2.dat", 20 | "bci2000/eeg1_3.dat", 21 | ] 22 | 23 | 24 | if __name__ == "__main__": 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /neo/test/iotest/test_biocamio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.BiocamIO 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import BiocamIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestBiocamIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = BiocamIO 16 | entities_to_download = ["biocam"] 17 | entities_to_test = [ 18 | "biocam/biocam_hw3.0_fw1.6.brw", 19 | "biocam/biocam_hw3.0_fw1.7.0.12_raw.brw", 20 | ] 21 | 22 | 23 | if __name__ == "__main__": 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /neo/test/iotest/test_brainvisionio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.brainvisionio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import BrainVisionIO 8 | 9 | from neo.test.iotest.common_io_test import BaseTestIO 10 | 11 | 12 | class TestBrainVisionIO( 13 | BaseTestIO, 14 | unittest.TestCase, 15 | ): 16 | ioclass = BrainVisionIO 17 | entities_to_download = ["brainvision"] 18 | entities_to_test = [ 19 | "brainvision/File_brainvision_1.vhdr", 20 | "brainvision/File_brainvision_2.vhdr", 21 | "brainvision/File_brainvision_3_float32.vhdr", 22 | "brainvision/File_brainvision_3_int16.vhdr", 23 | "brainvision/File_brainvision_3_int32.vhdr", 24 | ] 25 | 26 | 27 | if __name__ == "__main__": 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /neo/test/iotest/test_cedio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from platform import system 3 | from sys import maxsize 4 | 5 | try: 6 | if system() == "Windows": 7 | if maxsize > 2**32: 8 | import sonpy.amd64.sonpy 9 | else: 10 | import sonpy.win32.sonpy 11 | elif system() == "Darwin": 12 | import sonpy.darwin.sonpy 13 | elif system() == "Linux": 14 | import sonpy.linux.sonpy 15 | from neo.io import CedIO 16 | except ImportError: 17 | HAVE_SONPY = False 18 | CedIO = None 19 | else: 20 | HAVE_SONPY = True 21 | 22 | from neo.test.iotest.common_io_test import BaseTestIO 23 | 24 | 25 | @unittest.skipUnless(HAVE_SONPY, "sonpy") 26 | class TestCedIO( 27 | BaseTestIO, 28 | unittest.TestCase, 29 | ): 30 | ioclass = CedIO 31 | entities_to_test = ["spike2/m365_1sec.smrx", "spike2/File_spike2_1.smr", "spike2/Two-mice-bigfile-test000.smr"] 32 | entities_to_download = ["spike2"] 33 | 34 | 35 | if __name__ == "__main__": 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /neo/test/iotest/test_elanio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.elanio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import ElanIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestElanIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = ElanIO 16 | entities_to_download = ["elan"] 17 | entities_to_test = [ 18 | "elan/File_elan_1.eeg", 19 | ] 20 | 21 | 22 | if __name__ == "__main__": 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /neo/test/iotest/test_elphyio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.elphyo 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import ElphyIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestElphyIO(BaseTestIO, unittest.TestCase): 12 | ioclass = ElphyIO 13 | entities_to_download = ["elphy"] 14 | entities_to_test = [ 15 | "elphy/DATA1.DAT", 16 | "elphy/ElphyExample.DAT", 17 | "elphy/ElphyExample_Mode1.dat", 18 | "elphy/ElphyExample_Mode2.dat", 19 | "elphy/ElphyExample_Mode3.dat", 20 | ] 21 | 22 | def test_read_data(self): 23 | for filename in self.entities_to_test: 24 | io = ElphyIO(self.get_local_path(filename)) 25 | bl = io.read_block() 26 | 27 | self.assertTrue(len(bl.segments) > 0) 28 | # ensure that at least one data object is generated for each file 29 | self.assertTrue(any(list(bl.segments[0].size.values()))) 30 | 31 | 32 | if __name__ == "__main__": 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /neo/test/iotest/test_get_io.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from tempfile import TemporaryDirectory 3 | import platform 4 | from neo.io import get_io, list_candidate_ios, NixIO 5 | import pytest 6 | 7 | try: 8 | import nixio 9 | 10 | HAVE_NIX = True 11 | except: 12 | HAVE_NIX = False 13 | 14 | 15 | def test_list_candidate_ios_non_existant_file(): 16 | # use plexon io suffix for testing here 17 | non_existant_file = Path("non_existant_folder/non_existant_file.plx") 18 | non_existant_file.unlink(missing_ok=True) 19 | ios = list_candidate_ios(non_existant_file) 20 | 21 | assert ios 22 | 23 | # cleanup 24 | non_existant_file.unlink(missing_ok=True) 25 | 26 | 27 | def test_list_candidate_ios_filename_stub(): 28 | # create dummy folder with dummy files 29 | with TemporaryDirectory(prefix="filename_stub_test_") as test_folder: 30 | test_folder = Path(test_folder) 31 | test_filename = test_folder / "dummy_file.nix" 32 | test_filename.touch() 33 | filename_stub = test_filename.with_suffix("") 34 | 35 | # check that io is found even though file suffix was not provided 36 | ios = list_candidate_ios(filename_stub) 37 | 38 | assert NixIO in ios 39 | 40 | 41 | @pytest.mark.skipif(not HAVE_NIX or platform.system() == "Windows", reason="Need nixio in order to return NixIO class") 42 | def test_get_io_non_existant_file_writable_io(): 43 | # use nixio for testing with writable io 44 | non_existant_file = Path("non_existant_file.nix") 45 | non_existant_file.unlink(missing_ok=True) 46 | io = get_io(non_existant_file) 47 | 48 | assert isinstance(io, NixIO) 49 | 50 | # cleanup 51 | non_existant_file.unlink(missing_ok=True) # cleanup will fail on Windows so need to skip 52 | -------------------------------------------------------------------------------- /neo/test/iotest/test_igorio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.igorproio 3 | """ 4 | 5 | import unittest 6 | 7 | try: 8 | import igor2 9 | 10 | HAVE_IGOR = True 11 | except ImportError: 12 | HAVE_IGOR = False 13 | from neo.io.igorproio import IgorIO 14 | from neo.test.iotest.common_io_test import BaseTestIO 15 | 16 | 17 | @unittest.skipUnless(HAVE_IGOR, "requires igor") 18 | class TestIgorIO(BaseTestIO, unittest.TestCase): 19 | ioclass = IgorIO 20 | entities_to_download = ["igor"] 21 | entities_to_test = ["igor/mac-version2.ibw", "igor/win-version2.ibw"] 22 | 23 | 24 | if __name__ == "__main__": 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /neo/test/iotest/test_intanio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.intanio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import IntanIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestIntanIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = IntanIO 16 | entities_to_download = ["intan"] 17 | entities_to_test = [ 18 | "intan/intan_rhs_test_1.rhs", # Format header-attached 19 | "intan/intan_rhd_test_1.rhd", # Format header-attached 20 | "intan/rhs_fpc_multistim_240514_082243/rhs_fpc_multistim_240514_082243.rhs", # Format header-attached newer version 21 | "intan/intan_fpc_test_231117_052630/info.rhd", # Format one-file-per-channel 22 | "intan/intan_fps_test_231117_052500/info.rhd", # Format one file per signal 23 | "intan/intan_fpc_rhs_test_240329_091637/info.rhs", # Format one-file-per-channel 24 | "intan/intan_fps_rhs_test_240329_091536/info.rhs", # Format one-file-per-signal 25 | "intan/rhd_fpc_multistim_240514_082044/info.rhd", # Multiple digital channels one-file-per-channel rhd 26 | "intan/rhs_stim_data_single_file_format/intanTestFile.rhs", # header-attached rhs data with stimulus current 27 | "intan/test_fcs_dc_250327_154333/info.rhs", # this is an example of only having dc amp rather than amp files 28 | # "intan/test_fpc_stim_250327_151617/info.rhs", # wrong files Heberto will fix 29 | ] 30 | 31 | 32 | if __name__ == "__main__": 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /neo/test/iotest/test_kwikio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.kwikio 3 | """ 4 | 5 | import unittest 6 | 7 | try: 8 | from klusta import kwik 9 | 10 | HAVE_KWIK = True 11 | except ImportError: 12 | HAVE_KWIK = False 13 | 14 | from neo.io import kwikio 15 | from neo.test.iotest.common_io_test import BaseTestIO 16 | 17 | 18 | @unittest.skipUnless(HAVE_KWIK, "requires klusta") 19 | class TestKwikIO(BaseTestIO, unittest.TestCase): 20 | ioclass = kwikio.KwikIO 21 | entities_to_download = ["kwik"] 22 | entities_to_test = ["kwik/neo.kwik"] 23 | 24 | 25 | if __name__ == "__main__": 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /neo/test/iotest/test_maxwellio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | 4 | from neo.io import MaxwellIO 5 | from neo.test.iotest.common_io_test import BaseTestIO 6 | 7 | from neo.rawio.maxwellrawio import auto_install_maxwell_hdf5_compression_plugin 8 | 9 | 10 | class TestMaxwellIO( 11 | BaseTestIO, 12 | unittest.TestCase, 13 | ): 14 | ioclass = MaxwellIO 15 | entities_to_download = ["maxwell"] 16 | entities_to_test = files_to_test = [ 17 | "maxwell/MaxOne_data/Record/000011/data.raw.h5", 18 | "maxwell/MaxTwo_data/Network/000028/data.raw.h5", 19 | ] 20 | 21 | def setUp(self): 22 | auto_install_maxwell_hdf5_compression_plugin(force_download=False) 23 | BaseTestIO.setUp(self) 24 | 25 | 26 | if __name__ == "__main__": 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /neo/test/iotest/test_mearecio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.mearecio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import MEArecIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | try: 12 | import MEArec as mr 13 | 14 | HAVE_MEAREC = True 15 | except ImportError: 16 | HAVE_MEAREC = False 17 | 18 | 19 | @unittest.skipUnless(HAVE_MEAREC, "requires MEArec package") 20 | class TestMEArecIO(BaseTestIO, unittest.TestCase): 21 | entities_to_download = ["mearec"] 22 | entities_to_test = ["mearec/mearec_test_10s.h5"] 23 | ioclass = MEArecIO 24 | 25 | 26 | if __name__ == "__main__": 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /neo/test/iotest/test_micromedio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.neomatlabio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import MicromedIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestMicromedIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = MicromedIO 16 | entities_to_download = ["micromed"] 17 | entities_to_test = ["micromed/File_micromed_1.TRC"] 18 | 19 | 20 | if __name__ == "__main__": 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /neo/test/iotest/test_neuroexplorerio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.neuroexplorerio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import NeuroExplorerIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestNeuroExplorerIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = NeuroExplorerIO 16 | entities_to_download = ["neuroexplorer"] 17 | entities_to_download_test = [ 18 | "neuroexplorer/File_neuroexplorer_1.nex", 19 | "neuroexplorer/File_neuroexplorer_2.nex", 20 | ] 21 | 22 | def test_signal_group_mode(self): 23 | filename = self.get_local_path("neuroexplorer/File_neuroexplorer_1.nex") 24 | 25 | # test that 2 signals are rendered with 2 sampling_rate 26 | for signal_group_mode in ("group-by-same-units", "split-all"): 27 | reader = NeuroExplorerIO(filename=filename) 28 | bl = reader.read_block(signal_group_mode=signal_group_mode) 29 | seg = bl.segments[0] 30 | assert len(seg.analogsignals) == 2 31 | anasig0 = seg.analogsignals[0] 32 | anasig1 = seg.analogsignals[1] 33 | assert anasig0.sampling_rate != anasig1.sampling_rate 34 | assert anasig0.shape != anasig1.shape 35 | # ~ for anasig in seg.analogsignals: 36 | # ~ print(anasig.shape, anasig.sampling_rate) 37 | 38 | 39 | if __name__ == "__main__": 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /neo/test/iotest/test_neuronexusio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.neuronexusio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import NeuroNexusIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestNeuroNexusIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = NeuroNexusIO 16 | entities_to_download = ["neuronexus"] 17 | entities_to_test = ["neuronexus/allego_1/allego_2__uid0701-13-04-49.xdat.json"] 18 | 19 | 20 | if __name__ == "__main__": 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /neo/test/iotest/test_neuroscopeio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.neuroscopeio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import NeuroScopeIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestNeuroScopeIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = NeuroScopeIO 16 | entities_to_download = ["neuroscope"] 17 | entities_to_test = ["neuroscope/test1/test1.xml"] 18 | 19 | 20 | if __name__ == "__main__": 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /neo/test/iotest/test_openephysbinaryio.py: -------------------------------------------------------------------------------- 1 | """ """ 2 | 3 | import unittest 4 | 5 | import quantities as pq 6 | 7 | from neo.io import OpenEphysBinaryIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | from neo.test.rawiotest.test_openephysbinaryrawio import TestOpenEphysBinaryRawIO 10 | 11 | 12 | class TestOpenEphysBinaryIO(BaseTestIO, unittest.TestCase): 13 | ioclass = OpenEphysBinaryIO 14 | entities_to_download = TestOpenEphysBinaryRawIO.entities_to_download 15 | entities_to_test = TestOpenEphysBinaryRawIO.entities_to_test 16 | 17 | 18 | if __name__ == "__main__": 19 | unittest.main() 20 | -------------------------------------------------------------------------------- /neo/test/iotest/test_openephysio.py: -------------------------------------------------------------------------------- 1 | """ """ 2 | 3 | import unittest 4 | 5 | import quantities as pq 6 | 7 | from neo.io import OpenEphysIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | from neo.test.rawiotest.test_openephysrawio import TestOpenEphysRawIO 10 | 11 | 12 | class TestOpenEphysIO( 13 | BaseTestIO, 14 | unittest.TestCase, 15 | ): 16 | ioclass = OpenEphysIO 17 | entities_to_download = TestOpenEphysRawIO.entities_to_download 18 | entities_to_test = TestOpenEphysRawIO.entities_to_test 19 | 20 | 21 | if __name__ == "__main__": 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /neo/test/iotest/test_phyio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.phyio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io.phyio import PhyIO # , HAVE_SCIPY 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | from neo.io.proxyobjects import AnalogSignalProxy, SpikeTrainProxy, EventProxy, EpochProxy 10 | from neo import AnalogSignal, SpikeTrain 11 | 12 | import quantities as pq 13 | import numpy as np 14 | 15 | import tempfile 16 | from pathlib import Path 17 | 18 | 19 | class TestPhyIO(BaseTestIO, unittest.TestCase): 20 | ioclass = PhyIO 21 | entities_to_download = ["phy"] 22 | entities_to_test = ["phy/phy_example_0"] 23 | 24 | def test_read_segment_lazy(self): 25 | dirname = self.get_local_path("phy/phy_example_0") 26 | r = PhyIO(dirname=dirname) 27 | seg = r.read_segment(lazy=True) 28 | for ana in seg.analogsignals: 29 | assert isinstance(ana, AnalogSignalProxy) 30 | ana = ana.load() 31 | assert isinstance(ana, AnalogSignal) 32 | for st in seg.spiketrains: 33 | assert isinstance(st, SpikeTrainProxy) 34 | st = st.load() 35 | assert isinstance(st, SpikeTrain) 36 | 37 | seg = r.read_segment(lazy=False) 38 | for anasig in seg.analogsignals: 39 | assert isinstance(ana, AnalogSignal) 40 | self.assertNotEqual(anasig.size, 0) 41 | for st in seg.spiketrains: 42 | assert isinstance(st, SpikeTrain) 43 | self.assertNotEqual(st.size, 0) 44 | 45 | # annotations 46 | assert seg.name == "Seg #0 Block #0" 47 | for anasig in seg.analogsignals: 48 | assert anasig.name is not None 49 | for st in seg.spiketrains: 50 | assert st.name is not None 51 | for ev in seg.events: 52 | assert ev.name is not None 53 | for ep in seg.epochs: 54 | assert ep.name is not None 55 | 56 | def test_read_block(self): 57 | dirname = self.get_local_path("phy/phy_example_0") 58 | r = PhyIO(dirname=dirname) 59 | bl = r.read_block(lazy=True) 60 | 61 | def test_read_segment_with_time_slice(self): 62 | dirname = self.get_local_path("phy/phy_example_0") 63 | r = PhyIO(dirname=dirname) 64 | seg = r.read_segment(time_slice=None) 65 | spikes_full = seg.spiketrains[0] 66 | 67 | t_start, t_stop = 260 * pq.ms, 1.854 * pq.s 68 | seg = r.read_segment(time_slice=(t_start, t_stop)) 69 | spikes_slice = seg.spiketrains[0] 70 | 71 | assert spikes_full.size > spikes_slice.size 72 | assert np.all(spikes_slice >= t_start) 73 | assert np.all(spikes_slice <= t_stop) 74 | assert spikes_slice.t_start == t_start 75 | assert spikes_slice.t_stop == t_stop 76 | 77 | 78 | if __name__ == "__main__": 79 | unittest.main() 80 | -------------------------------------------------------------------------------- /neo/test/iotest/test_pickleio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of the neo.io.pickleio.PickleIO class 3 | """ 4 | 5 | import os 6 | 7 | import unittest 8 | 9 | import numpy as np 10 | import quantities as pq 11 | 12 | from neo.core import Block, Segment, AnalogSignal, SpikeTrain, Epoch, Event, IrregularlySampledSignal, Group 13 | from neo.io import PickleIO 14 | from numpy.testing import assert_array_equal 15 | from neo.test.tools import assert_arrays_equal, assert_file_contents_equal 16 | from neo.test.iotest.common_io_test import BaseTestIO 17 | 18 | NCELLS = 5 19 | 20 | 21 | class CommonTestPickleIO(BaseTestIO, unittest.TestCase): 22 | ioclass = PickleIO 23 | 24 | 25 | class TestPickleIO(unittest.TestCase): 26 | def test__issue_285(self): 27 | # Spiketrain 28 | train = SpikeTrain([3, 4, 5] * pq.s, t_stop=10.0) 29 | unit = Group() 30 | unit.add(train) 31 | 32 | epoch = Epoch(np.array([0, 10, 20]), np.array([2, 2, 2]), np.array(["a", "b", "c"]), units="ms") 33 | 34 | blk = Block() 35 | seg = Segment() 36 | seg.spiketrains.append(train) 37 | seg.epochs.append(epoch) 38 | blk.segments.append(seg) 39 | 40 | reader = PickleIO(filename="blk.pkl") 41 | reader.write(blk) 42 | 43 | reader = PickleIO(filename="blk.pkl") 44 | r_blk = reader.read_block() 45 | r_seg = r_blk.segments[0] 46 | 47 | self.assertIsInstance(r_seg.epochs[0], Epoch) 48 | os.remove("blk.pkl") 49 | 50 | # Epoch 51 | epoch = Epoch( 52 | times=np.arange(0, 30, 10) * pq.s, 53 | durations=[10, 5, 7] * pq.ms, 54 | labels=np.array(["btn0", "btn1", "btn2"], dtype="U"), 55 | ) 56 | blk = Block() 57 | seg = Segment() 58 | seg.epochs.append(epoch) 59 | blk.segments.append(seg) 60 | 61 | reader = PickleIO(filename="blk.pkl") 62 | reader.write(blk) 63 | 64 | reader = PickleIO(filename="blk.pkl") 65 | r_blk = reader.read_block() 66 | r_seg = r_blk.segments[0] 67 | self.assertIsInstance(r_seg.epochs[0].segment, Segment) 68 | os.remove("blk.pkl") 69 | 70 | # Event 71 | event = Event(np.arange(0, 30, 10) * pq.s, labels=np.array(["trig0", "trig1", "trig2"], dtype="U")) 72 | blk = Block() 73 | seg = Segment() 74 | seg.events.append(event) 75 | blk.segments.append(seg) 76 | 77 | reader = PickleIO(filename="blk.pkl") 78 | reader.write(blk) 79 | 80 | reader = PickleIO(filename="blk.pkl") 81 | r_blk = reader.read_block() 82 | r_seg = r_blk.segments[0] 83 | self.assertIsInstance(r_seg.events[0].segment, Segment) 84 | os.remove("blk.pkl") 85 | 86 | # IrregularlySampledSignal 87 | signal = IrregularlySampledSignal([0.0, 1.23, 6.78], [1, 2, 3], units="mV", time_units="ms") 88 | blk = Block() 89 | seg = Segment() 90 | seg.irregularlysampledsignals.append(signal) 91 | blk.segments.append(seg) 92 | 93 | reader = PickleIO(filename="blk.pkl") 94 | reader.write(blk) 95 | 96 | reader = PickleIO(filename="blk.pkl") 97 | r_blk = reader.read_block() 98 | r_seg = r_blk.segments[0] 99 | self.assertIsInstance(r_seg.irregularlysampledsignals[0].segment, Segment) 100 | os.remove("blk.pkl") 101 | 102 | 103 | if __name__ == "__main__": 104 | unittest.main() 105 | -------------------------------------------------------------------------------- /neo/test/iotest/test_plexon2io.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.plexon2io 3 | """ 4 | 5 | import unittest 6 | import os 7 | 8 | from neo.io import Plexon2IO 9 | from neo.test.iotest.common_io_test import BaseTestIO 10 | 11 | from neo.test.rawiotest.test_plexon2rawio import TestPlexon2RawIO 12 | 13 | 14 | try: 15 | from neo.rawio.plexon2rawio.pypl2 import pypl2lib 16 | 17 | HAVE_PYPL2 = True 18 | except (ImportError, TimeoutError): 19 | HAVE_PYPL2 = False 20 | 21 | TEST_PLEXON2 = bool(os.getenv("PLEXON2_TEST")) 22 | 23 | 24 | @unittest.skipUnless(HAVE_PYPL2 and TEST_PLEXON2, "requires pypl package and all its dependencies") 25 | class TestPlexon2IO(BaseTestIO, unittest.TestCase): 26 | entities_to_download = TestPlexon2RawIO.entities_to_download 27 | entities_to_test = TestPlexon2RawIO.entities_to_test 28 | ioclass = Plexon2IO 29 | 30 | 31 | if __name__ == "__main__": 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /neo/test/iotest/test_plexonio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.plexonio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import PlexonIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestPlexonIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = PlexonIO 16 | entities_to_download = ["plexon"] 17 | entities_to_test = [ 18 | "plexon/File_plexon_1.plx", 19 | "plexon/File_plexon_2.plx", 20 | "plexon/File_plexon_3.plx", 21 | "plexon/4chDemoPLX.plx", 22 | ] 23 | 24 | 25 | if __name__ == "__main__": 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /neo/test/iotest/test_rawbinarysignalio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of io.rawbinarysignal 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import RawBinarySignalIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestRawBinarySignalIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = RawBinarySignalIO 16 | entities_to_download = ["rawbinarysignal"] 17 | entities_to_test = ["rawbinarysignal/File_rawbinary_10kHz_2channels_16bit.raw"] 18 | 19 | # Skip this test because there are not mechanisim 20 | # in neo.tests.iotests to set parameters for the ioclass 21 | # in a generic way. In that case nb_channel must be given 22 | # to pass the the set 23 | def test_write_then_read(self): 24 | pass 25 | 26 | 27 | if __name__ == "__main__": 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /neo/test/iotest/test_rawmcsio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.io import RawMCSIO 4 | from neo.test.iotest.common_io_test import BaseTestIO 5 | 6 | 7 | class TestRawMcsIO( 8 | BaseTestIO, 9 | unittest.TestCase, 10 | ): 11 | ioclass = RawMCSIO 12 | entities_to_download = ["rawmcs"] 13 | entities_to_test = ["rawmcs/raw_mcs_with_header_1.raw"] 14 | 15 | 16 | if __name__ == "__main__": 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /neo/test/iotest/test_spike2io.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.spike2io 3 | """ 4 | 5 | import unittest 6 | 7 | import quantities as pq 8 | 9 | from neo.io import Spike2IO 10 | from neo.test.iotest.common_io_test import BaseTestIO 11 | 12 | 13 | class TestSpike2IO( 14 | BaseTestIO, 15 | unittest.TestCase, 16 | ): 17 | ioclass = Spike2IO 18 | entities_to_download = ["spike2"] 19 | entities_to_test = [ 20 | "spike2/File_spike2_1.smr", 21 | "spike2/File_spike2_2.smr", 22 | "spike2/File_spike2_3.smr", 23 | "spike2/130322-1LY.smr", # this is for bug 182 24 | "spike2/multi_sampling.smr", # this is for bug 466 25 | "spike2/Two-mice-bigfile-test000.smr", # SONv9 file 26 | ] 27 | 28 | def test_multi_sampling_no_grouping(self): 29 | """ 30 | Some file can have several sampling_rate. 31 | This one contain 3 differents signals sampling rate 32 | """ 33 | filename = self.get_local_path("spike2/multi_sampling.smr") 34 | reader = Spike2IO(filename=filename, try_signal_grouping=False) 35 | bl = reader.read_block(signal_group_mode="group-by-same-units") 36 | assert len(bl.segments) == 10 37 | seg = bl.segments[0] 38 | 39 | # 7 group_id one per channel 40 | assert len(seg.analogsignals) == 7 41 | 42 | # 1 channel for 1kHz 43 | assert seg.analogsignals[0].shape == (14296, 1) 44 | assert seg.analogsignals[0].sampling_rate == 1000 * pq.Hz 45 | 46 | # 4 channel for 2kHz 47 | for c in range(1, 5): 48 | assert seg.analogsignals[c].shape == (28632, 1) 49 | assert seg.analogsignals[c].sampling_rate == 2000 * pq.Hz 50 | 51 | # 2 channel for 10kHz 52 | for c in range(5, 7): 53 | assert seg.analogsignals[c].shape == (114618, 1) 54 | assert seg.analogsignals[c].sampling_rate == 10000 * pq.Hz 55 | 56 | def test_multi_sampling_no_grouping(self): 57 | """ 58 | Some files can contain multiple sampling rates. 59 | This file contains three signals with different sampling rates. 60 | """ 61 | filename = self.get_local_path("spike2/multi_sampling.smr") 62 | reader = Spike2IO(filename=filename, try_signal_grouping=True) 63 | bl = reader.read_block(signal_group_mode="group-by-same-units") 64 | assert len(bl.segments) == 10 65 | seg = bl.segments[0] 66 | 67 | # 3 groups 68 | assert len(seg.analogsignals) == 3 69 | 70 | # 1 channel for 1kHz 71 | assert seg.analogsignals[0].shape == (14296, 1) 72 | assert seg.analogsignals[0].sampling_rate == 1000 * pq.Hz 73 | 74 | # 4 channel for 2kHz 75 | assert seg.analogsignals[1].shape == (28632, 4) 76 | assert seg.analogsignals[1].sampling_rate == 2000 * pq.Hz 77 | 78 | # 2 channel for 10kHz 79 | assert seg.analogsignals[2].shape == (114618, 2) 80 | assert seg.analogsignals[2].sampling_rate == 10000 * pq.Hz 81 | 82 | 83 | if __name__ == "__main__": 84 | unittest.main() 85 | -------------------------------------------------------------------------------- /neo/test/iotest/test_spikegadgetsio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.io import SpikeGadgetsIO 4 | from neo.test.iotest.common_io_test import BaseTestIO 5 | 6 | 7 | class TestSpikeGadgetsIO( 8 | BaseTestIO, 9 | unittest.TestCase, 10 | ): 11 | ioclass = SpikeGadgetsIO 12 | entities_to_download = ["spikegadgets"] 13 | entities_to_test = ["spikegadgets/20210225_em8_minirec2_ac.rec", "spikegadgets/W122_06_09_2019_1_fromSD.rec"] 14 | 15 | 16 | if __name__ == "__main__": 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /neo/test/iotest/test_spikeglxio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.spikeglxio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import SpikeGLXIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | from neo.test.rawiotest.test_spikeglxrawio import TestSpikeGLXRawIO 10 | 11 | 12 | class TestSpikeGLXIO(BaseTestIO, unittest.TestCase): 13 | ioclass = SpikeGLXIO 14 | entities_to_download = TestSpikeGLXRawIO.entities_to_download 15 | entities_to_test = TestSpikeGLXRawIO.entities_to_test 16 | 17 | 18 | if __name__ == "__main__": 19 | unittest.main() 20 | -------------------------------------------------------------------------------- /neo/test/iotest/test_stimfitio.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Tests of neo.io.stimfitio 4 | """ 5 | 6 | import sys 7 | 8 | import unittest 9 | 10 | from neo.io import StimfitIO 11 | from neo.test.iotest.common_io_test import BaseTestIO 12 | 13 | try: 14 | import stfio 15 | except Exception: 16 | HAS_STFIO = False 17 | else: 18 | HAS_STFIO = True 19 | 20 | 21 | @unittest.skipIf(sys.version_info[0] > 2, "not Python 3 compatible") 22 | @unittest.skipUnless(HAS_STFIO, "requires stfio") 23 | class TestStimfitIO(BaseTestIO, unittest.TestCase): 24 | ioclass = StimfitIO 25 | entities_to_download = ["stimfit"] 26 | entities_to_test = [ 27 | "stimfit/File_stimfit_1.h5", 28 | "stimfit/File_stimfit_2.h5", 29 | "stimfit/File_stimfit_3.h5", 30 | "stimfit/File_stimfit_4.h5", 31 | "stimfit/File_stimfit_5.h5", 32 | "stimfit/File_stimfit_6.h5", 33 | ] 34 | 35 | 36 | if __name__ == "__main__": 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /neo/test/iotest/test_tdtio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.tdtio 3 | """ 4 | 5 | import unittest 6 | from neo.io import TdtIO 7 | from neo.test.iotest.common_io_test import BaseTestIO 8 | import numpy as np 9 | 10 | 11 | class TestTdtIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = TdtIO 16 | entities_to_download = ["tdt"] 17 | entities_to_test = [ 18 | # test structure directory with multiple blocks 19 | "tdt/aep_05", 20 | # test single block 21 | "tdt/dataset_0_single_block/512ch_reconly_all-181123_B24_rest.Tdx", 22 | "tdt/dataset_1_single_block/ECTest-220207-135355_ECTest_B1.Tdx", 23 | "tdt/aep_05/Block-1/aep_05_Block-1.Tdx", 24 | ] 25 | 26 | def test_signal_group_mode(self): 27 | dirname = self.get_local_path("tdt/aep_05") 28 | 29 | # In this TDT dataset there are 3 signal streams 30 | nb_sigs_by_stream = [16, 1, 16] 31 | 32 | reader = TdtIO(dirname=dirname) 33 | bl = reader.read_block() 34 | for seg in bl.segments: 35 | assert len(seg.analogsignals) == 3 36 | i = 0 37 | for anasig in seg.analogsignals: 38 | # print(anasig.shape, anasig.sampling_rate, nb_sigs_by_stream[i]) 39 | assert anasig.shape[1] == nb_sigs_by_stream[i] 40 | i += 1 41 | 42 | 43 | if __name__ == "__main__": 44 | unittest.main() 45 | -------------------------------------------------------------------------------- /neo/test/iotest/test_tiffio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | from PIL import Image 4 | import numpy as np 5 | import shutil 6 | from neo.io.tiffio import TiffIO 7 | import quantities as pq 8 | 9 | 10 | class TestTiffIO(unittest.TestCase): 11 | 12 | def test_read_group_of_tiff_grayscale(self): 13 | directory = "test_tiff" 14 | if not os.path.exists(directory): 15 | os.makedirs(directory) 16 | # directory is live 17 | img = [] 18 | for picture in range(10): 19 | img.append([]) 20 | for x in range(50): 21 | img[picture].append([]) 22 | for y in range(50): 23 | img[picture][x].append(y) 24 | img = np.array(img, dtype=float) 25 | for image in range(10): 26 | # rotate image by 90 deg so that shifting the origin is meaningful in later test 27 | Image.fromarray(np.rot90(img[image])).save(directory + "/tiff_exemple" + str(image) + ".tif") 28 | 29 | ioclass = TiffIO( 30 | directory_path=directory, units="V", sampling_rate=1.0 * pq.Hz, spatial_scale=1.0 * pq.micrometer 31 | ) 32 | blck = ioclass.read_block() 33 | self.assertEqual(len(blck.segments), 1) 34 | self.assertEqual(len(blck.segments[0].imagesequences), 1) 35 | self.assertEqual(blck.segments[0].imagesequences[0].any(), img.any()) 36 | self.assertEqual(blck.segments[0].imagesequences[0].sampling_rate, 1.0 * pq.Hz) 37 | self.assertEqual(blck.segments[0].imagesequences[0].spatial_scale, 1.0 * pq.micrometer) 38 | 39 | ioclass_bl_origin = TiffIO( 40 | directory_path=directory, 41 | units="V", 42 | sampling_rate=1.0 * pq.Hz, 43 | spatial_scale=1.0 * pq.micrometer, 44 | origin="bottom-left", 45 | ) 46 | blck_bl_origin = ioclass_bl_origin.read_block() 47 | 48 | self.assertAlmostEqual( 49 | blck.segments[0].imagesequences[0][0][0, 0].magnitude, 50 | blck_bl_origin.segments[0].imagesequences[0][0][49, 0].magnitude, # since flipped over y, [0,0] == [49,0] 51 | places=3, 52 | ) 53 | 54 | # end of directory 55 | shutil.rmtree(directory) 56 | 57 | 58 | if __name__ == "__main__": 59 | unittest.main() 60 | -------------------------------------------------------------------------------- /neo/test/iotest/test_winedrio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.wineedrio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import WinEdrIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestWinedrIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = WinEdrIO 16 | entities_to_download = ["winedr"] 17 | entities_to_test = [ 18 | "winedr/File_WinEDR_1.EDR", 19 | "winedr/File_WinEDR_2.EDR", 20 | "winedr/File_WinEDR_3.EDR", 21 | ] 22 | 23 | 24 | if __name__ == "__main__": 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /neo/test/iotest/test_winwcpio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.io.winwcpio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.io import WinWcpIO 8 | from neo.test.iotest.common_io_test import BaseTestIO 9 | 10 | 11 | class TestRawBinarySignalIO( 12 | BaseTestIO, 13 | unittest.TestCase, 14 | ): 15 | ioclass = WinWcpIO 16 | entities_to_download = ["winwcp"] 17 | entities_to_test = ["winwcp/File_winwcp_1.wcp"] 18 | 19 | 20 | if __name__ == "__main__": 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /neo/test/rawiotest/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NeuralEnsemble/python-neo/8e1b6ada3b385c2e5e99b0b5b2e5f7c4dc59fb1a/neo/test/rawiotest/__init__.py -------------------------------------------------------------------------------- /neo/test/rawiotest/test_axographrawio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.rawio.axographrawio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.rawio.axographrawio import AxographRawIO 8 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 9 | 10 | 11 | class TestAxographRawIO(BaseTestRawIO, unittest.TestCase): 12 | rawioclass = AxographRawIO 13 | entities_to_test = [ 14 | "axograph/AxoGraph_Graph_File", # version 1 file, provided with AxoGraph 15 | "axograph/AxoGraph_Digitized_File", # version 2 file, provided with AxoGraph 16 | "axograph/AxoGraph_X_File.axgx", # version 5 file, provided with AxoGraph 17 | "axograph/File_axograph.axgd", # version 6 file 18 | "axograph/episodic.axgd", 19 | "axograph/events_and_epochs.axgx", 20 | "axograph/written-by-axographio-with-linearsequence.axgx", 21 | "axograph/written-by-axographio-without-linearsequence.axgx", 22 | "axograph/corrupt-comment.axgx", 23 | ] 24 | entities_to_download = ["axograph"] 25 | 26 | 27 | if __name__ == "__main__": 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_axonarawio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.rawio.axonarawio 3 | 4 | Author: Steffen Buergers 5 | 6 | """ 7 | 8 | import unittest 9 | 10 | from neo.rawio.axonarawio import AxonaRawIO 11 | 12 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 13 | 14 | 15 | class TestAxonaRawIO(BaseTestRawIO, unittest.TestCase): 16 | rawioclass = AxonaRawIO 17 | entities_to_download = ["axona"] 18 | entities_to_test = [ 19 | "axona/axona_raw.set", 20 | "axona/dataset_unit_spikes/20140815-180secs.set", 21 | "axona/dataset_multi_modal/axona_sample.set", 22 | ] 23 | 24 | 25 | if __name__ == "__main__": 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_axonrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.axonrawio import AxonRawIO 4 | 5 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 6 | 7 | 8 | class TestAxonRawIO( 9 | BaseTestRawIO, 10 | unittest.TestCase, 11 | ): 12 | rawioclass = AxonRawIO 13 | entities_to_test = [ 14 | "axon/File_axon_1.abf", # V2.0 15 | "axon/File_axon_2.abf", # V1.8 16 | "axon/File_axon_3.abf", # V1.8 17 | "axon/File_axon_4.abf", # 2.0 18 | "axon/File_axon_5.abf", # V.20 19 | "axon/File_axon_6.abf", # V.20 20 | "axon/File_axon_7.abf", # V2.6 21 | "axon/test_file_edr3.abf", # EDR3 22 | ] 23 | entities_to_download = ["axon"] 24 | 25 | def test_read_raw_protocol(self): 26 | reader = AxonRawIO(filename=self.get_local_path("axon/File_axon_7.abf")) 27 | reader.parse_header() 28 | 29 | reader.read_raw_protocol() 30 | 31 | 32 | if __name__ == "__main__": 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_bci2000rawio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.rawio.bci2000rawio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.rawio.bci2000rawio import BCI2000RawIO 8 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 9 | 10 | 11 | class TestBCI2000RawIO( 12 | BaseTestRawIO, 13 | unittest.TestCase, 14 | ): 15 | rawioclass = BCI2000RawIO 16 | 17 | entities_to_download = ["bci2000/eeg1_1.dat", "bci2000/eeg1_2.dat", "bci2000/eeg1_3.dat"] 18 | 19 | entities_to_download = [ 20 | "bci2000", 21 | ] 22 | 23 | 24 | if __name__ == "__main__": 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_biocamrawio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.rawio.BiocamRawIO 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.rawio.biocamrawio import BiocamRawIO 8 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 9 | 10 | 11 | class TestBiocamRawIO( 12 | BaseTestRawIO, 13 | unittest.TestCase, 14 | ): 15 | rawioclass = BiocamRawIO 16 | 17 | entities_to_download = [ 18 | "biocam", 19 | ] 20 | entities_to_test = [ 21 | "biocam/biocam_hw3.0_fw1.6.brw", 22 | "biocam/biocam_hw3.0_fw1.7.0.12_raw.brw", 23 | ] 24 | 25 | 26 | if __name__ == "__main__": 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_brainvisionrawio.py: -------------------------------------------------------------------------------- 1 | """ """ 2 | 3 | import unittest 4 | 5 | from neo.rawio.brainvisionrawio import BrainVisionRawIO 6 | 7 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 8 | 9 | 10 | class TestBrainVisionRawIO( 11 | BaseTestRawIO, 12 | unittest.TestCase, 13 | ): 14 | rawioclass = BrainVisionRawIO 15 | entities_to_test = [ 16 | "brainvision/File_brainvision_1.vhdr", 17 | "brainvision/File_brainvision_2.vhdr", 18 | "brainvision/File_brainvision_3_float32.vhdr", 19 | "brainvision/File_brainvision_3_int16.vhdr", 20 | "brainvision/File_brainvision_3_int32.vhdr", 21 | "brainvision/File_brainvision_4_float32.vhdr", 22 | ] 23 | 24 | entities_to_download = ["brainvision"] 25 | 26 | 27 | if __name__ == "__main__": 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_cedrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.cedrawio import CedRawIO 4 | 5 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 6 | 7 | try: 8 | import sonpy 9 | 10 | HAVE_SONPY = True 11 | except ImportError: 12 | HAVE_SONPY = False 13 | 14 | 15 | # This runs standard tests, this is mandatory for all IOs 16 | @unittest.skipUnless(HAVE_SONPY, "requires sonpy package and all its dependencies") 17 | class TestCedRawIO( 18 | BaseTestRawIO, 19 | unittest.TestCase, 20 | ): 21 | rawioclass = CedRawIO 22 | entities_to_test = ["spike2/m365_1sec.smrx", "spike2/File_spike2_1.smr", "spike2/Two-mice-bigfile-test000.smr"] 23 | entities_to_download = ["spike2"] 24 | 25 | 26 | if __name__ == "__main__": 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_edfrawio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.rawio.edfrawio 3 | """ 4 | 5 | import unittest 6 | 7 | from neo.rawio.edfrawio import EDFRawIO 8 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 9 | 10 | 11 | class TestExampleRawIO( 12 | BaseTestRawIO, 13 | unittest.TestCase, 14 | ): 15 | rawioclass = EDFRawIO 16 | entities_to_download = ["edf"] 17 | entities_to_test = [ 18 | "edf/edf+C.edf", 19 | ] 20 | 21 | def test_context_handler(self): 22 | filename = self.get_local_path("edf/edf+C.edf") 23 | with EDFRawIO(filename) as io: 24 | io.parse_header() 25 | 26 | # Check that file was closed properly and can be opened again 27 | with open(filename) as f: 28 | pass 29 | 30 | def test_close(self): 31 | filename = self.get_local_path("edf/edf+C.edf") 32 | 33 | # Open file and close it again 34 | io1 = EDFRawIO(filename) 35 | io1.parse_header() 36 | io1.close() 37 | 38 | # Check that file was closed properly and can be opened again 39 | io2 = EDFRawIO(filename) 40 | io2.parse_header() 41 | io2.close() 42 | 43 | 44 | if __name__ == "__main__": 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_elanrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.elanrawio import ElanRawIO 4 | 5 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 6 | 7 | 8 | class TestElanRawIO( 9 | BaseTestRawIO, 10 | unittest.TestCase, 11 | ): 12 | rawioclass = ElanRawIO 13 | entities_to_test = ["elan/File_elan_1.eeg"] 14 | entities_to_download = [ 15 | "elan", 16 | ] 17 | 18 | 19 | if __name__ == "__main__": 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_examplerawio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.rawio.examplerawio 3 | 4 | Note for dev: 5 | if you write a new RawIO class your need to put some file 6 | to be tested at g-node portal, Ask neuralensemble list for that. 7 | The file need to be small. 8 | 9 | Then you have to copy/paste/renamed the TestExampleRawIO 10 | class and a full test will be done to test if the new coded IO 11 | is compliant with the RawIO API. 12 | 13 | If you have problems, do not hesitate to ask help github (prefered) 14 | of neuralensemble list. 15 | 16 | Note that same mechanism is used a neo.io API so files are tested 17 | several time with neo.rawio (numpy buffer) and neo.io (neo object tree). 18 | See neo.test.iotest.* 19 | 20 | 21 | Author: Samuel Garcia 22 | 23 | """ 24 | 25 | import unittest 26 | 27 | from neo.rawio.examplerawio import ExampleRawIO 28 | 29 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 30 | 31 | 32 | class TestExampleRawIO( 33 | BaseTestRawIO, 34 | unittest.TestCase, 35 | ): 36 | rawioclass = ExampleRawIO 37 | # here obliviously there is nothing to download: 38 | entities_to_download = [] 39 | 40 | # here we will test 1 fake file 41 | # note that for IOs based on directory names you can put the directory 42 | # name here instead of the filename. 43 | entities_to_test = ["fake1"] 44 | 45 | 46 | if __name__ == "__main__": 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_get_rawio.py: -------------------------------------------------------------------------------- 1 | from neo.rawio import get_rawio 2 | from pathlib import Path 3 | from tempfile import TemporaryDirectory 4 | 5 | 6 | def test_get_rawio_class(): 7 | # use plexon io suffix for testing here 8 | non_existant_file = Path("non_existant_folder/non_existant_file.plx") 9 | non_existant_file.unlink(missing_ok=True) 10 | ios = get_rawio(non_existant_file) 11 | 12 | assert ios 13 | 14 | # cleanup 15 | non_existant_file.unlink(missing_ok=True) 16 | 17 | 18 | def test_get_rawio_class_nonsupported_rawio(): 19 | 20 | non_existant_file = Path("non_existant_folder/non_existant_file.fake") 21 | non_existant_file.unlink(missing_ok=True) 22 | ios = get_rawio(non_existant_file) 23 | 24 | assert ios is None 25 | 26 | # cleanup 27 | non_existant_file.unlink(missing_ok=True) 28 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_maxwellrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.maxwellrawio import MaxwellRawIO, auto_install_maxwell_hdf5_compression_plugin 4 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 5 | 6 | 7 | class TestMaxwellRawIO( 8 | BaseTestRawIO, 9 | unittest.TestCase, 10 | ): 11 | 12 | rawioclass = MaxwellRawIO 13 | entities_to_download = ["maxwell"] 14 | entities_to_test = files_to_test = [ 15 | "maxwell/MaxOne_data/Record/000011/data.raw.h5", 16 | "maxwell/MaxTwo_data/Network/000028/data.raw.h5", 17 | ] 18 | 19 | def setUp(self): 20 | auto_install_maxwell_hdf5_compression_plugin(force_download=False) 21 | 22 | 23 | if __name__ == "__main__": 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_mearecrawio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.rawio.mearecrawio 3 | 4 | """ 5 | 6 | import unittest 7 | 8 | from neo.rawio.mearecrawio import MEArecRawIO 9 | 10 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 11 | 12 | 13 | try: 14 | import MEArec as mr 15 | 16 | HAVE_MEAREC = True 17 | except ImportError: 18 | HAVE_MEAREC = False 19 | 20 | 21 | @unittest.skipUnless(HAVE_MEAREC, "requires MEArec package") 22 | class TestMEArecRawIO( 23 | BaseTestRawIO, 24 | unittest.TestCase, 25 | ): 26 | rawioclass = MEArecRawIO 27 | entities_to_download = ["mearec"] 28 | entities_to_test = ["mearec/mearec_test_10s.h5"] 29 | 30 | def test_not_loading_recordings(self): 31 | 32 | filename = self.entities_to_test[0] 33 | filename = self.get_local_path(filename) 34 | rawio = self.rawioclass(filename=filename, load_analogsignal=False) 35 | rawio.parse_header() 36 | 37 | # Test that rawio does not have a _recordings attribute 38 | self.assertFalse(hasattr(rawio, "_recordings")) 39 | 40 | # Test that calling get_spike_timestamps works 41 | rawio.get_spike_timestamps() 42 | 43 | # Test that caling anlogsignal chunk raises the right error 44 | with self.assertRaises(AttributeError): 45 | rawio.get_analogsignal_chunk() 46 | 47 | def test_not_loading_spiketrain(self): 48 | 49 | filename = self.entities_to_test[0] 50 | filename = self.get_local_path(filename) 51 | rawio = self.rawioclass(filename=filename, load_spiketrains=False) 52 | rawio.parse_header() 53 | 54 | # Test that rawio does not have a _spiketrains attribute 55 | self.assertFalse(hasattr(rawio, "_spiketrains")) 56 | 57 | # Test that calling analogsignal chunk works 58 | rawio.get_analogsignal_chunk() 59 | 60 | # Test that calling get_spike_timestamps raises an the right error 61 | with self.assertRaises(AttributeError): 62 | rawio.get_spike_timestamps() 63 | 64 | 65 | if __name__ == "__main__": 66 | unittest.main() 67 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_micromedrawio.py: -------------------------------------------------------------------------------- 1 | """ """ 2 | 3 | import unittest 4 | 5 | from neo.rawio.micromedrawio import MicromedRawIO 6 | 7 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 8 | 9 | import numpy as np 10 | 11 | 12 | class TestMicromedRawIO( 13 | BaseTestRawIO, 14 | unittest.TestCase, 15 | ): 16 | rawioclass = MicromedRawIO 17 | entities_to_download = ["micromed"] 18 | entities_to_test = [ 19 | "micromed/File_micromed_1.TRC", 20 | "micromed/File_mircomed2.TRC", 21 | "micromed/File_mircomed2_2segments.TRC", 22 | ] 23 | 24 | def test_micromed_multi_segments(self): 25 | file_full = self.get_local_path("micromed/File_mircomed2.TRC") 26 | file_splitted = self.get_local_path("micromed/File_mircomed2_2segments.TRC") 27 | 28 | # the second file contains 2 pieces of the first file 29 | # so it is 2 segments with the same traces but reduced 30 | # note that traces in the splited can differ at the very end of the cut 31 | 32 | reader1 = MicromedRawIO(file_full) 33 | reader1.parse_header() 34 | assert reader1.segment_count(block_index=0) == 1 35 | assert reader1.get_signal_t_start(block_index=0, seg_index=0, stream_index=0) == 0.0 36 | traces1 = reader1.get_analogsignal_chunk(stream_index=0) 37 | 38 | reader2 = MicromedRawIO(file_splitted) 39 | reader2.parse_header() 40 | print(reader2) 41 | assert reader2.segment_count(block_index=0) == 2 42 | 43 | # check that pieces of the second file is equal to the first file (except a truncation at the end) 44 | for seg_index in range(2): 45 | t_start = reader2.get_signal_t_start(block_index=0, seg_index=seg_index, stream_index=0) 46 | assert t_start > 0 47 | sr = reader2.get_signal_sampling_rate(stream_index=0) 48 | ind_start = int(t_start * sr) 49 | traces2 = reader2.get_analogsignal_chunk(block_index=0, seg_index=seg_index, stream_index=0) 50 | traces1_chunk = traces1[ind_start : ind_start + traces2.shape[0]] 51 | # we remove the last 100 sample because tools that cut traces is truncating the last buffer 52 | assert np.array_equal(traces2[:-100], traces1_chunk[:-100]) 53 | 54 | 55 | if __name__ == "__main__": 56 | unittest.main() 57 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_neuroexplorerrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.neuroexplorerrawio import NeuroExplorerRawIO 4 | 5 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 6 | 7 | 8 | class TestNeuroExplorerRawIO( 9 | BaseTestRawIO, 10 | unittest.TestCase, 11 | ): 12 | rawioclass = NeuroExplorerRawIO 13 | entities_to_download = ["neuroexplorer"] 14 | files_to_download = [ 15 | "neuroexplorer/File_neuroexplorer_1.nex", 16 | "neuroexplorer/File_neuroexplorer_2.nex", 17 | ] 18 | 19 | 20 | if __name__ == "__main__": 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_neuronexusrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import numpy as np 3 | 4 | from neo.rawio.neuronexusrawio import NeuroNexusRawIO 5 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 6 | 7 | 8 | class TestNeuroNexusRawIO( 9 | BaseTestRawIO, 10 | unittest.TestCase, 11 | ): 12 | rawioclass = NeuroNexusRawIO 13 | entities_to_download = ["neuronexus"] 14 | entities_to_test = ["neuronexus/allego_1/allego_2__uid0701-13-04-49.xdat.json"] 15 | 16 | 17 | if __name__ == "__main__": 18 | unittest.main() 19 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_neuroscoperawio.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from pathlib import Path 4 | import unittest 5 | 6 | from neo.rawio.neuroscoperawio import NeuroScopeRawIO 7 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 8 | from neo.test.rawiotest import rawio_compliance as compliance 9 | from neo.utils.datasets import get_local_testing_data_folder 10 | 11 | 12 | class TestNeuroScopeRawIO(BaseTestRawIO, unittest.TestCase): 13 | rawioclass = NeuroScopeRawIO 14 | entities_to_download = ["neuroscope"] 15 | entities_to_test = [ 16 | "neuroscope/test1/test1", 17 | "neuroscope/test1/test1.dat", 18 | "neuroscope/dataset_1/YutaMouse42-151117.eeg", 19 | ] 20 | 21 | def test_signal_scale(self): 22 | local_test_dir = get_local_testing_data_folder() 23 | fname = os.path.join(local_test_dir, "neuroscope/test1/test1.xml") 24 | reader = NeuroScopeRawIO(filename=fname) 25 | reader.parse_header() 26 | 27 | gain = reader.header["signal_channels"][0]["gain"] 28 | 29 | # scale is in mV = range of recording in volts * 1000 mV/V /(number of bits * ampification) 30 | self.assertAlmostEqual(20.0 * 1000 / (2**16 * 1000), gain) 31 | 32 | def test_binary_argument_with_non_canonical_xml_file(self): 33 | 34 | local_test_dir = get_local_testing_data_folder() 35 | filename = local_test_dir / "neuroscope/test2/recording.xml" 36 | binary_file = local_test_dir / "neuroscope/test2/signal1.dat" 37 | reader = NeuroScopeRawIO(filename=filename, binary_file=binary_file) 38 | 39 | msg = "Before parser_header() no header information should be present" 40 | assert reader.header is None, msg 41 | 42 | reader.parse_header() 43 | 44 | # After the file resolution test that the right file is being loaded 45 | assert reader.data_file_path == binary_file 46 | assert reader.xml_file_path == filename 47 | 48 | txt = reader.__repr__() 49 | msg = "After parser_header() nb_block should be known" 50 | assert "nb_block" in txt, msg 51 | txt = reader._repr_annotations() 52 | 53 | # launch a series of test compliance 54 | compliance.header_is_total(reader) 55 | compliance.count_element(reader) 56 | compliance.read_analogsignals(reader) 57 | compliance.read_spike_times(reader) 58 | compliance.read_spike_waveforms(reader) 59 | compliance.read_events(reader) 60 | compliance.has_annotations(reader) 61 | 62 | 63 | if __name__ == "__main__": 64 | unittest.main() 65 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_nixrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from neo.rawio.nixrawio import NIXRawIO 3 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 4 | 5 | 6 | testfname = "" 7 | 8 | 9 | class TestNixRawIO(BaseTestRawIO, unittest.TestCase): 10 | rawioclass = NIXRawIO 11 | entities_to_download = ["nix/nixrawio-1.5.nix"] 12 | entities_to_test = ["nix/nixrawio-1.5.nix"] 13 | 14 | 15 | if __name__ == "__main__": 16 | unittest.main() 17 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_openephysrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.openephysrawio import OpenEphysRawIO 4 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 5 | 6 | 7 | class TestOpenEphysRawIO( 8 | BaseTestRawIO, 9 | unittest.TestCase, 10 | ): 11 | rawioclass = OpenEphysRawIO 12 | entities_to_download = ["openephys"] 13 | entities_to_test = [ 14 | "openephys/OpenEphys_SampleData_1", 15 | # this file has gaps and this is now handle corretly 16 | "openephys/OpenEphys_SampleData_2_(multiple_starts)", 17 | # 'openephys/OpenEphys_SampleData_3', 18 | # two nodes with the new naming convention for openephys 19 | "openephys/openephys_rhythmdata_test_nodes/Record Node 120", 20 | "openephys/openephys_rhythmdata_test_nodes/Record Node 121", 21 | ] 22 | 23 | def test_raise_error_if_strange_timestamps(self): 24 | # In this dataset CH32 have strange timestamps 25 | reader = OpenEphysRawIO(dirname=self.get_local_path("openephys/OpenEphys_SampleData_3")) 26 | with self.assertRaises(Exception): 27 | reader.parse_header() 28 | 29 | def test_channel_order(self): 30 | reader = OpenEphysRawIO(dirname=self.get_local_path("openephys/OpenEphys_SampleData_1")) 31 | reader.parse_header() 32 | reader.header["signal_channels"]["name"][0].startswith("CH") 33 | 34 | 35 | if __name__ == "__main__": 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_plexon2rawio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests of neo.rawio.plexon2 3 | 4 | """ 5 | 6 | import unittest 7 | import os 8 | 9 | from neo.rawio.plexon2rawio import Plexon2RawIO 10 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 11 | from numpy.testing import assert_equal 12 | 13 | try: 14 | from neo.rawio.plexon2rawio.pypl2 import pypl2lib 15 | 16 | HAVE_PYPL2 = True 17 | except (ImportError, TimeoutError): 18 | HAVE_PYPL2 = False 19 | 20 | TEST_PLEXON2 = bool(os.getenv("PLEXON2_TEST")) 21 | 22 | 23 | @unittest.skipUnless(HAVE_PYPL2 and TEST_PLEXON2, "requires pypl package and all its dependencies") 24 | class TestPlexon2RawIO( 25 | BaseTestRawIO, 26 | unittest.TestCase, 27 | ): 28 | rawioclass = Plexon2RawIO 29 | entities_to_download = ["plexon"] 30 | entities_to_test = ["plexon/4chDemoPL2.pl2", "plexon/NC16FPSPKEVT_1m.pl2"] 31 | 32 | def test_check_enabled_flags(self): 33 | """ 34 | This test loads a 1-minute PL2 file with 16 channels' each 35 | of field potential (FP), and spike (SPK) data. The channels 36 | cycle through 4 possible combinations of m_ChannelEnabled 37 | and m_ChannelRecordingEnabled - (True, True), (True, False), 38 | (False, True), and (False, False). With 16 channels for each 39 | source, each combination of flags occurs 4 times. Only the 40 | first combination (True, True) causes data to be recorded to 41 | disk. Therefore, we expect the following channels to be loaded by 42 | Neo: FP01, FP05, FP09, FP13, SPK01, SPK05, SPK09, and SPK13. 43 | 44 | Note: the file contains event (EVT) data as well. Although event 45 | channel headers do contain m_ChannelEnabled and m_ChannelRecording- 46 | Enabled flags, the UI for recording PL2 files does not expose any 47 | controls by which these flags can be changed from (True, True). 48 | Therefore, no test for event channels is necessary here. 49 | """ 50 | 51 | # Load data from NC16FPSPKEVT_1m.pl2, a 1-minute PL2 recording containing 52 | # 16-channels' each of field potential (FP), spike (SPK), and event (EVT) 53 | # data. 54 | reader = Plexon2RawIO(filename=self.get_local_path("plexon/NC16FPSPKEVT_1m.pl2")) 55 | reader.parse_header() 56 | 57 | # Check that the names of the loaded signal channels match what we expect 58 | signal_channel_names = reader.header["signal_channels"]["name"].tolist() 59 | expected_signal_channel_names = ["FP01", "FP05", "FP09", "FP13"] 60 | assert_equal(signal_channel_names, expected_signal_channel_names) 61 | 62 | # Check that the names of the loaded spike channels match what we expect 63 | spike_channel_names = reader.header["spike_channels"]["name"].tolist() 64 | expected_spike_channel_names = ["SPK01.0", "SPK05.0", "SPK09.0", "SPK13.0"] 65 | assert_equal(spike_channel_names, expected_spike_channel_names) 66 | 67 | 68 | if __name__ == "__main__": 69 | unittest.main() 70 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_plexonrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.plexonrawio import PlexonRawIO 4 | 5 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 6 | 7 | 8 | class TestPlexonRawIO( 9 | BaseTestRawIO, 10 | unittest.TestCase, 11 | ): 12 | rawioclass = PlexonRawIO 13 | entities_to_download = ["plexon"] 14 | entities_to_test = [ 15 | "plexon/File_plexon_1.plx", 16 | "plexon/File_plexon_2.plx", 17 | "plexon/File_plexon_3.plx", 18 | "plexon/4chDemoPLX.plx", 19 | ] 20 | 21 | 22 | if __name__ == "__main__": 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_rawbinarysignalrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.rawbinarysignalrawio import RawBinarySignalRawIO 4 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 5 | 6 | 7 | class TestRawBinarySignalRawIO( 8 | BaseTestRawIO, 9 | unittest.TestCase, 10 | ): 11 | rawioclass = RawBinarySignalRawIO 12 | entities_to_download = ["rawbinarysignal"] 13 | entities_to_test = ["rawbinarysignal/File_rawbinary_10kHz_2channels_16bit.raw"] 14 | 15 | 16 | if __name__ == "__main__": 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_rawmcsrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.rawmcsrawio import RawMCSRawIO 4 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 5 | 6 | 7 | class TestRawMCSRawIO( 8 | BaseTestRawIO, 9 | unittest.TestCase, 10 | ): 11 | rawioclass = RawMCSRawIO 12 | entities_to_download = ["rawmcs"] 13 | entities_to_test = ["rawmcs/raw_mcs_with_header_1.raw"] 14 | 15 | 16 | if __name__ == "__main__": 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_spike2rawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.spike2rawio import Spike2RawIO 4 | 5 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 6 | 7 | 8 | class TestSpike2RawIO( 9 | BaseTestRawIO, 10 | unittest.TestCase, 11 | ): 12 | rawioclass = Spike2RawIO 13 | entities_to_download = ["spike2"] 14 | entities_to_test = [ 15 | "spike2/File_spike2_1.smr", 16 | "spike2/File_spike2_2.smr", 17 | "spike2/File_spike2_3.smr", 18 | "spike2/130322-1LY.smr", # this is for bug 182 19 | "spike2/multi_sampling.smr", # this is for bug 466 20 | "spike2/Two-mice-bigfile-test000.smr", # SONv9 file 21 | ] 22 | 23 | 24 | if __name__ == "__main__": 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_spikegadgetsrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from pathlib import Path 3 | 4 | from neo.rawio.spikegadgetsrawio import SpikeGadgetsRawIO 5 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 6 | from numpy.testing import assert_array_equal 7 | 8 | 9 | class TestSpikeGadgetsRawIO( 10 | BaseTestRawIO, 11 | unittest.TestCase, 12 | ): 13 | rawioclass = SpikeGadgetsRawIO 14 | entities_to_download = ["spikegadgets"] 15 | entities_to_test = [ 16 | "spikegadgets/20210225_em8_minirec2_ac.rec", 17 | "spikegadgets/W122_06_09_2019_1_fromSD.rec", 18 | "spikegadgets/SpikeGadgets_test_data_2xNpix1.0_20240318_173658.rec", 19 | ] 20 | 21 | def test_parse_header_missing_channels(self): 22 | 23 | file_path = Path(self.get_local_path("spikegadgets/SL18_D19_S01_F01_BOX_SLP_20230503_112642_stubbed.rec")) 24 | reader = SpikeGadgetsRawIO(filename=file_path) 25 | reader.parse_header() 26 | 27 | assert_array_equal( 28 | reader.header["signal_channels"]["id"], 29 | # fmt: off 30 | [ 31 | 'ECU_Ain1', 'ECU_Ain2', 'ECU_Ain3', 'ECU_Ain4', 'ECU_Ain5', 'ECU_Ain6', 32 | 'ECU_Ain7', 'ECU_Ain8', 'ECU_Aout1', 'ECU_Aout2', 'ECU_Aout3', 'ECU_Aout4', '0', 33 | '32', '96', '160', '192', '224', '1', '33', '65', '97', '161', '193', '225', '2', '34', 34 | '98', '162', '194', '226', '3', '35', '67', '99', '163', '195', '227', '4', '36', 35 | '100', '164', '196', '228', '5', '37', '69', '101', '165', '197', '229', '6', '38', 36 | '102', '166', '198', '230', '7', '39', '71', '103', '167', '199', '231', '8', '40', 37 | '72', '104', '136', '168', '200', '232', '9', '41', '73', '105', '137', '169', '201', 38 | '233', '10', '42', '74', '106', '138', '170', '202', '234', '11', '43', '75', '107', 39 | '139', '171', '203', '235', '12', '44', '76', '108', '140', '172', '204', '236', '13', 40 | '45', '77', '109', '141', '173', '205', '237', '14', '46', '78', '110', '142', '174', 41 | '206', '238', '15', '47', '79', '111', '143', '175', '207', '239', '80', '144', '176', 42 | '208', '240', '17', '49', '81', '145', '177', '209', '241', '82', '146', '178', '210', 43 | '242', '19', '51', '83', '147', '179', '211', '243', '84', '148', '180', '212', '244', 44 | '21', '53', '85', '149', '181', '213', '245', '86', '150', '182', '214', '246', '23', 45 | '55', '87', '151', '183', '215', '247', '24', '56', '88', '152', '184', '216', '248', 46 | '25', '57', '89', '121', '153', '185', '217', '249', '26', '58', '90', '154', '186', 47 | '218', '250', '27', '59', '91', '123', '155', '187', '219', '251', '28', '60', '92', 48 | '156', '188', '220', '252', '29', '61', '93', '125', '157', '189', '221', '253', '30', 49 | '62', '94', '158', '190', '222', '254', '31', '63', '95', '127', '159', '191', '223', 50 | '255' 51 | ] 52 | # fmt: on 53 | ) 54 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_tdtrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from pathlib import Path 3 | from numpy.testing import assert_array_equal, assert_ 4 | 5 | from neo.rawio.tdtrawio import TdtRawIO 6 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 7 | 8 | 9 | class TestTdtRawIO( 10 | BaseTestRawIO, 11 | unittest.TestCase, 12 | ): 13 | rawioclass = TdtRawIO 14 | entities_to_download = ["tdt"] 15 | entities_to_test = [ 16 | # test structure directory with multiple blocks 17 | "tdt/aep_05", 18 | # test single block 19 | "tdt/dataset_0_single_block/512ch_reconly_all-181123_B24_rest.Tdx", 20 | "tdt/dataset_1_single_block/ECTest-220207-135355_ECTest_B1.Tdx", 21 | "tdt/aep_05/Block-1/aep_05_Block-1.Tdx", 22 | ] 23 | 24 | def test_invalid_dirname(self): 25 | invalid_name = "random_non_existant_tdt_filename" 26 | assert not Path(invalid_name).exists() 27 | 28 | with self.assertRaises(ValueError): 29 | TdtRawIO(invalid_name) 30 | 31 | def test_compare_load_multi_single_block(self): 32 | dirname = self.get_local_path("tdt/aep_05") 33 | filename = self.get_local_path("tdt/aep_05/Block-1/aep_05_Block-1.Tdx") 34 | 35 | io_single = TdtRawIO(filename) 36 | io_multi = TdtRawIO(dirname) 37 | 38 | io_single.parse_header() 39 | io_multi.parse_header() 40 | 41 | self.assertEqual(io_single.tdt_block_mode, "single") 42 | self.assertEqual(io_multi.tdt_block_mode, "multi") 43 | 44 | self.assertEqual(io_single.block_count(), 1) 45 | self.assertEqual(io_multi.block_count(), 1) 46 | 47 | self.assertEqual(io_single.segment_count(0), 1) 48 | self.assertEqual(io_multi.segment_count(0), 2) 49 | 50 | # compare header infos 51 | assert_array_equal(io_single.header["signal_streams"], io_multi.header["signal_streams"]) 52 | assert_array_equal(io_single.header["signal_channels"], io_multi.header["signal_channels"]) 53 | assert_array_equal(io_single.header["event_channels"], io_multi.header["event_channels"]) 54 | 55 | # not all spiking channels are present in first tdt block (segment) 56 | for spike_channel in io_single.header["spike_channels"]: 57 | self.assertIn(spike_channel, io_multi.header["spike_channels"]) 58 | 59 | # check that extracted signal chunks are identical 60 | assert_array_equal( 61 | io_single.get_analogsignal_chunk(0, 0, 0, 100, 0), io_multi.get_analogsignal_chunk(0, 0, 0, 100, 0) 62 | ) 63 | 64 | 65 | if __name__ == "__main__": 66 | unittest.main() 67 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_winedrrawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.winedrrawio import WinEdrRawIO 4 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 5 | 6 | 7 | class TestWinEdrRawIO( 8 | BaseTestRawIO, 9 | unittest.TestCase, 10 | ): 11 | rawioclass = WinEdrRawIO 12 | entities_to_download = ["winedr"] 13 | entities_to_test = [ 14 | "winedr/File_WinEDR_1.EDR", 15 | "winedr/File_WinEDR_2.EDR", 16 | "winedr/File_WinEDR_3.EDR", 17 | ] 18 | 19 | 20 | if __name__ == "__main__": 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /neo/test/rawiotest/test_winwcprawio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from neo.rawio.winwcprawio import WinWcpRawIO 4 | from neo.test.rawiotest.common_rawio_test import BaseTestRawIO 5 | 6 | 7 | class TestWinWcpRawIO( 8 | BaseTestRawIO, 9 | unittest.TestCase, 10 | ): 11 | rawioclass = WinWcpRawIO 12 | entities_to_download = ["winwcp"] 13 | entities_to_test = ["winwcp/File_winwcp_1.wcp"] 14 | 15 | 16 | if __name__ == "__main__": 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /neo/test/rawiotest/tools.py: -------------------------------------------------------------------------------- 1 | """ 2 | Common tools that are useful for neo.io object tests 3 | """ 4 | 5 | import logging 6 | import os 7 | import importlib.util 8 | 9 | 10 | logger = logging.getLogger("neo.test") 11 | 12 | 13 | def can_use_network(): 14 | """ 15 | Return True if network access is allowed 16 | """ 17 | 18 | # env variable for local dev 19 | if os.environ.get("NEO_TESTS_NO_NETWORK", False): 20 | return False 21 | 22 | # check for datalad presence 23 | datalad_spec = importlib.util.find_spec("datalad") 24 | if datalad_spec is not None: 25 | HAVE_DATALAD = True 26 | else: 27 | HAVE_DATALAD = False 28 | 29 | if not HAVE_DATALAD: 30 | return False 31 | 32 | return True 33 | -------------------------------------------------------------------------------- /neo/test/utils/test_datasets.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import pytest 3 | from neo.utils.datasets import download_dataset, default_testing_repo 4 | from neo.test.rawiotest.tools import can_use_network 5 | 6 | 7 | @pytest.mark.skipif(not can_use_network(), reason="Must have acess to network to run test") 8 | class TestDownloadDataset(unittest.TestCase): 9 | def test_download_dataset(self): 10 | local_path = download_dataset(repo=default_testing_repo, remote_path="blackrock/blackrock_2_1") 11 | assert local_path.is_dir() 12 | 13 | 14 | if __name__ == "__main__": 15 | unittest.main() 16 | -------------------------------------------------------------------------------- /neo/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utils package 3 | """ 4 | 5 | from .misc import ( 6 | get_events, 7 | get_epochs, 8 | add_epoch, 9 | match_events, 10 | cut_block_by_epochs, 11 | cut_segment_by_epoch, 12 | is_block_rawio_compatible, 13 | ) 14 | from .datasets import download_dataset, get_local_testing_data_folder 15 | -------------------------------------------------------------------------------- /neo/utils/datasets.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utility functions to retrieve public datasets. 3 | """ 4 | 5 | import os 6 | from pathlib import Path 7 | 8 | default_testing_repo = "https://gin.g-node.org/NeuralEnsemble/ephy_testing_data" 9 | 10 | global local_testing_data_folder 11 | if os.getenv("EPHY_TESTING_DATA_FOLDER", default=None) is not None: 12 | local_testing_data_folder = Path(os.getenv("EPHY_TESTING_DATA_FOLDER")) 13 | else: 14 | # set in home 15 | local_testing_data_folder = Path.home() / "ephy_testing_data" 16 | 17 | 18 | def get_local_testing_data_folder(): 19 | global local_testing_data_folder 20 | return local_testing_data_folder 21 | 22 | 23 | def download_dataset(repo=default_testing_repo, remote_path=None, local_folder=None): 24 | """ 25 | Download a dataset with datalad client. 26 | 27 | By default it download the "NeuralEnsemble/ephy_testing_data" on gin platform 28 | which is used for neo testing. 29 | 30 | Usage: 31 | 32 | download_dataset( 33 | repo='https://gin.g-node.org/NeuralEnsemble/ephy_testing_data', 34 | remote_path='blackrock/blackrock_2_1', 35 | local_folder='/home/myname/Documents/') 36 | 37 | Parameters 38 | ---------- 39 | repo: str 40 | The url of the repo. 41 | If None then 'https://gin.g-node.org/NeuralEnsemble/ephy_testing_data' 42 | is used 43 | remote_path: str of Path 44 | The distant path to retrieve (file or folder) 45 | local_folder: str or Path or None 46 | The local folder where to download the data. 47 | If None, a default project testing folder is used. Default: None 48 | 49 | Returns 50 | ------- 51 | local_path: 52 | The local path of the downloaded file or folder 53 | """ 54 | import datalad.api 55 | from datalad.support.gitrepo import GitRepo 56 | 57 | if local_folder is None: 58 | global local_testing_data_folder 59 | local_folder = local_testing_data_folder 60 | local_folder = Path(local_folder) 61 | 62 | if local_folder.exists() and GitRepo.is_valid_repo(local_folder): 63 | dataset = datalad.api.Dataset(path=local_folder) 64 | # make sure git repo is in clean state 65 | repo = dataset.repo 66 | repo.call_git(["checkout", "--force", "master"]) 67 | dataset.update(merge=True) 68 | else: 69 | dataset = datalad.api.install(path=local_folder, source=repo) 70 | 71 | if remote_path is None: 72 | print('Bad boy: you have to provide "remote_path"') 73 | return 74 | 75 | dataset.get(remote_path) 76 | 77 | local_path = local_folder / remote_path 78 | 79 | return local_path 80 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | if __name__ == "__main__": 4 | setuptools.setup() 5 | --------------------------------------------------------------------------------