source: sasview/guitools/PlotPanel.py @ 96f13a9

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 96f13a9 was ac9c465, checked in by Gervaise Alina <gervyh@…>, 16 years ago

plotpanel clean up

  • Property mode set to 100644
File size: 29.2 KB
RevLine 
[52b1f77]1import wx.lib.newevent
[2bf92f2]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
[52b1f77]9import fittings
[831149e]10import transform
[2bf92f2]11from canvas import FigureCanvas
[f193585]12from matplotlib.widgets import RectangleSelector
13from pylab import  gca, gcf
[bbec827]14from plottables import Theory1D
[df25521]15
16#from matplotlib.backend_bases import MouseEvent
[bbec827]17#from plottables import Data1D
[2bf92f2]18#TODO: make the plottables interactive
19
[05da1f89]20DEBUG = False
[df25521]21print "hello"
[05da1f89]22
[52b1f77]23from plottables import Graph
24#(FuncFitEvent, EVT_FUNC_FIT) = wx.lib.newevent.NewEvent()
[b6972a0f]25import math,pylab,re
26
[2bf92f2]27def show_tree(obj,d=0):
28    """Handy function for displaying a tree of graph objects"""
29    print "%s%s" % ("-"*d,obj.__class__.__name__)
30    if 'get_children' in dir(obj):
31        for a in obj.get_children(): show_tree(a,d+1)
[43bf807]32     
33from unitConverter import UnitConvertion as convertUnit   
34def _convertUnit(pow,unit):
[b6972a0f]35    """
36        Displays the unit with the proper convertion
37        @param pow: the user set the power of the unit
38        @param unit: the unit of the data
39    """ 
[052a66bc]40    return unit
[b6972a0f]41    toks=re.match("^", unit)
42    if not toks==None:
43        unitValue= re.split("{",unit)
44        unitPower= re.split("}",unitValue[1])
45        power= int(unitPower[0])*pow
46        word= unitValue[0]+"{"+str(power)+"}"
47        if power==1:
48            tempUnit=re.split("\^",unitValue[0])
49            unit=tempUnit[0]
50        else:
51            unit = word
52    #print"this is unit",unit
53    return unit
[47f695c9]54def _rescale(lo,hi,step,pt=None,bal=None,scale='linear'):
55        """
56        Rescale (lo,hi) by step, returning the new (lo,hi)
57        The scaling is centered on pt, with positive values of step
58        driving lo/hi away from pt and negative values pulling them in.
59        If bal is given instead of point, it is already in [0,1] coordinates.
60   
61        This is a helper function for step-based zooming.
62        """
63        # Convert values into the correct scale for a linear transformation
64        # TODO: use proper scale transformers
[150c04a]65        loprev = lo
66        hiprev = hi
67        ptprev = pt
[47f695c9]68        if scale=='log':
[34ab06d]69            assert lo >0
[150c04a]70            if lo > 0 :
71                lo = math.log10(lo)
72            if hi > 0 :
73                hi = math.log10(hi)
[34ae302]74            if pt is not None: pt = math.log10(pt)
[150c04a]75       
[47f695c9]76        # Compute delta from axis range * %, or 1-% if persent is negative
77        if step > 0:
78            delta = float(hi-lo)*step/100
79        else:
80            delta = float(hi-lo)*step/(100-step)
81   
82        # Add scale factor proportionally to the lo and hi values, preserving the
83        # point under the mouse
84        if bal is None:
85            bal = float(pt-lo)/(hi-lo)
86        lo = lo - bal*delta
87        hi = hi + (1-bal)*delta
88   
89        # Convert transformed values back to the original scale
90        if scale=='log':
[34ab06d]91            if (lo <= -250) or (hi >= 250):
[150c04a]92                lo=loprev
93                hi=hiprev
[ac9c465]94                #print "Not possible to scale"
[34ab06d]95           
[150c04a]96            else:
97                lo,hi = math.pow(10.,lo),math.pow(10.,hi)
98                #assert lo >0,"lo = %g"%lo
[ac9c465]99                #print "possible to scale"
[150c04a]100           
[ac9c465]101            #print "these are low and high",lo,hi
[150c04a]102
[47f695c9]103        return (lo,hi)
[2bf92f2]104
105
106class PlotPanel(wx.Panel):
107    """
108    The PlotPanel has a Figure and a Canvas. OnSize events simply set a
109    flag, and the actually redrawing of the
110    figure is triggered by an Idle event.
111    """
112    def __init__(self, parent, id = -1, color = None,\
113        dpi = None, **kwargs):
114        wx.Panel.__init__(self, parent, id = id, **kwargs)
[52b1f77]115        self.parent = parent
[2bf92f2]116        self.figure = Figure(None, dpi)
117        #self.figure = pylab.Figure(None, dpi)
118        #self.canvas = NoRepaintCanvas(self, -1, self.figure)
119        self.canvas = FigureCanvas(self, -1, self.figure)
120        self.SetColor(color)
121        #self.Bind(wx.EVT_IDLE, self._onIdle)
122        #self.Bind(wx.EVT_SIZE, self._onSize)
123        self._resizeflag = True
124        self._SetSize()
125        self.subplot = self.figure.add_subplot(111)
126        self.figure.subplots_adjust(left=.2, bottom=.2)
127        self.yscale = 'linear'
[52b1f77]128        self.xscale = 'linear'
[2bf92f2]129        sizer = wx.BoxSizer(wx.VERTICAL)
130        sizer.Add(self.canvas,1,wx.EXPAND)
131        self.SetSizer(sizer)
[f193585]132       
[057210c]133        # Graph object to manage the plottables
134        self.graph = Graph()
[52b1f77]135        #self.Bind(EVT_FUNC_FIT, self.onFitRange)
[2bf92f2]136        self.Bind(wx.EVT_CONTEXT_MENU, self.onContextMenu)
[df25521]137       
[52b1f77]138        #self.Bind(EVT_PROPERTY, self._onEVT_FUNC_PROPERTY)
[2bf92f2]139        # Define some constants
140        self.colorlist = ['b','g','r','c','m','y']
141        self.symbollist = ['o','x','^','v','<','>','+','s','d','D','h','H','p']
[52b1f77]142        #User scale
[b43a009]143        self.xLabel ="x"
[052a66bc]144        self.yLabel ="y"
[dfca3de]145        self.viewModel ="--"
[e2914b1]146        # keep track if the previous transformation of x and y in Property dialog
[052a66bc]147        self.prevXtrans ="x"
148        self.prevYtrans ="y"
[6ed101a]149        self.canvas.mpl_connect('scroll_event',self.onWheel)
[df25521]150        #taking care of dragging
151        self.canvas.mpl_connect('motion_notify_event',self.onMouseMotion)
152        self.canvas.mpl_connect('button_press_event',self.onLeftDown)
153        self.canvas.mpl_connect('button_release_event',self.onLeftUp)
[38fc601]154       
[df25521]155       
156        self.leftdown=False
157        self.leftup=False
158        self.mousemotion=False
159       
160        #self.canvas.Bind(wx.EVT_MOUSE_EVENTS,self.onTest)
[47f695c9]161        self.axes = [self.subplot]
[bbec827]162         # new data for the fit
163        self.fit_result = Theory1D(x=[], y=[], dy=None)
164        #self.fit_result = Data1D(x=[], y=[],dx=None, dy=None)
165        self.fit_result.name = "Fit"
[b43a009]166        # For fit Dialog initial display
[ddff053]167        self.xmin=0.0
168        self.xmax=0.0
169        self.xminView=0.0
170        self.xmaxView=0.0
[b43a009]171        self.Avalue=None
172        self.Bvalue=None
173        self.ErrAvalue=None
174        self.ErrBvalue=None
175        self.Chivalue=None
[df25521]176        self.begDrag=False
177        #self.begDragI=False
178        self.xInit=None
179        self.yInit=None
180        self.xFinal=None
181        self.yFinal=None
[38fc601]182 
[df25521]183    def onLeftDown(self,event): 
184        """ left button down and ready to drag"""
185        self.leftdown=True
186        ax = event.inaxes
187        if ax !=None:
[4101eea]188            self.xInit,self.yInit=event.xdata,event.ydata
[ac9c465]189           
190           
[df25521]191    def onLeftUp(self,event): 
192        """ Dragging is done """
[38fc601]193        self.leftdown=False
194        self.mousemotion=False 
[df25521]195        self.leftup=True
[ac9c465]196     
[df25521]197    def onMouseMotion(self,event): 
[ac9c465]198        """
199            check if the left button is press and the mouse in moving.
200            computer delta for x and y coordinates and then calls draghelper
201            to perform the drag
202        """
[38fc601]203        self.mousemotion=True 
204        if self.leftdown==True and self.mousemotion==True:
[df25521]205           
[38fc601]206            ax = event.inaxes
[ac9c465]207            if ax !=None:#the dragging is perform inside the figure
[4101eea]208                self.xFinal,self.yFinal=event.xdata,event.ydata
[38fc601]209               
210                xdelta = self.xFinal -self.xInit
211                ydelta = self.yFinal -self.yInit
212               
213                if self.xscale=='log':
214                    xdelta = math.log10(self.xFinal) -math.log10(self.xInit)
215                if self.yscale=='log':
216                    ydelta = math.log10(self.yFinal) -math.log10(self.yInit)
217                self.dragHelper(xdelta,ydelta)
[ac9c465]218             
219            else:# no dragging is perform elsewhere
[38fc601]220                self.dragHelper(0,0)
[ac9c465]221               
[df25521]222    def dragHelper(self,xdelta,ydelta):
223        """ dragging occurs here"""
224       
225        # Event occurred inside a plotting area
226        for ax in self.axes:
227            lo,hi= ax.get_xlim()
228            #print "x lo %f and x hi %f"%(lo,hi)
229            newlo,newhi= lo- xdelta, hi- xdelta
230            if self.xscale=='log':
[06290c8]231                if lo > 0:
232                    newlo= math.log10(lo)-xdelta
233                if hi > 0:
234                    newhi= math.log10(hi)-xdelta
[df25521]235            if self.xscale=='log':
236                ax.set_xlim(math.pow(10,newlo),math.pow(10,newhi))
237            else:
238                ax.set_xlim(newlo,newhi)
[38fc601]239            #print "new lo %f and new hi %f"%(newlo,newhi)
[df25521]240           
241            lo,hi= ax.get_ylim()
[38fc601]242            #print "y lo %f and y hi %f"%(lo,hi)
[df25521]243            newlo,newhi= lo- ydelta, hi- ydelta
244            if self.yscale=='log':
[06290c8]245                if lo > 0:
246                    newlo= math.log10(lo)-ydelta
247                if hi > 0:
248                    newhi= math.log10(hi)-ydelta
[38fc601]249                #print "new lo %f and new hi %f"%(newlo,newhi)
[df25521]250            if  self.yscale=='log':
251                ax.set_ylim(math.pow(10,newlo),math.pow(10,newhi))
252            else:
253                ax.set_ylim(newlo,newhi)
254        self.canvas.draw_idle()
255       
[052a66bc]256       
[df25521]257   
[b43a009]258    def resetFitView(self):
[edce46e]259        """
260             For fit Dialog initial display
261        """
[b43a009]262        self.xmin=0.0
263        self.xmax=0.0
264        self.xminView=0.0
265        self.xmaxView=0.0
266        self.Avalue=None
267        self.Bvalue=None
268        self.ErrAvalue=None
269        self.ErrBvalue=None
270        self.Chivalue=None
[df25521]271   
[6ed101a]272    def onWheel(self, event):
273        """
[05da1f89]274            Process mouse wheel as zoom events
275            @param event: Wheel event
[6ed101a]276        """
277        ax = event.inaxes
278        step = event.step
279
280        if ax != None:
281            # Event occurred inside a plotting area
282            lo,hi = ax.get_xlim()
[05da1f89]283            lo,hi = _rescale(lo,hi,step,pt=event.xdata,scale=ax.get_xscale())
284            if not self.xscale=='log' or lo>0:
285                ax.set_xlim((lo,hi))
[6ed101a]286
287            lo,hi = ax.get_ylim()
[05da1f89]288            lo,hi = _rescale(lo,hi,step,pt=event.ydata,scale=ax.get_yscale())
289            if not self.yscale=='log' or lo>0:
290                ax.set_ylim((lo,hi))
[6ed101a]291        else:
[47f695c9]292             # Check if zoom happens in the axes
[6ed101a]293            xdata,ydata = None,None
294            x,y = event.x,event.y
[34ae302]295           
[6ed101a]296            for ax in self.axes:
297                insidex,_ = ax.xaxis.contains(event)
298                if insidex:
299                    xdata,_ = ax.transAxes.inverse_xy_tup((x,y))
300                insidey,_ = ax.yaxis.contains(event)
301                if insidey:
302                    _,ydata = ax.transAxes.inverse_xy_tup((x,y))
303            if xdata is not None:
304                lo,hi = ax.get_xlim()
[34ae302]305                lo,hi = _rescale(lo,hi,step,bal=xdata,scale=ax.get_xscale())
[05da1f89]306                if not self.xscale=='log' or lo>0:
307                    ax.set_xlim((lo,hi))
[6ed101a]308            if ydata is not None:
309                lo,hi = ax.get_ylim()
[34ae302]310                lo,hi = _rescale(lo,hi,step,bal=ydata,scale=ax.get_yscale())
[05da1f89]311                if not self.yscale=='log' or lo>0:
312                    ax.set_ylim((lo,hi))
[150c04a]313               
[6ed101a]314        self.canvas.draw_idle()
315
316
[f52bea1]317    def returnTrans(self):
[edce46e]318        """
319            Return values and labels used by Fit Dialog
320        """
[b43a009]321        return self.xLabel,self.yLabel, self.Avalue, self.Bvalue,\
[edce46e]322                self.ErrAvalue,self.ErrBvalue,self.Chivalue
[dfca3de]323   
[e2914b1]324    def setTrans(self,xtrans,ytrans): 
325        """
326            @param xtrans: set x transformation on Property dialog
327            @param ytrans: set y transformation on Property dialog
328        """
329        self.prevXtrans =xtrans
330        self.prevYtrans =ytrans
[dfca3de]331   
[52b1f77]332    def onFitting(self, event): 
[e2914b1]333        """
334            when clicking on linear Fit on context menu , display Fitting Dialog
335        """
[52b1f77]336        list =[]
337        list = self.graph.returnPlottable()
338        from fitDialog import LinearFit
[7a03e65]339       
[52b1f77]340        if len(list.keys())>0:
341            first_item = list.keys()[0]
[05da1f89]342            dlg = LinearFit( None, first_item, self.onFitDisplay,self.returnTrans, -1, 'Linear Fit')
[b43a009]343           
[ddff053]344            if (self.xmin !=0.0 )and ( self.xmax !=0.0)\
345                and(self.xminView !=0.0 )and ( self.xmaxView !=0.0):
346                dlg.setFitRange(self.xminView,self.xmaxView,self.xmin,self.xmax)
[52b1f77]347            dlg.ShowModal() 
348
[052a66bc]349    def linear_plottable_fit(self, plot): 
350        """
351            when clicking on linear Fit on context menu , display Fitting Dialog
352        """
353        from fitDialog import LinearFit
354       
355        dlg = LinearFit( None, plot, self.onFitDisplay,self.returnTrans, -1, 'Linear Fit')
356       
357        if (self.xmin !=0.0 )and ( self.xmax !=0.0)\
358            and(self.xminView !=0.0 )and ( self.xmaxView !=0.0):
359            dlg.setFitRange(self.xminView,self.xmaxView,self.xmin,self.xmax)
360        dlg.ShowModal() 
361
[52b1f77]362    def _onProperties(self, event):
[e2914b1]363        """
364            when clicking on Properties on context menu ,The Property dialog is displayed
365            The user selects a transformation for x or y value and a new plot is displayed
366        """
[34ae302]367        list =[]
368        list = self.graph.returnPlottable()
369        if len(list.keys())>0:
370            first_item = list.keys()[0]
371            if first_item.x !=[]:
372                from PropertyDialog import Properties
373                dial = Properties(self, -1, 'Properties')
374                dial.setValues( self.prevXtrans, self.prevYtrans,self.viewModel )
375                if dial.ShowModal() == wx.ID_OK:
[b43a009]376                    self.xLabel, self.yLabel,self.viewModel = dial.getValues()
[34ae302]377                    if self.viewModel =="Guinier lny vs x^(2)":
[b43a009]378                        self.xLabel="x^(2)"
379                        self.yLabel="ln(y)"
[34ae302]380                        self.viewModel = "--"
[b43a009]381                        dial.setValues( self.xLabel, self.yLabel,self.viewModel )
[34ae302]382                    self._onEVT_FUNC_PROPERTY()
383                dial.Destroy()
384           
[831149e]385 
[2bf92f2]386    def set_yscale(self, scale='linear'):
[e2914b1]387        """
388            Set the scale on Y-axis
389            @param scale: the scale of y-axis
390        """
[2bf92f2]391        self.subplot.set_yscale(scale)
392        self.yscale = scale
393       
394    def get_yscale(self):
[e2914b1]395        """
396             @return: Y-axis scale
397        """
[2bf92f2]398        return self.yscale
[52b1f77]399   
400    def set_xscale(self, scale='linear'):
[e2914b1]401        """
402            Set the scale on x-axis
403            @param scale: the scale of x-axis
404        """
[52b1f77]405        self.subplot.set_xscale(scale)
406        self.xscale = scale
[e2914b1]407       
[52b1f77]408    def get_xscale(self):
[e2914b1]409        """
410             @return: x-axis scale
411        """
[52b1f77]412        return self.xscale
[2bf92f2]413
414    def SetColor(self, rgbtuple):
415        """Set figure and canvas colours to be the same"""
416        if not rgbtuple:
417            rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
418        col = [c/255.0 for c in rgbtuple]
419        self.figure.set_facecolor(col)
420        self.figure.set_edgecolor(col)
421        self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
422
423    def _onSize(self, event):
424        self._resizeflag = True
425
426    def _onIdle(self, evt):
427        if self._resizeflag:
428            self._resizeflag = False
429            self._SetSize()
430            self.draw()
431
432    def _SetSize(self, pixels = None):
433        """
434        This method can be called to force the Plot to be a desired size, which defaults to
435        the ClientSize of the panel
436        """
437        if not pixels:
438            pixels = self.GetClientSize()
439        self.canvas.SetSize(pixels)
440        self.figure.set_size_inches(pixels[0]/self.figure.get_dpi(),
441        pixels[1]/self.figure.get_dpi())
442
443    def draw(self):
444        """Where the actual drawing happens"""
445        self.figure.canvas.draw_idle()
446       
[f193585]447       
[2bf92f2]448    def onSaveImage(self, evt):
449        #figure.savefig
[7a03e65]450        #print "Save image not implemented"
[2bf92f2]451        path = None
452        dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.png", wx.SAVE)
453        if dlg.ShowModal() == wx.ID_OK:
454            path = dlg.GetPath()
455            mypath = os.path.basename(path)
456            print path
457        dlg.Destroy()
458        if not path == None:
459            self.subplot.figure.savefig(path,dpi=300, facecolor='w', edgecolor='w',
460                                        orentation='portrait', papertype=None, format='png')
461       
462    def onContextMenu(self, event):
463        """
464            Default context menu for a plot panel
465        """
466        # Slicer plot popup menu
[052a66bc]467        id = wx.NewId()
[2bf92f2]468        slicerpop = wx.Menu()
[052a66bc]469        slicerpop.Append(id,'&Save image', 'Save image as PNG')
470        wx.EVT_MENU(self, id, self.onSaveImage)
[bceddd6]471       
[105614c]472        #id = wx.NewId()
473        #slicerpop.Append(id, '&Load 1D data file')
474        #wx.EVT_MENU(self, id, self._onLoad1DData)
[bceddd6]475       
[052a66bc]476        id = wx.NewId()
[52b1f77]477        slicerpop.AppendSeparator()
[052a66bc]478        slicerpop.Append(id, '&Properties')
479        wx.EVT_MENU(self, id, self._onProperties)
[52b1f77]480       
[052a66bc]481        id = wx.NewId()
[52b1f77]482        slicerpop.AppendSeparator()
[052a66bc]483        slicerpop.Append(id, '&Linear Fit')
484        wx.EVT_MENU(self, id, self.onFitting)
[34ae302]485       
[052a66bc]486        id = wx.NewId()
[34ae302]487        slicerpop.AppendSeparator()
[052a66bc]488        slicerpop.Append(id, '&Reset Graph')
489        wx.EVT_MENU(self, id, self.onResetGraph)
[52b1f77]490       
[2bf92f2]491        pos = event.GetPosition()
492        pos = self.ScreenToClient(pos)
493        self.PopupMenu(slicerpop, pos)
494   
495    ## The following is plottable functionality
496
497
498    def properties(self,prop):
499        """Set some properties of the graph.
500       
501        The set of properties is not yet determined.
502        """
503        # The particulars of how they are stored and manipulated (e.g., do
504        # we want an inventory internally) is not settled.  I've used a
505        # property dictionary for now.
506        #
507        # How these properties interact with a user defined style file is
508        # even less clear.
509
510        # Properties defined by plot
511        self.subplot.set_xlabel(r"$%s$" % prop["xlabel"])
512        self.subplot.set_ylabel(r"$%s$" % prop["ylabel"])
513        self.subplot.set_title(prop["title"])
514
515        # Properties defined by user
516        #self.axes.grid(True)
517
518    def clear(self):
519        """Reset the plot"""
520       
521        # TODO: Redraw is brutal.  Render to a backing store and swap in
522        # TODO: rather than redrawing on the fly.
523        self.subplot.clear()
524        self.subplot.hold(True)
[6ed101a]525   
[2bf92f2]526    def render(self):
527        """Commit the plot after all objects are drawn"""
528        # TODO: this is when the backing store should be swapped in.
529        from matplotlib.font_manager import FontProperties
530        self.subplot.legend(prop=FontProperties(size=10))
531        #self.subplot.legend()
532        pass
533
534    def xaxis(self,label,units):
535        """xaxis label and units.
536       
537        Axis labels know about units.
538       
539        We need to do this so that we can detect when axes are not
540        commesurate.  Currently this is ignored other than for formatting
541        purposes.
542        """
543        if units != "": label = label + " (" + units + ")"
544        self.subplot.set_xlabel(label)
545        pass
546   
547    def yaxis(self,label,units):
548        """yaxis label and units."""
549        if units != "": label = label + " (" + units + ")"
550        self.subplot.set_ylabel(label)
551        pass
552
553    def _connect_to_xlim(self,callback):
554        """Bind the xlim change notification to the callback"""
555        def process_xlim(axes):
556            lo,hi = subplot.get_xlim()
557            callback(lo,hi)
558        self.subplot.callbacks.connect('xlim_changed',process_xlim)
559   
560    #def connect(self,trigger,callback):
561    #    print "PlotPanel.connect???"
562    #    if trigger == 'xlim': self._connect_to_xlim(callback)
563
564    def points(self,x,y,dx=None,dy=None,color=0,symbol=0,label=None):
565        """Draw markers with error bars"""
566        self.subplot.set_yscale('linear')
[52b1f77]567        self.subplot.set_xscale('linear')
[052a66bc]568       
[2bf92f2]569        # Convert tuple (lo,hi) to array [(x-lo),(hi-x)]
570        if dx != None and type(dx) == type(()):
571            dx = nx.vstack((x-dx[0],dx[1]-x)).transpose()
572        if dy != None and type(dy) == type(()):
573            dy = nx.vstack((y-dy[0],dy[1]-y)).transpose()
574
575        if dx==None and dy==None:
576            h = self.subplot.plot(x,y,color=self._color(color),
577                                   marker=self._symbol(symbol),linestyle='',label=label)
578        else:
[052a66bc]579            col = self._color(color)
[2bf92f2]580            self.subplot.errorbar(x, y, yerr=dy, xerr=None,
[052a66bc]581             ecolor=col, capsize=2,linestyle='', barsabove=False,
582             mec=col, mfc=col,
[2bf92f2]583             marker=self._symbol(symbol),
584             lolims=False, uplims=False,
[52b1f77]585             xlolims=False, xuplims=False,label=label)
[2bf92f2]586           
587        self.subplot.set_yscale(self.yscale)
[52b1f77]588        self.subplot.set_xscale(self.xscale)
[2bf92f2]589
590    def curve(self,x,y,dy=None,color=0,symbol=0,label=None):
591        """Draw a line on a graph, possibly with confidence intervals."""
592        c = self._color(color)
593        self.subplot.set_yscale('linear')
[52b1f77]594        self.subplot.set_xscale('linear')
[2bf92f2]595       
596        hlist = self.subplot.plot(x,y,color=c,marker='',linestyle='-',label=label)
597       
598        self.subplot.set_yscale(self.yscale)
[52b1f77]599        self.subplot.set_xscale(self.xscale)
[2bf92f2]600
601    def _color(self,c):
602        """Return a particular colour"""
603        return self.colorlist[c%len(self.colorlist)]
604
605    def _symbol(self,s):
606        """Return a particular symbol"""
607        return self.symbollist[s%len(self.symbollist)]
[52b1f77]608   
[052a66bc]609    def _replot(self):
610        """
611            Rescale the plottables according to the latest
612            user selection and update the plot
613        """
614        self.graph.reset_scale()
615        self._onEVT_FUNC_PROPERTY(remove_fit=False)
616       
617        #TODO: Why do we have to have the following line?
618        self.fit_result.reset_view()
619       
620        self.graph.render(self)
621        self.subplot.figure.canvas.draw_idle()
622   
623    def _onEVT_FUNC_PROPERTY(self, remove_fit=True):
[52b1f77]624        """
[8cebf9b]625             Receive the x and y transformation from myDialog,Transforms x and y in View
626              and set the scale   
[52b1f77]627        """ 
628        list =[]
629        list = self.graph.returnPlottable()
[052a66bc]630       
631        if remove_fit:
632            self.fit_result.x =[] 
633            self.fit_result.y =[] 
634            self.fit_result.dx=None
635            self.fit_result.dy=None
636            self.graph.delete(self.fit_result)
[f193585]637       
[52b1f77]638        for item in list:
[b43a009]639            item.setLabel(self.xLabel,self.yLabel)
640            if ( self.xLabel=="x" ):
641                item.transformX(transform.toX,transform.errToX)
[52b1f77]642                self.set_xscale("linear")
[f52bea1]643                name, units = item.get_xaxis()
[b6972a0f]644                self.graph.xaxis("%s" % name,  "%s" % units)
645               
[52b1f77]646               
[b43a009]647            if ( self.xLabel=="x^(2)" ):
648                item.transformX(transform.toX2,transform.errToX2)
[52b1f77]649                self.set_xscale('linear')
[f52bea1]650                name, units = item.get_xaxis()
[b6972a0f]651                units=convertUnit(2,units) 
652                self.graph.xaxis("%s^{2}" % name,  "%s" % units)
653               
[52b1f77]654               
[b43a009]655            if (self.xLabel=="log10(x)" ):
656                item.transformX(transform.toX,transform.errToX)
[8cebf9b]657                self.set_xscale("log")
[f193585]658                name, units = item.get_xaxis() 
[b6972a0f]659                self.graph.xaxis("\log_{10}\ \  (%s)" % name,  "%s" % units)
660               
[52b1f77]661               
[b43a009]662            if ( self.yLabel=="ln(y)" ):
663                item.transformY(transform.toLogX,transform.errToLogX)
[831149e]664                self.set_yscale("linear")
665                name, units = item.get_yaxis()
[b6972a0f]666                self.graph.yaxis("log\ \ %s" % name,  "%s" % units)
667               
[831149e]668               
[b43a009]669            if ( self.yLabel=="y" ):
670                item.transformY(transform.toX,transform.errToX)
[52b1f77]671                self.set_yscale("linear")
[f52bea1]672                name, units = item.get_yaxis()
[b6972a0f]673                self.graph.yaxis("%s" % name,  "%s" % units)
674               
[52b1f77]675               
[b43a009]676            if ( self.yLabel=="log10(y)" ): 
677                item.transformY(transform.toX,transform.errToX)
[52b1f77]678                self.set_yscale("log") 
[f52bea1]679                name, units = item.get_yaxis()
[b6972a0f]680                self.graph.yaxis("\log_{10}\ \ (%s)" % name,  "%s" % units)
681               
[52b1f77]682               
[b43a009]683            if ( self.yLabel=="y^(2)" ):
684                item.transformY( transform.toX2,transform.errToX2 )   
[52b1f77]685                self.set_yscale("linear")
[f52bea1]686                name, units = item.get_yaxis()
[b6972a0f]687                units=convertUnit(2,units) 
688                self.graph.yaxis("%s^{2}" % name,  "%s" % units)
689               
[35891ce]690               
[b43a009]691            if ( self.yLabel =="1/y"):
692                item.transformY(transform.toOneOverX,transform.errOneOverX )
[3d3a0e5]693                self.set_yscale("linear")
694                name, units = item.get_yaxis()
[b6972a0f]695                units=convertUnit(-1,units)
696                self.graph.yaxis("1/%s" % name,  "%s" % units)
[35891ce]697               
[b43a009]698            if ( self.yLabel =="1/sqrt(y)" ):
699                item.transformY(transform.toOneOverSqrtX,transform.errOneOverSqrtX )
[3d3a0e5]700                self.set_yscale("linear")
701                name, units = item.get_yaxis()
[43bf807]702                units=convertUnit(-0.5,units)
[05da1f89]703                self.graph.yaxis("1/\sqrt{%s}" %name,  "%s" % units)
[7a03e65]704               
[b43a009]705            if ( self.yLabel =="ln(y*x)"):
706                item.transformY( transform.toLogXY,transform.errToLogXY)
[7a03e65]707                self.set_yscale("linear")
[3d3a0e5]708                yname, yunits = item.get_yaxis()
709                xname, xunits = item.get_xaxis()
[b6972a0f]710                self.graph.yaxis("log\ (%s \ \ %s)" % (yname,xname),  "%s%s" % (yunits,xunits))
711               
[831149e]712               
[b43a009]713            if ( self.yLabel =="ln(y*x^(2))"):
714                item.transformY( transform.toLogYX2,transform.errToLogYX2)
[7a03e65]715                self.set_yscale("linear")
[3d3a0e5]716                yname, yunits = item.get_yaxis()
[47f695c9]717                xname, xunits = item.get_xaxis() 
[b6972a0f]718                xunits = convertUnit(2,xunits) 
[43bf807]719                self.graph.yaxis("Log (%s \ \ %s^{2})" % (yname,xname),  "%s%s" % (yunits,xunits))
[b6972a0f]720               
[831149e]721           
[b43a009]722            if ( self.yLabel =="ln(y*x^(4))"):
723                item.transformY(transform.toLogYX4,transform.errToLogYX4)
[831149e]724                self.set_yscale("linear")
725                yname, yunits = item.get_yaxis()
726                xname, xunits = item.get_xaxis()
[b6972a0f]727                xunits = convertUnit(4,xunits) 
[43bf807]728                self.graph.yaxis("Log (%s \ \ %s^{4})" % (yname,xname),  "%s%s" % (yunits,xunits))
[b6972a0f]729               
[dfca3de]730            if ( self.viewModel == "Guinier lny vs x^(2)"):
[b43a009]731               
732                item.transformX(transform.toX2,transform.errToX2)
[dfca3de]733                self.set_xscale('linear')
734                name, units = item.get_xaxis()
[b6972a0f]735                units = convertUnit(2,units) 
736                self.graph.xaxis("%s^{2}" % name,  "%s" % units)
737               
[b43a009]738               
739                item.transformY(transform.toLogX,transform.errToLogX )
[dfca3de]740                self.set_yscale("linear")
741                name, units = item.get_yaxis()
[b6972a0f]742                self.graph.yaxis("$Log %s$" % name,  "%s" % units)
743               
[b43a009]744               
[bbec827]745            item.transformView()
[b43a009]746           
[b6972a0f]747         
[71c64d6]748        self.resetFitView()   
[b43a009]749        self.prevXtrans = self.xLabel
750        self.prevYtrans = self.yLabel 
[52b1f77]751        self.graph.render(self)
752        self.subplot.figure.canvas.draw_idle()
[46693050]753       
[b6972a0f]754       
755   
[b43a009]756    def onFitDisplay(self, tempx,tempy,xminView,xmaxView,xmin,xmax,func):
[e2914b1]757        """
758            Add a new plottable into the graph .In this case this plottable will be used
759            to fit some data
[edce46e]760            @param tempx: The x data of fit line
761            @param tempy: The y data of fit line
762            @param xminView: the lower bound of fitting range
763            @param xminView: the upper bound of  fitting range
764            @param xmin: the lowest value of data to fit to the line
765            @param xmax: the highest value of data to fit to the line
[e2914b1]766        """
[edce46e]767        # Saving value to redisplay in Fit Dialog when it is opened again
[b43a009]768        self.Avalue,self.Bvalue,self.ErrAvalue,self.ErrBvalue,self.Chivalue=func
[edce46e]769        self.xminView=xminView
770        self.xmaxView=xmaxView
771        self.xmin= xmin
772        self.xmax= xmax
773        #In case need to change the range of data plotted
[34ae302]774        list =[]
775        list = self.graph.returnPlottable()
776        for item in list:
[150c04a]777            #item.onFitRange(xminView,xmaxView)
778            item.onFitRange(None,None)
[edce46e]779       
[bbec827]780        # Create new data plottable with result
781        self.fit_result.x =[] 
782        self.fit_result.y =[]
783        self.fit_result.x =tempx 
784        self.fit_result.y =tempy     
785        self.fit_result.dx=None
786        self.fit_result.dy=None
787        #Load the view with the new values
[edce46e]788        self.fit_result.reset_view()
789        # Add the new plottable to the graph
[bbec827]790        self.graph.add(self.fit_result) 
791        self.graph.render(self)
[52b1f77]792        self.subplot.figure.canvas.draw_idle()
[edce46e]793       
[f193585]794   
[34ae302]795    def onResetGraph(self,event):
[edce46e]796        """
797            Reset the graph by plotting the full range of data
798        """
[34ae302]799        list =[]
800        list = self.graph.returnPlottable()
801        for item in list:
802            item.onReset()
803        self.graph.render(self)
804        self.subplot.figure.canvas.draw_idle()
[f193585]805       
[2bf92f2]806class NoRepaintCanvas(FigureCanvasWxAgg):
807    """We subclass FigureCanvasWxAgg, overriding the _onPaint method, so that
808    the draw method is only called for the first two paint events. After that,
809    the canvas will only be redrawn when it is resized.
810    """
811    def __init__(self, *args, **kwargs):
812        FigureCanvasWxAgg.__init__(self, *args, **kwargs)
813        self._drawn = 0
814
815    def _onPaint(self, evt):
816        """
817        Called when wxPaintEvt is generated
818        """
819        if not self._isRealized:
820            self.realize()
821        if self._drawn < 2:
822            self.draw(repaint = False)
823            self._drawn += 1
824        self.gui_repaint(drawDC=wx.PaintDC(self))
825           
Note: See TracBrowser for help on using the repository browser.