Clear a matplotlib plot in PyQt - python

My code opens a PyQt window with a matplotlib plot inside of it. At the top there are 10 buttons, each with their own data values to plot. I want to know how can I clear the previous plot that is currently showing and then plot the new one when I click on the buttons.
I use PyQt4 and Python 3.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import scipy.io
import sys
import os
from matplotlib.backends.backend_qt4agg import (FigureCanvasQTAgg as FigureCanvas)
from matplotlib.figure import Figure
from PyQt4.QtGui import *
from PyQt4 import QtCore
plt.style.use('ggplot')
def Extract_Data(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(1000):
msbc = b/1000
msb = []
for t in v:
if t > msbc and t < msbc + 0.001:
msb.append(t)
fmsb.append(len(msb))
ffmsb.append(fmsb)
#returns list of stimuli firings per milisecond bin
return(ffmsb)
class DisplayWidget(QMainWindow):
def __init__(self, parent=None):
super(DisplayWidget, self).__init__( parent )
self.initUI()
def initUI(self):
self.main_frame = QWidget()
self.canvas = PlotCanvas(self)
self.canvas.setParent(self.main_frame)
self.one = QPushButton('Intensity 1')
self.two = QPushButton('Intensity 2')
self.three = QPushButton('Intensity 3')
self.four = QPushButton('Intensity 4')
self.five = QPushButton('Intensity 5')
self.six = QPushButton('Intensity 6')
self.seven = QPushButton('Intensity 7')
self.eight = QPushButton('Intensity 8')
self.nine = QPushButton('Intensity 9')
self.ten = QPushButton('Intensity 10')
self.one.connect(self.one, QtCore.SIGNAL('clicked()'), self.setIntensity_one)
self.two.connect(self.two, QtCore.SIGNAL('clicked()'), self.setIntensity_two)
self.three.connect(self.three, QtCore.SIGNAL('clicked()'), self.setIntensity_three)
self.four.connect(self.four, QtCore.SIGNAL('clicked()'), self.setIntensity_four)
self.five.connect(self.five, QtCore.SIGNAL('clicked()'), self.setIntensity_five)
self.six.connect(self.six, QtCore.SIGNAL('clicked()'), self.setIntensity_six)
self.seven.connect(self.seven, QtCore.SIGNAL('clicked()'), self.setIntensity_seven)
self.eight.connect(self.eight, QtCore.SIGNAL('clicked()'), self.setIntensity_eight)
self.nine.connect(self.nine, QtCore.SIGNAL('clicked()'), self.setIntensity_nine)
self.ten.connect(self.ten, QtCore.SIGNAL('clicked()'), self.setIntensity_ten)
grid = QGridLayout()
grid.addWidget(self.canvas, 1, 0, 10, 10) # the matplotlib canvas
grid.addWidget(self.one, 0, 0)
grid.addWidget(self.two, 0, 1)
grid.addWidget(self.three, 0, 2)
grid.addWidget(self.four, 0, 3)
grid.addWidget(self.five, 0, 4)
grid.addWidget(self.six, 0, 5)
grid.addWidget(self.seven, 0, 6)
grid.addWidget(self.eight, 0, 7)
grid.addWidget(self.nine, 0, 8)
grid.addWidget(self.ten, 0, 9)
self.main_frame.setLayout(grid)
self.setCentralWidget(self.main_frame)
self.setWindowTitle('Neurons')
self.showMaximized()
def setIntensity_one(self):
self.data(intensity = 1)
def setIntensity_two(self):
self.data(intensity = 2)
def setIntensity_three(self):
self.data(intensity = 3)
def setIntensity_four(self):
self.data(intensity = 4)
def setIntensity_five(self):
self.data(intensity = 5)
def setIntensity_six(self):
self.data(intensity = 6)
def setIntensity_seven(self):
self.data(intensity = 7)
def setIntensity_eight(self):
self.data(intensity = 8)
def setIntensity_nine(self):
self.data(intensity = 9)
def setIntensity_ten(self):
self.data(intensity = 10)
def data(self, intensity):
stimuli = (Extract_Data("654508_rec02_all.mat")[intensity])
numberlist = []
for i in range(1000):
numberlist.append(i/1000)
d = pd.Series(stimuli, index = numberlist)
self.df = pd.DataFrame(d)
self.canvas.plot_data_frame(self.df)
class PlotCanvas(FigureCanvas, DisplayWidget):
def __init__(self, parent = None, width = 12, height = 9):
self.fig = Figure(figsize = (width, height))
self.axes = self.fig.add_subplot(111)
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def plot_data_frame(self, df):
df.plot( ax = self.axes,
kind = 'line',
title = 'Number of neurons firing',
legend = False,
xlim = (0, 1))
self.draw()
if __name__ == "__main__":
app = QApplication( [] )
widget = DisplayWidget()
widget.show()
app.exec_()

Just call self.axes.cla() before each plot at your plot_data_frame function. This will clear the axes.

Related

How do I make QtableWidget cell squared the size I want?

I'm trying to have a zoom in/zoom out effet on a QtableWidget.
to do so I have to variables
self.myfont which is a Qfont objet and self.table_size which is an int.
When I want zoom in/out I call those two functions :
def zoomin(self):
fontsize = self.myfont.pointSize() + 1
if fontsize < 1:
fontsize = 1
self.myfont.setPointSize(fontsize)
self.table_size += 5
if self.table_size < 1:
self.table_size = 1
print(self.table_size,fontsize)
self.redrawCMLayout()
def zoomout(self):
fontsize = self.myfont.pointSize() - 1
if fontsize < 1:
fontsize = 1
self.myfont.setPointSize(fontsize)
self.table_size -= 5
if self.table_size < 1:
self.table_size = 1
print(self.table_size,fontsize)
self.redrawCMLayout()
which change my two variables.
Then I redraw the QtableWidget with
self.tableWidget = QTableWidget()
self.tableWidget.verticalHeader().setDefaultSectionSize(self.table_size)
self.tableWidget.horizontalHeader().setDefaultSectionSize(self.table_size)
self.tableWidget.horizontalHeader().setFixedHeight(self.table_size)
self.tableWidget.verticalHeader().setFixedWidth(self.table_size)
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
self.tableWidget.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
self.tableWidget.horizontalHeader().setFont(self.myfont)
self.tableWidget.verticalHeader().setFont(self.myfont)
When I'm zooming in it works fine
but when I'm zooming out, the horizontal header width does not match the vertical height anymore.
How can I force them to have the cells squared even for small width and height?
Here is a MRE
import sys
import os
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class ExampleWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(440, 240))
self.setWindowTitle("PyQt5 Textarea example")
self.myarray = [[4, 0, 2, 1],
[6, 0, 3, 7],
[4, 2, 2, 8],
[3, 2, 1, 0]]
self.myfont = QFont()
self.myfont.setPointSize(10)
self.table_size = 35
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.gridCM = QHBoxLayout()
self.update_CMLayout()
zoomin = QAction('zoomin', self)
zoomin.setShortcut('Ctrl+shift+Z')
zoomin.setToolTip('Redo')
zoomin.triggered.connect(self.zoomin)
zoomout = QAction( 'zoomout',self)
zoomout.setShortcut('Ctrl+shift+Z')
zoomout.setToolTip('Redo')
zoomout.triggered.connect(self.zoomout)
# toolbar
toolbar = self.addToolBar('')
toolbar.addAction(zoomin)
toolbar.addAction(zoomout)
self.centralWidget.setLayout(self.gridCM)
def update_CMLayout(self):
print('update_CMLayout')
#self.gridCM = QHBoxLayout()
self.grid3_layout = QGroupBox('Connectivity Matrix')
grid3 = QGridLayout()
self.grid3_layout.setLayout(grid3)
self.tableWidget = QTableWidget()
self.tableWidget.horizontalHeader().setFont(self.myfont)
self.tableWidget.verticalHeader().setFont(self.myfont)
self.tableWidget.verticalHeader().setDefaultSectionSize(self.table_size)
self.tableWidget.horizontalHeader().setDefaultSectionSize(self.table_size)
self.tableWidget.horizontalHeader().setFixedHeight(self.table_size)
self.tableWidget.verticalHeader().setFixedWidth(self.table_size)
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
self.tableWidget.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
line = len(self.myarray)
column = len(self.myarray[0])
self.tableWidget.setRowCount(line)
self.tableWidget.setColumnCount(column)
for c in range(column):
for l in range(line):
item = QTableWidgetItem(str(self.myarray[c][l]))
item.setFont(self.myfont)
item.setSizeHint(QSize(self.table_size, self.table_size))
self.tableWidget.setItem(c, l, item)
grid3.addWidget(self.tableWidget, 1, 1, 1, 1)
self.gridCM.insertWidget(0, self.grid3_layout)
def zoomin(self):
fontsize = self.myfont.pointSize() + 1
if fontsize < 1:
fontsize = 1
self.myfont.setPointSize(fontsize)
self.table_size += 5
if self.table_size < 1:
self.table_size = 1
print(self.table_size,fontsize)
self.redrawCMLayout()
def zoomout(self):
fontsize = self.myfont.pointSize() - 1
if fontsize < 1:
fontsize = 1
self.myfont.setPointSize(fontsize)
self.table_size -= 5
if self.table_size < 1:
self.table_size = 1
print(self.table_size,fontsize)
self.redrawCMLayout()
def redrawCMLayout(self):
self.gridCM.removeWidget(self.grid3_layout)
self.grid3_layout.deleteLater()
self.grid3_layout = None
self.tableWidget.deleteLater()
self.tableWidget = None
self.update_CMLayout()
# self.layout_Main.insertItem(2,self.gridCM)
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setStyle("Windows")
mainWin = ExampleWindow()
mainWin.show()
sys.exit( app.exec_() )
You have to set the setMinimumSectionSize to 0. On the other hand instead of deleting and creating the elements it is better to reuse:
class Delegate(QStyledItemDelegate):
def sizeHint(self, option, index):
s = QStyledItemDelegate.sizeHint(self, option, index)
return max(s.width(), s.height()) * QSize(1, 1)
class ExampleWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.myfont = QFont()
self.myfont.setPointSize(10)
self.setMinimumSize(QSize(440, 240))
self.setWindowTitle("PyQt5 Textarea example")
self.myarray = [[4, 0, 2, 1], [6, 0, 3, 7], [4, 2, 2, 8], [3, 2, 1, 0]]
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.gridCM = QHBoxLayout(self.centralWidget)
zoomin = QAction("zoomin", self)
zoomin.setShortcut("Ctrl+shift+Z")
zoomin.setToolTip("Redo")
zoomin.triggered.connect(self.zoomin)
zoomout = QAction("zoomout", self)
zoomout.setShortcut("Ctrl+shift+Z")
zoomout.setToolTip("Redo")
zoomout.triggered.connect(self.zoomout)
# toolbar
toolbar = self.addToolBar("")
toolbar.addAction(zoomin)
toolbar.addAction(zoomout)
self.grid3_layout = QGroupBox("Connectivity Matrix")
grid3 = QGridLayout()
self.grid3_layout.setLayout(grid3)
self.gridCM.insertWidget(0, self.grid3_layout)
self.tableWidget = QTableWidget()
grid3.addWidget(self.tableWidget, 1, 1, 1, 1)
line = len(self.myarray)
column = len(self.myarray[0])
self.tableWidget.setRowCount(line)
self.tableWidget.setColumnCount(column)
self.delegate = Delegate()
self.tableWidget.setItemDelegate(self.delegate)
for c, row in enumerate(self.myarray):
for r, e in enumerate(row):
item = QTableWidgetItem(str(e))
self.tableWidget.setItem(r, c, item)
for header in (
self.tableWidget.horizontalHeader(),
self.tableWidget.verticalHeader(),
):
header.setSectionResizeMode(QHeaderView.ResizeToContents)
header.setMinimumSectionSize(0)
self.update_font()
def zoomin(self):
self.myfont.setPointSize(self.myfont.pointSize() + 1)
self.update_font()
def zoomout(self):
if self.myfont.pointSize() > 1:
self.myfont.setPointSize(self.myfont.pointSize() - 1)
self.update_font()
def update_font(self):
self.tableWidget.setFont(self.myfont)

How to draw a large amont of signal faster in matplotlib embedded within Qt environment?

I'm trying to plot a large among of signal in a matplotlib figure which is embedded in a Qt environment.
The plots are updated according to QScrollBar which modify the part of signals that I need to show.
My issue is the update of the figure takes a pretty long time, especially because I have 250 signals to update. So, I'm seeking for a way to optimize the EEG_plot.update function to reduce its draw time.
I don't know how I could use an animate function to speed up the process or something else.
My concern is I need to update the time axis ticks and probably also the y axis label positions.
The other thing is if the last segment that I need to plot does not correspond exactly with the window size chosen I need to plot only a part of the window (for instance the last segment will be 5s but the window size is 10s)
I give the entire script right below
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
class Viewer(QMainWindow):
def __init__(self, parent=None):
super(Viewer, self).__init__()
self.parent = parent
#######################################
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.mainVBOX_param_scene = QVBoxLayout()
self.mascene = plot(self)
self.paramPlotV = QVBoxLayout()
self.horizontalSliders = QScrollBar(Qt.Horizontal)
self.horizontalSliders.setFocusPolicy(Qt.StrongFocus)
self.horizontalSliders.valueChanged.connect(self.update_plot)
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(1)
self.paramPlot = QHBoxLayout()
l_gain = QLabel('Gain')
self.e_gain = QLineEdit('5')
l_win = QLabel('Window')
self.e_win = QLineEdit('10')
l_spacing = QLabel('vertical spacing')
self.e_spacing = QLineEdit('10')
l_linewidth = QLabel('linewidth')
self.e_linewidth = QLineEdit('1')
self.e_gain.returnPressed.connect(self.update_plot)
self.e_win.returnPressed.connect(self.udpate_plot_plus_slider)
self.e_spacing.returnPressed.connect(self.update_plot)
self.e_linewidth.returnPressed.connect(self.update_plot)
self.paramPlot.addWidget(l_gain)
self.paramPlot.addWidget(self.e_gain)
self.paramPlot.addWidget(l_win)
self.paramPlot.addWidget(self.e_win)
self.paramPlot.addWidget(l_spacing)
self.paramPlot.addWidget(self.e_spacing)
self.paramPlot.addWidget(l_linewidth)
self.paramPlot.addWidget(self.e_linewidth)
self.paramPlotV.addWidget(self.horizontalSliders)
self.paramPlotV.addLayout(self.paramPlot)
self.mainVBOX_param_scene.addWidget(self.mascene)
self.mainVBOX_param_scene.addLayout(self.paramPlotV)
self.centralWidget.setLayout(self.mainVBOX_param_scene)
self.Fs = 1024
self.Sigs_dict = np.random.rand(250,105*self.Fs)
self.t = np.arange(self.Sigs_dict.shape[1])/self.Fs
self.parent.processEvents()
self.update()
def updateslider(self):
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(np.ceil(self.t[-1]/int(self.e_win.text()))-1)
self.horizontalSliders.setPageStep(1)
self.horizontalSliders.update()
def udpate_plot_plus_slider(self):
self.updateslider()
self.mascene.update()
def update_plot(self):
self.mascene.update()
def update(self):
self.updateslider()
self.mascene.modify_sigs()
self.mascene.update()
class plot(QGraphicsView):
def __init__(self, parent=None):
super(plot, self).__init__(parent)
self.parent = parent
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.figure = plt.figure(facecolor='white')#Figure()
self.canvas = FigureCanvas(self.figure)
self.widget = QWidget()
self.widget.setLayout(QVBoxLayout())
self.widget.layout().setContentsMargins(0, 0, 0, 0)
self.widget.layout().setSpacing(0)
self.scroll = QScrollArea(self.widget)
self.scroll.setWidget(self.canvas)
layout = QVBoxLayout()
layout.addWidget(self.scroll)
self.setLayout(layout)
def modify_sigs(self):
self.Sigs_dict = self.parent.Sigs_dict
self.t = self.parent.t
self.Fs= self.parent.Fs
def update(self):
win_num = self.parent.horizontalSliders.value()
self.figure.clear()
plt.figure(self.figure.number)
plt.subplots_adjust(left=0.1, bottom=0.01, right=1, top=1, wspace=0.0 , hspace=0.0 )
self.axes = plt.subplot(1, 1, 1)
gain = float(self.parent.e_gain.text())
win= float(self.parent.e_win.text())
self.spacing = float(self.parent.e_spacing.text())
linewidth = float(self.parent.e_linewidth.text())
ts = int(win*(win_num) * self.Fs)
te = ts + int(win * self.Fs)
if te > len(self.t):
te=len(self.t)
for i in range(self.Sigs_dict.shape[0]):
line, = plt.plot(self.t[ts:te], gain*(self.Sigs_dict[i,ts:te]-np.mean(self.Sigs_dict[i,ts:te]))+i*self.spacing, linewidth=linewidth )
self.axes.autoscale(enable=True, axis='both', tight=True)
self.axes.set_ylim((-self.spacing,(self.Sigs_dict.shape[0]+1)*self.spacing))
self.axes.set_xlim((ts/ self.Fs, ts / self.Fs + win ))
self.axes.set_yticks(np.arange(self.Sigs_dict.shape[0]) * self.spacing)
self.axes.set_yticklabels([str(n) for n in np.arange(self.Sigs_dict.shape[0])])
self.canvas.setGeometry(0, 0, self.parent.width()-100, (self.parent.height()-100)*self.spacing)
self.canvas.draw_idle()
def main():
app = QApplication(sys.argv)
app.setStyle('Windows')
ex = Viewer(app)
ex.showMaximized()
sys.exit(app.exec())
if __name__ == '__main__':
main()
Update
I made a new implementation where I try to update data instead of reploting all the figure each time (update_set_data function), I don't plot all the point of the curve (for instance if the number of point > 10000 points, I take only 50% of them) I used decimate = len(self.t[ts:te]) // 10000 + 1 to compute the decimation, and last I don't replot the figure when the user is draging the slider.
When I use the old version I get thos time to update the figure:
time old: 4.148899078369141
time old: 4.117990255355835
time old: 4.152893781661987
With the new version I get:
time new: 2.0400094985961914
time new: 2.0248610973358154
time new: 2.0305933952331543
I have to say, I expected more than a 50% time reduction.
Does someone have idea to optimize this more?
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
import time
class Viewer(QMainWindow):
def __init__(self, parent=None):
super(Viewer, self).__init__()
self.parent = parent
#######################################
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.mainVBOX_param_scene = QVBoxLayout()
self.mascene = plot(self)
self.paramPlotV = QVBoxLayout()
self.horizontalSliders = QScrollBar(Qt.Horizontal)
self.horizontalSliders.setFocusPolicy(Qt.StrongFocus)
self.horizontalSliders.valueChanged.connect(self.sliderReleasedfun)
self.horizontalSliders.sliderPressed.connect(self.sliderPressedfun)
self.horizontalSliders.sliderMoved.connect(self.sliderMovedfun)
self.horizontalSliders.sliderReleased.connect(self.sliderReleasedfun)
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(1)
self.paramPlot = QHBoxLayout()
l_gain = QLabel('Gain')
self.e_gain = QLineEdit('5')
l_win = QLabel('Window')
self.e_win = QLineEdit('10')
l_spacing = QLabel('vertical spacing')
self.e_spacing = QLineEdit('10')
l_linewidth = QLabel('linewidth')
self.e_linewidth = QLineEdit('1')
self.e_gain.returnPressed.connect(self.update_plot)
self.e_win.returnPressed.connect(self.udpate_plot_plus_slider)
self.e_spacing.returnPressed.connect(self.update_plot)
self.e_linewidth.returnPressed.connect(self.update_plot)
self.paramPlot.addWidget(l_gain)
self.paramPlot.addWidget(self.e_gain)
self.paramPlot.addWidget(l_win)
self.paramPlot.addWidget(self.e_win)
self.paramPlot.addWidget(l_spacing)
self.paramPlot.addWidget(self.e_spacing)
self.paramPlot.addWidget(l_linewidth)
self.paramPlot.addWidget(self.e_linewidth)
self.paramPlotV.addWidget(self.horizontalSliders)
self.paramPlotV.addLayout(self.paramPlot)
self.mainVBOX_param_scene.addWidget(self.mascene)
self.mainVBOX_param_scene.addLayout(self.paramPlotV)
self.centralWidget.setLayout(self.mainVBOX_param_scene)
self.Fs = 1024
self.Sigs_dict = np.random.rand(250,105*self.Fs)
self.t = np.arange(self.Sigs_dict.shape[1])/self.Fs
self.parent.processEvents()
self.update()
def sliderPressedfun(self):
self.horizontalSliders.valueChanged.disconnect()
def sliderMovedfun(self,e):
self.horizontalSliders.setValue(e)
def sliderReleasedfun(self):
self.horizontalSliders.valueChanged.connect(self.movesliderfun)
self.movesliderfun()
def movesliderfun(self):
t0 = time.time()
self.horizontalSliders.setEnabled(False)
self.update_data()
self.horizontalSliders.setEnabled(True)
print('time new:', time.time()-t0)
def updateslider(self):
self.horizontalSliders.setMinimum(0)
self.horizontalSliders.setMaximum(np.ceil(self.t[-1]/int(self.e_win.text()))-1)
self.horizontalSliders.setPageStep(1)
self.horizontalSliders.update()
def udpate_plot_plus_slider(self):
self.updateslider()
self.mascene.update()
def update_plot(self):
self.mascene.update()
def update_data(self):
self.mascene.update_set_data()
def update(self):
self.updateslider()
self.mascene.modify_sigs()
self.mascene.update()
class plot(QGraphicsView):
def __init__(self, parent=None):
super(plot, self).__init__(parent)
self.parent = parent
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.figure = plt.figure(facecolor='white')#Figure()
self.canvas = FigureCanvas(self.figure)
self.widget = QWidget()
self.widget.setLayout(QVBoxLayout())
self.widget.layout().setContentsMargins(0, 0, 0, 0)
self.widget.layout().setSpacing(0)
self.scroll = QScrollArea(self.widget)
self.scroll.setWidget(self.canvas)
layout = QVBoxLayout()
layout.addWidget(self.scroll)
self.setLayout(layout)
self.win=10
def modify_sigs(self):
self.Sigs_dict = self.parent.Sigs_dict
self.t = self.parent.t
self.Fs= self.parent.Fs
def update_set_data(self):
win_num = self.parent.horizontalSliders.value()
gain = float(self.parent.e_gain.text())
win= float(self.parent.e_win.text())
if not self.spacing == float(self.parent.e_spacing.text()):
self.spacing = float(self.parent.e_spacing.text())
spacing = True
else:
spacing = False
self.linewidth = float(self.parent.e_linewidth.text())
ts = int(self.win * (win_num) * self.Fs)
te = ts + int(self.win * self.Fs)
if te > len(self.t):
diff = te - len(self.t)
ts = ts - diff
te = len(self.t)
decimate = len(self.t[ts:te]) // 10000 + 1
for i in range(self.Sigs_dict.shape[0]):
self.Lines[i].set_data(self.t[ts:te:decimate], gain*(self.Sigs_dict[i,ts:te:decimate]-np.mean(self.Sigs_dict[i,ts:te:decimate]))+i*self.spacing )
self.Lines[i].set_linewidth(self.linewidth)
if spacing:
self.axes.set_ylim((-self.spacing,(self.Sigs_dict.shape[0]+1)*self.spacing))
self.axes.set_yticks(np.arange(self.Sigs_dict.shape[0]) * self.spacing)
self.axes.set_yticklabels([str(n) for n in np.arange(self.Sigs_dict.shape[0])])
self.axes.set_xlim((ts/ self.Fs, ts / self.Fs + win ))
# self.canvas.draw_idle()
self.canvas.draw()
def update(self):
win_num = self.parent.horizontalSliders.value()
self.figure.clear()
plt.figure(self.figure.number)
plt.subplots_adjust(left=0.1, bottom=0.01, right=1, top=1, wspace=0.0 , hspace=0.0 )
self.axes = plt.subplot(1, 1, 1)
gain = float(self.parent.e_gain.text())
win= float(self.parent.e_win.text())
self.spacing = float(self.parent.e_spacing.text())
linewidth = float(self.parent.e_linewidth.text())
ts = int(self.win * (win_num) * self.Fs)
te = ts + int(self.win * self.Fs)
if te > len(self.t):
diff = te - len(self.t)
ts = ts - diff
te = len(self.t)
decimate = len(self.t[ts:te]) // 10000 + 1
self.Lines = []
for i in range(self.Sigs_dict.shape[0]):
line, = plt.plot(self.t[ts:te:decimate], gain*(self.Sigs_dict[i,ts:te:decimate]-np.mean(self.Sigs_dict[i,ts:te:decimate]))+i*self.spacing, linewidth=linewidth )
self.Lines.append(line)
self.axes.autoscale(enable=True, axis='both', tight=True)
self.axes.set_ylim((-self.spacing,(self.Sigs_dict.shape[0]+1)*self.spacing))
self.axes.set_xlim((ts/ self.Fs, ts / self.Fs + win ))
self.axes.set_yticks(np.arange(self.Sigs_dict.shape[0]) * self.spacing)
self.axes.set_yticklabels([str(n) for n in np.arange(self.Sigs_dict.shape[0])])
self.canvas.setGeometry(0, 0, self.parent.width()-100, (self.parent.height()-100)*self.spacing)
self.canvas.draw_idle()
def main():
app = QApplication(sys.argv)
app.setStyle('Windows')
ex = Viewer(app)
ex.showMaximized()
sys.exit(app.exec())
if __name__ == '__main__':
main()
You can try this with multi threading,
so that you can break the whole code in many sub code
and your all code will run in same time with multi threading

How to get x-axis value in wx canvas from mouse click?

I have a wx plot which is defined like so
import wx
import numpy as np
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigCanvas
import pylab
class GraphFrame(wx.Panel):
def __init__(self, parent, chart_name, nsamples, varnames, krefresh=150):
wx.Panel.__init__(self, parent=parent)
self.display_function = self._display_abs
self.need_to_copy_background = False
self.chart_name = chart_name
self.nsamples = nsamples
self.varnames = varnames
self.krefresh = krefresh
self.data = np.zeros((self.nsamples, len(self.varnames)))
self._create_panel(chart_name)
def _create_panel(self, chart_name=None):
self.init_plot()
self.canvas = FigCanvas(self, -1, self.fig)
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.vbox.Add(self.canvas, 1, flag=wx.ALIGN_CENTER)
self.SetSizer(self.vbox)
self.vbox.Fit(self)
def set_title(self, new_title):
self.axes.set_title(new_title, size=10)
self.canvas.draw()
def init_plot(self):
self.yrange = [-1.0, +1.0]
self.yrange2 = [-555.0, +555.0]
t0 = -0.125
t1 = 0.0
self.time = np.linspace(t0, t1, self.nsamples)
self.k = 0
self.dpi = 100
self.fig = Figure(dpi=self.dpi)
self.fig.set_tight_layout(True)
self.axes = self.fig.add_subplot(111)
self.axes2 = self.axes.twinx()
self.axes.set_title(self.chart_name, size=10)
self.axes.grid(True)
pylab.setp(self.axes.get_xticklabels(), fontsize=8)
pylab.setp(self.axes.get_yticklabels(), fontsize=8)
pylab.setp(self.axes2.get_yticklabels(), fontsize=8)
self.plot = []
self.plot2 = []
for i in range(len(self.varnames)):
ax = self.axes.plot([],
[],
"%s-" % ("krgbym"[i]),
linewidth=0.5,
color=(0, 0, 1))[0]
ax2 = self.axes2.plot(
[],
[],
"%s-" % ("krgbym"[i]),
linewidth=2,
color=(1, 0, 0)
)[0]
self.plot.append(ax)
self.plot2.append(ax2)
def draw_plot(self):
data = self.data[:, 0]
occ = self.data[:, 1]
self.need_to_copy_background = True
dmin = data.min()
dmax = data.max()
if dmin == 0.0 and dmax == 0.0:
self.yrange = [-1.0, +1.0]
self.need_to_copy_background= False
elif dmin < self.yrange[0] or dmax > self.yrange[1]:
self.yrange[0] = dmin - 0.1666 * (dmax - dmin)
self.yrange[1] = dmax + 0.1666 * (dmax - dmin)
self.need_to_copy_background= False
elif (dmax - dmin) < 0.25 * (self.yrange[1] - self.yrange[0]):
self.yrange[0] = dmin - 0.1666 * (dmax - dmin)
self.yrange[1] = dmax + 0.1666 * (dmax - dmin)
self.need_to_copy_background= False
ymin = self.yrange[0]
ymax = self.yrange[1]
self.need_to_copy_background = False
self.axes.set_xbound(0, self.nsamples)
self.axes.set_ybound(lower=ymin, upper=ymax)
self.axes2.set_ybound(lower=occ.min(), upper=occ.max())
t0 = -0.125
t1 = 0.0
self.time = np.linspace(t0, t1, self.nsamples)
self.plot[0].set_data(np.arange(self.nsamples), data)
self.plot2[0].set_data(np.arange(self.nsamples), occ)
if self.need_to_copy_background:
self.copy_background()
self.canvas.restore_region(self.background)
for i in range(len(self.varnames)):
self.axes.draw_artist(self.plot[i])
self.axes2.draw_artist(self.plot2[i])
self.canvas.blit(self.fig.bbox)
else:
self.canvas.draw()
def copy_background(self):
self.axes.cla()
self.axes.set_xlim(self.time[0], self.time[-1])
self.axes.set_ylim(self.yrange[0], self.yrange[1])
for i in range(len(self.varnames)):
self.plot[i] = self.axes.plot([], [], "%s-" % ("krgby"[i]), lw=2.0)[0]
self.axes.grid(True)
self.axes2.cla()
self.axes2.set_xlim(self.time[0], self.time[-1])
self.axes2.set_ylim(self.yrange2[0], self.yrange2[1])
for i in range(len(self.varnames)):
self.plot2[i] = self.axes2.plot([], [], "%s-" % ("krgby"[i]), lw=2.0)[0]
self.axes2.grid(True)
self.canvas.draw()
self.background = self.canvas.figure.canvas.copy_from_bbox(self.canvas.figure.bbox)
def _display_abs(self, v):
return np.abs(v)
def add_data(self, val):
self.data[:-1] = self.data[1:]
self.data[-1] = self.display_function(val)
self.k += 1
if (self.k % self.krefresh) == 0:
self.draw_plot()
This works fine.
When add_data is called, the graph is updated and refreshed correctly.
I want to add a feature that would allow the user to mouse click on somewhere on the graph (canvas), and a callback would be issued with an argument that has the x-value of the selected point on the graph.
For example
Y
^
| /\ /\
| / \/ \ X<<< pressing on this point would give 14
| / \ _
| / \/ \_
|/_________________________>x
012345678901234567890123456
Pressing the point where the X is on the beautiful graph above should return 14, as the X value at that point is 14.
Notice, if the X value does not start from 0, is float (and not int), or anything, else, still the data's value should be returned, and not the data's index.
Is this possible with wx? How?
It seems this is built into mpl, see https://matplotlib.org/3.1.1/users/event_handling.html
cid = fig.canvas.mpl_connect('button_press_event', onclick)
I created this sample to try it out and it works perfectly.
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
from matplotlib.backends.backend_wx import _load_bitmap
from matplotlib.figure import Figure
import numpy as np
import wx
class MyNavigationToolbar(NavigationToolbar):
"""Extend the default wx toolbar with your own event handlers."""
def __init__(self, canvas, cankill):
NavigationToolbar.__init__(self, canvas)
# for simplicity I'm going to reuse a bitmap from wx, you'll
# probably want to add your own.
tool = self.AddTool(wx.ID_ANY, 'Click me', _load_bitmap('back.png'),
'Activate custom contol')
self.Bind(wx.EVT_TOOL, self._on_custom, id=tool.GetId())
def _on_custom(self, evt):
# add some text to the axes in a random location in axes (0,1)
# coords) with a random color
# get the axes
ax = self.canvas.figure.axes[0]
# generate a random location can color
x, y = np.random.rand(2)
rgb = np.random.rand(3)
# add the text and draw
ax.text(x, y, 'You clicked me',
transform=ax.transAxes,
color=rgb)
self.canvas.draw()
evt.Skip()
class CanvasFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1,
'CanvasFrame', size=(550, 350))
self.figure = Figure(figsize=(5, 4), dpi=100)
self.axes = self.figure.add_subplot(111)
t = np.arange(0.0, 3.0, 0.01)
s = np.sin(2 * np.pi * t)
self.axes.plot(t, s)
self.canvas = FigureCanvas(self, -1, self.figure)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND)
self.toolbar = MyNavigationToolbar(self.canvas, True)
self.toolbar.Realize()
# By adding toolbar in sizer, we are able to put it at the bottom
# of the frame - so appearance is closer to GTK version.
self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
# update the axes menu on the toolbar
self.toolbar.update()
self.SetSizer(self.sizer)
self.Fit()
self.canvas.mpl_connect('button_press_event', self.OnClick)
#self.canvas.Bind(wx.MOUSE_BTN_LEFT, self.OnClick)
def OnClick(self, e):
print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
('double' if e.dblclick else 'single', e.button,
e.x, e.y, e.xdata, e.ydata))
class App(wx.App):
def OnInit(self):
'Create the main window and insert the custom frame'
frame = CanvasFrame()
frame.Show(True)
return True
app = App(0)
app.MainLoop()

How to aesthetically show a generic number of axes in matplotlib?

I want to do a simple GUI that allows the user to add or remove traces from a plot for any number of traces. It looks like this:
The problems I'm having:
I don't know how to make the axes not to superpose with each other for a generic number of plots.
When I plot more than one trace, and then delete all but one, there are two axes showing for some reason. There should always be one axis per trace being shown.
Is there a way to fix these issues? You can find my code below. The only function that should be changed is update_canvas(), I believe. To try it out, just modify the list name_vars in the main with the number of variables you want. The rest of the example code is self-contained.
import numpy as np
from matplotlib.backends.qt_compat import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(ApplicationWindow, self).__init__(parent)
global name_vars
self.x = np.array([1,2,3,4,5])
self.y = np.random.random((5, len(name_vars)))
self.num_vars = np.size(self.y,1)
self.name_vars = name_vars
self.tags_on = [0] * self.num_vars
self.colors = ['#1F77B4','#FF7F0E','#2CA02C','#D62728','#9467BD',
'#8C564B','#E377C2','#F7F7F7','#BCBD22','#17BECF']
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
canvas = FigureCanvas(Figure(figsize=(10, 10)))
self.canvas_ax = canvas.figure.subplots()
self.canvas_ax.set_xlabel("Time")
self.canvas_ax_twin = []
self.list_tags = QtWidgets.QComboBox(self)
for name in self.name_vars:
self.list_tags.addItem(name)
button_add = QtWidgets.QPushButton('Add', self)
button_remove = QtWidgets.QPushButton('Remove', self)
button_add.clicked.connect(self.add_plot)
button_remove.clicked.connect(self.remove_plot)
layout = QtWidgets.QGridLayout(self._main)
layout.addWidget(canvas, 0, 0)
dropdown_layout = QtWidgets.QHBoxLayout()
dropdown_layout.addWidget(self.list_tags)
dropdown_layout.addWidget(button_add)
dropdown_layout.addWidget(button_remove)
layout.addLayout(dropdown_layout, 1, 0)
self.show()
def add_plot(self):
selected_tag = self.list_tags.currentIndex()
self.tags_on[selected_tag] = 1
self.update_canvas()
def remove_plot(self):
selected_tag = self.list_tags.currentIndex()
self.tags_on[selected_tag] = 0
self.update_canvas()
def update_canvas(self):
# Delete all traces
self.canvas_ax.clear()
[i.clear() for i in self.canvas_ax_twin]
self.canvas_ax_twin = []
num_plots = 0
for ii in range(self.num_vars):
if self.tags_on[ii] == 1:
# If it's not the first trace, create a twin axis
if num_plots != 0:
self.canvas_ax_twin.append(self.canvas_ax.twinx())
self.canvas_ax_twin[-1].plot(self.x, self.y[:,ii], self.colors[num_plots])
self.canvas_ax_twin[-1].set_ylabel(self.name_vars[ii])
self.canvas_ax_twin[-1].yaxis.label.set_color(self.colors[num_plots])
self.canvas_ax_twin[-1].tick_params(axis='y', colors=self.colors[num_plots])
num_plots += 1
# If it's the first trace, use the original axis
else:
self.canvas_ax.plot(self.x, self.y[:,ii], self.colors[num_plots])
self.canvas_ax.set_ylabel(self.name_vars[ii])
self.canvas_ax.yaxis.label.set_color(self.colors[num_plots])
self.canvas_ax.tick_params(axis='y', colors=self.colors[num_plots])
num_plots += 1
# Show the final plot
self.canvas_ax.figure.canvas.draw()
if __name__ == '__main__':
# Edit the number of elements in name_vars to try the code
name_vars = ['V1','V2','V3','V4']
app = QtWidgets.QApplication([])
ex = ApplicationWindow()
ex.show()
app.exec_()
I would suggest to separate the logic from the actual plotting. This makes it easier to follow through. This solves the second question about not removing all axes.
The question about not letting the axes superimpose may be solved by setting the position of additional twin axes to some distance from the axes, depending on how many axes you have.
ax.spines["right"].set_position(("axes", 1+(n-1)*0.1))
where n is the axes number starting from 0. The main axes (n=0) should be excluded, and the first axes will stay at position 1. Further axes are positionned in steps of 0.1.
Then it makes sense to also adjust the right margin of the main axes to give enough space for the extra spines.
import numpy as np
from matplotlib.backends.qt_compat import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None, name_vars=[]):
super(ApplicationWindow, self).__init__(parent)
self.x = np.array([1,2,3,4,5])
self.y = np.random.random((5, len(name_vars)))
self.num_vars = np.size(self.y,1)
self.name_vars = name_vars
self.tags_on = [0] * self.num_vars
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
self.figure = Figure(figsize=(10, 10))
canvas = FigureCanvas(self.figure)
self.left = self.figure.subplotpars.left
self.right = self.figure.subplotpars.right
self.canvas_ax = canvas.figure.subplots()
self.canvas_ax.set_xlabel("Time")
self.axes = [self.canvas_ax]
self.list_tags = QtWidgets.QComboBox(self)
for name in self.name_vars:
self.list_tags.addItem(name)
button_add = QtWidgets.QPushButton('Add', self)
button_remove = QtWidgets.QPushButton('Remove', self)
button_add.clicked.connect(self.add_plot)
button_remove.clicked.connect(self.remove_plot)
layout = QtWidgets.QGridLayout(self._main)
layout.addWidget(canvas, 0, 0)
dropdown_layout = QtWidgets.QHBoxLayout()
dropdown_layout.addWidget(self.list_tags)
dropdown_layout.addWidget(button_add)
dropdown_layout.addWidget(button_remove)
layout.addLayout(dropdown_layout, 1, 0)
self.show()
def add_plot(self):
selected_tag = self.list_tags.currentIndex()
self.tags_on[selected_tag] = 1
self.update_canvas()
def remove_plot(self):
selected_tag = self.list_tags.currentIndex()
self.tags_on[selected_tag] = 0
self.update_canvas()
def create_nth_axes(self, n, dataset):
if n == 0:
ax = self.canvas_ax
else:
ax = self.canvas_ax.twinx()
ax.spines["right"].set_position(("axes", 1+(n-1)*0.1))
for direction in ["left", "bottom", "top"]:
ax.spines[direction].set_visible(False)
# adjust subplotparams to make space for new axes spine
new_right = (self.right-self.left)/(1+(n-1)*0.1)+self.left
self.figure.subplots_adjust(right=new_right)
color = next(self.canvas_ax._get_lines.prop_cycler)['color']
ax.set_ylabel(self.name_vars[dataset], color=color)
ax.plot(self.x, self.y[:,dataset], color=color)
return ax
def clear_canvas(self):
# Clear main axes
self.canvas_ax.clear()
# clear and remove other axes
for ax in self.axes[1:]:
ax.clear()
ax.remove()
self.axes = [self.canvas_ax]
self.figure.subplots_adjust(right=0.9)
def update_canvas(self):
self.clear_canvas()
k = 0
for i, tag in enumerate(self.tags_on):
if tag:
ax = self.create_nth_axes(k, i)
if k > 0:
self.axes.append(ax)
k += 1
self.canvas_ax.figure.canvas.draw()
if __name__ == '__main__':
# Edit the number of elements in name_vars to try the code
name_vars = ['V1','V2','V3','V4']
app = QtWidgets.QApplication([])
ex = ApplicationWindow(name_vars=name_vars)
ex.show()
app.exec_()

Matplotlib Live Plot in PyQt4 GUI

I am writing a GUI using PyQt4, and am trying to implement a live updating pyplot chart using the matplotlib animate module.
The attached code works exactly as I am intending if an error conveniently occurs just before plt.show() is called in the main method (I have caused a div0 error here for demonstration).
If plt.show() is called however, 2 other windows are opened alongside the embedded graph (see screenshots). If any of these extra windows are closed, the embedded graph crashes. If plt.show() is removed from the code entirely, the chart live chart never works at all.
I am at a bit of a loss as to what is going on there. This behaviour is unexpected and quite confusing. It would be fantastic if anyone has any suggestions for how I might get everything working properly.
import sys
import json
import time
import math
import dateutil
import requests
from PyQt4 import QtGui, QtCore
import matplotlib.pyplot as plt
from matplotlib import style
import matplotlib.animation as animation
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
style.use('ggplot')
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.time = []
self.recorded_temp = []
self.recorded_setpoint = []
self.runtime = 0
self.element_status = ""
self.temp = 0
self.setpoint = 0
self.setWindowTitle("Distillation Control Panel")
#self.setGeometry(100, 100, 500, 100)
self.stacked_layout = QtGui.QStackedLayout()
self.connect_page = QtGui.QWidget()
self.home_page = QtGui.QWidget()
self.home_UI()
self.connect_UI()
self.stacked_layout.addWidget(self.connect_page)
self.stacked_layout.addWidget(self.home_page)
self.setLayout(self.stacked_layout)
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.update_gui)
self.show()
def main(self):
self.timer.start(1000)
ani = animation.FuncAnimation(self.fig, self.animate, interval=1000)
1 / 0 # Code works if an error occurs here
plt.show()
def home_UI(self):
grid = QtGui.QGridLayout()
runtime_indicator_label = QtGui.QLabel()
self.runtime = QtGui.QLabel()
runtime_indicator_label.setText("Runtime: ")
element_status_indicator = QtGui.QLabel()
self.element_status = QtGui.QLabel()
element_status_indicator.setText("Element Status: ")
temp_indicator_label = QtGui.QLabel()
self.temp = QtGui.QLabel()
temp_indicator_label.setText("Temperature: ")
setpoint_label = QtGui.QLabel()
self.setpoint = QtGui.QLabel()
setpoint_label.setText("Setpoint: ")
up_btn = QtGui.QPushButton("Increase", self)
up_btn.resize(up_btn.minimumSizeHint())
down_btn = QtGui.QPushButton("Decrease", self)
down_btn.resize(down_btn.minimumSizeHint())
self.fig = plt.figure(figsize=(15, 5))
self.canvas = FigureCanvas(self.fig)
self.toolbar = NavigationToolbar(self.canvas, self)
grid.addWidget(runtime_indicator_label, 0, 0, 2, 1)
grid.addWidget(self.runtime, 0, 1, 2, 1)
grid.addWidget(element_status_indicator, 0, 2, 2, 1)
grid.addWidget(self.element_status, 0, 3, 2, 1)
grid.addWidget(temp_indicator_label, 0, 4, 2, 1)
grid.addWidget(self.temp, 0, 5, 2, 1)
grid.addWidget(setpoint_label, 0, 6, 2, 1)
grid.addWidget(self.setpoint, 0, 7, 2, 1)
grid.addWidget(up_btn, 0, 8, 1, 1)
grid.addWidget(down_btn, 1, 8, 1, 1)
grid.addWidget(self.canvas, 3, 0, 1, 9)
grid.addWidget(self.toolbar, 4, 0, 1, 9)
self.home_page.setLayout(grid)
def connect_UI(self):
'''
User interface for connecting to distillation controller server. Enter local IP address for ESP8266
assigned by router
'''
grid = QtGui.QGridLayout()
addr = QtGui.QLineEdit()
addr.setPlaceholderText("Enter IP address for distiller server")
grid.addWidget(addr, 1, 1)
btn = QtGui.QPushButton("Connect!", self)
btn.clicked.connect(lambda: self.connect(addr.text()))
btn.setFocus()
grid.addWidget(btn, 1, 2)
self.connect_page.setLayout(grid)
def connect(self, addr):
'''
Check connection with controller server and verify address
'''
full_address = 'http://' + addr + "/connect"
try:
data = requests.get(str(full_address), timeout=1.0)
if data.status_code == requests.codes.ok:
QtGui.QMessageBox.information(self, 'test', "Connected!", QtGui.QMessageBox.Ok)
self.address = addr
self.stacked_layout.setCurrentIndex(1)
else:
# Add handling if non-200 http code returned
pass
except Exception:
QtGui.QMessageBox.information(self, 'test', "Device not found at {}. Please enter a valid address".format(addr), QtGui.QMessageBox.Ok)
self.connect_UI()
self.main()
def update_gui(self):
full_address = 'http://' + self.address + "/request_data"
data = json.loads(requests.get(full_address).text)
runtime = convertMillis(data["Runtime"])
temp = data['Temp']
setpoint = data["Setpoint"]
self.runtime.setText(runtime)
self.element_status.setText(data["Element status"])
self.temp.setText(str(temp))
self.setpoint.setText(str(setpoint))
self.time.append(dateutil.parser.parse(runtime))
self.recorded_temp.append(temp)
self.recorded_setpoint.append(setpoint)
def animate(self, i):
plt.cla()
plt.plot(self.time, self.recorded_temp)
plt.plot(self.time, self.recorded_setpoint)
plt.xlabel("Running Time", fontsize=6)
plt.ylabel("Temperature (°C)", fontsize=6)
plt.xticks(fontsize=6, rotation=45)
plt.yticks(fontsize=6)
plt.tight_layout()
plt.draw()
def convertMillis(millis):
seconds = math.floor((millis/1000)%60)
minutes = math.floor((millis/(1000*60))%60)
hours = math.floor((millis/(1000*60*60))%24)
return "{:02}:{:02}:{:02}".format(hours, minutes, seconds)
def main():
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I am unable to post screenshots, so here is a link to the image

Categories

Resources