2017-08-06 49 views
10

當我運行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被設置爲false。

我也一直在尋找source for RectangleSelector,但我還沒有看到任何啓發。

我也發現,當我使用RectangleSelector.extents = new_extents修改所選區域的範圍時,我遇到了這個問題。當例如使用滑塊小部件修改.extents時,所選區域消失,直到再次單擊該圖。

如果RectangleSelectoruseblit=False作爲@ImportanceOfBeingErnest的建議進行初始化,所有這些問題都會消失,但正如他們所說,這不是一個非常好的解決方案。

+0

你有沒有檢查這個問題的答案:https://stackoverflow.com/questions/34517484/persistent-rectangle-selector? –

+0

@JafferWilson:感謝您指出這個問題。不幸的是,答案不起作用。按照原樣使用時,矩形將立即消失。如果與'interactive = True'一起使用,則與上述問題相同的問題仍然存在。 – ImportanceOfBeingErnest

回答

3

添加回調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_rectfigure.draw之前調用,而mycallback是後來被稱爲。 figure.draw不繪製RectangleSelection,但它確實繪製了用於背景的Rectangle。所以figure.draw模糊RectangleSelection。 因此persist_rect暫時顯示RectangleSelection,但它未能堅持。 mycallback因爲在figure.draw之後被調用。

+0

確實!有沒有什麼好的解釋?原則上,這非常接近OP在限制改變(並且不起作用)上的回調。此外,調用'.update'似乎不太直觀,它實際上會在繪製事件的回調*上繪製矩形*。感覺有點像蛇咬自己的尾巴,但它顯然是工作。 – ImportanceOfBeingErnest

+1

我認爲它歸結爲相對於'figure.draw'調用回調的順序。在'figure.draw'之前調用'persist_rect',而之後調用'mycallback'。由於'figure.draw'在'RectangleSelector'之上繪製,'persist_rect'不能保持'RectangleSelector'持久可見。我已經在上面添加了一些猴子補丁代碼來顯示何時調用「figure.draw」。 – unutbu

5

如果我理解正確,矩形選擇器應該在整個平移或縮放過程中保持可見。這可以通過不使用位圖傳輸來實現,

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

這樣做的副作用是,繪圖速度可能會變慢視情節的複雜性,因爲沒有塊傳輸,完整的情節不斷重繪同時使用矩形選擇。

+1

感謝您的幫助,不幸的是,這不是我的最佳解決方案。我想使用矩形選擇器來選擇用'imshow'繪製的瀑布圖上的區域。這些瀑布陣列中最小的是〜18MB,最大的是〜220MB。 'RectangleSelector'除了這個重畫問題之外,還有blitting的功能。有什麼辦法可以手動強制它在縮放/移動後重繪? – alessandro

+1

這對於簡單的情節非常有用。當我有足夠的代表時,我會很高興地+1。 – alessandro

0

在用於RectangularSelector源代碼中的釋放方法(line 2119) 處理選擇器的能見度

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

子類RectangleSelector使用doc例如

修改釋放方法

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 

示例代碼

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() 
+1

感謝您關注此問題。但是,似乎這個解決方案只能工作,因爲你在[我的回答](https://stackoverflow.com/a/45531329/4124317)中使用了'blit = False'。當使用blit = False時,根本不需要子類。使用'blit = True'嘗試此解決方案時,RectangleSelector仍會消失。所以它似乎不能解決問題。 – ImportanceOfBeingErnest

+0

從上面的 看@ JafferWilson的評論,這個答案是對[這個問題]的答案的** plagiate **(https://stackoverflow.com/questions/34517484/persistent-rectangle-selector)。 – ImportanceOfBeingErnest