Matplotlib 使用wx.SplitterWindow时如何在wxPython中显示光标坐标

Matplotlib 使用wx.SplitterWindow时如何在wxPython中显示光标坐标,matplotlib,wxpython,marker,Matplotlib,Wxpython,Marker,我正在尝试做一些类似于本文所示的事情,以绘制一个光标并在状态栏中报告数据坐标。但是,我的代码有点不同,因为我需要使用wx.SplitterWindow来分离按钮和绘图。基本上,在主框架模块中,我创建了状态栏,但绘图是在单独的模块中生成的。请参见下面我的当前代码: from matplotlib.figure import Figure from matplotlib.backends.backend_wxagg import \ FigureCanvasWxAgg as FigCanva

我正在尝试做一些类似于本文所示的事情,以绘制一个光标并在状态栏中报告数据坐标。但是,我的代码有点不同,因为我需要使用wx.SplitterWindow来分离按钮和绘图。基本上,在主框架模块中,我创建了状态栏,但绘图是在单独的模块中生成的。请参见下面我的当前代码:

from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
    FigureCanvasWxAgg as FigCanvas, \
    NavigationToolbar2WxAgg as NavigationToolbar, \
    wxc as wxc

import pylab
import wx
from numpy import arange, sin, pi

class data:
    def __init__(self):
        self.t = []
        self.s = []

class Plot_Panel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        # create some sizers
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        checkSizer = wx.BoxSizer(wx.HORIZONTAL)

        # create figrue
        self.fig = Figure()
        self.canvas = FigCanvas(self, -1, self.fig)
        self.axes = self.fig.add_subplot(111)

        # create the widgets
        self.toggleMarker = wx.CheckBox(self, label="Show Marker")

        # layout the widgets
        mainSizer.Add(self.canvas, 1, wx.EXPAND)
        checkSizer.Add(self.toggleMarker, 0, wx.ALL, 5)
        mainSizer.Add(checkSizer)
        self.SetSizer(mainSizer)

    def draw_plot(self, data):
        # Clear the previous figure
        self.fig.clear()

        # Redraw figure
        self.axes = self.fig.add_subplot(111)

        # Define data to plot
        self.plot_data= self.axes.plot(data.t, data.s, linewidth=3, color='y',)[0]

        # Draw Cursor or not
        if self.toggleMarker.IsChecked():
            # Note that event is a MplEvent
            self.canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar)
            self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor)

        self.canvas.draw()

    def ChangeCursor(self, event):
        self.canvas.SetCursor(wxc.StockCursor(wx.CURSOR_BULLSEYE))

    def UpdateStatusBar(self, event):
        if event.inaxes:
            x, y = event.xdata, event.ydata
            # self.statusBar.SetStatusText(("x= "+str(Pos.x)+"  y="+str(Pos.y)))


class Button_Panel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        # create the widgets
        self.toggleStart = wx.Button(self, id=wx.ID_ANY, label="Plot data")


class ProportionalSplitter(wx.SplitterWindow):
    def __init__(self,parent, id = -1, proportion=0.66, size = wx.DefaultSize, **kwargs):
        wx.SplitterWindow.__init__(self,parent,id,wx.Point(0, 0),size, **kwargs)
        self.SetMinimumPaneSize(50) #the minimum size of a pane.
        self.proportion = proportion
        if not 0 < self.proportion < 1:
            raise ValueError, "proportion value for ProportionalSplitter must be between 0 and 1."
        self.ResetSash()
        self.Bind(wx.EVT_SIZE, self.OnReSize)
        self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged, id=id)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.firstpaint = True

    def SplitHorizontally(self, win1, win2):
        if self.GetParent() is None: return False
        return wx.SplitterWindow.SplitHorizontally(self, win1, win2,
            int(round(self.GetParent().GetSize().GetHeight() * self.proportion)))

    def SplitVertically(self, win1, win2):
        if self.GetParent() is None: return False
        return wx.SplitterWindow.SplitVertically(self, win1, win2,
            int(round(self.GetParent().GetSize().GetWidth() * self.proportion)))

    def GetExpectedSashPosition(self):
        if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
        else:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
        return int(round(tot * self.proportion))

    def ResetSash(self):
        self.SetSashPosition(self.GetExpectedSashPosition())

    def OnReSize(self, event):
        "Window has been resized, so we need to adjust the sash based on self.proportion."
        self.ResetSash()
        event.Skip()

    def OnSashChanged(self, event):
        "We'll change self.proportion now based on where user dragged the sash."
        pos = float(self.GetSashPosition())
        if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
        else:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
        self.proportion = pos / tot
        event.Skip()

    def OnPaint(self, event):
        if self.firstpaint:
            if self.GetSashPosition() != self.GetExpectedSashPosition():
                self.ResetSash()
            self.firstpaint = False
        event.Skip()

class Main_Window(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title = title)

        # Create a StatusBar at the bottom of the window
        self.statusBar = wx.StatusBar(self, -1)
        self.SetStatusBar(self.statusBar)

        # Set plot panel
        self.splitter = ProportionalSplitter(self,-1, 0.85)
        self.ppanel = Plot_Panel(self.splitter)
        self.ppanel.SetBackgroundColour('#ffffff')

        # Set button panel                           
        self.bpanel = Button_Panel(self.splitter)

        # Set frame 
        self.splitter.SplitVertically(self.ppanel, self.bpanel)
        self.Show(True)
        self.Maximize(True)  

        # bind the widgets
        self.ppanel.toggleMarker.Bind(wx.EVT_CHECKBOX, self.onToggleMarker)
        self.bpanel.toggleStart.Bind(wx.EVT_BUTTON, self.onToggleStart)        

        # Set classes
        self.data = data()


    def onToggleMarker(self, event):
        self.ppanel.draw_plot(self.data)

    def onToggleStart(self, event):

        self.data.t = arange(0.0, 1.0, 0.01)
        self.data.s = sin(2*2*pi*self.data.t)

        # plot data
        self.ppanel.draw_plot(self.data)


def main():
    app = wx.App(False)
    frame = Main_Window(None, "GUI")
    frame.Show()
    app.MainLoop()


if __name__ == "__main__" :
    main()
从matplotlib.figure导入图形
从matplotlib.backends.backend_wxagg导入\
图CAVASWXAGG作为FigCanvas\
导航工具栏2WXAGG作为导航工具栏\
wxc作为wxc
进口派拉布
导入wx
来自numpy import arange,sin,pi
类别数据:
定义初始化(自):
self.t=[]
self.s=[]
类绘图面板(wx.Panel):
定义初始化(自身,父级):
wx.Panel.\uuuuu init\uuuuuuuuuuuux(自,父)
#创建一些大小写
mainSizer=wx.BoxSizer(wx.VERTICAL)
checkSizer=wx.BoxSizer(wx.HORIZONTAL)
#创建figrue
self.fig=图()
self.canvas=FigCanvas(self,-1,self.fig)
self.axes=self.fig.add_子批次(111)
#创建小部件
self.toggleMarker=wx.CheckBox(self,label=“Show Marker”)
#布局小部件
mainSizer.Add(self.canvas,1,wx.EXPAND)
checkSizer.Add(self.toggleMarker,0,wx.ALL,5)
mainSizer.Add(checkSizer)
自我设定器(主施胶器)
def绘图(自身、数据):
#清除上一个图
self.fig.clear()
#重画数字
self.axes=self.fig.add_子批次(111)
#定义要打印的数据
self.plot_data=self.axes.plot(data.t,data.s,线宽=3,color='y',)[0]
#是否绘制光标
如果self.toggleMarker.IsChecked():
#请注意,事件是一个事件
self.canvas.mpl\u connect('motion\u notify\u event',self.UpdateStatusBar)
self.canvas.Bind(wx.EVT_ENTER_窗口,self.ChangeCursor)
self.canvas.draw()
def ChangeCursor(自身、事件):
self.canvas.SetCursor(wxc.StockCursor(wx.CURSOR\u BULLSEYE))
def UpdateStatusBar(自身,事件):
如果event.inaxes:
x、 y=event.xdata,event.ydata
#self.statusBar.SetStatusText((((“x=“+str(Pos.x)+”y=“+str(Pos.y)))
类按钮面板(wx.面板):
定义初始化(自身,父级):
wx.Panel.\uuuuu init\uuuuuuuuuuuux(自,父)
#创建小部件
self.toggleStart=wx.Button(self,id=wx.id\u ANY,label=“绘图数据”)
类比例拆分器(wx.SplitterWindow):
def u uu init_uuuu(self,parent,id=-1,proporty=0.66,size=wx.DefaultSize,**kwargs):
wx.SplitterWindow.\uuuuu init\uuuuuuux(self,parent,id,wx.Point(0,0),size,**kwargs)
self.setminimumpanese(50)#窗格的最小尺寸。
自成比例
如果不是0<自身比例<1:
raise value ERROR,“比例拆分器的比例值必须介于0和1之间。”
self.ResetSash()
self.Bind(wx.EVT_SIZE,self.OnReSize)
self.Bind(wx.EVT\u SPLITTER\u SASH\u POS\u已更改,self.OnSashChanged,id=id)
self.Bind(wx.EVT_-PAINT,self.OnPaint)
self.firstpaint=True
def水平拆分(自、win1、win2):
如果self.GetParent()为None:返回False
返回wx.SplitterWindow.splitanvely(self、win1、win2、,
int(舍入(self.GetParent().GetSize().GetHeight()*self.proportion)))
def垂直拆分(自、win1、win2):
如果self.GetParent()为None:返回False
返回wx.SplitterWindow.splitvertical(self、win1、win2、,
int(舍入(self.GetParent().GetSize().GetWidth()*self.proportion)))
def GetExpectedSashPosition(自身):
如果self.GetSplitMode()==wx.SPLIT\u水平:
tot=max(self.getMinimumPanese(),self.GetParent().GetClientSize().height)
其他:
tot=max(self.getMinimumPanese(),self.GetParent().GetClientSize().width)
返回整数(四舍五入(总和*自身比例))
def重置安全带(自身):
self.SetSashPosition(self.GetExpectedSashPosition())
def OnReSize(自我,事件):
窗口已调整大小,因此我们需要根据自身比例调整窗扇
self.ResetSash()
event.Skip()
def OnSashChanged(自身、事件):
“我们现在将根据用户拖动窗框的位置更改self.proportion。”
pos=float(self.GetSashPosition())
如果self.GetSplitMode()==wx.SPLIT\u水平:
tot=max(self.getMinimumPanese(),self.GetParent().GetClientSize().height)
其他:
tot=max(self.getMinimumPanese(),self.GetParent().GetClientSize().width)
自身比例=pos/tot
event.Skip()
def OnPaint(自身、事件):
如果self.firstpaint:
如果self.GetSashPosition()!=self.GetExpectedSashPosition():
self.ResetSash()
self.firstpaint=False
event.Skip()
类主窗口(wx.Frame):
定义初始(自我、父母、头衔):
wx.Frame.\uuuuu init\uuuuuuuux(自我,父,标题=标题)
#在窗口底部创建一个状态栏
self.statusBar=wx.statusBar(self,-1)
self.SetStatusBar(self.statusBar)
#设置绘图面板
self.splitter=比例分配器(self,-1,0.85)
self.ppanel=绘图面板(self.splitter)
self.ppanel.setbackgroundColor(“#ffffff”)
#设置按钮面板
self.bpanel=按钮面板(self.splitter)
#定格
self.splitter.splitvertical(self.ppanel、self.bpanel)
自我展示(真实)
自我最大化(真)
#绑定小部件
self.ppanel.toggleMarker.Bind(wx.EVT_复选框,self.ontogleMarker)
self.bpanel.toggleStart.Bind(wx.EVT_按钮,self.ontogleStart)
#定级
self.data=data()
def onToggleMarker(自身、事件):
self.ppanel.draw_绘图(self.data)
def onToggleStart(自我,
self.ppanel = Plot_Panel(self.splitter, self)
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
    FigureCanvasWxAgg as FigCanvas, \
    NavigationToolbar2WxAgg as NavigationToolbar, \
    wxc as wxc

import pylab
import wx
from numpy import arange, sin, pi

class data:
    def __init__(self):
        self.t = []
        self.s = []

class Plot_Panel(wx.Panel):
    def __init__(self, parent, base):
        wx.Panel.__init__(self, parent)
        self.base = base
        # create some sizers
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        checkSizer = wx.BoxSizer(wx.HORIZONTAL)

        # create figrue
        self.fig = Figure()
        self.canvas = FigCanvas(self, -1, self.fig)
        self.axes = self.fig.add_subplot(111)

        # create the widgets
        self.toggleMarker = wx.CheckBox(self, label="Show Marker")

        # layout the widgets
        mainSizer.Add(self.canvas, 1, wx.EXPAND)
        checkSizer.Add(self.toggleMarker, 0, wx.ALL, 5)
        mainSizer.Add(checkSizer)
        self.SetSizer(mainSizer)

    def draw_plot(self, data):
        # Clear the previous figure
        self.fig.clear()

        # Redraw figure
        self.axes = self.fig.add_subplot(111)

        # Define data to plot
        self.plot_data= self.axes.plot(data.t, data.s, linewidth=3, color='y',)[0]

        # Draw Cursor or not
        if self.toggleMarker.IsChecked():
            # Note that event is a MplEvent
            self.canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar)
            self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor)

        self.canvas.draw()

    def ChangeCursor(self, event):
        self.canvas.SetCursor(wxc.StockCursor(wx.CURSOR_BULLSEYE))

    def UpdateStatusBar(self, event):
        if event.inaxes:
            x, y = event.xdata, event.ydata
            self.base.statusBar.SetStatusText(("x= "+str(x)+"  y="+str(y)))

class Button_Panel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        # create the widgets
        self.toggleStart = wx.Button(self, id=wx.ID_ANY, label="Plot data")


class ProportionalSplitter(wx.SplitterWindow):
    def __init__(self,parent, id = -1, proportion=0.66, size = wx.DefaultSize, **kwargs):
        wx.SplitterWindow.__init__(self,parent,id,wx.Point(0, 0),size, **kwargs)
        self.SetMinimumPaneSize(50) #the minimum size of a pane.
        self.proportion = proportion
        if not 0 < self.proportion < 1:
            raise ValueError, "proportion value for ProportionalSplitter must be between 0 and 1."
        self.ResetSash()
        self.Bind(wx.EVT_SIZE, self.OnReSize)
        self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged, id=id)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.firstpaint = True

    def SplitHorizontally(self, win1, win2):
        if self.GetParent() is None: return False
        return wx.SplitterWindow.SplitHorizontally(self, win1, win2,
            int(round(self.GetParent().GetSize().GetHeight() * self.proportion)))

    def SplitVertically(self, win1, win2):
        if self.GetParent() is None: return False
        return wx.SplitterWindow.SplitVertically(self, win1, win2,
            int(round(self.GetParent().GetSize().GetWidth() * self.proportion)))

    def GetExpectedSashPosition(self):
        if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
        else:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
        return int(round(tot * self.proportion))

    def ResetSash(self):
        self.SetSashPosition(self.GetExpectedSashPosition())

    def OnReSize(self, event):
        "Window has been resized, so we need to adjust the sash based on self.proportion."
        self.ResetSash()
        event.Skip()

    def OnSashChanged(self, event):
        "We'll change self.proportion now based on where user dragged the sash."
        pos = float(self.GetSashPosition())
        if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
        else:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
        self.proportion = pos / tot
        event.Skip()

    def OnPaint(self, event):
        if self.firstpaint:
            if self.GetSashPosition() != self.GetExpectedSashPosition():
                self.ResetSash()
            self.firstpaint = False
        event.Skip()

class Main_Window(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title = title)

        # Create a StatusBar at the bottom of the window
        self.statusBar = wx.StatusBar(self, -1)
        self.SetStatusBar(self.statusBar)

        # Set plot panel
        self.splitter = ProportionalSplitter(self,-1, 0.85)
        self.ppanel = Plot_Panel(self.splitter, self)
        self.ppanel.SetBackgroundColour('#ffffff')

        # Set button panel
        self.bpanel = Button_Panel(self.splitter)

        # Set frame
        self.splitter.SplitVertically(self.ppanel, self.bpanel)
        self.Show(True)
        self.Maximize(True)

        # bind the widgets
        self.ppanel.toggleMarker.Bind(wx.EVT_CHECKBOX, self.onToggleMarker)
        self.bpanel.toggleStart.Bind(wx.EVT_BUTTON, self.onToggleStart)

        # Set classes
        self.data = data()


    def onToggleMarker(self, event):
        self.ppanel.draw_plot(self.data)

    def onToggleStart(self, event):

        self.data.t = arange(0.0, 1.0, 0.01)
        self.data.s = sin(2*2*pi*self.data.t)

        # plot data
        self.ppanel.draw_plot(self.data)


def main():
    app = wx.App(False)
    frame = Main_Window(None, "GUI")
    frame.Show()
    app.MainLoop()


if __name__ == "__main__" :
    main()