2

I am trying to develop a pipeline to process astronomical data. At some point, I need to draw a rectangle over an image to select an area. I am doing that using matplotlib.widgets.RectangleSelector. It is very convenient for me to use it since it is very easy to use. The only "problem" that I have is that the rectangle that I draw on the axis disappears after I release the mouse button. Is there any way to make it persistent? I mean, is there any way that I can make it stay there even once I release the button?

I am using Matplotlib's examples as reference. http://matplotlib.org/examples/widgets/rectangle_selector.html

Bruno Quint
  • 111
  • 1
  • 7

1 Answers1

3

Update: This is no longer needed. Using the current version of matplotlib, 2.0.2, the example in the docs persists when the mouse is released.


The rectangle disappears because RectangleSelector's release method calls

    # make the box/line invisible again
    self.to_draw.set_visible(False)
    self.canvas.draw()

To modify this behavior you could subclass RectangleSelector and give it its own release method:

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

Thus building on the example from the docs,

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

class MyRectangleSelector(widgets.RectangleSelector):
    def release(self, event):
        super(MyRectangleSelector, 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 plotingrange
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 = MyRectangleSelector(current_ax, line_select_callback,
                                       drawtype='box', useblit=True,
                                       button=[1, 3],  # don't use middle button
                                       minspanx=5, minspany=5,
                                       spancoords='pixels')
plt.connect('key_press_event', toggle_selector)
plt.show()
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 1
    When running this code with matplotlib 2.0.2, the rectangle selector does not persist. Is this due to the new version? There is [this new question](https://stackoverflow.com/questions/45531164/rectangleselector-disappears-on-zoom) about a related issue (rectangle should persist after zooming), which also does not yet have a working solution for the case when blitting needs to be used. – ImportanceOfBeingErnest Aug 16 '17 at 13:10