# draw the zoom rectangle to the QPainter
# changed code below...
# change the color of zooming rectangle from black to red
if self.drawRect:
p.setPen( QtGui.QPen( QtCore.Qt.red, 1, QtCore.Qt.DotLine ) )
p.drawRect( self.rect[0], self.rect[1], self.rect[2], self.rect[3] )
p.end()
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
import PyQt4.QtCore as QCore
import PyQt4.QtGui as QGui
class FigureCanvas(FigureCanvasQTAgg):
"""
Subclassing to change the paint event hosted in matplotlib.backends.backend_qt5agg.
Removed all comments for sake of brevity.
Paintcolor can be set by settings canvas.rectanglecolor to a QColor.
"""
def paintEvent(self, e):
paintcolor = QCore.Qt.black if not hasattr(self, "rectanglecolor") else self.rectanglecolor
if not hasattr(self, 'renderer'):
return
if self.blitbox is None:
if QCore.QSysInfo.ByteOrder == QCore.QSysInfo.LittleEndian:
stringBuffer = self.renderer._renderer.tostring_bgra()
else:
stringBuffer = self.renderer._renderer.tostring_argb()
refcnt = sys.getrefcount(stringBuffer)
qImage = QGui.QImage(stringBuffer, self.renderer.width,
self.renderer.height,
QGui.QImage.Format_ARGB32)
rect = qImage.rect()
p = QGui.QPainter(self)
p.eraseRect(rect)
p.drawPixmap(QCore.QPoint(0, 0), QGui.QPixmap.fromImage(qImage))
if self._drawRect is not None:
p.setPen(QGui.QPen(paintcolor, 1, QCore.Qt.DotLine))
x, y, w, h = self._drawRect
p.drawRect(x, y, w, h)
p.end()
del qImage
if refcnt != sys.getrefcount(stringBuffer):
_decref(stringBuffer)
else:
bbox = self.blitbox
l, b, r, t = bbox.extents
w = int(r) - int(l)
h = int(t) - int(b)
t = int(b) + h
reg = self.copy_from_bbox(bbox)
stringBuffer = reg.to_string_argb()
qImage = QGui.QImage(stringBuffer, w, h,
QGui.QImage.Format_ARGB32)
if QT_API == 'PySide' and six.PY3:
ctypes.c_long.from_address(id(stringBuffer)).value = 1
pixmap = QGui.QPixmap.fromImage(qImage)
p = QGui.QPainter(self)
p.drawPixmap(QCore.QPoint(l, self.renderer.height-t), pixmap)
if self._drawRect is not None:
p.setPen(QGui.QPen(paintcolor, 1, QCore.Qt.DotLine))
x, y, w, h = self._drawRect
p.drawRect(x, y, w, h)
p.end()
self.blitbox = None
class CustomToolbar(mptk.NavigationToolbar2Tk):
def __init__(self, figcanvas, parent):
super().__init__(figcanvas, parent) # init the base class as usual
# you can copy the method 'draw_rubberband()' right from
# NavigationToolbar2Tk - we're only changing one line
def draw_rubberband(self, event, x0, y0, x1, y1):
self.remove_rubberband()
height = self.canvas.figure.bbox.height
y0 = height - y0
y1 = height - y1
# this is the line we want to change
self.lastrect = self.canvas._tkcanvas.create_rectangle(
x0, y0, x1, y1
outline = 'red' # add your outline color here
)
# hex color strings -> '#FF3344' and named colors -> 'gainsboro' both work
您可以像使用NavigationToolbar2Tk一样按名称使用CustomToolbar类
self.toolbar = CustomToolbar(self.root, self.canvas, self.frame) # for example...
import six
import ctypes
import sys
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QSizePolicy, QWidget, QVBoxLayout
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
QT_API = 'PyQt5'
DEBUG = False
_decref = ctypes.pythonapi.Py_DecRef
_decref.argtypes = [ctypes.py_object]
_decref.restype = None
class MplCanvas(FigureCanvas):
def __init__(self):
FigureCanvas.__init__(self,self.fig)
FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
#Change de color of rectangle zoom toolbar rewriting painEvent
#the original code is in the backend_qt5agg.py file inside
#matplotlib/backends directory
def paintEvent(self, e):
"""
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 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
if DEBUG:
print('FigureCanvasQtAgg.paintEvent: ', self,
self.get_width_height())
if len(self.blitbox) == 0:
# matplotlib is in rgba byte order. QImage wants to put the bytes
# into argb format and is in a 4 byte unsigned int. Little endian
# system is LSB first and expects the bytes in reverse order
# (bgra).
if QtCore.QSysInfo.ByteOrder == QtCore.QSysInfo.LittleEndian:
stringBuffer = self.renderer._renderer.tostring_bgra()
else:
stringBuffer = self.renderer._renderer.tostring_argb()
refcnt = sys.getrefcount(stringBuffer)
# convert the Agg rendered image -> qImage
qImage = QtGui.QImage(stringBuffer, self.renderer.width,
self.renderer.height,
QtGui.QImage.Format_ARGB32)
if hasattr(qImage, 'setDevicePixelRatio'):
# Not available on Qt4 or some older Qt5.
qImage.setDevicePixelRatio(self._dpi_ratio)
# get the rectangle for the image
rect = qImage.rect()
p = QtGui.QPainter(self)
# reset the image area of the canvas to be the back-ground color
p.eraseRect(rect)
# draw the rendered image on to the canvas
p.drawPixmap(QtCore.QPoint(0, 0), QtGui.QPixmap.fromImage(qImage))
# draw the zoom rectangle to the QPainter
########################################################
# HERE CHANGE THE COLOR, IN THIS EXAMPLE #
# THE COLOR IS WHITE #
########################################################
if self._drawRect is not None:
pen = QtGui.QPen(QtCore.Qt.white, 1 / self._dpi_ratio,
QtCore.Qt.DotLine)
p.setPen(pen)
x, y, w, h = self._drawRect
p.drawRect(x, y, w, h)
p.end()
# This works around a bug in PySide 1.1.2 on Python 3.x,
# where the reference count of stringBuffer is incremented
# but never decremented by QImage.
# TODO: revert PR #1323 once the issue is fixed in PySide.
del qImage
if refcnt != sys.getrefcount(stringBuffer):
_decref(stringBuffer)
else:
p = QtGui.QPainter(self)
while len(self.blitbox):
bbox = self.blitbox.pop()
l, b, r, t = bbox.extents
w = int(r) - int(l)
h = int(t) - int(b)
t = int(b) + h
reg = self.copy_from_bbox(bbox)
stringBuffer = reg.to_string_argb()
qImage = QtGui.QImage(stringBuffer, w, h,
QtGui.QImage.Format_ARGB32)
if hasattr(qImage, 'setDevicePixelRatio'):
# Not available on Qt4 or some older Qt5.
qImage.setDevicePixelRatio(self._dpi_ratio)
# Adjust the stringBuffer reference count to work
# around a memory leak bug in QImage() under PySide on
# Python 3.x
if QT_API == 'PySide' and six.PY3:
ctypes.c_long.from_address(id(stringBuffer)).value = 1
origin = QtCore.QPoint(l, self.renderer.height - t)
pixmap = QtGui.QPixmap.fromImage(qImage)
p.drawPixmap(origin / self._dpi_ratio, pixmap)
# draw the zoom rectangle to the QPainter
if self._drawRect is not None:
pen = QtGui.QPen(QtCore.Qt.black, 1 / self._dpi_ratio,
QtCore.Qt.DotLine)
p.setPen(pen)
x, y, w, h = self._drawRect
p.drawRect(x, y, w, h)
p.end()
适用于MATLAB库2.2.2
from PyQt5.QtWidgets import QSizePolicy, QWidget, QVBoxLayout
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
class MplCanvas(FigureCanvas):
def __init__(self):
FigureCanvas.__init__(self, self.fig)
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
# HERE CHANGE THE COLOR OF ZOOM RECTANGLE
def drawRectangle(self, rect):
# Draw the zoom rectangle to the QPainter. _draw_rect_callback needs
# to be called at the end of paintEvent.
if rect is not None:
def _draw_rect_callback(painter):
# IN THIS EXAMPLE CHANGE BLACK FOR WHITE
pen = QtGui.QPen(QtCore.Qt.white, 1 / self._dpi_ratio,
QtCore.Qt.DotLine)
painter.setPen(pen)
painter.drawRect(*(pt / self._dpi_ratio for pt in rect))
else:
def _draw_rect_callback(painter):
return
self._draw_rect_callback = _draw_rect_callback
self.update()
class MplWidget (QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.canvas = MplCanvas()
# add the toolbar
self.ntb = NavigationToolbar(self.canvas, self)
self.vbl = QVBoxLayout()
self.vbl.addWidget(self.canvas)
self.vbl.addWidget(self.ntb)
self.setLayout(self.vbl)
4条答案
按热度按时间wz8daaqr1#
在文件中
后端处理器_qt4agg.py
只需在上面的代码中添加/更改矩形绘制部分。
vhipe2zx2#
这可以通过子类化和覆盖(而不是扩展)paintevent来完成:(代码是从原始绘画事件复制粘贴的,将颜色更改为变量)
根据您的应用程序,您可能可以再缩短一点(比如删除PySide特定的部分)。上面的代码可以正常工作,您可以像往常一样使用FigureCanvas。
sqougxex3#
请原谅死灵术,但我想为任何试图用tkinter解决这个问题的人戴上帽子(因为这里的大多数答案都涉及Qt)。
你需要重写
NavigationToolbar2Tk.draw_rubberband()
方法。这里我使用了一个自定义类,但这不是唯一的方法:您可以像使用
NavigationToolbar2Tk
一样按名称使用CustomToolbar
类实现一个继承自
NavigationToolbar2Tk
的自定义工具栏类还提供了其他可能性,比如修改工具栏按钮、添加自定义工具等等......但这是另一篇文章的内容。bvhaajcl4#
除了Gloweye的React,在PyQt5中你应该这样做。
适用于MATLAB库2.2.2