Matplotlib rectangleSelector - Set initial position

此生再无相见时 提交于 2019-12-12 20:46:06

问题


I am working on a project on which I want to select an area on an image in order to do some treatments on this area. So I found this wonderful tool RectangleSelector of matplotlib. But what I want is setting the rectangle at an initial position on the image, instead of waiting for the user clicking a first area (for example a rectangle of 10x10 pixels on top/left of the image).

At first I thought I have to use state_modifier_keys but it doesn't seem to be this.

So, is it possible ?

An example (with plots but it is the same question) can be:

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


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=True,
                                       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:


Without blitting

If you're willing not to use blitting, the solution would be to set the RectangleSelector's patch visible (RS.to_draw.set_visible(True)) and set its extent to the data you want it to be (RS.extents = (0,4,0,1)).

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


def line_select_callback(eclick, erelease):
    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))

fig, current_ax = plt.subplots()
N = 100000 
x = np.linspace(0.0, 10.0, N) 

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)


# drawtype is 'box' or 'line' or 'none'
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)

RS.to_draw.set_visible(True)
fig.canvas.draw()
RS.extents = (0,4,0,1)

plt.show()

With blitting

The above will unfortunately not work when blitting is used.
A solution with blitting would need to involve copying the background, then setting the rectangle visible, but setting the animated property to false. Then for the first time the canvas is drawn the rectangle is shown. However for later use we would need to set the animated property to True again. Hence for the first time a click happens inside the figure, we need to set the animated property to True and blit the canvas with a background which has been saved before showing the rectangle.

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


def line_select_callback(eclick, erelease):
    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))

fig, current_ax = plt.subplots()
N = 100000 
x = np.linspace(0.0, 10.0, N) 

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)


# drawtype is 'box' or 'line' or 'none'
RS = RectangleSelector(current_ax, line_select_callback,
                                       drawtype='box', useblit=True,
                                       button=[1, 3],  # don't use middle button
                                       minspanx=5, minspany=5,
                                       spancoords='pixels',
                                       interactive=True)
fig.canvas.draw()
bg = fig.canvas.copy_from_bbox(RS.ax.bbox)
RS.set_visible(True)

ext = (0,4,0,1)
RS.draw_shape(ext)
# Update displayed handles
RS._corner_handles.set_data(*RS.corners)
RS._edge_handles.set_data(*RS.edge_centers)
RS._center_handle.set_data(*RS.center)
for artist in RS.artists:
    RS.ax.draw_artist(artist)
    artist.set_animated(False)
fig.canvas.draw()

def initclick(evt):
    RS.background = bg
    RS.update()
    for artist in RS.artists:
        artist.set_animated(True)
    fig.canvas.mpl_disconnect(cid)

cid = fig.canvas.mpl_connect("button_press_event",initclick)

plt.show()


来源:https://stackoverflow.com/questions/47529558/matplotlib-rectangleselector-set-initial-position

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!