Patch-clamp data analysis in Python: action potentials

The analysis of neurophysiological data is usually time-consuming and programming languages such as R and Python are powerful tools to automatize the analysis of large datasets. Moreover, learning how to code is becoming a valuable and needed skill for neuroscientists, as nicely pointed out by Ashley Juavinett.

I will focus on Python because it is an open-source programming language and is widely used for the analysis of neurophysiological data. An accessible introduction to Python applied to electrophysiology can be the great online notebooks (web-based interactive files) designed by Ashley Juavinett to explore The Allen Cell Types Database. Check out the course website.

There are also several packages available for the analysis of whole-cell patch-clamp data in Python, which can be a good complement or alternative to data analysis in Clampfit (see posts). However, most of the packages require an intermediate knowledge of Python, whereas others were a standalone effort with no further resources to keep the package up to date. For these reasons, I will focus on two libraries/packages for patch-clamp analysis with current support: IPFX (Intrinsic Physiology Feature eXtractor) from the Allen Institute and eFEL (Electrophys Feature Extraction Library) from the Blue Brain Project. In this blog post series, you can also find tutorials for the analysis of passive membrane properties in Clampfit (post) and Python (post).

I am also a beginner in Python so I will just describe the basics to use the packages, and I will refer to resources to know more about specific topics. Of course, all the credit goes to the creators of the packages and I just hope this brief tutorial can be useful for new users of Python. Please contact me if you have suggestions or corrections to improve this tutorial.


Python installation

This is a brief explanation of how to install Python (there are other ways) and use the packages in Jupyter notebooks.
Important notes:
▪ Replace path/to/directory, filename, or myenv with your actual directory, name of your file, and name of your Python environment, respectively.
▪ Read about the difference between absolute and relative paths.
▪ The # symbol in Python means a comment.

  • Install a Python distribution: Miniconda or Anaconda. The main difference is that Anaconda has more packages pre-installed and has a graphical user interface called Navigator.
  • Run the Anaconda Prompt and type the commands in bold:
    • To change the path to your working directory: cd Path/to/directory.
    • To create a Conda environment (libraries, packages, etc. are isolated from other environments) with some useful packages (Anaconda might have some pre-installed): conda create -n myenv pip jupyterlab matplotlib ipympl numpy pandas scipy
    • Then, activate your new environment: conda activate myenv
    • Other packages can be installed in your Python environment using pip or conda install: pip install name-of-the-package or conda install name-of-the-package
    • Run the Jupyter notebook (more about notebooks here): jupyter lab


Data examples

I will give examples of how to analyze ABF files generated with the software pClamp (Molecular Devices) that can be also analyzed with the software Clampfit (see post). You can also use Clampfit to convert other data files such as ATF to ABF or to NumPy arrays (CSV, comma delimited).

For the scripts below, I used a whole-cell patch-clamp recording (in current-clamp mode) of a Parvalbumin interneuron (post) from an acute brain slice (see video) containing the Prefrontal Cortex (post). You can download the ABF file here, and the same file in csv. format here. Then, paste the scripts below into your Jupyter Notebook and play around with them.


pyABF

You need this easy and up-to-date package to read ABF files in Python. The package was created by Scott W Harden and you can read tutorials, documentation, and examples on his website and GitHub. The scripts also include some examples to nicely visualize traces. To learn more about plotting in Python, visit the pyABF and matplotlib websites.
Install pyABF (info): pip install pyabf


IPFX by The Allen Institute for Brain Science

This package was created to analyze intrinsic cell features from electrophysiological data collected by The Allen Institute (NWB files). As far as I know, only a couple of features work also on NumPy arrays (but it would be great if the Allen Institute makes all the features available in the future). You can find documentation and tutorials on the IPFX GitHub and website,

Install the package (info). A new environment is required and it seems that IPFX does not work with the latest versions of Python yet.

  • Create a new environment with packages (see above): conda create -n ipfx
  • Activate the environment and type:  conda install python=3.7 anaconda
  • Then, install the IPFX package via pip: pip install ipfx Note: The installation may take several minutes and errors may show during the installation.


Load packages and define paths for ABF files
This is the common part for the rest of the IPFX features so you just need to write it at the beginning of your notebook. Note: Replace path/to/file, and filename, with your actual directory and filename.

# Import the packages 
from ipfx.feature_extractor import (SpikeFeatureExtractor,
                                    SpikeTrainFeatureExtractor)
import pyabf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Set the file path
data = 'path/to/file/filename.abf'
abf = pyabf.ABF(data)

print (abf)  # Optional: extract information from the ABF file  


Spike features (sfx) from one or several traces
You get more than 30 features for each action potential with this function but some of them are not very useful. See the IPFX documentation for a definition of each parameter.
You can play around with start, end to adapt the range of the analysis to the first action potentials in the trace (like the example below), to a ramp or short current protocol, etc.
The loop function for i in x also works if you only have one trace. If you do not need the loop, remove for sweepNumber in abf.sweepList, and type instead abf.setSweep(sweepNumber=0, channel=0) (or the number and channel you need), and then move all the lines below to the left.

# Set the table from the dataframe below
dataframe = [] 

# Loop function to analyze each voltage trace of the file
for sweepNumber in abf.sweepList: # e.g. abf.sweepList[1:3] to select the range
    abf.setSweep(sweepNumber)
    time = abf.sweepX
    voltage = abf.sweepY
    current = abf.sweepC
    # Define the region (in seconds)
    start, end = 0.24, 0.265
    # Parameters for analysis: 
    # Filter = None to avoid conflicts with your recording settings
    # dv/dt cutoff (mV/ms), min_peak (mV)
    sfx = SpikeFeatureExtractor (start, end, 
                                 filter=None, 
                                 dv_cutoff=20.0, min_peak=0) 
    sfx_results = sfx.process(time, voltage, current)
    dataframe.append(sfx_results)  # To get the mean: df.append(sfx_results.mean())
    
# Table with the features from all the action potentials
table = pd.concat(dataframe)

# Optional: Plot the trace/s
plt.figure(figsize=(6,4))
plt.xlabel ("Time (s)")
plt.ylabel("Voltage (mV)")
for sweepNumber in abf.sweepList:  # Loop to plot all the traces
    abf.setSweep(sweepNumber)
    plt.plot(abf.sweepX, abf.sweepY, alpha=.6, label="sweep %d" % (sweepNumber))
# To highllight one trace
abf.setSweep(3) 
plt.plot(abf.sweepX, abf.sweepY, linewidth=1, color='black')
plt.xlim(0.24, 0.265)

# Export the graph (png) and the table (csv)
plt.savefig('path/to/file/filename.png', dpi=300)
table.to_csv('path/to/file/spike_features.csv')
    
# Display the graph and the table
plt.show()
table

# Remove the below # to show only selected columns. E.g:
#columns = ['threshold_i', 'threshold_v', 'width', 'upstroke', 'downstroke']
#table[columns]

Output:


Spike train features (stfx) from one trace
You can obtain some useful features related to the firing rate (see post): adaptation, latency, CV of ISI, mean of ISI, and first ISI. You can also change start, end to adapt the analysis to your recording.

# Select the sweep/trace and channel
abf.setSweep(sweepNumber=10, channel=0)

# Define each variable
time = abf.sweepX
voltage = abf.sweepY
current = abf.sweepC

# Optional: Current step
currents = [] # Current value between t1 and t2 (ms) for each step
t1 = int(400*abf.dataPointsPerMs) 
t2 = int(500*abf.dataPointsPerMs)
current_mean = np.average(abf.sweepC[t1:t2])

# Define the region (in sec) and detection parameters
start, end = 0, 1
sfx = SpikeFeatureExtractor (start=start, end=end, 
                             filter=None, 
                             dv_cutoff=20.0, min_peak=0) 
sfx_results = sfx.process(time, voltage, current)
stfx = SpikeTrainFeatureExtractor (start, end)
stfx_results = stfx.process(time, voltage, current, sfx_results)

# Optional: Create a table with the stfx results
table = pd.DataFrame()
length = len(table)
table.loc[length, 'Current_step'] = current_mean
table.loc[length, 'adaptation'] = stfx_results ["adapt"]
table.loc[length, 'Latency'] = stfx_results ["latency"]
table.loc[length, 'ISI_CV'] = stfx_results ["isi_cv"]
table.loc[length, 'ISI_mean'] = stfx_results ["mean_isi"]
table.loc[length, 'ISI_first'] = stfx_results ["first_isi"]
table.loc[length, 'Firing_rate_Hz'] = stfx_results ["avg_rate"]

# Optional: Plotting the voltage trace and the current step
fig = plt.figure(figsize=(7, 5)) #Figure size
# Voltage traces
ax1 = fig.add_subplot(211)
ax1.plot(abf.sweepX, abf.sweepY)
# Show detection of action potential peak
ax1.plot(sfx_results["peak_t"], sfx_results["peak_v"], 'r.')
# Show detection of action potential threshold
ax1.plot(sfx_results["threshold_t"], sfx_results["threshold_v"], 'k.')
ax1.set_ylabel("Voltage (mV)")
# Current stimulus
ax2 = fig.add_subplot(212, sharex=ax1) 
ax2.plot(abf.sweepX, abf.sweepC, color='r')
ax2.set_ylabel("Current (pA)")
ax2.set_xlabel("Time (s)")
# Zoom in and out
ax2.axes.set_xlim(0, 1) # Shared x-axis (range in sec)

# Optional: Export the table (csv file) and the figure
fig.savefig('Path/to/file/filename.png', dpi=300)
table.to_csv('Path/to/file/filename.csv')

# View the graph and the table
plt.show()
table

Output:


Spike train features (stfx) from several traces
To analyze several traces, you can use the ForLoop function in Python. It is also possible to plot the input-output curve (no. of action potentials vs current stimulus).

# Set the dataframe for the table
table = pd.DataFrame()

# Loop function to analyze each voltage and current trace of the file
for sweep in abf.sweepList:
    abf.setSweep(sweep)
    time = abf.sweepX
    voltage = abf.sweepY
    current = abf.sweepC
    
    currents = [] # Current value between t1 and t2 (ms) for each step
    t1 = int(400*abf.dataPointsPerMs) 
    t2 = int(500*abf.dataPointsPerMs)
    current_mean = np.average(abf.sweepC[t1:t2])
    
    start, end = 0.1, 1.1
    sfx = SpikeFeatureExtractor(start=start, end=end, filter=None)
    sfx_results = sfx.process(time, voltage, current)
    stfx = SpikeTrainFeatureExtractor (start=start, end=end)
    stfx_results = stfx.process(time, voltage, current, sfx_results)
    
    # Create a table with the stfx results
    length = len(table)
    table.loc[length, 'current_step'] = current_mean
    table.loc[length, 'avg_rate'] = stfx_results["avg_rate"]
    if stfx_results ['avg_rate'] > 0:
        table.loc[length, 'adaptation'] = stfx_results ["adapt"]
        table.loc[length, 'Latency_s'] = stfx_results ["latency"]
        table.loc[length, 'ISI_CV'] = stfx_results ["isi_cv"]
        table.loc[length, 'ISI_mean_ms'] = stfx_results ["mean_isi"]*1000
        table.loc[length, 'ISI_first_ms'] = stfx_results ["first_isi"]*1000
     
# Optional Plotting: example with three subplots
fig = plt.figure(figsize=(15, 5))

# Input-output curve
ax1 = fig.add_subplot(1, 2, 1)
currents = []
for sweep in abf.sweepList:
    abf.setSweep(sweep)
    currents.append(np.average(abf.sweepC[t1:t2]))
ax1.plot(currents, table.loc[:,'avg_rate'])
ax1.set_xlabel('Current step (pA)')
ax1.set_ylabel('Action potentials')

# All traces
ax2 = fig.add_subplot(2, 2, 2)
for sweep in abf.sweepList:
    abf.setSweep(sweep)
    ax2.plot(abf.sweepX, abf.sweepY, alpha=.6, label="Sweep %d" % (sweepNumber))
ax2.set_ylabel('Membrane voltage (mV)')
# ax2.legend() # Optional
# To highllight one trace
abf.setSweep(3) 
ax2.plot(abf.sweepX, abf.sweepY, linewidth=1, color='black')
ax2.axes.set_xlim(0, 1.1) # Range of the x-axis (seconds)

# All current steps
ax3 = fig.add_subplot(2, 2, 4, sharex=ax2) 
for sweep in abf.sweepList:
    abf.setSweep(sweep)
    current = abf.sweepC
    ax3.plot(abf.sweepX, current)
ax3.set_ylabel("Current (pA)")
ax3.set_xlabel("Time (s)")
# To highllight one current trace
abf.setSweep(3) 
ax3.plot(abf.sweepX, abf.sweepC, linewidth=1, color='black')
fig.tight_layout()

# Optional: Export the graph (png) and the table (csv)
fig.savefig("Path/to/file/filename.png", dpi=300)
table.to_csv('Path/to/file/filename.csv')

# Show the graph and the table results 
plt.show()
table

Output:


Spike Train Features from data in NumPy arrays
This post does not aim to be the “definitive guide” but you can also use NumPy arrays (see tutorial) as input data. In Clampfit: Edit > Transfer traces: Results window (selecting the traces you want to export) and save the results as “.csv” file. I attach one example for the analysis of spike train features.

# Load the file
data = np.loadtxt(fname="Path/to/file/filename.csv", delimiter=",")

table = pd.DataFrame()

# Define the time, voltage, and current columns
time = data [:, 0]/1000
voltages = data [:, 1:14]
currents = data [:, 14:28]

# Create a loop
for voltage in voltages.T:
    start, end = 0.1, 1.1
    stfx = SpikeTrainFeatureExtractor (start=start, end=end)
    sfx = SpikeFeatureExtractor(start=start, end=end, filter=None)
    spikes_df = sfx.process(t=time, v=voltage, i=current)
    stfx = stfx.process(t=time, v=voltage, i=current, spikes_df=spikes_df)

    # Create the table    
    length = len(table)
    table.loc[length, 'avg_rate'] = stfx["avg_rate"]
    if stfx['avg_rate'] > 0:
        table.loc[length, 'adaptation'] = stfx ["adapt"]
        table.loc[length, 'Latency'] = stfx ["latency"]
        table.loc[length, 'ISI_CV'] = stfx ["isi_cv"]
        table.loc[length, 'ISI_mean'] = stfx ["mean_isi"]
        table.loc[length, 'ISI_first'] = stfx ["first_isi"] 

# Optional: plotting
fig = plt.figure(figsize=(6, 4))
plt.plot (time, voltages, linewidth=1.0, alpha=.6)
trace_highlight = data[:, 4]  # Highlight a trace of interest in the plot
plt.plot (time, trace_highlight,  linewidth=1, color='black')
plt.xlabel ("Time (s)")
plt.ylabel("Voltage (mV)")
plt.xlim(0, 1)

# Export the graph (png) and the table (csv)
fig.savefig("Path/to/file/filename.png", dpi=300)
table.to_csv('Path/to/file/filename.csv')

# Display the graph and the table
plt.show()
table

# Optional: Get the current step values
# t1 = currents[(time > 0.3) & (time < 0.4), :]
# t2 = currents[(time > 0) & (time < 0.1), :]
# current_mean = np.mean(t1, axis=0) - np.mean(t2, axis=0)
# list(current_mean)

Output:


eFEL by the Blue Brain Project

EFEL package was created by the Blue Brain Project to extract electrophysiological features recorded from neurons. This package is more versatile than IPFX and allows you to analyze passive membrane properties (see post), different file formats, and a ton of other features (check the description of features here). You can find documentation, examples, and notebooks on the eFEL GitHub and website.

Install the package (info). It should work in any environment (you can install it in the same environment as the IPFX, see above). Activate the environment and install the package in the Anaconda Prompt: pip install efel

Load packages and define paths
This is the common part for the rest of the eFEL features so you just need to write it at the beginning of your notebook. Note: Change path/to/directory and filename for your actual directory and name of your file, respectively.

# Import the packages 
import efel
import pyabf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import nanmean

# Define the path to your file
# data = 'path/to/file/filename.abf'
abf = pyabf.ABF(data)
# print (abf)  # Optional: extract information from the ABF file. 

# List of available features in the eFEL package
# efel.getFeatureNames() 


Spike features from one sweep
You can use the code below to analyze only one action potential or the first action potential by limiting the stim_start and stim_end. Edit the output features (see above) in efel.getFeatureValues and add the new features to the table (in table and a new table.loc line).

# Set the sweep and channel
sweep = abf.setSweep(sweepNumber=10, channel=0)

# Define the variables
time = abf.sweepX*1000 # in miliseconds
voltage = abf.sweepY
current = abf.sweepC

# Define the variables and region of analysis
trace = {'T': abf.sweepX*1000, 
         'V': abf.sweepY,
         'stim_start': [100],
         'stim_end': [800]} 
traces = [trace]

# Optional: Current step values
currents = [] # Current value between t1 and t2 (ms) for each step
t1 = int(400*abf.dataPointsPerMs) 
t2 = int(500*abf.dataPointsPerMs)
current_mean = np.average(abf.sweepC[t1:t2])

# Detection parameters
efel.api.setThreshold(0)  # Voltage threshold 
efel.api.setDerivativeThreshold(20) # dV/dt threshold 

# Define the output features
# Or use instead efel.getMeanFeatureValues() to get mean values
feature_values = efel.getFeatureValues(traces,
                                       ['AP_amplitude', 'AP_width',
                                        'AP_begin_voltage', 'AP_rise_rate',
                                        'AP_fall_rate'],
                                       raise_warnings=None)[0] # If true, returns warnings (e.g. no spikes in trace)
# Results without table and graph
# traces_results

# OptionaL Create a table with the results
table = pd.DataFrame(columns=['Sweep', 'Current_step', 'AP_amplitude', 'AP_width', 
                              'AP_begin_voltage', 'AP_rise_rate', 
                              'AP_fall_rate'])

# Optional: Create a table with the results
# [0] returns values of first action potential, [1], for 2nd, etc. 
length = len(table)
table.loc[length, 'Sweep'] = 7 # SweepNumber
table.loc[length, 'Current_step'] = current_mean
table.loc[length, 'AP_amplitude'] = list(feature_values['AP_amplitude'])[0]
table.loc[length, 'AP_width'] = feature_values['AP_width'][0]
table.loc[length, 'AP_begin_voltage'] = feature_values['AP_begin_voltage'][0]
table.loc[length, 'AP_rise_rate'] = feature_values['AP_rise_rate'][0]
table.loc[length, 'AP_fall_rate'] = feature_values['AP_fall_rate'][0]

# Optional: ploting the trace
fig = plt.figure(figsize=(10, 4))
ax1 = fig.add_subplot(121)
ax1.plot(time, voltage)
ax1.set_xlabel('Time (ms)')
ax1.set_ylabel('Membrane voltage (mV)')
ax1.axes.set_xlim(0, 1000)
# Zoom in to one action potential
ax2 = fig.add_subplot(122, sharey=ax1)
ax2.plot(time, voltage)
ax2.set_xlabel('Time (ms)')
ax2.set_ylabel('Membrane voltage (mV)')
ax2.axes.set_xlim(240, 254)
plt.tight_layout()
plt.show()

# Optional: export the graph and the table
fig.savefig('Path/to/file/filename.png', dpi=300)
table.to_csv('Path/to/file/filename.csv')

# Display the table and the graph
plt.show()
table

Output:


Firing properties from all the traces
You can adapt the previous block for several traces by using the ForLoop function in Python. The eFEL package has also a cool set of features to analyze bursts (see above efel.getFeatureNames()) that may be even useful for cell-attached recordings (Perkins, 2006). You can change the burst parameter by adding efel.api.setFeatureDouble('burst_factor', [1.5]).

# Define the result outputs for the table
table = pd.DataFrame(columns=['Current_step', 'Spikecount',
                              'adaptation', 'Latency_ms', 
                              'ISI_CV', 'ISI_mean_ms'])  

# Loop function
# Define region of analysis
for sweep in abf.sweepList: # e.g. abf.sweepList[1:3] to select the range
    abf.setSweep(sweep)
    # Defines a trace
    trace = {'T': abf.sweepX*1000, 
             'V': abf.sweepY,
             'stim_start': [100],
             'stim_end': [800]} 
    traces = [trace]
    
    # Define the parameters for detection
    efel.api.setThreshold(0) # Voltage threshold for detection
    efel.api.setDerivativeThreshold(20) # dV/dt threshold for detection
    
    # Define the output results
    feature_values = efel.getFeatureValues(traces,
                                           ['Spikecount','adaptation_index',
                                            'time_to_first_spike', 
                                            'ISI_CV', 'ISI_values'],
                                           raise_warnings=None)[0] # If true, returns warnings

    # Optional: add a column with the current steps
    current = abf.sweepC
    currents = [] # Current value between t1 and t2 (ms) for each step
    t1 = int(400*abf.dataPointsPerMs) 
    t2 = int(500*abf.dataPointsPerMs)
    current_mean = np.average(abf.sweepC[t1:t2])
    currents.append(current_mean)
    

    # Create table from the results
    # Use [0] to extract the values from the Spikecount array
    length = len(table)
    table.loc[length, 'Current_step'] = current_mean
    table.loc[length, 'Spikecount'] = feature_values['Spikecount'][0] 
    # Some features requires AP > 0 or more
    if feature_values['Spikecount'] is not None: 
        table.loc[length, 'Latency_ms'] = feature_values['time_to_first_spike']
        if feature_values['Spikecount'] > 4:  
            table.loc[length, 'adaptation'] = feature_values['adaptation_index'][0]
            table.loc[length, 'ISI_CV'] = feature_values['ISI_CV'][0] 
            table.loc[length, 'ISI_mean'] = feature_values['ISI_values'][0]/1000

# Optional plotting: example with three subplots
# Optional: ploting the trace
fig = plt.figure(figsize=(12, 4))
ax1 = fig.add_subplot(121)
for sweep in abf.sweepList:
    abf.setSweep(sweep)
    ax1.plot(abf.sweepX*1000, abf.sweepY, alpha=0.3)
ax1.set_xlabel('Time (ms)')
ax1.set_ylabel('Membrane voltage (mV)')
ax1.axes.set_xlim(0, 1000)
# Plot an individual trace
ax2 = fig.add_subplot(122, sharey=ax1)
sweep_label = abf.setSweep(10) 
ax2.plot(time, voltage, label='sweep 10')
ax2.set_xlabel('Time (ms)')
ax2.set_ylabel('Membrane voltage (mV)')
ax2.axes.set_xlim(0, 1000)
plt.tight_layout()

# Optional : Export the graph and the table
fig.savefig('Path/to/file/filename.png', dpi=300)
table.to_csv('Path/to/file/filename.csv')
            
# Display the graph and the table
plt.show()
table

Output:


Spike Train Features from data in NumPy arrays
The package pyABF nicely extracts the data from the traces but you can directly use NumPy arrays (see tutorial) as input data. In Clampfit: Edit > Transfer traces: Results window and save the results as “.csv” file. I attach one example for the analysis of spike train features.

data = np.loadtxt(fname="path/to/file/filename.csv", delimiter=",")

# Define the columns with the time, current, and voltage values
time = data[:, 0] # in ms
voltages = data [:, 1:14]
currents = data [:, 14:28]

# Create a table with the values
table = pd.DataFrame(columns=['Spikecount',
                              'adaptation', 'Latency_ms', 
                              'ISI_CV', 'ISI_mean_ms']) 

# A loop for each voltage column
for voltage in voltages.T:
    trace = {'T' : time,
             'V' : voltage,
             'stim_start' : [100],
             'stim_end' : [700]}
    traces = [trace]
    
    # Define the parameters for detection
    efel.api.setThreshold(0) # Voltage threshold for detection
    efel.api.setDerivativeThreshold(20) # dV/dt threshold for detection

    # Select which features you want to calculate. See efel.getFeatureNames()
    feature_values = efel.getFeatureValues(traces, ['Spikecount','adaptation_index',
                                                    'time_to_first_spike','ISI_CV',
                                                    'ISI_values'],
                                                    raise_warnings=None)[0]
             
    # Create a table with the results
    length = len(table)
    table.loc[length, 'Spikecount'] = feature_values['Spikecount'][0] 
    # Some features requires AP > 0 or more
    if feature_values['Spikecount'] is not None: 
        table.loc[length, 'Latency_ms'] = feature_values['time_to_first_spike']
        if feature_values['Spikecount'] > 4:  
            table.loc[length, 'adaptation'] = feature_values['adaptation_index'][0]
            table.loc[length, 'ISI_CV'] = feature_values['ISI_CV'][0] 
            table.loc[length, 'ISI_mean_ms'] = feature_values['ISI_values'][0]/1000

# Optional: Plotting
fig = plt.figure(figsize=(6, 4))
plt.plot (time, voltages, linewidth=1.0, alpha=.6)
trace_highlight = data[:, 8] # Highlight a trace of interest in the plot
plt.plot (time, trace_highlight,  linewidth = 1, color='black')
plt.xlabel ("Time (ms)")
plt.ylabel("Voltage (mV)")
plt.xlim(0, 1000)

# Optional : Export the graph and the table
plt.savefig('Path/to/file/filename.png', dpi=300)
table.to_csv('Path/to/file/filename.csv')

# Display the graph and the table
plt.show()
table

#Optional: Get the current step values
# t1 = currents[(time > 300) & (time < 400), :]
# t2 = currents[(time > 0) & (time < 100), :]
# current_mean = np.mean(t1, axis=0) - np.mean(t2, axis=0)
# list(current_mean)

Output:


Further reading and resources

— Updated on May 7, 2022

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s