Skip to main content

A python reimplementation of the matlab AxIS file reader.

Project description

PyAxion

Introduction

This project serves as a mostly faithful reimplementation of the official matlab loader for data produced by Axion Biosystem's AxIS software in the form of .raw and .spk files.

This project is neither funded nor endorsed by Axion Biosystem and thus does not guarantee functionality and timely updates.

Features

The current version supports .raw and .spk files of version 1.x <= 1.3. Unlike the original matlab implementation, this project does not support legacy files of version 0.x but I would be happy to collaborate on a future inclusion.

This project also contains code to write an older version of .spk files. However, it is currently not up to date with the new structure of the matlab/python code so it will likely not work. I might update it in the future but I cannot guarantee it, since I am not sure if the use case will come up for me. Feel free to open an issue or pull request for any updates an we will see what we can do.

On a similar veine there is also a rudimentary binding for python-neo and probeinterface that is unfortunately now outdated. If the interest comes up we can also discuss updating this binding.

Installation

PyAxion is available on PyPi. Installation can be done through pip.

python -m pip install pyaxion

Examples

Accessing datasets in the file

The AxisFile object provides a number of properties that can help you indentify relevant datasets in the loaded file. Each of the methods returns the appropriate dataset or None if it doesn't exist.

It is unlikely/impossible for multiple dataset types to occur in the same file. A notable exception would be high and low frequency components of the broad band signal

from pyaxion.axis_reader import AxisFile, ReturnDimension

# use the file as a context manager to properly release the file opened for reading
with AxisFile("example_file.raw") as af:
    # the broad band signal
    dataset = af.raw_voltage
    # check the output for validity
    if dataset is not None:
        ...
    # the high-pass filtered portion of the broad band signal
    dataset = af.broad_band_high
    # contractility data as a continuous waveform
    dataset = af.raw_contractility
    # discontinous spike events
    dataset = af.spikes
    # discontinuous local field potential events
    dataset = af.lfp_events

The returned objects are datasets that define further methods to load the data. They do not directly represent the raw data array and as such do not create a large loading overhead.

Reading raw voltage data from a file

Once you have obtained your dataset you will want to load the raw data from it. This can be either spikes or continuous waveforms. Loading data creates numpy object arrays that hold further containers that combine metadata about the raw data like electrode positions with the actual data array. This section explains how to create and work with these object arrays to obtain the actual numpy arrays containing the data. This example considers continuous waveform data, but it works equivalently with spike data and other types of continuous data.

Data can be loaded in as a 4-D channel array structure. Data is indexed as well row, well column, electrode column, electrode row.

from pyaxion.axis_reader import AxisFile, ReturnDimension

# use the file as a context manager to properly release the file opened for reading
with AxisFile("example_file.raw") as af:
    # numpy array of shape n_well_rows, n_well_cols, n_el_cols, n_el_rows
    data = af.raw_voltage.load_raw_data(dimension = ReturnDimension.BYELECTRODE)

The returned array is an object numpy array where the objects represent datacontainers that can be of several types: For continuous waveform data (e.g. regular traces):

  • VoltageWaveform object defining the .get_voltage_vector() method
  • ContractilityWaveform object defining the .get_contractility_vector() method

Both classes also define a get_time_vector() method and a combined method for their respective data vector methods that returns a time axis or a tuple of the data and the time axis.

For discontinuous event data (e.g. spikes):

  • Spike_v1 object defining the .get_voltage_vector() method that returns the spike waveforms
with AxisFile("example_file.raw") as af:
    # numpy array of shape n_well_rows, n_well_cols, n_el_cols, n_el_rows
    data = af.raw_voltage.load_raw_data(dimension = ReturnDimension.BYELECTRODE)

    # numpy array of shape n_samples x sample_rate (typically 12.5 kHz)
    # the data is returned volts
    voltage_vector = data[0,0,0,0].get_voltage_vector()

Raw ADC bits can be accessed by calling the .data field of waveforms.

The return dimensions can be manipulated by changing the dimension argument. The default argument is ReturnDimension.BYPLATE

with AxisFile("example_file.raw") as af:
    # numpy array of shape n_well_rows, n_well_cols, n_el_cols, n_el_rows
    data = af.raw_voltage.load_raw_data(dimension = ReturnDimension.BYELECTRODE)
    # numpy array of n_well_rows, n_well_cols
    data = af.raw_voltage.load_raw_data(dimension = ReturnDimension.BYWELL)
    # numpy array of n_wells x n_electrodes_per_well
    data = af.raw_voltage.load_raw_data(dimension = ReturnDimension.BYPLATE)

Electrodes are named by their column and row, such that electrode 23 refers to the electrode in the second column and third row

Wells and electrodes can be specified during loading to reduce the data size.

with AxisFile("example_file.raw") as af:
    # numpy array of shape n_well_rows, n_well_cols, n_el_cols, n_el_rows
    data = af.raw_voltage.load_raw_data(
        wells = "A1,A2,B4,",
        electrodes = "11,12,23,44", # for a plate with 16 electrodes per well
        # alternatively this package also allows lists of integers
        # electrodes = [11,12,23,44] # equivalent to the argument above
        dimension = ReturnDimension.BYELECTRODE)

Data can be subsampled during loading. Subsampling is done by simply skipping the appropriate number of samples, the data is not interpolated. A subsampling factor of 1 results in no subsampling.

with AxisFile("example_file.raw") as af:
    # numpy array of shape n_well_rows, n_well_cols, n_el_cols, n_el_rows
    data = af.raw_voltage.load_raw_data(
        wells = "A1,A2,B4,",
        electrodes = [11,12,23,44], # for a plate with 16 electrodes per well
        dimension = ReturnDimension.BYELECTRODE),
        subsampling_factor = 2 # only every second sample is loaded

The time range of the loaded data can be adjusted during loading as well.

with AxisFile("example_file.raw") as af:
    # numpy array of shape n_well_rows, n_well_cols, n_el_cols, n_el_rows
    data = af.raw_voltage.load_raw_data(
        wells = "A1,A2,B4,",
        electrodes = [11,12,23,44], # for a plate with 16 electrodes per well
        dimension = ReturnDimension.BYELECTRODE),
        time_range = [0, 10], # data from the first 10 seconds
        subsampling_factor = 2 # only every second sample is loaded

Accessing stimulation events

If the recording contains stimulation that was properly flagged using the inverted triangle marker during recording setup (you cannot change this after the recording is done), the file will contain stimulation events that mark the beginning of the stimulation. It can be accessed using

with AxisFile("example_file.raw") as af:
    # list of StimulationEvent instances
    af.stimulation_events
    # timing of the events in seconds
    times = sorted([event.event_time for event in af.stimulation_events])

On the 'pythonicity' of this package

This package was created to make accessing AxIS files easier in python. It was not created to be the most efficient interface for the data that can be updated relatively easy along with the original matlab implementation. Hence, it sometimes favors closeness to the matlab source over traditional pythonic practices. However, it does make some significant deviations in some places either due to limitations of either of the languages or because of code that would run extremely poorly in python.

Nevertheless, it isn't out of the question to transform this into a more self contained project since I am sure there are a number of ways in which the loading of the data can be made quicker and more pythonic. Feel free to use this project as a stepping stone or to create pull requests.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyaxion-1.0.1.tar.gz (62.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyaxion-1.0.1-py3-none-any.whl (85.0 kB view details)

Uploaded Python 3

File details

Details for the file pyaxion-1.0.1.tar.gz.

File metadata

  • Download URL: pyaxion-1.0.1.tar.gz
  • Upload date:
  • Size: 62.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.5

File hashes

Hashes for pyaxion-1.0.1.tar.gz
Algorithm Hash digest
SHA256 d1d6cd51333aedc5717a5162eba2c95e062bef53eba2bcb10ee0b6a242072aa2
MD5 38553ece7dbc94ab7d3cb524c584e2b1
BLAKE2b-256 21c7510e1c9697d4c7279532ff11065ac37b84a366545cd888c4e2924b11f46f

See more details on using hashes here.

File details

Details for the file pyaxion-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: pyaxion-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 85.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.5

File hashes

Hashes for pyaxion-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 00b05a5170f4c07eb611cbfb50620da6036d833c94d64320e98b3f80b1f2f657
MD5 401a3091c5aaad3b4f9f9796acd843a9
BLAKE2b-256 d2b586d728c132f730c745fb69936960cb8ef4f065eb3fb5027fa331db329946

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page