How To Change The Color Of The Interactive Zoom Rectangle?
I have a simple interactive plot. When I click on the magnifying glass button I can draw a rectangle to do interactive zooming. You can see the dotted rectangle in the image below.
Solution 1:
It depends on what backend you're using there is no (at least I don't know a) universal solution. As stated in the comments this can be achieved only with monkey-patching. Here is my attempt using Qt5 backend. Note that you need to have PyQt5 installed too in order to make this work.
from PyQt5 import QtGui, QtCore
from matplotlib.backends.backend_qt5 import FigureCanvasQT
# extending the original FigureCanvasQT classclassNewFigureCanvasQT(FigureCanvasQT):
def__init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
defdrawRectangle(self, rect):
# Draw the zoom rectangle to the QPainter. _draw_rect_callback needs# to be called at the end of paintEvent.if rect isnotNone:
def_draw_rect_callback(painter):
pen = QtGui.QPen(QtCore.Qt.red, 1 / self._dpi_ratio, # <-- change the color here
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()
# do the imports and replace the old FigureCanvasQTimport matplotlib
import matplotlib.pyplot as plt
matplotlib.backends.backend_qt5.FigureCanvasQT = NewFigureCanvasQT
# switch backend and setup the dark background
matplotlib.use('Qt5Agg')
matplotlib.style.use('dark_background')
# do the plotting
plt.plot(range(9))
plt.show()
which produces the following picture:
EDIT: This seem to be fixed in release 3.3.1. See the release notes.
Solution 2:
For matplotlib 2.1.1 (installed using apt-get install python-matplotlib
on Ubuntu 18.04), the answer by Peter does not work on the verison.
Hope it will helps someone with legacy system.
Instead, I managed to patch as following:
from PyQt5 import QtCore, QtGui
import matplotlib
try:
matplotlib.use('Qt5Agg')
except ValueError:
passimport matplotlib.pyplot as plt
## NOTE: Override paintEvent method to bolden zoom rectangle and change its color to red.defpaintEvent(caller, _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 there is a pending draw, run it now as we need the updated render# to paint the widgetif caller._agg_draw_pending:
try:
caller.__draw_idle_agg()
except AttributeError:
pass# As described in __init__ above, we need to be careful in cases with# mixed resolution displays if dpi_ratio is changing between painting# events.if caller._dpi_ratio != caller._dpi_ratio_prev:
# We need to update the figure DPI
caller._update_figure_dpi()
caller._dpi_ratio_prev = caller._dpi_ratio
# The easiest way to resize the canvas is to emit a resizeEvent# since we implement all the logic for resizing the canvas for# that event.
event = QtGui.QResizeEvent(caller.size(), caller.size())
# We use caller.resizeEvent here instead of QApplication.postEvent# since the latter doesn't guarantee that the event will be emitted# straight away, and this causes visual delays in the changes.
caller.resizeEvent(event)
# resizeEvent triggers a paintEvent itself, so we exit this one.return# if the canvas does not have a renderer, then give up and wait for# FigureCanvasAgg.draw(caller) to be calledifnothasattr(caller, 'renderer'):
return
painter = QtGui.QPainter(caller)
if caller._bbox_queue:
bbox_queue = caller._bbox_queue
else:
painter.eraseRect(caller.rect())
bbox_queue = [
matplotlib.transforms.Bbox(
[[0, 0], [caller.renderer.width, caller.renderer.height]])]
caller._bbox_queue = []
for bbox in bbox_queue:
l, b, r, t = map(int, bbox.extents)
w = r - l
h = t - b
reg = caller.copy_from_bbox(bbox)
buf = reg.to_string_argb()
qimage = QtGui.QImage(buf, w, h, QtGui.QImage.Format_ARGB32)
ifhasattr(qimage, 'setDevicePixelRatio'):
# Not available on Qt4 or some older Qt5.
qimage.setDevicePixelRatio(caller._dpi_ratio)
origin = QtCore.QPoint(l, caller.renderer.height - t)
painter.drawImage(origin / caller._dpi_ratio, qimage)
# Adjust the buf reference count to work around a memory# leak bug in QImage under PySide on Python 3.import six
if matplotlib.backends.qt_compat.QT_API == 'PySide'and six.PY3:
import ctypes
ctypes.c_long.from_address(id(buf)).value = 1# draw the zoom rectangle to the QPainterif caller._drawRect isnotNone:
pen = QtGui.QPen(QtCore.Qt.red, 3 / caller._dpi_ratio,
QtCore.Qt.DotLine)
painter.setPen(pen)
x, y, w, h = caller._drawRect
painter.drawRect(x, y, w, h)
painter.end()
# Use custom figure canvas to override zoom rectangle visual
matplotlib.backends.backend_qt5agg.FigureCanvasQTAggBase.paintEvent = paintEvent
Post a Comment for "How To Change The Color Of The Interactive Zoom Rectangle?"