当我运行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
时,例如使用滑块小部件,所选区域将消失,直到我再次单击该图。
如果RectangleSelector
被useblit=False
初始化为@ImportanceOfBeingErnest建议,所有这些问题都会消失,但正如他们所说,它不是一个非常高效的解决方案。
答案 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
,之后调用mycallback
。 figure.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()