""" Render to qt from agg """ import ctypes from matplotlib.transforms import Bbox from .. import cbook from .backend_agg import FigureCanvasAgg from .backend_qt5 import ( QtCore, QtGui, QtWidgets, _BackendQT5, FigureCanvasQT, FigureManagerQT, NavigationToolbar2QT, backend_version) from .qt_compat import QT_API class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT): def __init__(self, figure): # Must pass 'figure' as kwarg to Qt base class. super().__init__(figure=figure) def paintEvent(self, event): """Copy the image from the Agg canvas to the qt.drawable. In Qt, all drawing should be done inside of here when a widget is shown onscreen. """ if self._update_dpi(): # The dpi update triggered its own paintEvent. return self._draw_idle() # Only does something if a draw is pending. # if the canvas does not have a renderer, then give up and wait for # FigureCanvasAgg.draw(self) to be called if not hasattr(self, 'renderer'): return painter = QtGui.QPainter(self) if self._erase_before_paint: painter.eraseRect(self.rect()) self._erase_before_paint = False rect = event.rect() left = rect.left() top = rect.top() width = rect.width() height = rect.height() # See documentation of QRect: bottom() and right() are off by 1, so use # left() + width() and top() + height(). bbox = Bbox( [[left, self.renderer.height - (top + height * self._dpi_ratio)], [left + width * self._dpi_ratio, self.renderer.height - top]]) reg = self.copy_from_bbox(bbox) buf = cbook._unmultiplied_rgba8888_to_premultiplied_argb32( memoryview(reg)) qimage = QtGui.QImage(buf, buf.shape[1], buf.shape[0], QtGui.QImage.Format_ARGB32_Premultiplied) if hasattr(qimage, 'setDevicePixelRatio'): # Not available on Qt4 or some older Qt5. qimage.setDevicePixelRatio(self._dpi_ratio) origin = QtCore.QPoint(left, top) painter.drawImage(origin / self._dpi_ratio, qimage) # Adjust the buf reference count to work around a memory # leak bug in QImage under PySide on Python 3. if QT_API in ('PySide', 'PySide2'): ctypes.c_long.from_address(id(buf)).value = 1 self._draw_rect_callback(painter) painter.end() def blit(self, bbox=None): """Blit the region in bbox. """ # If bbox is None, blit the entire canvas. Otherwise # blit only the area defined by the bbox. if bbox is None and self.figure: bbox = self.figure.bbox # repaint uses logical pixels, not physical pixels like the renderer. l, b, w, h = [pt / self._dpi_ratio for pt in bbox.bounds] t = b + h self.repaint(l, self.renderer.height / self._dpi_ratio - t, w, h) def print_figure(self, *args, **kwargs): super().print_figure(*args, **kwargs) self.draw() @_BackendQT5.export class _BackendQT5Agg(_BackendQT5): FigureCanvas = FigureCanvasQTAgg