在 PyQt5 中嵌入 Matplotlib 图形
Posted
技术标签:
【中文标题】在 PyQt5 中嵌入 Matplotlib 图形【英文标题】:Embed Matplotlib Graph in a PyQt5 【发布时间】:2021-06-30 08:40:36 【问题描述】:我正在尝试将 matplotlib 图形嵌入到 PqQt5 中,我有一个现成的函数可以调用它们,但是我没有成功。图的代码如下:
import re
import os
import sys
import json
import numpy as np
import pylab
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.pyplot as plt
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA_DIR = BASE_DIR + os.path.sep + 'data'
if not os.path.exists(DATA_DIR ):
popup_critical('Грешен път до данните')
with open('./data/71161.json', 'r') as f:
data = json.load(f)
for distro in data:
downwelling_radiance = np.array(distro['spectra']['ld']['data'])
irradiance_reflectance = np.array(distro['spectra']['r0minuscorr']['data'])
downwelling_irradiance = np.array(distro['spectra']['ed']['data'])
upwelling_radiance = np.array(distro['spectra']['lu']['data'])
wavelength = np.array(distro['spectra']['wavelength']['data'])
reflectance = np.array(distro['spectra']['r0minus']['data'])
date = np.array(distro['meta']['date'])
name = np.array(distro['meta']['id'])
def radiance_plot():
fig = plt.figure(figsize=(14, 8))
plt.title("Plot")
plt.xlabel('Wavelength [nm]')
plt.ylabel('Radiance [W/(m^2xnmxsr)]')
ax=plt.gca()
ax.set_xlim(400,800)
plt.grid(True, color='skyblue')
plt.plot(
wavelength, downwelling_radiance, 'orange',
wavelength, upwelling_radiance, 'burlywood',
lw=3,
)
print(np.arange(0, max(downwelling_radiance + 0.02) if max(downwelling_radiance) >
max(upwelling_radiance) else max(upwelling_radiance + 0.02), step=0.02))
print(list(np.arange(0, max(downwelling_radiance + 0.02) if max(downwelling_radiance) >
max(upwelling_radiance) else max(upwelling_radiance + 0.02), step=0.02)))
plt.ylim(0.00)
plt.yticks(list(np.arange(0, max(downwelling_radiance + 0.02) if max(downwelling_radiance)
> max(upwelling_radiance) else max(upwelling_radiance + 0.02), step=0.02)))
plt.legend(['Upwelling radiance', 'Downwelling radiance'], loc='upper left')
plt.twinx(ax = None)
plt.plot(
wavelength, downwelling_irradiance, 'c',
lw=3,
)
plt.grid(True)
plt.ylabel('Irradiance [W/(m^2xnm)]')
plt.yticks(list(np.arange(0, max(downwelling_irradiance + 0.2), 0.2)))
plt.legend(['Downwelling irradiance'], loc='upper right')
fig.tight_layout()
return plt.show()
def reflectance_plot():
fig = plt.figure(figsize=(14, 8))
plt.title("Plot")
plt.xlabel('Wavelength [nm]')
plt.ylabel('Reflectance [-]')
ax=plt.gca()
ax.set_xlim(400,800)
plt.grid(True)
plt.plot(
wavelength, reflectance, 'burlywood',
lw=3,
)
plt.ylim(0.00)
plt.yticks(list(np.arange(0, max(reflectance + 0.02), step=0.01)))
plt.legend(['Radiance'], loc='upper right')
fig.tight_layout()
return plt.show()
def date_print():
return date
def name_print():
return name
#radiance_plot()
#reflectance_plot()
#name_print()
#date_print()
上面的代码打印图表,现在我想在 PyQt5 中打印图表,这样当用户按下按钮 1 时,它会打印第一个图表,第二个按钮打印第二个图表。有 PyQt5 的代码
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QListWidget,
QMainWindow, QPushButton
import sys
from PyQt5.QtGui import QIcon, QFont
from read import date_print, name_print, radiance_plot, reflectance_plot
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 400, 300)
self.setWindowTitle("Python and Matplotlib")
self.create_list()
self.myUI()
#chart = Canvas(self)
def create_list(self):
vbox = QVBoxLayout()
self.list_widget = QListWidget()
self.list_widget.insertItem(0, "File1")
self.list_widget.insertItem(1, "File2")
self.list_widget.insertItem(2, "file3")
self.list_widget.setStyleSheet("background-color:red")
self.list_widget.setFont(QFont("Sanserif", 15))
self.list_widget.clicked.connect(self.item_clicked)
self.label = QLabel("")
self.setFont(QFont("Sanserif", 14))
self.label.setStyleSheet("color:green")
vbox.addWidget(self.list_widget)
vbox.addWidget(self.label)
self.setLayout(vbox)
def item_clicked(self):
item = self.list_widget.currentItem()
self.label.setText("You have selected file:" + str(name_print()) + "; Date: " +
str(date_print()))
def myUI(self):
#canvas = Canvas(self, width=8, height=4)
#canvas.move(0,0)
butt = QPushButton("Click Me", self)
butt.move(100, 100)
butt2 = QPushButton("Click Me 2", self)
butt2.move(250, 100)
"""
class Canvas(FigureCanvas):
def __init__(self, parent):
fig, self.ax = plt.subplots(figsize=(5,4), dpi = 50)
super().__init__(fig)
self.setParent(parent)
self.plot()
def plot(self):
ref = self.figure.add_subplot(111)
ref.pie(reflectance_plot(), labels=labels)
"""
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec_())
我尝试连接它们,但无法打印任何内容。我找到了一种打印图表的方法,但是在我的情况下它不起作用
import sys
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from read import wavelength, downwelling_radiance, upwelling_radiance
import pandas as pd
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
# Create the maptlotlib FigureCanvas object,
# which defines a single set of axes as self.axes.
sc = MplCanvas(self, width=10, height=5, dpi=100)
# Create our pandas DataFrame with some simple
# data and headers.
df = pd.DataFrame([
[0, 10], [5, 15], [2, 20], [15, 25], [4, 10],
], columns=['A', 'B'])
# plot the pandas DataFrame, passing in the
# matplotlib Canvas axes.
df.plot(ax=sc.axes)
# Create toolbar, passing canvas as first parament, parent (self, the MainWindow) as second.
toolbar = NavigationToolbar(sc, self)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(toolbar)
layout.addWidget(sc)
# Create a placeholder widget to hold our toolbar and canvas.
widget = QtWidgets.QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.show()
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
app.exec_()
知道如何连接它们
【问题讨论】:
【参考方案1】:我为您创建了这个最小的示例,展示了如何将 matplotlib 绘图嵌入到您的 pyqt5 应用程序中(同样适用于 pyside2)。 我在您的代码中看到,您一直在调用 matplotlib.pyplot。嵌入 gui 后端时,您不应该与 pyplot 交谈。 该示例还说明了如何通过调用轴/图形对象上的方法而不是通过 plt 来设置网格、图例等。 有 3 个按钮,玩弄它,您将很快了解如何嵌入 matplotlib 以及如何处理您的“自定义绘图小部件”。 编辑:使用键盘键 1、2、3,您也可以调用绘图方法。
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
# in case of pyside: just replace PyQt5->PySide2
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT
from matplotlib.figure import Figure
class MplWidget(qtw.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
fig = Figure(figsize=(5, 5))
self.can = FigureCanvasQTAgg(fig)
self.toolbar = NavigationToolbar2QT(self.can, self)
layout = qtw.QVBoxLayout(self)
layout.addWidget(self.toolbar)
layout.addWidget(self.can)
# here you can set up your figure/axis
self.ax = self.can.figure.add_subplot(111)
def plot_basic_line(self, X, Y, label):
# plot a basic line plot from x and y values.
self.ax.cla() # clears the axis
self.ax.plot(X, Y, label=label)
self.ax.grid(True)
self.ax.legend()
self.can.figure.tight_layout()
self.can.draw()
class MyQtApp(qtw.QWidget):
def __init__(self):
super(MyQtApp, self).__init__()
# layout
self.mpl_can = MplWidget(self)
self.btn_plot1 = qtw.QPushButton('plot1', self)
self.btn_plot2 = qtw.QPushButton('plot2', self)
self.btn_plot3 = qtw.QPushButton('scatter', self)
self.layout = qtw.QVBoxLayout(self)
self.layout.addWidget(self.mpl_can)
self.layout.addWidget(self.btn_plot1)
self.layout.addWidget(self.btn_plot2)
self.layout.addWidget(self.btn_plot3)
self.setLayout(self.layout)
# connects
self.btn_plot1.clicked.connect(self.plot1)
self.btn_plot2.clicked.connect(self.plot2)
self.btn_plot3.clicked.connect(self.plot_scatter)
def keyPressEvent(self, event):
if event.key() == qtc.Qt.Key_1: self.plot1()
elif event.key() == qtc.Qt.Key_2: self.plot2()
elif event.key() == qtc.Qt.Key_3: self.plot_scatter()
def plot1(self):
X, Y = (1, 2), (1, 2)
self.mpl_can.plot_basic_line(X, Y, label='plot1')
def plot2(self):
X, Y = (10, 20), (10, 20)
self.mpl_can.plot_basic_line(X, Y, label='plot2')
def plot_scatter(self):
X, Y = (1, 7, 9, 3, 2), (3, 6, 8, 2, 11)
self.mpl_can.ax.scatter(X, Y, label='scatter')
self.mpl_can.ax.legend()
self.mpl_can.can.draw()
if __name__ == '__main__':
app = qtw.QApplication([])
qt_app = MyQtApp()
qt_app.show()
app.exec_()
https://www.mfitzp.com/tutorials/plotting-matplotlib/ 是关于如何将 matplotlib 嵌入 pyqt5 的更深入的教程,但我认为出于您的目的,上面非常基本的示例就足够了。
【讨论】:
以上是关于在 PyQt5 中嵌入 Matplotlib 图形的主要内容,如果未能解决你的问题,请参考以下文章
将 Matplotlib 图形嵌入到小部件中 - PyQt5
在 PyQt5 中嵌入 Matplotlib:工具栏不起作用
为啥我不能在 pyqt5 gui 中嵌入的 matplotlib 颜色图中成功绘制感兴趣区域?