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.

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.0.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.0-py3-none-any.whl (84.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pyaxion-1.0.0.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.0.tar.gz
Algorithm Hash digest
SHA256 44aca78dcfbd09a8fa064424665d3634ba8ae0586eb9598fcc9de4404dc2a1ea
MD5 ac7fb533916d402fbe32a68e82659ea0
BLAKE2b-256 20c21fbf8b4cd9d86999b5c80a90adf8532523fb41e76105b6f539412926d9ed

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pyaxion-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 84.9 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 79695beb9c4886b3cd1cd2936acd9e51ddb940bdc876808d66ae1bc7e9030f18
MD5 384d2a62a61cd2debb93660768907eb4
BLAKE2b-256 b3ca03d3d13927603af9c52421d613b19381c8fc14db5055d952de2b43185437

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