使用wxPython可拖动Matplotlib子图

时间:2016-04-19 14:30:31

标签: python matplotlib wxpython

我试图通过创建一个可以拖动的子图(matplotlib曲线,而不是整个窗口)来扩展可拖动的绘图教程。我觉得我很接近但只是错过了一个关键的细节。

大多数代码只是创建cookie切割器子图,图3是我尝试拖动绘图数据的唯一一个。

任何帮助将不胜感激!

import wxversion
wxversion.ensureMinimal('2.8')

import numpy as np

import matplotlib
matplotlib.interactive(True)

matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure

import wx

class DraggableCurve:

    def __init__(self,curve):
        self.curve = curve[0]
        self.press = None

    def connect(self):
        'connect to all the events we need'
        self.cidpress = self.curve.figure.canvas.mpl_connect(
            'button_press_event', self.on_press)
        self.cidrelease = self.curve.figure.canvas.mpl_connect(
            'button_release_event', self.on_release)
        self.cidmotion = self.curve.figure.canvas.mpl_connect(
            'motion_notify_event', self.on_motion)

    def on_press(self, event):
        print "on_press"
        'on button press we will see if the mouse is over us and store some data'
        if event.inaxes != self.curve.axes: return

        contains, attrd = self.curve.contains(event)
        if not contains: return
        print 'event contains', self.curve.xy
        x0, y0 = self.curve.xy
        # print x0,y0
        self.press = x0, y0, event.xdata, event.ydata

    def on_motion(self, event):
        print "on_motion"
        'on motion we will move the curve if the mouse is over us'
        if self.press is None: return
        if event.inaxes != self.curve.axes: return
        x0, y0, xpress, ypress = self.press
        print xpress, ypress
        dx = event.xdata - xpress
        dy = event.ydata - ypress
        #print 'x0=%f, xpress=%f, event.xdata=%f, dx=%f, x0+dx=%f'%(x0, xpress, event.xdata, dx, x0+dx)
        self.curve.set_x(x0+dx)
        self.curve.set_y(y0+dy)
        # print x0+dx, y0+dy

        #self.curve.figure.canvas.draw()
        self.curve.figure.canvas.draw_idle()

    def on_release(self, event):
        print "on_release"
        'on release we reset the press data'
        self.press = None
        #self.curve.figure.canvas.draw()
        self.curve.figure.canvas.draw_idle()

    def disconnect(self):
        'disconnect all the stored connection ids'
        self.curve.figure.canvas.mpl_disconnect(self.cidpress)
        self.curve.figure.canvas.mpl_disconnect(self.cidrelease)
        self.curve.figure.canvas.mpl_disconnect(self.cidmotion)

class CanvasFrame(wx.Frame):

    def __init__(self):

        #create frame
        frame = wx.Frame.__init__(self,None,-1,
                         'Test',size=(550,350))

        #set background
        self.SetBackgroundColour(wx.NamedColour("WHITE"))

        #initialize figures
        self.figure1 = Figure()
        self.figure2 = Figure()
        self.figure3 = Figure()
        self.figure4 = Figure()

        #initialize figure1
        self.axes1 = self.figure1.add_subplot(111)
        self.axes1.text(0.5,0.5, 'Test 1', horizontalalignment='center', fontsize=15)
        self.axes1.get_xaxis().set_visible(False)
        self.axes1.get_yaxis().set_visible(False)
        self.canvas1 = FigureCanvas(self, -1, self.figure1)

        #initialize figure2
        self.axes2 = self.figure2.add_subplot(111)
        self.axes2.text(0.5,0.5, 'Test 2', horizontalalignment='center', fontsize=15)
        self.axes2.get_xaxis().set_visible(False)
        self.axes2.get_yaxis().set_visible(False)
        self.canvas2 = FigureCanvas(self, -1, self.figure2)

        #initialize figure3
        self.axes3 = self.figure3.add_subplot(111)
        curve = self.axes3.plot(np.arange(1,11),10*np.random.rand(10),color='r',marker='o')
        self.canvas3 = FigureCanvas(self, -1, self.figure3)
        # self.axes3.get_xaxis().set_visible(True)
        # self.axes3.get_yaxis().set_visible(True)
        # self.canvas3.draw()
        # self.canvas3.draw_idle()
        dc = DraggableCurve(curve)
        dc.connect()

        #initialize figure4
        self.axes4 = self.figure4.add_subplot(111)
        self.axes4.text(0.5,0.5, 'Test4', horizontalalignment='center', fontsize=15)
        self.axes4.get_xaxis().set_visible(False)
        self.axes4.get_yaxis().set_visible(False)
        self.canvas4 = FigureCanvas(self, -1, self.figure4)

        #create figures into the 2x2 grid
        self.sizer = wx.GridSizer(rows=2, cols=2, hgap=5, vgap=5)
        self.sizer.Add(self.canvas1, 1, wx.EXPAND)
        self.sizer.Add(self.canvas2, 1, wx.EXPAND)
        self.sizer.Add(self.canvas3, 1, wx.EXPAND)
        self.sizer.Add(self.canvas4, 1, wx.EXPAND)
        self.SetSizer(self.sizer)
        self.Fit()

        return

class App(wx.App):

    def OnInit(self):
        'Create the main window and insert the custom frame'
        frame = CanvasFrame()
        frame.Show(True)

        return True

app = App(0)
app.MainLoop()

enter image description here

1 个答案:

答案 0 :(得分:1)

检查此示例:

# -*- coding: utf-8 -*-
import wxversion
wxversion.ensureMinimal('2.8')
import wx
import numpy as np
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.figure import Figure

class FigureCanvas(FigureCanvasWxAgg):
    def __init__(self,parent,id,figure,**kwargs):
        FigureCanvasWxAgg.__init__(self,parent=parent, id=id, figure=figure,**kwargs)
        self.figure = figure
        self.axes = self.figure.get_axes()[0] # Get axes
        self.connect() # Connect event

    def connect(self):
        """Connect pick event"""
        self.MOVE_LINE_EVT = self.mpl_connect("pick_event", self.on_pick)

    def on_pick(self,event):
        self._selected_line = event.artist # Get selected line
        # Get initial x,y data
        self._p0 = (event.mouseevent.xdata, event.mouseevent.ydata)
        self._xdata0 = self._selected_line.get_xdata()
        self._ydata0 = self._selected_line.get_ydata()
        # Connect events for motion and release.
        self._on_motion = self.mpl_connect("motion_notify_event", self.on_motion)
        self._on_release = self.mpl_connect("button_release_event", self.on_release)

    def on_motion(self,event):
        cx = event.xdata # Current xdata
        cy = event.ydata # Current ydata
        deltax = cx - self._p0[0]
        deltay = cy - self._p0[1]
        self._selected_line.set_xdata(self._xdata0 + deltax)
        self._selected_line.set_ydata(self._ydata0 + deltay)
        self.draw()

    def on_release(self,event):
        """On release, disconnect motion and release"""
        self.mpl_disconnect(self._on_motion)
        self.mpl_disconnect(self._on_release)
        self.axes.relim()
        self.axes.autoscale_view(True,True,True)
        self.draw()


class Frame(wx.Frame):
    def __init__(self,parent,title):
        wx.Frame.__init__(self,parent,title=title,size=(800,600))
        self.initCtrls()
        self.plotting()
        self.Centre(True)
        self.Show()

    def initCtrls(self):
        self.mainsizer = wx.GridSizer(rows=2, cols=2, hgap=2, vgap=2)
        # 1
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self, wx.ID_ANY, self.figure)

        # 2
        self.figure2 = Figure()
        self.axes2 = self.figure2.add_subplot(111)
        self.canvas2 = FigureCanvas(self, wx.ID_ANY, self.figure2)

        self.figure3 = Figure()
        self.axes3 = self.figure3.add_subplot(111)
        self.canvas3 = FigureCanvas(self, wx.ID_ANY, self.figure3)

        self.figure4 = Figure()
        self.axes4 = self.figure4.add_subplot(111)
        self.canvas4 = FigureCanvas(self, wx.ID_ANY, self.figure4)

        self.mainsizer.Add(self.canvas, 1, wx.EXPAND)
        self.mainsizer.Add(self.canvas2, 1, wx.EXPAND)
        self.mainsizer.Add(self.canvas3, 1, wx.EXPAND)
        self.mainsizer.Add(self.canvas4, 1, wx.EXPAND)
        self.SetSizer(self.mainsizer)

    def plotting(self):
        # Set picker property -> true
        self.axes2.plot(np.arange(1,11),10*np.random.rand(10),color='b',
                       marker='o', picker=True)
        self.axes3.plot(np.arange(1,11),10*np.random.rand(10),color='r',
                       marker='o', picker=True)
        self.canvas.draw()


if __name__=='__main__':
    app = wx.App()
    frame = Frame(None, "Matplotlib Demo")
    frame.Show()
    app.MainLoop()

基本上,我们的想法是定义一个自定义的FigureCanvas,它支持使用pick事件选择和移动线条。

显然,这段代码仍然需要大量的审核才能正常运行。