Database usage and fetching results#

Here we show how to retrieve the data generated by recording the electrical activity of the organoids from the database.

Connection to the database#

Simply create a database object, and then use the available methods to retrieve your data of interest.

Make sure to have the up-to-date token for the experiment you are interested in. Every time we change the organoids on an MEA, we create a new fs ID such as "fs300".

This is accessible through your Experiment token, specifically the exp_name attribute. Make sure to record and recover the token you used during your experiment to perform the data analysis.

Example code#

from dateutil import parser
from datetime import timedelta

from neuroplatform import Database, Experiment

db = Database()
exp = Experiment("Your token here")
FS_NAME = (
    exp.exp_name
)  # FS ID for the MEA. This changes every time we change the organoids.

Tip

Please contact us if you need the fs ID for a specific MEA/time.

Database functions#

Note

All database times are in UTC.

Spike events#

A spike event is logged whenever the voltage from an electrode crosses a threshold of six times the standard deviation of the noise.

You can query a list of spike events with the timestamp, the amplitude (maximum absolute voltage of the peak across 3ms around the spike) and the channel number using get_spike_event

Caution

To avoid returning large amounts of data, keep the time window small.
We recommed starting with 5 minutes, and increasing/decreasing the window as needed.

start = parser.parse("2024-04-05T00:00:00.000Z")
stop = start + timedelta(minutes=5)

spike_event_df = db.get_spike_event(start, stop, FS_NAME)

Spike count per minute#

You can get the spike count per minute for all electrodes for a given experiment name using get_spike_count to get a DataFrame with the spike count per minute for each electrode, with the timestamp.

spike_per_min_df = db.get_spike_count(start, stop, FS_NAME)

Raw spike events#

Every spike event is recorded for 3ms around the spike. You can get the raw signal for these 3ms of spike events using get_raw_spike_event to get a DataFrame with the timestamp, the electrode number, and the amplitude values for each event in a long format.

Since the sampling rate is 30kHz, each spike event will have 90 samples.

Caution

Raw data is very memory-intensive. Make sure to query a small time window first, and increase/decrease as needed.

from tqdm import tqdm

df_spike_event = db.get_spike_event(start, start + timedelta(seconds=1), FS_NAME)

raws = []
for i, row in tqdm(df_spike_event.iterrows(), total=df_spike_event.shape[0]):
    t = row["Time"]
    t1 = t - timedelta(milliseconds=1)
    t2 = t + timedelta(milliseconds=2)
    raws.append(db.get_raw_spike(t1, t2, row["channel"]))

Example plot#

import numpy as np
from lets_plot import (
    ggplot,
    ggtitle,
    geom_line,
    aes,
    ggsize,
    gggrid,
)


def plot_raw_channel(channel: int):
    df_chan = df_spike_event[df_spike_event["channel"] == channel]
    # Start with an empty plot
    p = ggplot()
    p += ggtitle(f"Channel {channel}")

    for i, row in df_chan.iterrows():
        df_raw = raws[i]
        if df_raw.shape[0] == 90:
            df_raw["Time [ms]"] = np.linspace(-1, 2, 90)
            p += geom_line(aes(x="Time [ms]", y="Amplitude"), data=df_raw)

    return p


channels = df_spike_event["channel"].unique()
list_plot = []
for i, chan in enumerate(channels):
    list_plot.append(plot_raw_channel(chan))

nbCol = 3
nbRow = len(list_plot) // nbCol
if len(list_plot) % nbCol != 0:
    nbRow += 1
gggrid(list_plot, ncol=nbCol) + ggsize(800, 300 * nbRow)

Triggers#

You can obtain the triggers used for stimulation using get_triggers to return a DataFrame with the timestamp, the trigger number, the status (up/down, which corresponds to the times where the trigger was enabled/disabled respectively) and the tag if any.

triggers_df = db.get_all_triggers(start, stop, FS_NAME)

Impedance#

When you have measured impedance using the Intan, you can get the recorded impedance values using get_impedance to return a DataFrame with the timestamp, the electrode number, and the impedance values.

df_impedance = db.get_impedance(start, stop)

Miscellanous measurements#

We also provide access to various environmental measurements within the incubator hosting the MEAs :

  • CO2 levels

  • O2 levels

  • Temperature

  • Humidity

  • Pressure

  • Pump flowrate

  • Door opening/closing events

CO2, O2, Temperature, Humidity, Pressure#

Simply provide a start and stop time to obtain the recorded values.

co2_df = db.co2(start, stop)
o2_df = db.o2(start, stop)
temp_df = db.temperature(start, stop)
pressure_df = db.pressure(start, stop)
humidity_df = db.humidity(start, stop)

Flowrate#

There are 4 pumps, one for each MEA. You can access the flowrate values using :

port = 3  # port is the MEA number from 1 to 4
flow_df = db.flowrate(start, stop, port)

Door events#

There are currently two incubators:

  • Incubator 0 hosts the MEAs

  • Incubator 1 hosts the organoids in culture

Values of 0 or 1 indicate the door is being opened or closed respectively.

To access opening/closing events, use the following :

door_df = db.door(start, stop)