source: sasview/guitools/PlotPanel.py @ 2bf92f2

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 2bf92f2 was 2bf92f2, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Initial import for SANS guitools

  • Property mode set to 100644
File size: 8.5 KB
Line 
1import wx
2import matplotlib
3matplotlib.interactive(False)
4#Use the WxAgg back end. The Wx one takes too long to render
5matplotlib.use('WXAgg')
6from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
7from matplotlib.figure import Figure
8import os
9
10from canvas import FigureCanvas
11#TODO: make the plottables interactive
12
13def show_tree(obj,d=0):
14    """Handy function for displaying a tree of graph objects"""
15    print "%s%s" % ("-"*d,obj.__class__.__name__)
16    if 'get_children' in dir(obj):
17        for a in obj.get_children(): show_tree(a,d+1)
18
19
20
21class PlotPanel(wx.Panel):
22    """
23    The PlotPanel has a Figure and a Canvas. OnSize events simply set a
24    flag, and the actually redrawing of the
25    figure is triggered by an Idle event.
26    """
27    def __init__(self, parent, id = -1, color = None,\
28        dpi = None, **kwargs):
29        wx.Panel.__init__(self, parent, id = id, **kwargs)
30
31        self.figure = Figure(None, dpi)
32        #self.figure = pylab.Figure(None, dpi)
33        #self.canvas = NoRepaintCanvas(self, -1, self.figure)
34        self.canvas = FigureCanvas(self, -1, self.figure)
35        self.SetColor(color)
36        #self.Bind(wx.EVT_IDLE, self._onIdle)
37        #self.Bind(wx.EVT_SIZE, self._onSize)
38        self._resizeflag = True
39        self._SetSize()
40        self.subplot = self.figure.add_subplot(111)
41        self.figure.subplots_adjust(left=.2, bottom=.2)
42        self.yscale = 'linear'
43
44        sizer = wx.BoxSizer(wx.VERTICAL)
45        sizer.Add(self.canvas,1,wx.EXPAND)
46        self.SetSizer(sizer)
47
48
49       
50        self.Bind(wx.EVT_CONTEXT_MENU, self.onContextMenu)
51
52        # Define some constants
53        self.colorlist = ['b','g','r','c','m','y']
54        self.symbollist = ['o','x','^','v','<','>','+','s','d','D','h','H','p']
55
56    def set_yscale(self, scale='linear'):
57        self.subplot.set_yscale(scale)
58        self.yscale = scale
59       
60    def get_yscale(self):
61        return self.yscale
62
63    def SetColor(self, rgbtuple):
64        """Set figure and canvas colours to be the same"""
65        if not rgbtuple:
66            rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
67        col = [c/255.0 for c in rgbtuple]
68        self.figure.set_facecolor(col)
69        self.figure.set_edgecolor(col)
70        self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
71
72    def _onSize(self, event):
73        self._resizeflag = True
74
75    def _onIdle(self, evt):
76        if self._resizeflag:
77            self._resizeflag = False
78            self._SetSize()
79            self.draw()
80
81    def _SetSize(self, pixels = None):
82        """
83        This method can be called to force the Plot to be a desired size, which defaults to
84        the ClientSize of the panel
85        """
86        if not pixels:
87            pixels = self.GetClientSize()
88        self.canvas.SetSize(pixels)
89        self.figure.set_size_inches(pixels[0]/self.figure.get_dpi(),
90        pixels[1]/self.figure.get_dpi())
91
92    def draw(self):
93        """Where the actual drawing happens"""
94        self.figure.canvas.draw_idle()
95       
96
97
98    def onSaveImage(self, evt):
99        #figure.savefig
100        print "Save image not implemented"
101        path = None
102        dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.png", wx.SAVE)
103        if dlg.ShowModal() == wx.ID_OK:
104            path = dlg.GetPath()
105            mypath = os.path.basename(path)
106            print path
107        dlg.Destroy()
108        if not path == None:
109            self.subplot.figure.savefig(path,dpi=300, facecolor='w', edgecolor='w',
110                                        orentation='portrait', papertype=None, format='png')
111       
112    def onContextMenu(self, event):
113        """
114            Default context menu for a plot panel
115        """
116        # Slicer plot popup menu
117        slicerpop = wx.Menu()
118        slicerpop.Append(313,'&Save image', 'Save image as PNG')
119        wx.EVT_MENU(self, 313, self.onSaveImage)
120
121        pos = event.GetPosition()
122        pos = self.ScreenToClient(pos)
123        self.PopupMenu(slicerpop, pos)
124       
125   
126    ## The following is plottable functionality
127
128
129    def properties(self,prop):
130        """Set some properties of the graph.
131       
132        The set of properties is not yet determined.
133        """
134        # The particulars of how they are stored and manipulated (e.g., do
135        # we want an inventory internally) is not settled.  I've used a
136        # property dictionary for now.
137        #
138        # How these properties interact with a user defined style file is
139        # even less clear.
140
141        # Properties defined by plot
142        self.subplot.set_xlabel(r"$%s$" % prop["xlabel"])
143        self.subplot.set_ylabel(r"$%s$" % prop["ylabel"])
144        self.subplot.set_title(prop["title"])
145
146        # Properties defined by user
147        #self.axes.grid(True)
148
149    def clear(self):
150        """Reset the plot"""
151       
152        # TODO: Redraw is brutal.  Render to a backing store and swap in
153        # TODO: rather than redrawing on the fly.
154        self.subplot.clear()
155        self.subplot.hold(True)
156
157
158    def render(self):
159        """Commit the plot after all objects are drawn"""
160        # TODO: this is when the backing store should be swapped in.
161        from matplotlib.font_manager import FontProperties
162        self.subplot.legend(prop=FontProperties(size=10))
163        #self.subplot.legend()
164        pass
165
166    def xaxis(self,label,units):
167        """xaxis label and units.
168       
169        Axis labels know about units.
170       
171        We need to do this so that we can detect when axes are not
172        commesurate.  Currently this is ignored other than for formatting
173        purposes.
174        """
175        if units != "": label = label + " (" + units + ")"
176        self.subplot.set_xlabel(label)
177        pass
178   
179    def yaxis(self,label,units):
180        """yaxis label and units."""
181        if units != "": label = label + " (" + units + ")"
182        self.subplot.set_ylabel(label)
183        pass
184
185    def _connect_to_xlim(self,callback):
186        """Bind the xlim change notification to the callback"""
187        def process_xlim(axes):
188            lo,hi = subplot.get_xlim()
189            callback(lo,hi)
190        self.subplot.callbacks.connect('xlim_changed',process_xlim)
191   
192    #def connect(self,trigger,callback):
193    #    print "PlotPanel.connect???"
194    #    if trigger == 'xlim': self._connect_to_xlim(callback)
195
196    def points(self,x,y,dx=None,dy=None,color=0,symbol=0,label=None):
197        """Draw markers with error bars"""
198        self.subplot.set_yscale('linear')
199        # Convert tuple (lo,hi) to array [(x-lo),(hi-x)]
200        if dx != None and type(dx) == type(()):
201            dx = nx.vstack((x-dx[0],dx[1]-x)).transpose()
202        if dy != None and type(dy) == type(()):
203            dy = nx.vstack((y-dy[0],dy[1]-y)).transpose()
204
205        if dx==None and dy==None:
206            h = self.subplot.plot(x,y,color=self._color(color),
207                                   marker=self._symbol(symbol),linestyle='',label=label)
208        else:
209            self.subplot.errorbar(x, y, yerr=dy, xerr=None,
210             ecolor=self._color(color), capsize=2,linestyle='', barsabove=False,
211             marker=self._symbol(symbol),
212             lolims=False, uplims=False,
213             xlolims=False, xuplims=False,label=label)
214           
215        self.subplot.set_yscale(self.yscale)
216
217    def curve(self,x,y,dy=None,color=0,symbol=0,label=None):
218        """Draw a line on a graph, possibly with confidence intervals."""
219        c = self._color(color)
220        self.subplot.set_yscale('linear')
221       
222        hlist = self.subplot.plot(x,y,color=c,marker='',linestyle='-',label=label)
223       
224        self.subplot.set_yscale(self.yscale)
225
226    def _color(self,c):
227        """Return a particular colour"""
228        return self.colorlist[c%len(self.colorlist)]
229
230    def _symbol(self,s):
231        """Return a particular symbol"""
232        return self.symbollist[s%len(self.symbollist)]
233
234
235   
236
237class NoRepaintCanvas(FigureCanvasWxAgg):
238    """We subclass FigureCanvasWxAgg, overriding the _onPaint method, so that
239    the draw method is only called for the first two paint events. After that,
240    the canvas will only be redrawn when it is resized.
241    """
242    def __init__(self, *args, **kwargs):
243        FigureCanvasWxAgg.__init__(self, *args, **kwargs)
244        self._drawn = 0
245
246    def _onPaint(self, evt):
247        """
248        Called when wxPaintEvt is generated
249        """
250        if not self._isRealized:
251            self.realize()
252        if self._drawn < 2:
253            self.draw(repaint = False)
254            self._drawn += 1
255        self.gui_repaint(drawDC=wx.PaintDC(self))
256           
Note: See TracBrowser for help on using the repository browser.