I'm new here, and hope my question is right here.
I'm trying to programm a GUI where I can record some sound from the microphone and plot it in real-time, to see the left and right channel of the sound.
I'm using PyQt 5 for my GUI und Matplotlib-FigureCanvas for Plotting.
The streaming works fine, however the Plot only shows after the recording stops and does not update during recording, like it should.
In Debug-Mode I can see the plots everytime they should update, but when I run the code, the GUI freezes until the recording is done.
Is that, because the Plotting is too slow?
I tried different approaches with animate or threading, but nothing worked so far.
I would like to have a real-time-updating plot in the end, how can I achieve this? Also with longer recording?
I hope someone can help me, thanks in advance!
Here is the part of my code, where I'm recording and plotting:
import sys
from PyQt5 import QtGui, QtWidgets, QtCore
import numpy as np
import time
import pyaudio
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import matplotlib.gridspec as gridspec
import matplotlib.animation as animation
class Window(QtWidgets.QMainWindow):
def __init__(self): # sort of template for rest of GUI, is always there, menubar/ mainmenu eg.
super(Window, self).__init__()
self.setGeometry(50, 50, 1500, 900)
self.setWindowTitle("PyQt Tutorial!")
self.centralwidget = QtWidgets.QWidget(self)
self.centralwidget.setObjectName("centralwidget")
self.channels = 2
self.fs = 44100 # samplerate
self.Chunks = 1024
self.tapeLength = 2 # seconds
self.tape = np.empty(self.fs * self.tapeLength) * np.nan # tapes where recorded audio is stored
self.taper = np.empty(self.fs * self.tapeLength) * np.nan
self.tapel = np.empty(self.fs * self.tapeLength) * np.nan
self.home()
def home(self):
btn = QtWidgets.QPushButton("Stream and Plot", self) # Button to start streaming
btn.clicked.connect(self.plot)
btn.resize(btn.sizeHint())
btn.move(100, 100)
self.scrollArea = QtWidgets.QScrollArea(self)
self.scrollArea.move(75, 400)
self.scrollArea.resize(600, 300)
self.scrollArea.setWidgetResizable(False)
self.scrollArea2 = QtWidgets.QScrollArea(self)
self.scrollArea2.move(775, 400)
self.scrollArea2.resize(600, 300)
self.scrollArea2.setWidgetResizable(False)
self.scrollArea.horizontalScrollBar().valueChanged.connect(self.scrollArea2.horizontalScrollBar().setValue)
self.scrollArea2.horizontalScrollBar().valueChanged.connect(self.scrollArea.horizontalScrollBar().setValue)
self.figure = Figure((15, 2.8), dpi=100) # figure instance (to plot on) F(width, height, ...)
self.canvas = FigureCanvas(self.figure)
self.scrollArea.setWidget(self.canvas)
self.toolbar = NavigationToolbar(self.canvas, self.scrollArea)
self.canvas2 = FigureCanvas(self.figure)
self.scrollArea2.setWidget(self.canvas2)
self.toolbar2 = NavigationToolbar(self.canvas2, self.scrollArea2)
self.gs = gridspec.GridSpec(1, 1)
self.ax = self.figure.add_subplot(self.gs[0])
self.ax2 = self.figure.add_subplot(self.gs[0])
self.figure.subplots_adjust(left=0.05)
self.ax.clear()
def start_streamsignal(self, start=True):
# open and start the stream
if start is True:
print("start Signals")
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=pyaudio.paFloat32, channels=self.channels, rate=self.fs, input_device_index=1,
output_device_index=5, input=True, frames_per_buffer=self.Chunks)
print("recording...")
def start_streamread(self):
"""return values for Chunks of stream"""
data = self.stream.read(self.Chunks)
npframes2 = np.array(data).flatten()
npframes2 = np.fromstring(npframes2, dtype=np.float32)
norm_audio2 = (npframes2 / np.max(np.abs(npframes2))) # normalize
left2 = norm_audio2[::2]
right2 = norm_audio2[1::2]
print(norm_audio2)
return left2, right2
def tape_add(self):
"""add chunks to tape"""
self.tape[:-self.Chunks] = self.tape[self.Chunks:]
self.taper = self.tape
self.tapel = self.tape
self.taper[-self.Chunks:], self.tapel[-self.Chunks:] = self.start_streamread()
def plot(self, use_blit=True):
# Plot the Tape and update chunks
print('Plotting')
self.start_streamsignal(start=True)
start = True
for duration in range(0, 15, 1):
plotsec = 1
time.sleep(2)
self.timeArray = np.arange(self.taper.size)
self.timeArray = (self.timeArray / self.fs) * 1000 # scale to milliseconds
self.tape_add()
# self.canvas.draw()
while start is True and plotsec < 3:
# self.ani = animation.FuncAnimation(self.figure, self.animate, interval=25, blit=True)
self.ax2.plot(self.taper, '-b')
self.canvas.draw()
self.ax2.clear()
self.ax2.plot(self.tapel, 'g-')
self.canvas2.draw()
plotsec += 1
def animate(self):
self.line.set_xdata(self.taper)
return self.line,
def main():
app = QtWidgets.QApplication(sys.argv)
GUI = Window()
GUI.show()
sys.exit(app.exec_())
main()
I do have severe problems understanding the complete code as to what all the stuff in there should actually do. So all I can tell for now is that you may want to get rid of the loops and use FuncAnimation to display the animation.
def plot(self, use_blit=True):
# Plot the Tape and update chunks
print('Plotting')
self.start_streamsignal(start=True)
start = True
self.line, = self.ax2.plot([],[], '-b')
self.ax.set_xlim(0, len(self.tape))
self.ax2.set_xlim(0, len(self.tape))
self.ax.set_ylim(-3, 3)
self.ax2.set_ylim(-3, 3)
self.ani = animation.FuncAnimation(self.figure, self.animate, frames=100,
interval=25, blit=use_blit)
def animate(self,i):
self.timeArray = np.arange(self.taper.size)
self.timeArray = (self.timeArray / self.fs) * 1000 # scale to milliseconds
self.tape_add()
self.line.set_data(range(len(self.taper)),self.taper)
return self.line,
Thanks for all the Help, here is the now working code, if someone is interested:
import sys
from PyQt5 import QtGui, QtWidgets, QtCore
import numpy as np
import time
import pyaudio
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import matplotlib.gridspec as gridspec
import matplotlib.animation as animation
class Window(QtWidgets.QMainWindow):
def __init__(self): # sort of template for rest of GUI, is always there, menubar/ mainmenu eg.
super(Window, self).__init__()
self.setGeometry(50, 50, 1500, 900)
self.setWindowTitle("PyQt Tutorial!")
self.centralwidget = QtWidgets.QWidget(self)
self.centralwidget.setObjectName("centralwidget")
self.channels = 2
self.fs = 44100 # samplerate
self.Chunks = 1024
self.tapeLength = 2 # seconds
self.tape = np.empty(self.fs * self.tapeLength) * np.nan # tapes where recorded audio is stored
self.home()
def home(self):
btn = QtWidgets.QPushButton("Stream and Plot", self) # Button to start streaming
btn.clicked.connect(self.plot)
btn.resize(btn.sizeHint())
btn.move(100, 100)
self.scrollArea = QtWidgets.QScrollArea(self)
self.scrollArea.move(75, 400)
self.scrollArea.resize(600, 300)
self.scrollArea.setWidgetResizable(False)
self.scrollArea2 = QtWidgets.QScrollArea(self)
self.scrollArea2.move(775, 400)
self.scrollArea2.resize(600, 300)
self.scrollArea2.setWidgetResizable(False)
self.scrollArea.horizontalScrollBar().valueChanged.connect(self.scrollArea2.horizontalScrollBar().setValue)
self.scrollArea2.horizontalScrollBar().valueChanged.connect(self.scrollArea.horizontalScrollBar().setValue)
self.figure = Figure((15, 2.8), dpi=100) # figure instance (to plot on) F(width, height, ...)
self.canvas = FigureCanvas(self.figure)
self.scrollArea.setWidget(self.canvas)
self.toolbar = NavigationToolbar(self.canvas, self.scrollArea)
self.canvas2 = FigureCanvas(self.figure)
self.scrollArea2.setWidget(self.canvas2)
self.toolbar2 = NavigationToolbar(self.canvas2, self.scrollArea2)
self.gs = gridspec.GridSpec(1, 1)
self.ax = self.figure.add_subplot(self.gs[0])
self.ax2 = self.figure.add_subplot(self.gs[0])
self.figure.subplots_adjust(left=0.05)
self.ax.clear()
def start_streamsignal(self, start=True):
# open and start the stream
if start is True:
print("start Signals")
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=pyaudio.paFloat32, channels=self.channels, rate=self.fs, input_device_index=1,
output_device_index=5, input=True, frames_per_buffer=self.Chunks)
print("recording...")
def start_streamread(self):
"""return values for Chunks of stream"""
data = self.stream.read(self.Chunks)
npframes2 = np.array(data).flatten()
npframes2 = np.fromstring(npframes2, dtype=np.float32)
norm_audio2 = (npframes2 / np.max(np.abs(npframes2))) # normalize
left2 = norm_audio2[::2]
right2 = norm_audio2[1::2]
print(norm_audio2)
return left2, right2
def tape_add(self):
"""add chunks to tape"""
self.tape[:-self.Chunks] = self.tape[self.Chunks:]
self.taper = self.tape
self.tapel = self.tape
self.taper[-self.Chunks:], self.tapel[-self.Chunks:] = self.start_streamread()
def plot(self, use_blit=True):
# Plot the Tape and update chunks
print('Plotting')
self.start_streamsignal(start=True)
start = True
for duration in range(0, 15, 1):
QtWidgets.QApplication.processEvents()
plotsec = 1
time.sleep(2)
self.timeArray = np.arange(self.taper.size)
self.timeArray = (self.timeArray / self.fs) * 1000 # scale to milliseconds
self.tape_add()
while start is True and plotsec < 3:
self.ax.plot(self.taper, '-b')
self.canvas.draw()
self.ax2.clear()
self.ax2.plot(self.tapel, 'g-')
self.canvas2.draw()
plotsec += 1
def main():
app = QtWidgets.QApplication(sys.argv)
GUI = Window()
GUI.show()
sys.exit(app.exec_())
main()
Related
I'm trying to code a GUI which will allow the user to press a button "Open Simulation File", and from that create a variable "path_sim". The issue I am facing is that when I go to plot the file using this "path_sim" variable, it does not plot, as it sees the variable as undefined.
I tried passing it the function as "self.path_sim = open_dialog_box_sim()" but this causes another issue as it causes the file dialog box to open up before the rest of the GUI, which is not what I want. Is there another way to pass this "path_sim" variable into my class?
from PyQt5 import QtCore
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QFileDialog
import sys
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
import pandas as pd
from scipy.interpolate import UnivariateSpline
def open_dialog_box_sim():
filename_sim = QFileDialog.getOpenFileName()
path_sim = filename_sim[0]
return path_sim
def open_dialog_box_exp():
filename_exp = QFileDialog.getOpenFileName()
path_exp = filename_exp[0]
return path_exp
def simButton_handler():
print("Sim Button Pressed")
open_dialog_box_sim()
def expButton_handler():
print("Exp Button Pressed")
open_dialog_box_exp()
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.expButton = QPushButton("Open Experimental File", self)
self.simButton = QPushButton("Open Simulation File", self)
title = "Test"
top = 0
left = 0
width = 1920
height = 1080
self.setWindowTitle(title)
self.setGeometry(top, left, width, height)
self.MyUI()
def MyUI(self):
canvas = Canvas(self, width=11, height=6)
canvas.move(300, 35)
self.simButton.setGeometry(QtCore.QRect(30, 10, 221, 61))
self.simButton.move(30, 30)
self.simButton.clicked.connect(simButton_handler)
self.expButton.setGeometry(QtCore.QRect(30, 10, 221, 61))
self.expButton.move(30, 120)
self.expButton.clicked.connect(expButton_handler)
class Canvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=5, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
# self.plot()
self.path_sim = open_dialog_box_sim() #############
self.axes = fig.add_subplot(111)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self.plot()
def plot(self):
s = pd.read_excel(self.path_sim)
plt.scatter(s.energy, s.Simulation, label="Simulation Data") # plot the raw data
xp = np.linspace(400, 2800, 1201)
spl = UnivariateSpline(s.energy, s.Simulation) # fit the data to a spline
sply = spl(xp)
db_entry = { # puts the x's and y's together in one matrix
"energy": xp,
"Simulation": sply
}
df_spline = pd.DataFrame(db_entry) # out the values in a pandas dataframe
self.axes.plot(df_spline['energy'], df_spline['Simulation'])
app = QApplication(sys.argv)
window = Window()
window.show()
app.exec()
You must rewrite the "plot" method to receive the filename so you can change the plot for each filename. On the other hand you must create a slot in the same class to access the variable without problems with the scope:
import sys
from PyQt5.QtCore import QRect
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QFileDialog
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
import pandas as pd
from scipy.interpolate import UnivariateSpline
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.expButton = QPushButton("Open Experimental File", self)
self.simButton = QPushButton("Open Simulation File", self)
self.canvas = Canvas(self, width=11, height=6)
title = "Test"
top = 0
left = 0
width = 1920
height = 1080
self.setWindowTitle(title)
self.setGeometry(top, left, width, height)
self.MyUI()
def MyUI(self):
self.canvas.move(300, 35)
self.simButton.setGeometry(QRect(30, 10, 221, 61))
self.simButton.move(30, 30)
self.simButton.clicked.connect(self.sim_clicked)
self.expButton.setGeometry(QRect(30, 10, 221, 61))
self.expButton.move(30, 120)
def sim_clicked(self):
filename_sim, _ = QFileDialog.getOpenFileName()
if filename_sim:
self.canvas.plot(filename_sim)
class Canvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=5, dpi=100):
super().__init__(Figure(figsize=(width, height), dpi=dpi))
self.setParent(parent)
self.axes = self.figure.add_subplot(111)
def plot(self, filename):
self.axes.clear()
s = pd.read_excel(filename)
xp = np.linspace(400, 2800, 1201)
spl = UnivariateSpline(s.energy, s.Simulation) # fit the data to a spline
sply = spl(xp)
db_entry = { # puts the x's and y's together in one matrix
"energy": xp,
"Simulation": sply,
}
df_spline = pd.DataFrame(db_entry) # out the values in a pandas dataframe
self.axes.plot(df_spline["energy"], df_spline["Simulation"])
self.draw()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
I am trying to write a GUI in Python3 using PyQt4.
For data visualization, I need to isolate a specific point on a curve plotted by the function whole_plot(). To do so, I am currently using a slider that let the GUI user choose a point of interest. When the slider_value is changed, the point is selected and plotted by calling the function point_plot().
Regarding some previous answers, I am now trying to update my graph through matplotlib.animation (cf. post python matplotlib update scatter plot from a function). But for some reasons, I still got the wrong updating, can someone help me figure out what is the problem in my code?
import sys
import numpy as np
from PyQt4 import QtGui
from PyQt4 import QtCore
import matplotlib.pyplot as plt
import matplotlib.animation
#
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
#%%
# some Arbitrary data
nbr_points = 500
my_X_data = np.linspace(-10,10,nbr_points)
my_Y_data = my_X_data**3 + 100*np.cos(my_X_data*5)
class MyWidget(QtGui.QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(600,300,1000,600)
grid = QtGui.QGridLayout()
self.setLayout(grid)
self.figure_1 = plt.figure(figsize=(15,5))
self.canvas_1 = FigureCanvas(self.figure_1)
self.toolbar = NavigationToolbar(self.canvas_1, self)
grid.addWidget(self.canvas_1, 2,0,1,2)
grid.addWidget(self.toolbar, 0,0,1,2)
# Slider
self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
self.slider.setMinimum(0)
self.slider.setMaximum(nbr_points-1)
self.slider.setTickInterval(1)
self.slider.valueChanged.connect(self.point_plot)
# Slider info box
self.label = QtGui.QLabel(self)
grid.addWidget(self.label,4,0)
# +1 / -1 buttons
btn_plus_one = QtGui.QPushButton('+1', self)
btn_plus_one.clicked.connect(self.value_plus_one)
btn_minus_one = QtGui.QPushButton('-1', self)
btn_minus_one.clicked.connect(self.value_minus_one)
hbox = QtGui.QHBoxLayout()
hbox.addWidget(btn_minus_one)
hbox.addWidget(self.slider)
hbox.addWidget(btn_plus_one)
grid.addLayout(hbox, 3,0,1,3)
self.whole_plot()
self.point_plot()
self.show()
def whole_plot(self):
ax1 = self.figure_1.add_subplot(111)
ax1.clear()
ax1.cla()
#
ax1.plot(my_X_data,my_Y_data,'b-')
#
ax1.set_xlim([-10,10])
ax1.set_ylim([-1000,1000])
ax1.set_xlabel('X')
ax1.set_ylabel('Y')
#
self.canvas_1.draw()
def point_plot(self):
ax1 = self.figure_1.add_subplot(111)
#
X_point, Y_point = [],[]
scat = ax1.scatter(X_point,Y_point, s=100,c='k')
def animate(i):
index_slider_value = self.slider.value()
X_point = my_X_data[index_slider_value,]
Y_point = my_Y_data[index_slider_value,]
scat.set_offsets(np.c_[X_point,Y_point])
anim = matplotlib.animation.FuncAnimation(self.figure_1,animate, frames=my_X_data, interval=200, repeat=True)
self.canvas_1.draw()
def value_plus_one(self):
# slider +1
if self.slider.value() < (my_X_data.shape[0]-1):
index_slider_value = self.slider.value() + 1
self.slider.setValue(index_slider_value)
def value_minus_one(self):
# slider -1
if self.slider.value() > 0:
index_slider_value = self.slider.value() - 1
self.slider.setValue(index_slider_value)
def main():
app = QtGui.QApplication(sys.argv)
MyWidget()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You have to learn what is better to reuse than create, in this case you just need to create a scatter and update the data with set_offsets() when the value of the slider changes, so FuncAnimation is not necessary.
import numpy as np
from PyQt4 import QtCore, QtGui
import matplotlib.pyplot as plt
import matplotlib.animation
#
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
#%%
# some Arbitrary data
nbr_points = 500
my_X_data = np.linspace(-10,10,nbr_points)
my_Y_data = my_X_data**3 + 100*np.cos(my_X_data*5)
class MyWidget(QtGui.QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(600,300,1000,600)
self.figure_1 = plt.figure(figsize=(15,5))
self.canvas = FigureCanvas(self.figure_1)
self.toolbar = NavigationToolbar(self.canvas, self)
# Slider
self.slider = QtGui.QSlider(minimum=0,
maximum= nbr_points-1,
orientation=QtCore.Qt.Horizontal,
tickInterval=1)
self.slider.valueChanged.connect(self.on_valueChanged)
# Slider info box
self.label = QtGui.QLabel()
# +1 / -1 buttons
btn_plus_one = QtGui.QPushButton('+1')
btn_plus_one.clicked.connect(self.value_plus_one)
btn_minus_one = QtGui.QPushButton('-1')
btn_minus_one.clicked.connect(self.value_minus_one)
grid = QtGui.QGridLayout(self)
grid.addWidget(self.canvas, 2, 0, 1, 2)
grid.addWidget(self.toolbar, 0, 0, 1, 2)
grid.addWidget(self.label, 4, 0)
hbox = QtGui.QHBoxLayout()
hbox.addWidget(btn_minus_one)
hbox.addWidget(self.slider)
hbox.addWidget(btn_plus_one)
grid.addLayout(hbox, 3, 0, 1, 3)
self.whole_plot()
def whole_plot(self):
ax = self.figure_1.add_subplot(111)
ax.clear()
ax.plot(my_X_data,my_Y_data,'b-')
ax.set_xlim([-10,10])
ax.set_ylim([-1000,1000])
ax.set_xlabel('X')
ax.set_ylabel('Y')
self.canvas.draw()
X_point, Y_point = [],[]
self.scat = ax.scatter(X_point, Y_point, s=100,c='k')
# set initial
self.on_valueChanged(self.slider.value())
#QtCore.pyqtSlot(int)
def on_valueChanged(self, value):
X_point = my_X_data[value,]
Y_point = my_Y_data[value,]
self.scat.set_offsets(np.c_[X_point,Y_point])
self.canvas.draw()
#QtCore.pyqtSlot()
def value_plus_one(self):
self.slider.setValue(self.slider.value() + 1)
#QtCore.pyqtSlot()
def value_minus_one(self):
self.slider.setValue(self.slider.value() - 1)
def main():
import sys
app = QtGui.QApplication(sys.argv)
w = MyWidget()
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
On the other hand QSlider will not update the value if it is less than minimum or greater than maximum
I'm trying to make a program in which I have a main window and a second window. The second window should be opened by checking a Check-Box in the main window and closed by unchecking it.
The following minimal example works already fine (thanks to ImportanceOfBeingErnest !), but I want to spin the arrow (the one, which is already bent when you run the example) by changing the SpinBox in the main window.
Solution: See 5th comment in the first answer!
import sys
from PyQt4 import QtGui, QtCore
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib import animation
import numpy as np
class Newsphere(QtGui.QMainWindow):
def __init__(self):
super(Newsphere, self).__init__()
self.mainbox = QtGui.QWidget()
self.mainbox.setLayout(QtGui.QHBoxLayout())
self.setCentralWidget(self.mainbox)
self.spin = QtGui.QSpinBox()
self.spin.setValue(20)
self.spin.setMaximum(100)
self.spin.setMinimum(-100)
self.checkPlot = QtGui.QCheckBox("Check")
self.mainbox.layout().addWidget(self.spin)
self.mainbox.layout().addWidget(self.checkPlot)
self.Plot = None
self.checkPlot.clicked.connect(self.showPlot)
def showPlot(self):
if self.Plot == None:
self.Plot = Plot(self.kinematic())
self.Plot.show()
# register signal for closure
self.Plot.signalClose.connect(self.uncheck)
# register signal for spin value changed
self.spin.valueChanged.connect(self.kinematic)
else:
self.Plot.close()
self.Plot = None
def kinematic(self):
x = self.spin.value() / 100
v = np.matrix([[1.,x,0.],[0.,1.,0.],[0.,0.,1.]])
zero = np.matrix([[0.,0.,0.],[0.,0.,0.],[0.,0.,0.]])
pos = np.hstack([v, zero])
return pos
def uncheck(self):
self.checkPlot.setChecked(False)
self.Plot = None
class Plot(QtGui.QWidget):
signalClose = QtCore.pyqtSignal()
def __init__(self, pos=None):
super(Plot, self).__init__()
self.setLayout(QtGui.QHBoxLayout())
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111,projection = '3d')
self.fig.tight_layout()
self.ax.view_init(40, 225)
''' dashed coordinate system '''
self.ax.plot([0,1], [0,0], [0,0], label='$X_0$', linestyle="dashed", color="red")
self.ax.plot([0,0], [0,-10], [0,0], label='$Y_0$', linestyle="dashed", color="green")
self.ax.plot([0,0], [0,0], [0,1], label='$Z_0$', linestyle="dashed", color="blue")
self.ax.set_xlim3d(-3,3)
self.ax.set_ylim3d(-3,3)
self.ax.set_zlim3d(-3,3)
self.canvas = FigureCanvas(self.fig)
self.layout().addWidget(self.canvas)
self.pos = pos
self.setup_plot()
self.ani = animation.FuncAnimation(self.fig, self.update_plot, init_func=self.setup_plot, blit=True)
def setup_plot(self):
self.ax.legend(loc='best')
self.position = self.ax.quiver(0, 0, 0, 0, 0, 0, pivot="tail", color="black")
return self.position,
def update_plot(self, i):
x_zero = self.pos[:,3]
y_zero = self.pos[:,4]
z_zero = self.pos[:,5]
v_x = self.pos[0,0:3]
v_y = self.pos[1,0:3]
v_z = self.pos[2,0:3]
self.position = self.ax.quiver(-x_zero, -y_zero, z_zero, -v_x[0,:], v_y[0,:], v_z[0,:], pivot="tail", color="black")
self.canvas.draw()
return self.position,
# We need to make sure the animation stops, when the window is closed
def closeEvent(self, event):
self.signalClose.emit()
self.close()
super(Plot, self).closeEvent(event)
def close(self):
self.ani.event_source.stop()
super(Plot, self).close()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Newsphere()
main.show()
sys.exit(app.exec_())
Here is an working example of what I think you are trying to achieve.
The Main Window has a spin box and a check box. Once the checkbox is clicked, a new window with a plot will show up and an animation will start. The current value and some array will be given to the plot window. If you change the spin box value while the animation is running, it will be updated. When the plot window is closed or when the checkbox is unchecked, the animation will stop (and be deleted).
import sys
from PyQt4 import QtGui, QtCore
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib import animation
import numpy as np
class Newsphere(QtGui.QMainWindow):
def __init__(self):
super(Newsphere, self).__init__()
self.mainbox = QtGui.QWidget()
self.mainbox.setLayout(QtGui.QHBoxLayout())
self.setCentralWidget(self.mainbox)
self.spin = QtGui.QSpinBox()
self.spin.setValue(5)
self.spin.setMaximum(10)
self.spin.setMinimum(1)
self.checkPlot = QtGui.QCheckBox("Check")
self.mainbox.layout().addWidget(self.spin)
self.mainbox.layout().addWidget(self.checkPlot)
self.Plot = None
self.checkPlot.clicked.connect(self.showPlot)
def showPlot(self):
if self.Plot == None:
self.Plot = Plot(self.kinematic(), self.spin.value())
self.Plot.show()
# register signal for closure
self.Plot.signalClose.connect(self.uncheck)
# register signal for spin value changed
self.spin.valueChanged.connect(self.Plot.update_factor)
else:
self.Plot.close()
self.Plot = None
def kinematic(self):
v = np.array([[1.,2.,3.],[2.,1.,3.],[3.,2.,1.]])
return v
def uncheck(self):
self.checkPlot.setChecked(False)
self.Plot = None
class Plot(QtGui.QWidget):
signalClose = QtCore.pyqtSignal()
def __init__(self, v=None, factor=1):
super(Plot, self).__init__()
self.setLayout(QtGui.QHBoxLayout())
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111,projection = '3d')
self.ax.set_aspect('equal')
self.fig.tight_layout()
self.ax.view_init(40, 225)
self.ax.set_xlim3d(0,3)
self.ax.set_ylim3d(0,3)
self.ax.set_zlim3d(0,4)
self.canvas = FigureCanvas(self.fig)
self.layout().addWidget(self.canvas)
self.pos = v
self.setup_plot()
self.update_factor(factor)
self.ani = animation.FuncAnimation(self.fig, self.update_plot, blit=False)
def setup_plot(self):
xpos, ypos = np.meshgrid(np.arange(self.pos.shape[0]),np.arange(self.pos.shape[1]) )
self.xpos = xpos.flatten('F')
self.ypos = ypos.flatten('F')
self.zpos = np.zeros_like(self.xpos)
self.bar = None
def update_factor(self, factor):
self.factor = factor
self.dx = np.ones_like(self.xpos)*np.min(np.abs(self.factor/10.), 0.1)
self.dy = self.dx.copy()
def update_plot(self, i):
if self.bar != None:
self.bar.remove()
del self.bar
pos = self.pos+np.sin(i/8.)
dz = pos.flatten()
self.bar = self.ax.bar3d(self.xpos, self.ypos, self.zpos, self.dx, self.dy, dz,
color=(1.-self.factor/10.,0,self.factor/10.), zsort='average', linewidth=0)
self.canvas.draw()
# We need to make sure the animation stops, when the window is closed
def closeEvent(self, event):
self.signalClose.emit()
self.close()
super(Plot, self).closeEvent(event)
def close(self):
self.ani.event_source.stop()
super(Plot, self).close()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Newsphere()
main.show()
sys.exit(app.exec_())
Since I wasn't sure about what you want to animate, I changed the plot to a barplot, but you can change it back to whatever you need. Hope that helps.
Following up on this Question and the solution provided by tcaswell I tried to adopt the code for imshow() to generate a non-freezing window with a slider for image processing, such as gaussian blur filter. (I plotted two images on top of each other, because I want to display a partly transparent mask at a later stage.)
I hope some of you might find this useful, although I could still use some help.
EDIT: You can find the current state in section THIRD CODE below. I am keeping the old versions for other users who would like to dig into the details.
I derived two different working codes, each having some (minor) issues and I would really appreciate some advice.
First code:
As long as the QSlider is dragged around the thread is running. However, you can not simply click the slider bar. Any suggestion?
The image axes are not properly plotted, i.e. they disappear again. Why?
The plot updating is not what I would call fast, although it is faster than calling imshow() everytime. How can I speed this up even more?
The window is still frozen for the very short time during which the plot is updated. (The window dragging while the loop is running is stuttering.) Can this be improved?
To not run into QThread: Destroyed while thread is still running I have put a time.sleep(1) in closeEvent(). I know this is really bad, but how can I avoid it without a new flag?
import time, sys
from PyQt4 import QtCore
from PyQt4 import QtGui
from scipy import misc
from scipy import ndimage
from matplotlib.figure import Figure
import numpy as np
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class ApplicationWindow(QtGui.QMainWindow):
get_data = QtCore.pyqtSignal()
close_request = QtCore.pyqtSignal()
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.thread = QtCore.QThread(parent=self)
self.worker = Worker(parent=None)
self.worker.moveToThread(self.thread)
self.create_main_frame()
self.close_request.connect(self.thread.quit)
self.startButton.clicked.connect(self.start_calculation)
self.stopButton.clicked.connect(self.stop_calculation)
self.worker.started.connect(self.thread.start)
self.worker.new_pixel_array.connect(self.update_figure)
self.slider.sliderPressed.connect(self.start_calculation)
self.slider.valueChanged.connect(self.slider_value_changed)
self.slider.sliderReleased.connect(self.stop_calculation)
self.get_data.connect(self.worker.get_data)
self.thread.start()
def create_main_frame(self):
self.main_frame = QtGui.QWidget()
self.dpi = 100
self.width = 5
self.height = 5
self.fig = Figure(figsize=(self.width, self.height), dpi=self.dpi)
self.axes = self.fig.add_subplot(111)
self.axes.axis((0,512,0,512))
self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self.main_frame)
self.canvas.updateGeometry()
self.canvas.draw()
self.background = None
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
self.im1 = self.axes.imshow(misc.ascent(), cmap='bone', interpolation='lanczos', extent=[0,512,0,512], aspect=(1), animated=True)
self.im2 = self.axes.imshow(misc.lena(), cmap='afmhot', interpolation='lanczos', extent=[0,265,0,256], aspect=(1), animated=True)
self.startButton = QtGui.QPushButton(self.tr("Keep Calculating"))
self.stopButton = QtGui.QPushButton(self.tr("Stop Calculation"))
self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
self.slider.setRange(0, 100)
self.slider.setValue(50)
self.slider.setTracking(True)
self.slider.setTickPosition(QtGui.QSlider.TicksBothSides)
layout = QtGui.QGridLayout()
layout.addWidget(self.canvas, 0, 0)
layout.addWidget(self.slider, 1, 0)
layout.addWidget(self.startButton, 2, 0)
layout.addWidget(self.stopButton, 3, 0)
self.main_frame.setLayout(layout)
self.setCentralWidget(self.main_frame)
self.setWindowTitle(self.tr("Gaussian Filter - Slider not clickable"))
def slider_value_changed(self):
#self.worker.blockSignals(False)
self.worker.slider = self.slider.value()
def start_calculation(self):
self.worker.exiting = False
self.worker.slider = self.slider.value()
self.startButton.setEnabled(False)
self.stopButton.setEnabled(True)
self.get_data.emit()
def stop_calculation(self):
self.worker.exiting = True
self.startButton.setEnabled(True)
self.stopButton.setEnabled(False)
self.cleanup_UI()
def update_figure(self, im1_data,im2_data):
self.canvas.restore_region(self.background)
self.im1.set_array(im1_data)
self.im2.set_array(im2_data)
self.axes.draw_artist(self.im1)
self.axes.draw_artist(self.im2)
self.canvas.blit(self.axes.bbox)
def cleanup_UI(self):
self.background = None
self.canvas.draw()
def closeEvent(self, event):
self.stop_calculation()
self.close_request.emit()
time.sleep(1)
## ugly workaround to prevent window from closing before thread is closed. (calculation takes time) How can this be avoided without additional flag?
event.accept()
class Worker(QtCore.QObject):
new_pixel_array = QtCore.pyqtSignal(np.ndarray,np.ndarray)
started = QtCore.pyqtSignal()
def __init__(self, parent = None):
QtCore.QObject.__init__(self, parent)
self.exiting = True
self.slider = 0
#QtCore.pyqtSlot()
def get_data(self):
while self.exiting == False:
self.started.emit()
im1_data = self.gauss(misc.ascent(),self.slider)
im2_data = self.gauss(misc.lena(),self.slider)
self.new_pixel_array.emit(im1_data, im2_data)
print 'Slider Value: ', self.slider
def gauss(self,im,radius):
gaussed = ndimage.gaussian_filter(im, radius)
return gaussed
def main():
app = QtGui.QApplication(sys.argv)
form = ApplicationWindow()
form.show()
app.exec_()
if __name__ == "__main__":
main()
Second code:
You can now also click the slider bar.
Background (axes) reconstruction is still not working. Of course calling self.canvas.draw() in cleanup_UI() fixes this somehow.
When the slider bar is clicked, the calculation is performed once, but if the slider is dragged around and released, the calculation is performed twice at the same value. Why? I tried to catch this with blockSignals but then sometimes (when the slider is dragged around really fast and released) the second image in the plot is not updated properly. You recognize it by two different amounts of blur.
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
from scipy import misc
from scipy import ndimage
from matplotlib.figure import Figure
import numpy as np
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class ApplicationWindow(QtGui.QMainWindow):
get_data = QtCore.pyqtSignal()
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.thread = QtCore.QThread(parent=self)
self.worker = Worker(parent=None)
self.worker.moveToThread(self.thread)
self.create_main_frame()
self.startButton.clicked.connect(self.start_calculation)
self.worker.new_pixel_array.connect(self.update_figure)
self.worker.done.connect(self.stop_calculation)
self.slider.sliderPressed.connect(self.start_calculation)
self.slider.valueChanged.connect(self.slider_value_changed)
self.slider.actionTriggered.connect(self.start_calculation)
self.get_data.connect(self.worker.get_data)
self.thread.start()
def create_main_frame(self):
self.main_frame = QtGui.QWidget()
self.dpi = 100
self.width = 5
self.height = 5
self.fig = Figure(figsize=(self.width, self.height), dpi=self.dpi)
self.axes = self.fig.add_subplot(111)
self.axes.axis((0,512,0,512))
self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self.main_frame)
self.canvas.updateGeometry()
self.canvas.draw()
self.background = None
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
self.im1 = self.axes.imshow(misc.ascent(), cmap='bone', interpolation='lanczos', extent=[0,512,0,512], aspect=(1), animated=True)
self.im2 = self.axes.imshow(misc.lena(), cmap='afmhot', interpolation='lanczos', extent=[0,265,0,256], aspect=(1), animated=True)
self.startButton = QtGui.QPushButton(self.tr("Do a Calculation"))
self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
self.slider.setRange(0, 100)
self.slider.setValue(50)
self.slider.setTracking(True)
self.slider.setTickPosition(QtGui.QSlider.TicksBothSides)
layout = QtGui.QGridLayout()
layout.addWidget(self.canvas, 0, 0)
layout.addWidget(self.slider, 1, 0)
layout.addWidget(self.startButton, 2, 0)
self.main_frame.setLayout(layout)
self.setCentralWidget(self.main_frame)
self.setWindowTitle(self.tr("Gaussian Filter"))
def slider_value_changed(self):
#self.worker.blockSignals(False)
self.worker.slider = self.slider.value()
def start_calculation(self):
self.slider_value_changed()
self.worker.exiting = False
self.startButton.setEnabled(False)
self.get_data.emit()
def stop_calculation(self):
self.worker.exiting = True
self.startButton.setEnabled(True)
self.cleanup_UI()
def update_figure(self, im1_data,im2_data):
self.im1.set_array(im1_data)
self.im2.set_array(im2_data)
self.axes.draw_artist(self.im1)
self.axes.draw_artist(self.im2)
self.canvas.blit(self.axes.bbox)
def cleanup_UI(self):
self.canvas.restore_region(self.background)
#self.canvas.draw()
#self.worker.blockSignals(True)
class Worker(QtCore.QObject):
new_pixel_array = QtCore.pyqtSignal(np.ndarray,np.ndarray)
done = QtCore.pyqtSignal()
def __init__(self, parent = None):
QtCore.QObject.__init__(self, parent)
self.exiting = True
self.slider = 0
#QtCore.pyqtSlot()
def get_data(self):
if self.exiting == False:
im1_data = self.gauss(misc.ascent(),self.slider)
im2_data = self.gauss(misc.lena(),self.slider)
self.new_pixel_array.emit(im1_data,im2_data)
print 'Calculation performed, Slider Value: ', self.slider
self.done.emit()
else: None
def gauss(self,im,radius):
gaussed = ndimage.gaussian_filter(im, radius)
return gaussed
def main():
app = QtGui.QApplication(sys.argv)
form = ApplicationWindow()
form.show()
app.exec_()
if __name__ == "__main__":
main()
EDIT: Third Code (Major issues resolved and update rate limited)
The slider is now only starting a new thread when the calculation of the previous one has finished. That was acheived by disconnect.
The Plotting is still slow, (the blur function too).
restore_region still seems to have no effect at all.
I have now put the calculation of both images into threads and return the result via a Queue(). If you see some possibility for improvements, plese let me know.
I once tried to switch to the multiprocessing module and put the calculation inside a Pool(), but it throws me an Can't pickle... error. As I am totally new to multiprocessing, I would very much like to learn more about it.
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
from scipy import misc
from scipy import ndimage
from matplotlib.figure import Figure
import numpy as np
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from threading import Thread
from Queue import Queue
class ApplicationWindow(QtGui.QMainWindow):
get_data = QtCore.pyqtSignal()
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.thread = QtCore.QThread(parent=self)
self.worker = Worker(parent=None)
self.worker.moveToThread(self.thread)
self.create_main_frame()
self.startButton.clicked.connect(self.start_calculation)
self.stopButton.clicked.connect(self.stop_calculation)
self.worker.started.connect(self.thread.start)
self.worker.new_pixel_array.connect(self.update_figure)
self.slider.actionTriggered.connect(self.start_calculation)
self.slider.valueChanged.connect(self.slider_value_changed)
self.worker.done.connect(self.stop_calculation)
self.get_data.connect(self.worker.get_data)
self.thread.start()
def create_main_frame(self):
self.main_frame = QtGui.QWidget()
self.dpi = 100
self.width = 5
self.height = 5
self.fig = Figure(figsize=(self.width, self.height), dpi=self.dpi)
self.axes = self.fig.add_subplot(111)
self.axes.axis((0,512,0,512))
self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self.main_frame)
self.canvas.updateGeometry()
self.background = None
self.canvas.draw()
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
self.im1 = self.axes.imshow(misc.ascent(), cmap='bone', interpolation='lanczos', extent=[0,512,0,512], aspect=(1), animated=True)
self.im2 = self.axes.imshow(misc.lena(), cmap='afmhot', interpolation='lanczos', extent=[0,265,0,256], aspect=(1), animated=True)
self.startButton = QtGui.QPushButton(self.tr("Start Calculation"))
self.stopButton = QtGui.QPushButton(self.tr("Stop Calculation"))
self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
self.slider.setRange(0, 100)
self.slider.setValue(50)
self.slider.setTracking(True)
self.slider.setTickPosition(QtGui.QSlider.TicksBothSides)
layout = QtGui.QGridLayout()
layout.addWidget(self.canvas, 0, 0)
layout.addWidget(self.slider, 1, 0)
layout.addWidget(self.startButton, 2, 0)
layout.addWidget(self.stopButton, 3, 0)
self.main_frame.setLayout(layout)
self.setCentralWidget(self.main_frame)
self.setWindowTitle(self.tr("Gaussian Filter"))
def slider_value_changed(self):
self.worker.slider = self.slider.value()
def start_calculation(self):
if self.worker.exiting:
self.slider.actionTriggered.disconnect(self.start_calculation)
self.worker.slider = self.slider.value()
self.startButton.setEnabled(False)
self.stopButton.setEnabled(True)
self.get_data.emit()
self.worker.exiting = False
def stop_calculation(self):
if not self.worker.exiting:
self.slider.actionTriggered.connect(self.start_calculation)
self.worker.exiting = True
self.startButton.setEnabled(True)
self.stopButton.setEnabled(False)
self.cleanup_UI()
def update_figure(self, im1_data,im2_data):
#self.canvas.restore_region(self.background)
self.im1.set_array(im1_data)
self.im2.set_array(im2_data)
self.axes.draw_artist(self.im1)
self.axes.draw_artist(self.im2)
self.canvas.blit(self.axes.bbox)
def cleanup_UI(self):
self.background = None
self.canvas.draw()
class Worker(QtCore.QObject):
new_pixel_array = QtCore.pyqtSignal(np.ndarray,np.ndarray)
started = QtCore.pyqtSignal()
done = QtCore.pyqtSignal()
def __init__(self, parent = None):
QtCore.QObject.__init__(self, parent)
self.exiting = True
self.slider = 0
#QtCore.pyqtSlot()
def get_data(self):
while self.exiting == False:
self.started.emit()
queue1 = Queue()
queue2 = Queue()
im1T = Thread(target=self.gauss, args=(misc.ascent(),queue1))
im2T = Thread(target=self.gauss, args=(misc.lena(),queue2))
slider_val = self.slider
im1T.start()
im2T.start()
im1T.join()
im2T.join()
im1_data = queue1.get()
im2_data = queue2.get()
self.new_pixel_array.emit(im1_data, im2_data)
if slider_val == self.slider:
self.done.emit()
print 'Slider Value: ', self.slider
break
def gauss(self,im,output_queue):
gaussed = ndimage.gaussian_filter(im,self.slider)
output_queue.put(gaussed)
def main():
app = QtGui.QApplication(sys.argv)
form = ApplicationWindow()
form.show()
app.exec_()
if __name__ == "__main__":
main()
I have been trying unsuccessfully to embed a matplotlib into PyQt for the past few days and before you say anything, I have been to every site possible to help me.
When I run the code it produces a 1 by 1 graph but doesn't actually graph anything
from __future__ import unicode_literals
import sys
import os
import random
from matplotlib.backends import qt4_compat
use_pyside = qt4_compat.QT_API == qt4_compat.QT_API_PYSIDE
if use_pyside:
from PySide import QtGui, QtCore
else:
from PyQt4 import QtGui, QtCore
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
import scipy.io
import os
import pandas as pd
progname = os.path.basename(sys.argv[0])
progversion = "0.1"
class MyMplCanvas(FigureCanvas):
"""Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
# We want the axes cleared every time plot() is called
self.axes.hold(False)
self.compute_initial_figure()
#
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self):
pass
class MyStaticMplCanvas(MyMplCanvas):
def extract_data(self, name):
#setting up lists
Stim_trig = []
Stim_order = []
Sch_wav = []
data = scipy.io.loadmat(name)
for k,v in data.items():
#Sends Sch_wav data to a list
if "Sch_wav" in k:
for d in (((v[0])[0])[4]):
Sch_wav.append(d[0])
#Sends StimTrig to a list
if k=="StimTrig":
for g in (((v[0])[0])[4]):
Stim_trig.append(g[0])
Stim_trig.append(Stim_trig[-1]+1)
#Sends Stim order to a list
for w in (((v[0])[0])[5]):
Stim_order.append(w[0])
superdata = []
#Prepares grouping stimuli and trigger
for i in range(len(Stim_trig)-1):
fire = []
for p in Sch_wav:
if p > Stim_trig[i] and p < Stim_trig[i+1]:
fire.append(p - Stim_trig[i])
superdata.append([Stim_order[i],fire])
#sorts all the data
superdata.sort()
alladdedup = [[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[62]]
count = 0
for d in superdata:
if d[0] == (alladdedup[count])[0]:
for j in d[1]:
((alladdedup)[count]).append(j)
else:
count += 1
#places time stamps of triggers in lists for each trigger
for l in alladdedup:
l.pop(0)
l.sort()
#removes title and sorts data
ffmsb = []
#finds number of firings for each milisecond bin
for v in alladdedup:
fmsb = []
for b in range(100):
msbc = b/100
msb = []
for t in v:
if t > msbc and t < msbc + 0.01:
msb.append(t)
fmsb.append(len(msb))
ffmsb.append(fmsb)
#returns list of stimuli firings per milisecond bin
return ffmsb
#End of Sorting Code
#Start of Graphing Code
def stimuli_graph(self):
#Set file to use and the stimuli wanted. In this case stimuli 1 is being used
filename = ("654508_rec02_all.mat"[1])
self.extract_data(filename)
#Creates parameters for index
numberlist = []
for i in range(100):
numberlist.append(i/100)
#Adjusts the y-axis max according to the y-axis of a graphed stimuli e.g. If plotted graph has y-axis of 10
# then it'll be adjusted by 1.3. So it'll change to 13
x = 0
for i in filename:
if i > x:
x = i*1.3
#Dataframes the data from extract_data
c = pd.Series(filename, index = numberlist)
neurons = pd.DataFrame((c))
#This is where the data gets graphed. I know this is where the problem occurs, I just don't know where
#This code is a mess and for that I am sorry
times = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
ax = neurons.plot(
kind = 'bar',
title = 'Number of neurons firing for stimuli '+str(1),
legend = False,
xlim = (0, 100),
ylim = (0, x),
width = 1,
position = 0,
edgecolor = 'white',
xticks = (np.arange(min(times), max(times), 10)) #Makes the x-axis label in increments of 0.1 instead of 0.01
)
ax.set_xlabel('Time (s)')
ax.set_ylabel('Neurons Firing')
t = arange(0, 100, 1)
self.axes.plot(t, neurons)
class ApplicationWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setWindowTitle("application main window")
self.file_menu = QtGui.QMenu('&File', self)
self.file_menu.addAction('&Quit', self.fileQuit,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
self.menuBar().addMenu(self.file_menu)
self.help_menu = QtGui.QMenu('&Help', self)
self.menuBar().addSeparator()
self.menuBar().addMenu(self.help_menu)
self.main_widget = QtGui.QWidget(self)
l = QtGui.QVBoxLayout(self.main_widget)
sc = MyStaticMplCanvas(self.main_widget, width=5, height=4, dpi=100)
l.addWidget(sc)
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
self.statusBar().showMessage("All hail matplotlib!", 2000)
def fileQuit(self):
self.close()
def closeEvent(self, ce):
self.fileQuit()
qApp = QtGui.QApplication(sys.argv)
aw = ApplicationWindow()
aw.setWindowTitle("%s" % progname)
aw.show()
sys.exit(qApp.exec_())
#qApp.exec_()
The data used in the graph is extracted from an external file