0

i need to define 2 rectangleselector that moves at the same time and in same region, when i move one another moves at the same time how i can do that ?

that is a simple code with 2 plot in 2 panel and 2 rectangle

is possible to make the two rectangle move in the same time cause i didn't find any exemple for that in the web or in matplotlib

i use wxpython 4 for python3.6

import wx
from numpy import arange, sin, pi,cos
import numpy as np
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.widgets import RectangleSelector
from matplotlib.figure import Figure



class MainFrame(wx.Frame):
    def __init__(self, parent ):
        wx.Panel.__init__(self, parent,name="Main", size = (600,800))
        Top = PanelTop(self)
        Bottom = PanelBottom(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(Top, 1, wx.EXPAND)
        sizer.Add(Bottom, 1, wx.EXPAND)
        self.SetSizer(sizer)


class PanelTop(wx.Panel):
    def __init__(self,parent):
        wx.Panel.__init__(self,parent,size = (300,300))
        self.SetBackgroundColour('white')
        self.figure = Figure(figsize = (4,5))
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self,-1,self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)


        t = arange(0.5, 3.0, 0.01)
        s = cos(2 * pi * t)
        self.axes.plot(t, s)
        self.RS = RectangleSelector(self.axes,self.line_select_callback,
                                       drawtype='box', useblit=False,
                                       button=[1, 3],minspanx=1, minspany=1,
                                       spancoords='pixels',
                                       interactive=True, rectprops = dict(facecolor='None',edgecolor='red',alpha=5,fill=False))
        self.RS.to_draw.set_visible(True)
        self.RS.extents = (1,0,0,1)



    def line_select_callback(self, eclick, erelease):
         x1, y1 = eclick.xdata, eclick.ydata
         x2, y2 = erelease.xdata, erelease.ydata


class PanelBottom(wx.Panel):
    def __init__(self,parent):
        wx.Panel.__init__(self, parent, size = (300,300))
        self.SetBackgroundColour('grey77')
        self.figure = Figure(figsize = (4,5))
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self,-1,self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)

        t = arange(0.0, 3.0, 0.01)
        s = sin(2 * pi * t)
        self.axes.plot(t, s)
        self.RS = RectangleSelector(self.axes,self.line_select_callback,
                                       drawtype='box', useblit=False,
                                       button=[1, 3],minspanx=1, minspany=1,
                                       spancoords='pixels',
                                       interactive=True, rectprops = dict(facecolor='None',edgecolor='red',alpha=5,fill=False))
        self.RS.to_draw.set_visible(True)
        self.RS.extents = (1,0,0,1)



    def line_select_callback(self, eclick, erelease):
         x1, y1 = eclick.xdata, eclick.ydata
         x2, y2 = erelease.xdata, erelease.ydata



app = wx.App()
frame = MainFrame(None).Show()
app.MainLoop()

thank you in advance

Sarah Tohami
  • 59
  • 1
  • 12

1 Answers1

1

I have no idea if this is the way that it should be done but here is one way.
I've commented the code where appropriate.
The method simply grubs the cordinates of the first Rectangle forces them into the second and then redraws it.
The second rectangle is made Inactive as it is meant to be a slave of the first and if it isn't inactive, the control points at the corners and middle, fail to move with the rectangle. This leads me to believe that there may be a less hacky way of achieving the same result.

import wx
from numpy import arange, sin, pi,cos
import numpy as np
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.widgets import RectangleSelector
from matplotlib.figure import Figure

class MainFrame(wx.Frame):
    def __init__(self, parent ):
        wx.Panel.__init__(self, parent,name="Main", size = (600,800))
        self.Top = PanelTop(self)
        self.Bottom = PanelBottom(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.Top, 1, wx.EXPAND)
        sizer.Add(self.Bottom, 1, wx.EXPAND)
        self.SetSizer(sizer)

class PanelTop(wx.Panel):
    def __init__(self,parent):
        wx.Panel.__init__(self,parent,size = (300,300))
        self.SetBackgroundColour('white')
        self.figure = Figure(figsize = (4,5))
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self,-1,self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)


        t = arange(0.5, 3.0, 0.01)
        s = cos(2 * pi * t)
        self.axes.plot(t, s)
        self.RS = RectangleSelector(self.axes,self.line_select_callback,
                                       drawtype='box', useblit=False,
                                       button=[1, 3],minspanx=1, minspany=1,
                                       spancoords='pixels',
                                       interactive=True, rectprops = dict(facecolor='None',edgecolor='red',alpha=5,fill=False))
        self.RS.to_draw.set_visible(True)
        self.RS.extents = (1,0,0,1)

    def line_select_callback(self, eclick, erelease):
        x1, y1 = eclick.xdata, eclick.ydata
        x2, y2 = erelease.xdata, erelease.ydata
        rect = self.RS.artists[0] # Rectangle artist
        slave_rect = self.Parent.Bottom.RS.artists[0] # Rectangle artist
        slave_canvas = self.Parent.Bottom.canvas

        # Force new positional values into slave rectangle
        slave_rect.set_x(x1)
        slave_rect.set_y(y1)
        slave_rect.set_width(x2-x1)
        slave_rect.set_height(y2-y1)
        slave_rect.update(dict(facecolor='None',edgecolor='red',alpha=5,fill=False))
        #Force visible in case slave rectangle has been clicked on
        slave_rect.set_visible(True)
        #Redraw slave rectangle
        slave_canvas.draw()

class PanelBottom(wx.Panel):
    def __init__(self,parent):
        wx.Panel.__init__(self, parent, size = (300,300))
        self.SetBackgroundColour('grey77')
        self.figure = Figure(figsize = (4,5))
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self,-1,self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)

        t = arange(0.0, 3.0, 0.01)
        s = sin(2 * pi * t)
        self.axes.plot(t, s)
        self.RS = RectangleSelector(self.axes,self.line_select_callback,
                                       drawtype='box', useblit=False,
                                       button=[1, 3],minspanx=1, minspany=1,
                                       spancoords='pixels',
                                       interactive=False, rectprops = dict(facecolor='None',edgecolor='red',alpha=5,fill=False))
        self.RS.to_draw.set_visible(True)
        self.RS.extents = (1,0,0,1)

    def line_select_callback(self, eclick, erelease):
        x1, y1 = eclick.xdata, eclick.ydata
        x2, y2 = erelease.xdata, erelease.ydata

app = wx.App()
frame = MainFrame(None).Show()
app.MainLoop()
Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60