简体   繁体   English

如何更改交互式缩放矩形的颜色?

[英]How to change the color of the interactive zoom rectangle?

I have a simple interactive plot.我有一个简单的交互式 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.您可以在下图中看到虚线矩形。

在此处输入图像描述

However, when I use white grid on a dark background (with plt.style.use('dark_background') ), the zoom rectangle is barely visible.但是,当我在深色背景上使用白色网格(使用plt.style.use('dark_background') )时,缩放矩形几乎不可见。 It is still there but black on a largely black plot.它仍然存在,但在很大程度上是黑色的 plot 上是黑色的。

在此处输入图像描述

For completeness, the plots where generated with Matplotlib 3.1.3 as follows:为了完整起见,使用 Matplotlib 3.1.3 生成的图如下:

import matplotlib.pyplot as plt
import numpy as np

plt.style.use('dark_background')

fig = plt.figure()
ax = fig.add_subplot(111)

data = 2.5 * np.random.randn(400) + 3
ax.plot(data)
plt.show()

So my question therefore is: how can I change the color of the zoom rectangle?所以我的问题是:如何更改缩放矩形的颜色?

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.这是我使用 Qt5 后端的尝试。 Note that you need to have PyQt5 installed too in order to make this work.请注意,您还需要安装 PyQt5 才能使其正常工作。

from PyQt5 import QtGui, QtCore
from matplotlib.backends.backend_qt5 import FigureCanvasQT

# extending the original FigureCanvasQT class

class NewFigureCanvasQT(FigureCanvasQT):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    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):
                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 FigureCanvasQT
import 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.编辑:这似乎已在 3.3.1 版中修复。 See the release notes. 请参阅发行说明。

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.对于 matplotlib 2.1.1(在 Ubuntu 18.04 上使用apt-get install python-matplotlib ),Peter 的答案不适用于版本。 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:
    pass
import matplotlib.pyplot as plt

## NOTE: Override paintEvent method to bolden zoom rectangle and change its color to red.
def paintEvent(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 widget
    if 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 called
    if not hasattr(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)
        if hasattr(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 QPainter
    if caller._drawRect is not None:
        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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 单击“颜色”按钮时如何更改矩形的颜色 - How to change the color of the rectangle when you click on the button “Color” 如何更改检测对象边界框中矩形的颜色和字体的颜色 - How to change Color of the Rectangle and Color of the Font in Bounding Box of an Detected Object Matplotlib交互式导航的“缩放到矩形”按钮不起作用 - Matplotlib interactive navigation zoom-to-rectangle button doesn't work 更改 cv2.rectangle 的颜色 - Change the color of the cv2.rectangle 如何从图像中检测矩形块并将其更改为白色? - How to detect a rectangle block from an image and change it to white color? 如何不做任何改变而改变矩形的颜色? - How to make the color of a rectangle change without doing anything? 如何更改网格中单个矩形的颜色? - How do I change the color of a single rectangle in a grid? 如何在 matplotlib pyplot 中更改图形颜色并绘制垂直阴影矩形? - How to change color of graph and draw vertical shaded rectangle in matplotlib pyplot? 在 tkinter 中更改 matplotlib 中的缩放工具轮廓矩形的颜色 - Changing the Color of the Zoom Tool Outline Rectangle in matplotlib in tkinter 如何在抓取交互式地图时放大元素? - How to zoom in on an element when scraping an interactive map?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM