Thanks to visit codestin.com
Credit goes to github.com

Skip to content

2.1.0 serious regression in Qt5 backend #9406

Closed
@kawing-chiu

Description

@kawing-chiu

Bug report

Bug summary

My app worked well in previous matplotlib versions. After upgrading to 2.1.0, it is completely broken, flooded with QWidget::repaint: Recursive repaint detected messages.

Code for reproduction

import matplotlib as mpl
import matplotlib.lines
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg

class Qt5Canvas(FigureCanvasQTAgg):
    def __init__(self, parent=None, aspect_ratio=3/4, dpi=96,
            width=None, height=None):
        if width is not None:
            figsize = (width, height)
        else:
            figsize = mpl.figure.figaspect(aspect_ratio)
        fig = mpl.figure.Figure(figsize=figsize, dpi=dpi)
        super().__init__(fig)
        self.fig = fig
        self.ax = fig.add_subplot(111)
        self.setParent(parent)

class TestMplBug:
    def __init__(self):
        self.artist = None
        self.canvas = None
        self._blit_region = None
        self._drawed = False

    def set_canvas(self, canvas):
        self.canvas = canvas
        self.canvas.mpl_connect('draw_event', self._on_mpl_draw)

    def _on_mpl_draw(self, event):
        self._drawed = True
        self.blit_update()

    def draw(self):
        self._on_draw()
        self.canvas.draw()

    def _on_draw(self):
        if self.artist is None:
            import numpy as np
            x = np.arange(0.0, 3.0, 0.01)
            y = np.sin(2*np.pi*x)
            line = mpl.lines.Line2D(x, y, color='red', animated=True)
            self.canvas.ax.add_line(line)
            self.artist = line

    def blit_update(self):
        if self.canvas is None:
            return
        self.canvas.ax.draw_artist(self.artist)
        if self._drawed:
            self.canvas.blit()

def main():
    from PyQt5 import QtWidgets, QtCore, QtGui
    import sys
    app = QtWidgets.QApplication.instance()
    if app is None:
        app = QtWidgets.QApplication(sys.argv)
    t = TestMplBug()
    q = Qt5Canvas()
    t.set_canvas(q)
    t.draw()
    t.canvas.show()
    try:
        __IPYTHON__
    except NameError as e:
        app.exec_()
    return t

if __name__ == '__main__':
    main()

Actual outcome

QWidget::repaint: Recursive repaint detected
<many similar entries omited...>
QWidget::repaint: Recursive repaint detected
Traceback (most recent call last):
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/backends/backend_qt5agg.py", line 149, in __draw_idle_agg
    self.draw()
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/backends/backend_qt5agg.py", line 127, in draw
    super(FigureCanvasQTAggBase, self).draw()
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py", line 430, in draw
    self.figure.draw(self.renderer)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/figure.py", line 1295, in draw
    renderer, self, artists, self.suppressComposite)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/image.py", line 138, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/axes/_base.py", line 2399, in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/image.py", line 138, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/axis.py", line 1133, in draw
    ticks_to_draw = self._update_ticks(renderer)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/axis.py", line 974, in _update_ticks
    tick_tups = list(self.iter_ticks())
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/axis.py", line 917, in iter_ticks
    majorLocs = self.major.locator()
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/ticker.py", line 1957, in __call__
    return self.tick_values(vmin, vmax)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/ticker.py", line 1965, in tick_values
    locs = self._raw_ticks(vmin, vmax)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/ticker.py", line 1907, in _raw_ticks
    nbins = np.clip(self.axis.get_tick_space(),
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/axis.py", line 2039, in get_tick_space
    tick = self._get_tick(True)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/axis.py", line 1748, in _get_tick
    return XTick(self.axes, 0, '', major=major, **tick_kw)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/axis.py", line 152, in __init__
    self.apply_tickdir(tickdir)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/axis.py", line 403, in apply_tickdir
    self.stale = True
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 241, in stale
    self.stale_callback(self, val)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 68, in _stale_axes_callback
    self.axes.stale = val
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/artist.py", line 241, in stale
    self.stale_callback(self, val)
  File "/home/statistician/.local/lib/python3.6/site-packages/matplotlib/figure.py", line 56, in _stale_figure_callback
    self.figure.stale = val
RecursionError: maximum recursion depth exceeded while calling a Python object
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::end: Painter not active, aborted
<many similar entries omited...>
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::end: Painter not active, aborted

Expected outcome

Draw properly as in previous versions.

Matplotlib version

  • Operating system: Arch Linux
  • Matplotlib version: 2.1.0 (installed from pip)
  • Matplotlib backend (print(matplotlib.get_backend())): qt5
  • Python version: 3.6.2
  • Jupyter version (if applicable):
  • Other libraries:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions