Create multiple surface plots in GUI - python

so I just started a new project in which I need to present data I collected on a GUI. For that purpose I created a test script, that reads the data from a .mat file and then calculates the surface plots. So far everything is working. Now I need to start with the GUI. I already managed to create an other test program that can open the OpenFileName-Dialog and reads the data from the file.
from PyQt5 import QtCore, QtGui, QtWidgets
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QFileDialog
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as Navi
from matplotlib.figure import Figure
import seaborn as sns
import pandas as pd
import sip
import h5py
import mat73
import numpy as np
class MatplotlibCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width = 5, height = 4, dpi = 120):
fig = Figure(figsize = (width,height))
self.axes = fig.add_subplot(111)
super(MatplotlibCanvas,self).__init__(fig)
fig.tight_layout()
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1466, 910)
font = QtGui.QFont()
font.setFamily("Tahoma")
MainWindow.setFont(font)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView.setGeometry(QtCore.QRect(280, 0, 561, 441))
self.graphicsView.setObjectName("graphicsView")
self.graphicsView_2 = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView_2.setGeometry(QtCore.QRect(860, 0, 561, 441))
self.graphicsView_2.setObjectName("graphicsView_2")
self.graphicsView_3 = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView_3.setGeometry(QtCore.QRect(280, 440, 561, 441))
self.graphicsView_3.setObjectName("graphicsView_3")
self.graphicsView_4 = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView_4.setGeometry(QtCore.QRect(860, 440, 561, 441))
self.graphicsView_4.setObjectName("graphicsView_4")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(40, 90, 75, 23))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.action_Open = QtWidgets.QAction(MainWindow)
self.action_Open.setObjectName("action_Open")
self.action_Save = QtWidgets.QAction(MainWindow)
self.action_Save.setObjectName("action_Save")
self.action_Export = QtWidgets.QAction(MainWindow)
self.action_Export.setObjectName("action_Export")
self.action_Exit = QtWidgets.QAction(MainWindow)
self.action_Exit.setObjectName("action_Exit")
self.filename = ''
self.canv = MatplotlibCanvas(self)
self.df = []
self.toolbar = Navi(self.canv, self.centralwidget)
self.pushButton.clicked.connect(self.getFile)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def getFile(self):
""" this function will get the adress of the mat file location
also calls a readData function
"""
self.filename = QFileDialog.getOpenFileName(filter="mat (*.mat)")[0]
print("File: ", self.filename)
self.readData()
def readData(self):
self.df = mat73.loadmat(self.filename, use_attrdict=True)
struct = self.df['DemoData']
print(struct.Nr.data)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Open "))
self.action_Open.setText(_translate("MainWindow", "&Open"))
self.action_Save.setText(_translate("MainWindow", "&Save"))
self.action_Export.setText(_translate("MainWindow", "&Export"))
self.action_Exit.setText(_translate("MainWindow", "&Quit"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Since I can read the data, next step would be to create the surface plots and display the data. My idea was to use the graphicsView elements to display the four needed plots, but I just can't find how to link the figures, I used in the first test program (without GUI) to the graphicsView element. For the figure I used the following code line:
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
surf = ax.plot_surface(pArray, rArray, trArray, alpha = 0.5)
surf = ax.plot_surface(pArray, rArray, tArray, cmap=cm.jet, alpha = 1)
Can someone give me a tip, how I could achieve that?
Edit: I uploaded a .mat File .mat File

I have to note that:
mat73 has trouble reading the provided .mat so I use scipy.
The data contained in the .mat are one-dimensional arrays so they could not form a surface since for this two-dimensional arrays are required so I will only show how to draw the points.
Due to the large number of dots, painting takes time and may freeze
The logic is to work with the FigureCanvas and create 3d plots:
from functools import cached_property
from PyQt5.QtWidgets import QApplication, QFileDialog, QMainWindow
from matplotlib.backends.backend_qt5agg import (
FigureCanvas,
NavigationToolbar2QT as NavigationToolbar,
)
from matplotlib.figure import Figure
from matplotlib import cm
import scipy.io as sio
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ax = self.canvas.figure.add_subplot(projection="3d")
self.setCentralWidget(self.canvas)
self.addToolBar(self.toolbar)
file_menu = self.menuBar().addMenu("&File")
open_action = file_menu.addAction("&Open")
open_action.triggered.connect(self.handle_open_action_triggered)
#cached_property
def canvas(self):
return FigureCanvas()
#cached_property
def toolbar(self):
return NavigationToolbar(self.canvas, self)
def handle_open_action_triggered(self):
filename, _ = QFileDialog.getOpenFileName(self, filter="mat (*.mat)")
if filename:
self.load_mat(filename)
def load_mat(self, filename):
res = sio.loadmat(filename)
record = res["record"]
data = record["Data"]
temp_ref = data[0, 0]["TempRef"][0, 0][0, 0]["data"]
nr = data[0][0]["Nr"][0, 0][0, 0]["data"]
temp_act = data[0, 0]["TempAct"][0, 0][0, 0]["data"]
self.update_plot(temp_ref, nr, temp_act)
def update_plot(self, x, y, z):
print(x.shape, y.shape, z.shape)
self.ax.scatter(x, y, z)
self.canvas.draw()
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Related

PyQt5 3D scatterplot widget not showing up

Goal: Generate a 3D scatter plot from radar data obtained from vTrig_DataCollect.
Scatterplot_widget is not being shown in the MainWindow.
Step 1 is to make the plot show up from a single data collection.
Step 2 is to repeatedly call vTrig_DataCollect and have the plot refresh at 1 Hz.
from PyQt5 import QtCore, QtGui, QtWidgets
import time
from PyQt5 import QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import vTrig_DataCollect
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
self.scatterplot_widget = QtWidgets.QWidget(self.centralwidget)
self.scatterplot_widget.setGeometry(QtCore.QRect(0, 0, 800, 500))
self.scatterplot_widget.setObjectName("scatterplot_widget")
self.fig = Figure()
self.canvas = FigureCanvas(self.fig)
self.axes = self.fig.add_subplot(111, projection='3d')
payload_data = vTrig_DataCollect.data_collect()
x_points = payload_data['x']
y_points = payload_data['y']
z_points = payload_data['z']
intensity = payload_data['intensity']
self.scatterplot_widget = self.axes.scatter(x_points, y_points, z_points, s=4, c=intensity)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Visualization_Window"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
The majority of the code was generated using Qt Designer, then I added the 9 lines of code related to my plot.
You must not modify the file generated by pyuic5 so you must restore the file by running: python -m pyuic5 your_ui.ui -o mainwindow.py -x, also I will assume that the file vTrig_DataCollect.py is:
import numpy as np
def data_collect():
N = 50
return {
"x": np.random.rand(N),
"y": np.random.rand(N),
"z": np.random.rand(N),
"intensity": np.random.rand(N),
}
The idea is to create the canvas (which is a QWidget too) and place it on top of another widget using a layout, then update the canvas with the new data.
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from mainwindow import Ui_MainWindow
import vTrig_DataCollect
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.canvas = FigureCanvas(Figure())
self.axes = self.canvas.figure.add_subplot(111, projection="3d")
lay = QVBoxLayout(self.ui.scatterplot_widget)
lay.addWidget(self.canvas)
timer = QTimer(self, interval=1000, timeout=self.handle_timeout)
timer.start()
def handle_timeout(self):
payload_data = vTrig_DataCollect.data_collect()
x_points = payload_data["x"]
y_points = payload_data["y"]
z_points = payload_data["z"]
intensity = payload_data["intensity"]
self.axes.clear()
self.axes.scatter(x_points, y_points, z_points, s=4, c=intensity)
self.canvas.draw()
def main():
app = QApplication([])
w = MainWindow()
w.show()
app.exec_()
if __name__ == "__main__":
main()

The graph is not drawn in the matplotlib

I'm drawing a graph in the matplotlib by converting to FFT with Arduino data. However, the same error does not cause a graph. I think it's because of self in update() what should I do? I don't know how to change when there is a Typeerror in my code. If you find a problem, can you tell me?
+ I solved the error. However, the graph is not printed. The code has been modified as a whole. What happen?
from PyQt5.QtWidgets import*
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import random
from PyQt5 import QtCore, QtGui, QtWidgets
import datetime
import serial
import time
import random
import numpy as np
from matplotlib import animation
from collections import deque # import a "circular" list
from threading import Thread, Lock
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1212, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.widget = matplotlibWidget()
self.widget.setObjectName("widget")
self.gridLayout.addWidget(self.widget, 0, 0, 1, 1)
self.centralwidget.setLayout(self.gridLayout)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
#from matplotlibwidgetFile import matplotlibWidget
class matplotlibWidget(QWidget):
def __init__(self, parent = None):
QWidget.__init__(self,parent)
self.i = 0
self.data = []
lock = Lock()
freq = 2000 # 1/T
self.guarda = 100 # 200
r = range(0, int(freq/2+1), int(freq/self.guarda))
self.frequencia = np.fft.fftfreq(self.guarda, d=1/freq)
self.acelx = deque([], maxlen=self.guarda)
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111)
self.canvas = FigureCanvas(self.fig)
self.right_layout = QVBoxLayout()
self.right_layout.addWidget(self.canvas)
self.setLayout(self.right_layout)
self.ax.set_xlim((0,int(freq/2)))
self.ax.set_ylim((0,1000))
self.line, = self.ax.plot([],[])
self.ax.grid(True)
def data_input():
for line in arduinoData:
try:
self.i+=1
self.acelx.append(float(line))
with lock:
if self.i > len(self.acelx):
self.data = np.fft.fft(self.acelx)
except ValueError:
pass
t = Thread(target=data_input)
t.daemon = True
t.start()
S = Scope(self.line,self.frequencia, self.guarda, self.data, self.ax, self.acelx, self.i )
timer = QtCore.QTimer()
timer.timeout.connect(S.update)
timer.start(0)
class Scope(matplotlibWidget) :
def __init__(self, line, frequencia, guarda, data, ax, acelx, i) :
self.line, = line,
self.ax = ax
self.frequencia = frequencia
self.guarda = guarda
self.data = data
self.acelx = acelx
self.i = i
def update(self) :
if self.i > len(self.acelx) :
self.line.set_data(self.frequencia[:int(self.guarda/2)], abs(np.real(self.data[:int(self.guarda/2)])))
self.ax.figure.canvas.draw()
return (self.line,)
if __name__ == "__main__":
import sys
value = [0,0,0,0,0,0,0,0,0,0]
arduinoData = serial.Serial('com5', 9600)
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
You have to create instance:
s = Scope()
timer = QtCore.QTimer()
timer.timeout.connect(s.update)
or
timer = QtCore.QTimer()
timer.timeout.connect(Scope().update)

How to set yaxis tick label in a fixed position so that when i scroll left or right the yaxis tick label should be visible?

in my program i have taken figure first then i import figue into canvas. Then i import canvas into scroll area. when i run my program ,then if i turn left scroll the yaxis tick label goes hide or i turn right scroll the yaxis tick label goes also hide.
i have taken two axis. axis,axis2. i have set axes2.yaxis.tick_right() and axes.yaxis.tick_right().
I want that the yaxis tick label will stay at right side and alyas visible, whatever i turn scroll left or right .
import sys
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from PyQt5.QtWidgets import QMainWindow,QVBoxLayout
from PyQt5.QtWidgets import QApplication
from PyQt5 import QtCore, QtGui, QtWidgets
import datetime
from matplotlib.dates import num2date, date2num
from mpl_finance import candlestick_ochl as candlestick
import numpy as np
import matplotlib.ticker as ticker
import matplotlib.dates as mdates
import pylab as pl
class MainWindow_code_serarch(object):
def setup_code_serarch(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(870, 680)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayoutWidget1 = QtWidgets.QWidget(self.centralwidget)
self.verticalLayoutWidget1.setGeometry(QtCore.QRect(17, 30, 741, 13))
self.verticalLayoutWidget1.setObjectName("verticalLayoutWidget")
self.verticalLayout1 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget1)
self.verticalLayout1.setContentsMargins(0, 0, 0, 0)
self.verticalLayout1.setObjectName("verticalLayout1")
self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(17, 10, 940, 603))
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.figure = Figure(figsize=(100,7.2), dpi=80, facecolor='k')
self.canvas = FigureCanvas(self.figure)
self.widget = QtWidgets.QWidget()
self.scroll_area = QtWidgets.QScrollArea(self.widget)
self.scroll_area.setWidget(self.canvas)
self.verticalLayout.addWidget(self.scroll_area)
axes,axes2 = self.figure.subplots(nrows=2, sharex=True)
data = {
'date': ['2018/10/30', '2018/11/03', '2018/11/04', '2018/11/05', '2018/11/07', '2018/11/10', '2018/11/11'],
'open': [8824, 8726.31, 8642.14, 8531.51, 8630.25, 8602.50, 8640.22],
'high': [8858, 8748.60, 8551.36, 8653.16, 8476.69, 8630, 8570.56],
'low': [8688, 8743.67, 8550.76, 8449.50, 8631.83, 8602.18, 8743.22],
'close': [8820, 8747.17, 8550.52, 8553., 8517.10, 8628.78, 8588.52],
'volume': [17759.56, 120000.17, 18739.52, 38599.50, 16517.10, 17723.78, 15588.52]
}
x = date2num([datetime.datetime.strptime(d, '%Y/%m/%d').date() for d in data['date']])
t= np.arange(len(data['date']))
candle_trace = zip(t, data['open'], data['high'], data['low'], data['close'], data['volume'])
candlestick(axes, candle_trace, width=.75, colorup='g', colordown='r')
axes2.plot(t, [1, 2, 3, 4, 7, 8, 9])
axes.set_position([0.02, 0.37, 0.88, 0.6])
axes2.set_position([0.02, 0.15, 0.88, 0.22])
axes.tick_params(axis='both', color='#ffffff', labelcolor='#ffffff')
axes.yaxis.tick_right()
axes2.tick_params(axis='both', color='#ffffff', labelcolor='#ffffff')
axes2.grid(color='lightgray', linewidth=.5, linestyle=':')
axes.grid(color='lightgray', linewidth=.5, linestyle=':')
axes2.yaxis.tick_right()
axes.autoscale_view()
axes2.autoscale_view()
axes.set_facecolor('#041105')
axes2.set_facecolor('#041105')
# N = len(dates)
axes.set_xticks(range(0, len((x)), 1))
axes.set_xticklabels([mdates.num2date(d).strftime('%b-%d') for d in x])
axes.set_xticklabels([mdates.num2date(d).strftime('%Y-%m-%d') for d in x])
axes2.set_xticklabels([mdates.num2date(d).strftime('%Y-%m-%d') for d in x])
self.canvas.draw()
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 246, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
# self.pushButton.clicked.connect(self.graphShowCode)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
# self.pushButton.setText(_translate("MainWindow", "OK"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = MainWindow_code_serarch()
ui.setup_code_serarch(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Output image:
when i turn scroll left output image 2:
Here is a way to scroll the content of an axes with a PyQt QtScrollBar. This is done by changing the limits of the axes depending on the scroll bar's value. To this end, a callback to the QtScrollBar's actionTriggered method is registered that changes the limits of the axes.
import sys
import matplotlib
# Make sure that we are using QT5
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from PyQt5 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import numpy as np
class ScrollableWindow(QtWidgets.QMainWindow):
def __init__(self, fig, ax, step=0.1):
plt.close("all")
if not QtWidgets.QApplication.instance():
self.app = QtWidgets.QApplication(sys.argv)
else:
self.app = QtWidgets.QApplication.instance()
QtWidgets.QMainWindow.__init__(self)
self.widget = QtWidgets.QWidget()
self.setCentralWidget(self.widget)
self.widget.setLayout(QtWidgets.QVBoxLayout())
self.widget.layout().setContentsMargins(0,0,0,0)
self.widget.layout().setSpacing(0)
self.fig = fig
self.ax = ax
self.canvas = FigureCanvas(self.fig)
self.canvas.draw()
self.scroll = QtWidgets.QScrollBar(QtCore.Qt.Horizontal)
self.step = step
self.setupSlider()
self.nav = NavigationToolbar(self.canvas, self.widget)
self.widget.layout().addWidget(self.nav)
self.widget.layout().addWidget(self.canvas)
self.widget.layout().addWidget(self.scroll)
self.canvas.draw()
self.show()
self.app.exec_()
def setupSlider(self):
self.lims = np.array(self.ax.get_xlim())
self.scroll.setPageStep(self.step*100)
self.scroll.actionTriggered.connect(self.update)
self.update()
def update(self, evt=None):
r = self.scroll.value()/((1+self.step)*100)
l1 = self.lims[0]+r*np.diff(self.lims)
l2 = l1 + np.diff(self.lims)*self.step
self.ax.set_xlim(l1,l2)
print(self.scroll.value(), l1,l2)
self.fig.canvas.draw_idle()
# create a figure and some subplots
fig, ax = plt.subplots()
t = np.linspace(0,3000,101)
x = np.cumsum(np.random.randn(len(t)))
ax.plot(t,x, marker="o")
# pass the figure to the custom window
a = ScrollableWindow(fig,ax)
For a Scrollbar within the figure, see Scrollable Bar graph matplotlib
The above answer works well, but does not hand back control to the spyder window or python command line. Also in spyder it could be run only once. Added a few more points seen from another thread on exiting from QT window and improved to this.
import sys
import matplotlib
# Make sure that we are using QT5
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from PyQt5 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import numpy as np
from PyQt5.QtWidgets import QMainWindow, QLabel, QGridLayout, QWidget
from PyQt5.QtCore import QSize
class HelloWindow(QMainWindow):
def __init__(self, fig, ax , step = 0.1):
plt.close("all")
if not QtWidgets.QApplication.instance():
self.app = QtWidgets.QApplication(sys.argv)
else:
self.app = QtWidgets.QApplication.instance()
QMainWindow.__init__(self)
self.setMinimumSize(QSize(1500, 100))
self.setWindowTitle("Value Plotting")
self.step = step
self.widget = QWidget()
self.setCentralWidget( self.widget )
self.widget.setLayout(QtWidgets.QVBoxLayout())
self.widget.layout().setContentsMargins(0,0,0,0)
self.widget.layout().setSpacing(0)
self.fig = fig
self.ax = ax
self.canvas = FigureCanvas(self.fig)
self.canvas.draw()
self.scroll = QtWidgets.QScrollBar(QtCore.Qt.Horizontal)
self.step = step
self.setupSlider()
self.nav = NavigationToolbar(self.canvas, self.widget)# self.widget.layout().addWidget(self.nav)
self.widget.layout().addWidget(self.canvas)
self.widget.layout().addWidget(self.scroll)
menu = self.menuBar().addMenu('Action for quit')
action = menu.addAction('Quit')
action.triggered.connect(QtWidgets.QApplication.quit)
self.canvas.draw()
def setupSlider(self):
self.lims = np.array(self.ax.get_xlim())
self.scroll.setPageStep(self.step*100)
self.scroll.actionTriggered.connect(self.update)
self.update()
def update(self, evt=None):
r = self.scroll.value()/((1+self.step)*100)
l1 = self.lims[0]+r*np.diff(self.lims)
l2 = l1 + np.diff(self.lims)*self.step
self.ax.set_xlim(l1,l2)
print(self.scroll.value(), l1,l2)
self.fig.canvas.draw_idle()
if __name__ == "__main__":
def run_app(fig,ax):
app = QtWidgets.QApplication(sys.argv)
mainWin = HelloWindow(fig,ax)
mainWin.show()
app.exec_()
fig, ax = plt.subplots()
t = np.linspace(0,3000,101)
x = np.cumsum(np.random.randn(len(t)))
ax.plot(t,x, marker="o")
run_app(fig,ax)
Found it running well on the python console. Exiting roughly in Spyder. Top close button not working, but exiting when operating from menu.

Can seaborn and networkx be integrated into GUI via matplotlib?

Using the code below, I can plot basic matplotlib plots in a gui designed in pyqt5 (such as giving it a list of xs and ys and it plots the points). However, I cannot plug in advanced modules such as seaborn or networkx (lets focus on seaborn) that utilize the plotting functionality of matplotlib to display the data you generate with the functions.
from PyQt5 import QtCore, QtGui, QtWidgets
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.widget = MplWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(200, 110, 391, 311))
self.widget.setObjectName("widget")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(250, 40, 231, 61))
self.label.setObjectName("label")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(50, 180, 113, 32))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.pushButton.clicked.connect(self.Graphitdude)
def Graphitdude(self):
Lister3 = pd.read_csv("Betadata.csv",index_col=[0])#just a collection of labels and assorted correlation values ranging from 0 to 1 to be constructed into a heatmap.
plot = sns.heatmap(Lister3) # This is the problematic function, it does it, and I can display it IN LINE but not in the gui canvas?
plt.yticks(rotation=0)
self.widget.canvas.ax.plot()#if passed discreet x and y values, it graphs it, but it doesnt like to pass the seaborn figure?
self.widget.canvas.draw()
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:24pt; font-weight:600;\">Test</span></p></body></html>"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
from mplwidget import MplWidget
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
mplwidget.py is as follows:
from PyQt5 import QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
import matplotlib
matplotlib.use('QT5Agg')
# Matplotlib canvas class to create figure
class MplCanvas(Canvas):
def __init__(self):
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
Canvas.__init__(self, self.fig)
Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
Canvas.updateGeometry(self)
# Matplotlib widget
class MplWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) # Inherit from QWidget
self.canvas = MplCanvas() # Create canvas object
self.vbl = QtWidgets.QVBoxLayout() # Set box for plotting
self.vbl.addWidget(self.canvas)
self.setLayout(self.vbl)
My best idea is that these functions are designing their own matplotlib figure (or subplot, not sure), and this figure cannot be supplied to the widget code by the methods I have tried.
sns.heatmap(xxxx) returns "ax", which should be able to be used by the mplwidget.py script, right? Can I pass these to the canvas to display seaborn graphics?
According to the documentation:
seaborn.heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False, annot=None, fmt='.2g', annot_kws=None, linewidths=0, linecolor='white', cbar=True, cbar_kws=None, cbar_ax=None, square=False, xticklabels='auto', yticklabels='auto', mask=None, ax=None, **kwargs)
[...]
ax : matplotlib Axes, optional
Axes in which to draw the plot, otherwise use the currently-active Axes.
So then you should just pass the AxesSubplot of MplCanvas as parameter ax:
def Graphitdude(self):
Lister3 = pd.read_csv("Betadata.csv",index_col=[0])
plot = sns.heatmap(Lister3, ax=self.widget.canvas.ax)
plt.yticks(rotation=0)
self.widget.canvas.draw()
I have used many functions similar to heatmap and always provide that parameter.

Connecting Pyside with Matplotlib using QtDesigner - using pushButton to draw

This is a followup question from this one. Connecting Pyside with matplotlib
My PythonFu is failing me to do a simple thing: design a GUI using QtDesigner, convert it, and do a QPushButton to draw something. It works when QtDesigner is not being used, but QtDesigner will be needed as the application grows more complex, so it must be used. Here is the code:
** main.py **
import sys
import platform
import numpy as np
import PySide
from PySide import QtCore
from PySide.QtGui import QApplication, QMainWindow, QTextEdit,\
QPushButton, QMessageBox, QWidget, QVBoxLayout
__version__ = '0.0.1'
from mpl import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.main_frame = Ui_MainWindow()
self.main_frame.setupUi(self)
#self.button = QPushButton('Run')
def plot_stuff(self):
x = np.arange(1024)
self.main_frame.widget.axes.plot(np.exp(-x / 256) * np.cos(2 * np.pi * x / 32), 'g')
self.main_frame.widget.canvas.draw()
if __name__ == '__main__':
app = QApplication(sys.argv)
frame = MainWindow()
frame.main_frame.pushButton.clicked.connect(frame.plot_stuff)
frame.show()
app.exec_()
** matplotlibwidget.py **
import matplotlib
matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4']='PySide'
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class MatplotlibWidget(FigureCanvas):
def __init__(self, parent=None):
super(MatplotlibWidget, self).__init__(Figure())
self.setParent(parent)
self.figure = Figure()
self.canvas = FigureCanvas(self.figure)
self.axes = self.figure.add_subplot(111)
and ** mpl.py **, converted from mpl.ui
from PySide import QtCore, QtGui
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 480)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtGui.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(20, 410, 74, 20))
self.pushButton.setObjectName("pushButton")
self.widget = MatplotlibWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(100, 40, 471, 321))
self.widget.setObjectName("widget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 17))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton.setText(QtGui.QApplication.translate("MainWindow", "Run", None, QtGui.QApplication.UnicodeUTF8))
from widgets.matplotlibwidget import MatplotlibWidget
The button connection works, but the graph is never shown.
Thanks!
In your main.py module replace
self.main_frame.widget.canvas.draw()
with
self.main_frame.widget.draw()
From my understanding of matplotlib you were drawing the wrong canvas. According to the docs the widget that you promoted is now your canvas and that's the one you're supposed to draw.

Categories

Resources