RectangleSelector Disappears on Zoom

前端 未结 3 708
盖世英雄少女心
盖世英雄少女心 2021-02-14 07:59

When I run this example and create a rectangular selection if I zoom or move the plot window around the selection disappears until I deselect the move or zoom tool and click on

相关标签:
3条回答
  • 2021-02-14 08:36

    Adding a callback for draw_events:

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

    makes the RectangleSelector persist after zooming or panning, and is compatible with useblit=True.


    For example, using the code from the docs as a base:

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

    Why does mycallback work but persist_rect doesn't?

    If you uncomment the commented-out statements above, you'll get some printed output which will look something as this:

    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
    

    Notice that persist_rect gets called before figure.draw, while mycallback is called afterwards. figure.draw does not draw the RectangleSelection, but it does draw the Rectangle used for the background. So figure.draw obscures RectangleSelection. Thus persist_rect momentarily displays RectangleSelection, but it fails to persist. mycallback works because it is called after figure.draw.

    0 讨论(0)
  • 2021-02-14 08:44

    In the source code for RectangularSelector the release method (line 2119) handles the visibility of the selector

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

    Subclass RectangleSelector to modify the release method

    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
    

    Sample Code using doc example

    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()
    
    0 讨论(0)
  • If I understand correctly, the rectangle selector should stay visible throughout the process of panning or zooming. This could be achieved by not using blitting,

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

    A side effect of this is that the plotting may become slow depending on the complexity of the plot, as without blitting, the complete plot is continuously redrawn while using the rectangle selector.

    0 讨论(0)
提交回复
热议问题