如何在一个 PyQt5 窗口上应用 2 个动画(带有旋转扇区和轨迹的圆)?

问题描述 投票:0回答:1

如何在一个 PyQt5 窗口上应用 2 个动画(带有旋转扇区和轨迹的圆)?这是一段代码,这些函数分别工作,轨迹取自 JSON 文件。我尝试将 2 个动画组合成更新函数,但没有任何效果,因为我不明白如何使用“FuncAnimation”以及要传递给它的参数。如果你能帮助我,我会很高兴。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
    
class MyFigurePolar(FigureCanvas):

    def __init__(self,width=5, height=4, dpi=100, fig = None, ax = None):
        if fig == None:
            self.fig = Figure(figsize=(width, height), dpi=dpi)
            self.axes = self.fig.add_subplot(111, projection='polar')
        else:
            self.fig = fig
            self.axes = ax
        super(MyFigurePolar, self).__init__(self.fig)


def anim_2d(self):
        data = self.file
        fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})
        ax.set_xlabel("X")
        ax.set_ylabel("Y")
        ax.grid(True)

        points = make_points_between(data['trajectory']).T

        def update(num, points, ln):

            ln.set_data(np.arctan2(points[0, :num], points[1, :num]),
                        np.sqrt(points[0, :num] ** 2 + points[1, :num] ** 2))

            return ln,

        def update1(frame):
            ax.clear()
            r = 7
            period = np.pi / 64
            sector = ax.fill_between([], [], [], alpha=0.5, facecolor='red')  # Начинать с красного цвета
            theta = np.linspace(0, 2 * np.pi, 100)
            ax.set_theta_zero_location("N")
            ax.set_theta_direction(-1)
            ax.plot(theta, np.ones(100) * r, linestyle='-', color='black')
            start = frame * np.pi / 180
            end = start - period
            sector = ax.fill_between([start, end], 0, r, alpha=0.5, facecolor='red')
            ax.set_yticklabels([5000, 10000, 15000, 20000, 25000])

            return sector,


        ln, = ax.plot(np.arctan2(points[0, 0:1], points[1, 0:1]), np.sqrt(points[0, 0:1] ** 2 + points[1, 0:1] ** 2))
        ax.set_xlim([np.min(points[0, :]), np.max(points[0, :])])
        ax.set_xlabel('X')

        ax.set_ylim([np.min(points[1, :]), np.max(points[1, :])])
        ax.set_ylabel('Y')

        self.anim = FuncAnimation(fig, update, len(points[0]), fargs=(points, ln, None), interval=10000 / len(points[0]),
                              blit=False)
        self.anim0 = FuncAnimation(fig, update1, frames=360, fargs=(points, ln, None), interval=15, blit=True)

        return MyFigurePolar(fig=fig, ax=ax)

    def myfunc(self):
        F = self.anim_2d()


        self.gridlayout = QGridLayout(self.groupBox)
        self.gridlayout.addWidget(F, 0, 1)

我试图在互联网上查找信息,但一直没有找到。

pyqt5
1个回答
0
投票

要使用 FuncAnimation 将两个动画合并到一个 PyQt5 窗口中,您需要创建一个更新函数来同时更新两个动画。您可以通过以下方式修改代码来实现此目的:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt5.QtWidgets import QWidget, QVBoxLayout
import json

class MyFigurePolar(FigureCanvas):
    def __init__(self, width=5, height=4, dpi=100, fig=None, ax=None):
        if fig is None:
            self.fig = Figure(figsize=(width, height), dpi=dpi)
            self.axes = self.fig.add_subplot(111, projection='polar')
        else:
            self.fig = fig
            self.axes = ax
        super(MyFigurePolar, self).__init__(self.fig)

def make_points_between(trajectory):
    # Dummy function for demonstration
    # You should implement this according to your JSON data structure
    return np.array([[0, 1, 2, 3, 4], [0, 1, 2, 1, 0]])

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Animation Demo')
        layout = QVBoxLayout(self)
        self.figure_canvas = MyFigurePolar()
        layout.addWidget(self.figure_canvas)

        self.anim_2d()
        self.anim_sector()

        self.show()

    def anim_2d(self):
        with open('trajectory.json') as f:
            data = json.load(f)

        points = make_points_between(data['trajectory']).T
        self.ln, = self.figure_canvas.axes.plot(np.arctan2(points[0, 0:1], points[1, 0:1]),
                                                np.sqrt(points[0, 0:1] ** 2 + points[1, 0:1] ** 2))

        def update(num):
            self.ln.set_data(np.arctan2(points[0, :num], points[1, :num]),
                             np.sqrt(points[0, :num] ** 2 + points[1, :num] ** 2))
            self.update_sector(num)
            return self.ln,

        self.anim = FuncAnimation(self.figure_canvas.fig, update, frames=len(points[0]), interval=10000 / len(points[0]))

    def update_sector(self, frame):
        r = 7
        period = np.pi / 64
        self.sector.remove() if hasattr(self, 'sector') else None
        start = frame * np.pi / 180
        end = start - period
        self.sector = self.figure_canvas.axes.fill_between([start, end], 0, r, alpha=0.5, facecolor='red')
        self.figure_canvas.draw()

    def anim_sector(self):
        self.anim0 = FuncAnimation(self.figure_canvas.fig, self.update_sector, frames=360, interval=15)

if __name__ == '__main__':
    import sys
    from PyQt5.QtWidgets import QApplication

    app = QApplication(sys.argv)
    widget = MyWidget()
    sys.exit(app.exec_())

在此代码中:

  • 我创建了一个继承自 QWidget 的 MyWidget 类来保存 PyQt5 窗口。
  • 在 MyWidget 的 initUI 方法中,我创建了布局并向其中添加了 MyFigurePolar 实例。
  • 我添加了两个方法 anim_2d 和 anim_sector 分别处理轨迹和旋转扇区的动画。
  • 在 anim_2d 方法中,我从 JSON 文件加载轨迹数据(您需要将“trajectory.json”替换为 JSON 文件的路径)并创建轨迹动画。
  • 我定义了一个更新函数,可以同时更新轨迹和扇区动画。 update_sector 方法更新扇区动画。
  • 最后,我在anim_sector方法中创建了扇形动画的FuncAnimation实例。

此代码应创建一个 PyQt5 窗口,其中两个动画同时运行。根据您的应用程序的需要调整文件路径和动画参数。

© www.soinside.com 2019 - 2024. All rights reserved.