簡體   English   中英

在 pyqt5 gui 中顯示 matplotlib 動畫 plot 並同時保存在 mp4 中的問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM