Repository: matplotlib/matplotlib

Issue #25685: [Bug]: PySide 6.5.0 FuncAnimation TypeError
Created: 2023-04-14T21:11:08Z
Bug summary
Hi 👋🏼
When using the recently released PySide 6.5.0 with matplotlib 3.7.1 and python 3.10, an error is raised at FuncAnimation initialization that doesn't happen with the same code on previous PySide versions.
Code for reproduction
import sys

from PySide6.QtCore import Qt
from PySide6.QtWidgets import (QApplication, QLabel, QVBoxLayout, QWidget)
from matplotlib.artist import Artist
from matplotlib.animation import FuncAnimation
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
from matplotlib.figure import Figure
import numpy as np


class MplCanvas(FigureCanvasQTAgg, FuncAnimation):

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        self.fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = self.fig.add_subplot(111)
        self.axes.set_xlim(0, 2)
        self.axes.set_ylim(-2, 2)
        self.line,  = self.axes.plot([], [], lw=2)
        self.line.set_data([], [])
        FigureCanvasQTAgg.__init__(self, self.fig)
        FuncAnimation.__init__(
            self, 
            self.fig, 
            func=self.draw_frame, 
            frames=200,
            interval=20, 
            blit=True, 
            cache_frame_data=False
        )

    def draw_frame(self, frame: int) -> list[Artist]:
        x = np.linspace(0, 5, 1000)
        y = np.sin(2 * np.pi * (x - 0.01 * frame))
        self.line.set_data(x, y)
        return [self.line]


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

        self.text = QLabel("Hello World")
        self.text.setAlignment(Qt.AlignCenter)

        sc = MplCanvas(self, width=5, height=4, dpi=100)

        self.layout = QVBoxLayout()
        self.layout.addWidget(self.text)
        self.layout.addWidget(sc)
        self.setLayout(self.layout)


if __name__ == "__main__":
    app = QApplication(sys.argv)

    widget = MyWidget()
    widget.resize(800, 600)
    widget.show()

    sys.exit(app.exec())
Actual outcome
Traceback (most recent call last):
  File "/home/theguy/projects/test_matplotlib/plot.py", line 59, in <module>
    widget = MyWidget()
  File "/home/theguy/projects/test_matplotlib/plot.py", line 46, in __init__
    sc = MplCanvas(self, width=5, height=4, dpi=100)
  File "/home/theguy/projects/test_matplotlib/plot.py", line 21, in __init__
    FigureCanvasQTAgg.__init__(self, self.fig)
  File "/home/theguy/.cache/pypoetry/virtualenvs/test-matplotlib-WtQHVv9a-py3.10/lib64/python3.10/site-packages/matplotlib/backends/backend_qt.py", line 205, in __init__
    super().__init__(figure=figure)
  File "/home/theguy/.cache/pypoetry/virtualenvs/test-matplotlib-WtQHVv9a-py3.10/lib64/python3.10/site-packages/matplotlib/backend_bases.py", line 1695, in __init__
    super().__init__()  # Typically the GUI widget init (if any).
TypeError: FuncAnimation.__init__() missing 2 required positional arguments: 'fig' and 'func'

Expected outcome
A window opens and renders a simple sine wave animation.
Additional information
If I remove the FuncAnimation then the window opens and I can draw some static lines without issue.
No error is raised when using pyside6_essentials <=6.4.3
I've looked around the source code and tried a few things out to no avail.
Operating system
Arch, Fedora
Matplotlib Version
3.7.1
Matplotlib Backend
QtAgg
Python version
Python 3.10.10
Jupyter version
No response
Installation
pip

Duplicate issue #25856: [Bug]: Inheriting from both FigureCanvasQTAgg and FuncAnimation no longer possible
Created: 2023-05-11T06:21:52Z
Bug summary
FigureCanvasQTAgg.__init__(self, mpl_fig.Figure()) gives TypeError: FuncAnimation.__init__() missing 2 required positional arguments: 'fig' and 'func'. Was working in matplotlib 3.5.2. Same Problem appears by using FigureCanvas.
Code for reproduction
import matplotlib.figure as mpl_fig
import matplotlib.animation as anim
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg

class SimulationPrevCanvas(FigureCanvasQTAgg, anim.FuncAnimation):
    def __init__(self, x:List, y:List) -> None:
        FigureCanvasQTAgg.__init__(self, mpl_fig.Figure())
Actual outcome
    super().__init__()  # Typically the GUI widget init (if any).
TypeError: FuncAnimation.__init__() missing 2 required positional arguments: 'fig' and 'func'

Expected outcome
Animated plot inside QT.
Additional information
No response
Operating system
No response
Matplotlib Version
3.7
Matplotlib Backend
No response
Python version
No response
Jupyter version
No response
Installation
conda

Closing comment (2023-05-12T08:31:17Z): I think this is a duplicate of #25685 in that pyside change to cooperative inheritance.
There must be some example someplace that does this if we now have 2 reports on this?

You are correct it really is a duplicate of #25685.
Seems like the problem was solvable by re-factoring how to use FigureCanvasQTAgg and anim.FuncAnimation with Pyside 6.5. It seems to work that instead of inheriting use them as attributes:
class SimulationPrevCanvas:
     def __init__(self, x: List, y: List) -> None:
        """
        :param x:       The data to init with at x axis.
        :param y:       The data to init with at y axis.
        """
        self.figure = mpl_fig.Figure()
        self.canvas = FigureCanvasQTAgg(self.figure)
        self.animation = anim.FuncAnimation(self.figure, self.time_update, fargs=(), interval=self.interval, blit=True)