[英]Extracting information from a Matplotlib plot and displaying it in a PyQt5 GUI
[英]issues in displaying matplotlib animated plot in pyqt5 gui and save in mp4 at the same time
目标:在mp4中同时显示和保存plot
我可以保存视频,但是当它完成保存时,它开始覆盖导致崩溃的画布,并且不会在 gui 中显示 plot。 我想我必须使用某种线程来运行 animation 但我被困在如何做到这一点。 我也可以想象我的代码中有很多缺陷。
主文件
import matplotlib.animation as animation
from matplotlib import style
import csv
import os.path
from os import path
import matplotlib.animation as animation
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import datetime
import serial.tools.list_ports
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import random
from numpy import diff
import numpy as np
LARGE_FONT = ("Verdana", 12)
import pandas as pd
style.use('fivethirtyeight')
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (QTreeWidget, QTreeWidgetItem, QPushButton, QLabel, QDialog, QVBoxLayout, QApplication, QLineEdit)
from PyQt5.QtWidgets import (QPushButton, QDialog, QTreeWidget,
QTreeWidgetItem, QVBoxLayout,
QHBoxLayout, QFrame, QLabel, QComboBox,
QApplication, QTreeWidgetItemIterator, QMessageBox, QProxyStyle)
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
import matplotlib
from matplotlib.figure import Figure
matplotlib.use('QT5Agg')
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
plt.rcParams['animation.ffmpeg_path'] = 'C:/ffmpeg/bin/ffmpeg.exe'
from anim import Ui_MainWindow
plt.ion()
writer = animation.FFMpegWriter()
plt.show()
class Test(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super().__init__(parent)
QtWidgets.QMainWindow.__init__(self, parent)
self.i = 0
self.ui = Ui_MainWindow()
self.ui.setupUi(parent)
vlay1 = QVBoxLayout()
self.plotWidget1 = FigureCanvas(Figure())
toolbar1 = NavigationToolbar(self.plotWidget1, self)
openButton = QtWidgets.QPushButton("Open a file")
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(openButton.sizePolicy().hasHeightForWidth())
openButton.setSizePolicy(sizePolicy)
dateTimeEdit = QtWidgets.QDateTimeEdit()
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(dateTimeEdit.sizePolicy().hasHeightForWidth())
dateTimeEdit.setSizePolicy(sizePolicy)
vlay1.addWidget(openButton)
vlay1.addWidget(dateTimeEdit)
vlay1.addWidget(toolbar1)
vlay1.addWidget(self.plotWidget1)
self.ui.gridLayout.addLayout(vlay1, 0, 0, 1, 1)
openButton.clicked.connect(self.openFile)
self.ax1 = self.plotWidget1.figure.subplots()
self.line, = self.ax1.plot([], [], marker='o')
self.ax1.set_xlabel("Real")
self.ax1.set_ylabel("Imaginary")
self.ax1.relim()
self.ax1.autoscale_view(True, True, True)
self.ax1.set_title(str(self.i))
self.plotWidget1.figure.tight_layout()
self.openFile()
anim = animation.FuncAnimation(self.plotWidget1.figure, self.animate, init_func=self.init,
frames=self.len-1, interval=1, blit=True)
anim.save('plot.mp4', writer=writer, dpi=300, )
def readFile(self):
df = pd.read_excel(self.fileName)
self.Real1 = df["Real 1"]
self.Real2 = df["Real 2"]
self.Real3 = df["Real 3"]
self.Real4 = df["Real 4"]
self.Real5 = df["Real 5"]
self.Img1 = df["Imaginary 1 "]
self.Img2 = df["Imaginary 2"]
self.Img3 = df["Imaginary 3"]
self.Img4 = df["Imaginary 4"]
self.Img5 = df["Imaginary 5"]
self.len = len(self.Img1)
def getDataX(self):
self.i += 1
if self.i == self.len - 1:
print("complete")
return [self.Real1[self.i], self.Real2[self.i], self.Real3[self.i], self.Real4[self.i], self.Real5[self.i]]
def getDataY(self):
return [abs(self.Img1[self.i]), abs(self.Img2[self.i]), abs(self.Img3[self.i]), abs(self.Img4[self.i]), abs(self.Img5[self.i])]
def openFile(self):
dirAndName = QtWidgets.QFileDialog.getOpenFileName(self,'Open a File', "*.xlsx")
if dirAndName[0] != []:
self.fileName = dirAndName[0]
self.readFile()
print(dirAndName)
def init(self):
self.line.set_data([], [])
return self.line,
def animate(self, i):
x = self.getDataX()
y = self.getDataY()
x = np.asarray(x)
y = np.asarray(y)
self.ax1.set_title(str(self.i))
self.line.set_data(x, y)
self.ax1.relim()
self.ax1.autoscale_view(True, True, True)
return self.line,
def Home():
f = QtWidgets.QMainWindow()
#f.resize(1699, 980)
c = Test(f)
f.show()
r = qApp.exec_()
if __name__ == "__main__":
qApp = QtWidgets.QApplication(sys.argv)
qApp.setStyle(QStyleFactory.create('Fusion'))
proxy = QProxyStyle(qApp.style())
qApp.setStyle(proxy)
Home()
动画.py
from PyQt5 import QtCore, QtGui, QtWidgets
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.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
self.pushButton.setSizePolicy(sizePolicy)
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton)
self.dateTimeEdit = QtWidgets.QDateTimeEdit(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.dateTimeEdit.sizePolicy().hasHeightForWidth())
self.dateTimeEdit.setSizePolicy(sizePolicy)
self.dateTimeEdit.setObjectName("dateTimeEdit")
self.verticalLayout.addWidget(self.dateTimeEdit)
self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Open File"))
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_())
*** 我出于其他原因使用 Anim.py,即使我的 main.py 再次创建 qpushbutton 和 qtimeedit ***
免责声明:我不会使用 OP 的代码,因为它包含不必要的元素,只会分散注意力以及无用的导入,因此我将展示一个仅关注所需功能的示例。
如果要保存并显示 GUI,则不应使用 save() 方法,因为这是阻塞的,而应直接使用 writer (FFMpegWriter),使用 setup() 方法进行配置,然后使用 grab_frame() 方法记录帧。 需要注意的是,当记录 animation 的速度时,由于记录一帧会消耗时间,从而使 eventloop 忙碌,因此会降低速度。
import sys
import numpy as np
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure
from matplotlib import animation
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.animation_button = QtWidgets.QPushButton("Start", checkable=True)
self.canvas = FigureCanvas(Figure(figsize=(5, 3)))
self.ax = self.canvas.figure.subplots()
t = np.linspace(0, 10, 101)
x, y = self.generate_data(0)
(self._line,) = self.ax.plot(x, y)
self.writer = animation.FFMpegWriter()
self.writer.setup(self.canvas.figure, outfile="plot.mp4", dpi=300)
self.anim = animation.FuncAnimation(
self.canvas.figure,
self.callback_animation,
frames=200,
interval=20,
blit=True,
)
self.animation_button.toggled.connect(self.handle_toggled)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
layout = QtWidgets.QVBoxLayout(central_widget)
layout.addWidget(self.canvas)
layout.addWidget(self.animation_button)
def callback_animation(self, i):
x, y = self.generate_data(i)
self._line.set_data(x, y)
if self.animation_button.isChecked():
self.writer.grab_frame()
return (self._line,)
def generate_data(self, i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
return x, y
def handle_toggled(self):
self.animation_button.setText(
"Stop" if self.animation_button.isChecked() else "Start"
)
def closeEvent(self, event):
super().closeEvent(event)
self.writer.finish()
if __name__ == "__main__":
qapp = QtWidgets.QApplication.instance()
if not qapp:
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
app.activateWindow()
app.raise_()
qapp.exec_()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.