Last active
September 2, 2020 17:47
-
-
Save smestern/e0c08c0106efd2b11482e25283bce060 to your computer and use it in GitHub Desktop.
Create an 'unknown pleasures'-style artwork out of a real neuron's action potentials (Or really any other signal recorded in abf format) [Utilizes matplotlib's unchained.py and pyabf]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
======================== | |
MATPLOTLIB **UNCHAINED** | |
======================== | |
Orignal Author: Nicolas P. Rougier | |
This is a modified version. | |
Modified to take an abf file to visualize the action potentials present. | |
Preview: https://i.imgur.com/85hgMJm.mp4 | |
""" | |
import numpy as np | |
import matplotlib.pyplot as plt | |
import matplotlib.animation as animation | |
import pyabf | |
import tkinter as tk | |
from tkinter import filedialog | |
from sklearn.preprocessing import MinMaxScaler | |
scaler = MinMaxScaler() | |
root = tk.Tk() | |
root.withdraw() | |
sweepdsply=7 | |
file_path = filedialog.askopenfilename() | |
abf = pyabf.ABF(file_path) | |
# Fixing random state for reproducibility | |
abf.setSweep(0) | |
# Create new Figure with black background | |
fig = plt.figure(figsize=(8, 8), facecolor='black') | |
# Add a subplot with no frame | |
ax = plt.subplot(111, frameon=False) | |
abfdata = np.hstack(scaler.fit_transform(abf.sweepY.reshape(-1,1))) | |
# Generate data | |
i1 = abf.dataPointsPerMs * 0 | |
i2 = abf.dataPointsPerMs * 500 | |
ifull = i2 - i1 | |
iar = np.array((i1, i2)) | |
data = np.array(abfdata) | |
for i in range(0,35): | |
i1 = int(np.random.uniform(0, 6000, 1)[0]) | |
i2 = i1+ifull | |
iar = np.vstack((iar, (i1, i2))) | |
data = np.vstack((data, abfdata)) | |
X = np.linspace(-1, 1, ifull) | |
G = 9.5 * np.exp(-4 * X ** 2) | |
spacefac = 1.5 | |
speedfac = 100 | |
# Generate line plots | |
lines = [] | |
for i in range(len(data)): | |
i1 = iar[i, 0] | |
i2 = iar[i, 1] | |
# Small reduction of the X extents to get a cheap perspective effect | |
xscale = 1 - i / 100. | |
# Same for linewidth (thicker strokes on bottom) | |
lw = 1.5 - i / 70.0 | |
line, = ax.plot(xscale * X, (i * spacefac) + G * data[i, i1:i2], color="w", lw=lw) | |
lines.append(line) | |
# Set y limit (or first line is cropped because of thickness) | |
ax.set_ylim(-1, 70) | |
# No ticks | |
ax.set_xticks([]) | |
ax.set_yticks([]) | |
# 2 part titles to get different font weights | |
ax.text(0.5, 1.0, "UNKNOWN ", transform=ax.transAxes, | |
ha="right", va="bottom", color="w", | |
family="sans-serif", fontweight="light", fontsize=16) | |
ax.text(0.5, 1.0, "MEASURES", transform=ax.transAxes, | |
ha="left", va="bottom", color="w", | |
family="sans-serif", fontweight="bold", fontsize=16) | |
def update(frame, *args): | |
global i1, i2 | |
global abf | |
global abfdata | |
global ifull | |
# Update data | |
for i in range(len(data)): | |
i1 = iar[i, 0] | |
i2 = iar[i, 1] | |
if i2 > (data[i].shape[0] - (speedfac+1)): | |
data[i] = np.append(data[i, i1:], abfdata[:i1]) | |
i1 = 0 | |
i2 = i1 + ifull | |
i1 +=speedfac | |
i2 +=speedfac | |
lines[i].set_ydata((i * spacefac) + G * data[i, i1:i2]) | |
iar[i,0] = i1 | |
iar[i,1] = i2 | |
# Return modified artists | |
return lines | |
# Construct the animation, using the update function as the animation director. | |
anim = animation.FuncAnimation(fig, update, interval=10) | |
plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment