RectangleSelector在缩放时消失

时间:2017-08-06 10:42:57

标签: python python-2.7 matplotlib matplotlib-widget

当我运行this示例并创建矩形选区时,如果我缩放或移动选区周围的绘图窗口消失,直到我取消选择移动或缩放工具并再次单击绘图窗口。

我在IPython笔记本中使用%matplotlib tkinter

我试图挂钩窗口缩放时发生的极限变化,并将矩形选项设置为可见:

def persist_rect(newlims):
    rs = toggle_selector.RS
    print(rs.visible)
    rs.set_visible(True)
    rs.update()

current_ax.callbacks.connect('xlim_changed', persist_rect)
current_ax.callbacks.connect('ylim_changed', persist_rect)

但这似乎没有做任何事情。它甚至不会显示toggle_selector.RS.visible被设置为假。

我也一直在关注source for RectangleSelector,但我还没有看到任何启发。

当我使用RectangleSelector.extents = new_extents修改所选区域的范围时,我也发现我遇到此问题。修改.extents时,例如使用滑块小部件,所选区域将消失,直到我再次单击该图。

如果RectangleSelectoruseblit=False初始化为@ImportanceOfBeingErnest建议,所有这些问题都会消失,但正如他们所说,它不是一个非常高效的解决方案。

3 个答案:

答案 0 :(得分:5)

如果我理解正确,矩形选择器应在整个平移或缩放过程中保持可见。这可以通过不使用blitting实现,

toggle_selector.RS = RectangleSelector(ax, ...,  useblit=False, ...)

这样做的副作用是绘图可能会变慢,具体取决于绘图的复杂程度,因为没有blitting,使用矩形选择器时会不断重绘整个绘图。

答案 1 :(得分:4)

draw_event s添加回调:

def mycallback(event):
    if RS.active:
        RS.update()
plt.connect('draw_event', mycallback)

在缩放或平移后使RectangleSelector保持不变,并且与useblit=True兼容。

例如,使用code from the docs作为基础:

from __future__ import print_function
from matplotlib.widgets import RectangleSelector
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.widgets as widgets
import threading
import datetime as DT

def line_select_callback(eclick, erelease):
    'eclick and erelease are the press and release events'
    x1, y1 = eclick.xdata, eclick.ydata
    x2, y2 = erelease.xdata, erelease.ydata
    print("(%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1, x2, y2))
    print(" The button you used were: %s %s" % (eclick.button, erelease.button))

def toggle_selector(event):
    print(' Key pressed: {}'.format(event.key))
    if event.key in ['D', 'd'] and RS.active:
        print(' RectangleSelector deactivated.')
        RS.set_active(False)
        RS.set_visible(False)
        RS.update()
    if event.key in ['A', 'a'] and not RS.active:
        print(' RectangleSelector activated.')
        RS.set_active(True)
        RS.set_visible(True)
        RS.update()

def mycallback(event):
    if RS.active:
        # print('mycallback')
        RS.update()

# def persist_rect(newlims):
#     print('persist_rect')
#     RS.set_visible(True)
#     RS.update()

fig, ax = plt.subplots() 
# figtype = type(fig)
# figtype._draw = figtype.draw
# def mydraw(self, renderer):
#     print('figure.draw')
#     self._draw(renderer)
# figtype.draw = mydraw

N = 100000               
x = np.linspace(0.0, 10.0, N) 

RS = RectangleSelector(ax, line_select_callback,
                       drawtype='box', useblit=True,
                       button=[1, 3],  # don't use middle button
                       minspanx=5, minspany=5,
                       spancoords='pixels',
                       interactive=True)

plt.plot(x, +np.sin(.2*np.pi*x), lw=3.5, c='b', alpha=.7) 
plt.plot(x, +np.cos(.2*np.pi*x), lw=3.5, c='r', alpha=.5)
plt.plot(x, -np.sin(.2*np.pi*x), lw=3.5, c='g', alpha=.3)

plt.connect('key_press_event', toggle_selector)
plt.connect('draw_event', mycallback)
# ax.callbacks.connect('xlim_changed', persist_rect)
# ax.callbacks.connect('ylim_changed', persist_rect)

plt.show()

为什么mycallback有效但persist_rect没有?

如果您取消注释上面注释掉的语句,您将得到一些打印输出,看起来像这样:

figure.draw
mycallback
figure.draw
mycallback
(4.09, -0.53) --> (8.15, 0.38)
 The button you used were: 1 1
persist_rect
persist_rect
figure.draw
mycallback
 Key pressed: q

请注意persist_rect之前调用figure.draw,之后调用mycallbackfigure.draw不会绘制RectangleSelection,但会绘制用于背景的Rectangle。因此figure.draw掩盖了RectangleSelection。 因此persist_rect暂时显示RectangleSelection,但它无法持久存在。 mycallback有效,因为它是在figure.draw之后调用的。

答案 2 :(得分:0)

RectangularSelector的源代码中发布方法(line 2119)  处理选择器的可见性

def _release(self, event):   
"""on button release event"""
    if not self.interactive:
        self.to_draw.set_visible(False)

子类RectangleSelector修改释放方法

class visibleRectangleSelector(RectangleSelector):
    def release(self, event):
        super(visibleRectangleSelector, self).release(event)
        self.to_draw.set_visible(True)
        self.canvas.draw()   ##updates canvas for new selection

使用doc示例

的示例代码
from __future__ import print_function
"""
Do a mouseclick somewhere, move the mouse to some destination, release
the button.  This class gives click- and release-events and also draws
a line or a box from the click-point to the actual mouseposition
(within the same axes) until the button is released.  Within the
method 'self.ignore()' it is checked whether the button from eventpress
and eventrelease are the same.

"""
from matplotlib.widgets import RectangleSelector
import numpy as np
import matplotlib.pyplot as plt


class visibleRectangleSelector(RectangleSelector):
    def release(self, event):
        super(visibleRectangleSelector, self).release(event)
        self.to_draw.set_visible(True)
        self.canvas.draw() 


def line_select_callback(eclick, erelease):
    'eclick and erelease are the press and release events'
    x1, y1 = eclick.xdata, eclick.ydata
    x2, y2 = erelease.xdata, erelease.ydata
    print("(%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1, x2, y2))
    print(" The button you used were: %s %s" % (eclick.button,
                                                erelease.button))


def toggle_selector(event):
    print(' Key pressed.')
    if event.key in ['Q', 'q'] and toggle_selector.RS.active:
        print(' RectangleSelector deactivated.')
        toggle_selector.RS.set_active(False)
    if event.key in ['A', 'a'] and not toggle_selector.RS.active:
        print(' RectangleSelector activated.')
        toggle_selector.RS.set_active(True)


fig, current_ax = plt.subplots()  # make a new plotting range
N = 100000  # If N is large one can see
x = np.linspace(0.0, 10.0, N)  # improvement by use blitting!

plt.plot(x, +np.sin(.2 * np.pi * x), lw=3.5, c='b', alpha=.7)  # plot something
plt.plot(x, +np.cos(.2 * np.pi * x), lw=3.5, c='r', alpha=.5)
plt.plot(x, -np.sin(.2 * np.pi * x), lw=3.5, c='g', alpha=.3)

print("\n      click  -->  release")

# drawtype is 'box' or 'line' or 'none'
toggle_selector.RS = RectangleSelector(
    current_ax,
    line_select_callback,
    drawtype='box',
    useblit=False,
    button=[1, 3],  # don't use middle button
    minspanx=5,
    minspany=5,
    spancoords='pixels',
    interactive=True)
plt.connect('key_press_event', toggle_selector)
plt.show()