Как добавить ползунок к анимации FuncAnimation?

Мне нужен способ, который позволяет с помощью слайдера/ползунка QSlider управлять анимацией.

Анимация идёт непрерывно и за текущим кадром движется и ползунок. В любой момент я должен иметь возможность перемотать анимацию с помощью слайдера на нужный мне кадр. Код, в который требуется внедрить слайдер.

import matplotlib
import numpy as np
from PyQt5 import QtCore, QtWidgets

# Make sure that we are using QT5
matplotlib.use('Qt5Agg')
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.animation as animation


class MyMplCanvas(FigureCanvas):
    def __init__(self, slider, parent=None, width=5, height=4, dpi=100):
        self.slider = slider  # Save reference to the slider
        self.slider_is_manual = False  # Flag to track if slider change is manual
        fig = Figure(figsize=(width, height), dpi=dpi)

        ax = fig.add_subplot(111)    # The big subplot
        self.ax = fig.add_subplot(211)
        self.bx = fig.add_subplot(212)

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                                   QtWidgets.QSizePolicy.Expanding,
                                   QtWidgets.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        ax.set_title('TMP102 Temperature over Time')
        ax.spines['top'].set_color('none')
        ax.spines['bottom'].set_color('none')
        ax.spines['left'].set_color('none')
        ax.spines['right'].set_color('none')
        ax.tick_params(labelcolor='w', top=False, bottom=False, left=False, right=False)
        ax.set_xlabel('Samples')
        ax.set_ylabel('Temperature (deg C)')

        self.x_len = 200         # Number of points to display
        self.y_range = [10, 40]  # Range of possible Y values to display
        self.xs = list(range(0, 200))

        self.ys = [0 for _ in range(self.x_len)]

        frames = np.arange(0, 200)
        self.anim = animation.FuncAnimation(fig, self.animate, frames=frames, init_func=self.init, interval=50, blit=True, repeat=False)

        # Connect the slider to the update_frame method
        self.slider.valueChanged.connect(self.update_frame)

    def init(self):
        y_range = [10, 40]
        self.ax.set_ylim(*y_range)
        self.bx.set_ylim(*y_range)
        self.line, = self.ax.plot(self.xs, self.ys)
        self.line2, = self.bx.plot(self.xs, self.ys)
        return self.line, self.line2

    def animate(self, i):
        temp_c = random.randint(15, 35)
        self.ys.append(temp_c)
        self.ys = self.ys[-self.x_len:]
        self.line.set_ydata(self.ys)
        self.line2.set_ydata(self.ys)
        if not self.slider_is_manual:
            self.slider.blockSignals(True)
            self.slider.setValue(i)  # Update slider value
            self.slider.blockSignals(False)
        return self.line, self.line2

    def update_frame(self, i):
        if self.slider_is_manual:
            temp_c = random.randint(15, 35)
            self.ys.append(temp_c)
            self.ys = self.ys[-self.x_len:]
            self.line.set_ydata(self.ys)
            self.line2.set_ydata(self.ys)
            self.draw()

    def start_manual_update(self):
        self.slider_is_manual = True

    def end_manual_update(self):
        self.slider_is_manual = False


class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(ApplicationWindow, self).__init__(parent)
        main_widget = QtWidgets.QWidget()
        l = QtWidgets.QVBoxLayout(main_widget)

        self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.slider.setRange(0, 199)
        l.addWidget(self.slider)

        sc = MyMplCanvas(self.slider, main_widget, width=5, height=4, dpi=100)
        l.addWidget(sc)
        self.setCentralWidget(main_widget)

        # Connect signals to handle manual slider updates
        self.slider.sliderPressed.connect(sc.start_manual_update)
        self.slider.sliderReleased.connect(sc.end_manual_update)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)

    w = ApplicationWindow()
    w.show()
    sys.exit(app.exec_())```

Ответы (0 шт):