diff --git a/lib/matplotlib/backends/backend_qtagg.py b/lib/matplotlib/backends/backend_qtagg.py index 256e50a3d1c3..0fdea169a179 100644 --- a/lib/matplotlib/backends/backend_qtagg.py +++ b/lib/matplotlib/backends/backend_qtagg.py @@ -2,15 +2,14 @@ Render to qt from agg. """ -import ctypes +import numpy as np -from matplotlib.transforms import Bbox - -from .qt_compat import QT_API, QtCore, QtGui +from .qt_compat import QtGui from .backend_agg import FigureCanvasAgg from .backend_qt import _BackendQT, FigureCanvasQT from .backend_qt import ( # noqa: F401 # pylint: disable=W0611 FigureManagerQT, NavigationToolbar2QT) +from ..transforms import Bbox class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT): @@ -47,25 +46,19 @@ def paintEvent(self, event): right = left + width # create a buffer using the image bounding box bbox = Bbox([[left, bottom], [right, top]]) - buf = memoryview(self.copy_from_bbox(bbox)) + img = np.asarray(self.copy_from_bbox(bbox), dtype=np.uint8) - if QT_API == "PyQt6": - from PyQt6 import sip - ptr = int(sip.voidptr(buf)) - else: - ptr = buf + # Clear the widget canvas, to avoid issues as seen in + # https://github.com/matplotlib/matplotlib/issues/13012 + painter.eraseRect(rect) - painter.eraseRect(rect) # clear the widget canvas - qimage = QtGui.QImage(ptr, buf.shape[1], buf.shape[0], - QtGui.QImage.Format.Format_RGBA8888) + qimage = QtGui.QImage( + img, img.shape[1], img.shape[0], + QtGui.QImage.Format.Format_RGBA8888, + ) qimage.setDevicePixelRatio(self.device_pixel_ratio) # set origin using original QT coordinates - origin = QtCore.QPoint(rect.left(), rect.top()) - painter.drawImage(origin, qimage) - # Adjust the buf reference count to work around a memory - # leak bug in QImage under PySide. - if QT_API == "PySide2" and QtCore.__version_info__ < (5, 12): - ctypes.c_long.from_address(id(buf)).value = 1 + painter.drawImage(rect.topLeft(), qimage) self._draw_rect_callback(painter) finally: diff --git a/src/_backend_agg_wrapper.cpp b/src/_backend_agg_wrapper.cpp index eaf4bf6f5f9d..1f271a1aeaeb 100644 --- a/src/_backend_agg_wrapper.cpp +++ b/src/_backend_agg_wrapper.cpp @@ -472,6 +472,12 @@ static PyObject *PyRendererAgg_clear(PyRendererAgg *self, PyObject *args) static PyObject *PyRendererAgg_copy_from_bbox(PyRendererAgg *self, PyObject *args) { + // Note that whilst the copy_from_bbox call can technically return an image that + // is of a different rect than was requested, this is not used in the underlying + // backend. In the future, this copy_from_bbox will not return a PyBufferRegion, + // and instead simply return an image (the renderer interface may still expose a + // bbox in the response for convenience, but this doesn't need to be a special + // type at the C++ level). agg::rect_d bbox; BufferRegion *reg; PyObject *regobj;
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: