source: sasview/guitools/PlotPanel.py @ 87bff18

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 87bff18 was a17ffdf, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Fixed color management

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