Plot spikes and network bursts#

Generate images from datasets and files from previous analyses containing spikes and network bursts.#

autoMEA can also be used to visualize activity from a dataset that was previously analyzed - for which spikes and bursts were already detected.

Here we will show how to, given a dataset containing signal, spikes and bursts, how to generate images to visualize the analyzed data, and compare the results with those obtained using autoMEA.

We first import autoMEA, together with numpy and pandas, which will be used to manipulate data.

import automea
import numpy as np 
import pandas as pd 
am = automea.Analysis()

We create a variable containing the path to the dataset, the dataset name, and the well we want to analyze in the dataset.

path_to_dataset = '/Volumes/T7/automea_files_to_plot/'
dataset = 'MJ22C002-1782_DIV7.h5'
well = 'D5'

And we create separate folders to save signals and spikes rasters plots.

import os  
plots_dir = f'plots/{dataset}_{well}'
if os.path.exists(plots_dir) is False:
    os.mkdir(plots_dir)
    os.mkdir(plots_dir+'/signals')
    os.mkdir(plots_dir+'/rasters')

We inform autoMEA the path to find the dataset, and load it using the loadh5() method.

am.path_to_dataset = path_to_dataset
am.loadh5(dataset)

After loaded, we can check that autoMEA is already storing a signal array.

am.signal, am.signal.shape
(array([[ 27,  23, -17, ..., -24,  31,  31],
        [-70,  15,  69, ...,  42,   4,  -8],
        [ -5, -25, -41, ..., -13, -54, -11],
        ...,
        [-17, -14,   5, ..., -17, -80,  17],
        [-36,   7,  -7, ..., -37, -19, -29],
        [  8, -20,  22, ...,   9,  73,  71]], dtype=int32),
 (237, 6000000))

Following, we use the loadsignal() method, to keep in memory only the signal from the well we want to analyze.

am.loadsignal(am.signal[am.wellsFromData == am.wellLabelIndexDict[well]])

Here we load a model, and use autoMEA to detect all the variables we want to compare with the already-analyzed dataset.

am.model_name = 'signal30.h5'
am.loadmodel()
Metal device set to: Apple M1

systemMemory: 8.00 GB
maxCacheSize: 2.67 GB
am.detect_threshold()
am.detect_spikes()
am.detect_reverbs(method = 'model')
am.detect_bursts()
am.detect_net('reverbs')
am.detect_net('bursts')

Now we load the previously-analyzed spikes and network bursts, from deticated ‘csv’ files. We filter the dataset to keep only the activity from the well we want to analyze, and save the spikes in an array named spikes_manual, and the network bursts in a net_manual array.

path_to_manual_files = '/Volumes/T7/automea_files_to_plot/Examples list/RHEB_DIV07/'
spikes_manual_file = 'Timestamps_MJ22C002_1782_DIV07_D5.csv'
netbursts_manual_file = 'NetworkBursts_MJ22C002_1782_DIV07_D5.csv'
spikes_manual_df = pd.read_csv(path_to_manual_files + spikes_manual_file, encoding='unicode_escape')
spikes_manual_df
Channel ID Channel Label Well ID Well Label Compound ID Compound Name Experiment Dose [pM] Dose Label Timestamp [µs] Maximum Amplitude [pV] Minimum Amplitude [pV] Peak-to-peak Amplitude [pV]
0 191 21 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 426300 16212288 -25391304 41603592
1 191 21 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 435100 5066340 -11920800 16987140
2 191 21 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 452400 7569708 -14006940 21576648
3 191 21 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 494500 7808124 -12516840 20324964
4 191 21 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 503100 50007756 -59246376 109254132
... ... ... ... ... ... ... ... ... ... ... ... ... ...
65010 185 34 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 598999200 7629312 -23185956 30815268
65011 185 34 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 599003300 15079812 -2264952 17344764
65012 185 34 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 599010600 13470504 -8702184 22172688
65013 185 34 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 599039800 16391100 -7092876 23483976
65014 185 34 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 599148400 5721984 -13887732 19609716

65015 rows × 13 columns

channel_labels = np.unique(spikes_manual_df[spikes_manual_df['Well Label'] == well]['Channel Label'].iloc[:].values)
channel_labels
array([12, 13, 21, 22, 23, 24, 31, 32, 33, 34, 42, 43])
spikes_manual = []
for channel_label in channel_labels:
    spikes_manual.append([])
    for index in spikes_manual_df[(spikes_manual_df['Channel Label'] == channel_label) & (spikes_manual_df['Well Label'] == well)].index:
        spikes_manual[-1].append(spikes_manual_df['Timestamp [µs]'][index]//100)
netbursts_manual_df = pd.read_csv(path_to_manual_files + netbursts_manual_file, encoding='unicode_escape')
netbursts_manual_df

Well ID Well Label Compound ID Compound Name Experiment Dose [pM] Dose Label Start timestamp [µs] Duration [µs] Spike Count Spike Frequency [Hz]
0 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 494500 250600 296 98.430
1 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 14255400 319800 608 158.432
2 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 18646700 444100 749 140.546
3 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 26212300 305800 653 177.949
4 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 30838400 265700 603 189.123
... ... ... ... ... ... ... ... ... ... ... ...
91 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 573895000 311100 216 57.859
92 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 578123900 375300 725 160.982
93 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 585406500 363400 487 111.677
94 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 591906400 390700 690 147.172
95 22 D5 No compound No compound 20181127_No_compound_m201118_DIV7_rescue4EB_001 0 Control 598675200 379000 734 161.390

96 rows × 11 columns

net_manual = []
for index in netbursts_manual_df[netbursts_manual_df['Well Label']==well].index:
    start_ts = netbursts_manual_df['Start timestamp [µs]'][index]
    duration = netbursts_manual_df['Duration [µs]'][index]
    net_manual.append([start_ts//100, (start_ts+duration)//100])

After having spikes and network bursts both from a previously performed analysis, and obtained with autoMEA, we use the plot_raster() method to visualize raster plots, so that the two version can be compared.

duration = 60
duration_shorter = 5

for i, start_time in enumerate(np.random.randint(0,500,size=3)):

    end_time = start_time + duration

    am.plot_raster(am.spikes, net_bursts = am.net_reverbs, start_time = start_time, end_time = end_time, 
                   save = f'{plots_dir}/rasters/raster_start{start_time}_duration{duration}_allwell_prednetreverbs.eps', show = False)
    am.plot_raster(am.spikes, net_bursts = net_manual, start_time = start_time, end_time = end_time, 
                   save = f'{plots_dir}/rasters/raster_start{start_time}_duration{duration}_allwell_manual.eps', show = False)

    for j in range(5):
        start_time_shorter = start_time + np.random.randint(0,95)
        channel_random  = np.random.randint(len(am.signal))
        end_time_shorter = start_time_shorter + duration_shorter
        am.plot_raster(am.spikes[channel_random], net_bursts = am.net_reverbs, start_time = start_time_shorter, end_time = end_time_shorter, 
                        save = f'{plots_dir}/rasters/raster_start{start_time}_duration{duration}_zoomedstart{start_time+start_time_shorter}_zoomedduration{duration_shorter}_prednetreverbs.eps', show = False)
        am.plot_raster(am.spikes[channel_random], net_bursts = net_manual, start_time = start_time_shorter, end_time = end_time_shorter,
                        save = f'{plots_dir}/rasters/raster_start{start_time}_duration{duration}_zoomedstart{start_time+start_time_shorter}_zoomedduration{duration_shorter}_manual.eps', show = False)

And finally we plot a (randomly-selected) 5-second activity with signal and threshold, together with autoMEA and manual network bursts, to compare them.

duration_shorter = 5

for _ in range(20):
    random_net = am.net_reverbs[np.random.randint(len(am.net_reverbs))]
    middle_of_net = random_net[0] + ((random_net[-1] - random_net[0])/2)
    start_time = middle_of_net/am.samplingFreq - 2.5
    channel_random  = np.random.randint(len(am.signal))


    am.plot_window(am.signal[channel_random], start_time=start_time, duration=duration_shorter,
                    threshold=am.threshold[channel_random], spikes = am.spikes[channel_random],
                    bursts=am.net_reverbs, net_bursts=net_manual, yunits = 'V', show = False,
                    save = f'{plots_dir}/signals/signal_channel{channel_random}_start{start_time}_duration5.eps')