source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ 445f949

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 445f949 was 3cc533e, checked in by Gervaise Alina <gervyh@…>, 16 years ago

show linear fit option on context menu

  • Property mode set to 100644
File size: 17.0 KB
Line 
1"""
2This software was developed by the University of Tennessee as part of the
3Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4project funded by the US National Science Foundation.
5
6See the license text in license.txt
7
8copyright 2008, University of Tennessee
9"""
10
11
12import wx
13import sys
14import pylab, time
15
16import danse.common.plottools
17from danse.common.plottools.PlotPanel import PlotPanel
18from danse.common.plottools.plottables import Graph,Data1D,Theory1D,Data1D
19from sans.guicomm.events import EVT_NEW_PLOT
20from sans.guicomm.events import StatusEvent ,NewPlotEvent,SlicerEvent,ErrorDataEvent
21from sans.guiframe.utils import PanelMenu
22
23from binder import BindArtist
24
25
26DEFAULT_QMAX = 0.05
27DEFAULT_QSTEP = 0.001
28DEFAULT_BEAM = 0.005
29BIN_WIDTH =1
30
31
32class ModelPanel1D(PlotPanel):
33    """
34        Plot panel for use with the GUI manager
35    """
36   
37    ## Internal name for the AUI manager
38    window_name = "plotpanel"
39    ## Title to appear on top of the window
40    window_caption = "Plot Panel"
41    ## Flag to tell the GUI manager that this panel is not
42    #  tied to any perspective
43    ALWAYS_ON = True
44    ## Group ID
45    group_id = None
46   
47    def __init__(self, parent, id = -1, color = None,\
48        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
49        """
50            Initialize the panel
51        """
52        PlotPanel.__init__(self, parent, id = id, style = style, **kwargs)
53       
54        ## Reference to the parent window
55        self.parent = parent
56        ## Plottables
57        self.plots = {}
58        ## save errors dy  for each data plotted
59        self.err_dy={}
60        ## flag to determine if the hide or show context menu item should
61        ## be displayed
62        self.errors_hide=0
63        ## Unique ID (from gui_manager)
64        self.uid = None
65        ## Action IDs for internal call-backs
66        self.action_ids = {}
67        ## Graph       
68        self.graph = Graph()
69        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
70        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
71        self.graph.render(self)
72   
73   
74    def _reset(self):
75        """
76            Resets internal data and graph
77        """   
78        self.graph.reset()
79        self.plots      = {}
80        self.action_ids = {}
81   
82   
83    def _onEVT_1DREPLOT(self, event):
84        """
85            Data is ready to be displayed
86            @param event: data event
87        """
88       
89        #TODO: Check for existence of plot attribute
90        # Check whether this is a replot. If we ask for a replot
91        # and the plottable no longer exists, ignore the event.
92        if hasattr(event, "update") and event.update==True \
93            and event.plot.name not in self.plots.keys():
94            return
95       
96        if hasattr(event, "reset"):
97            self._reset()
98       
99        is_new = True
100        if event.plot.name in self.plots.keys():
101            # Check whether the class of plottable changed
102            if not event.plot.__class__==self.plots[event.plot.name].__class__:
103                #overwrite a plottable using the same name
104                self.graph.delete(self.plots[event.plot.name])
105            else:
106                # plottable is already draw on the panel
107                is_new = False
108       
109        if is_new:
110            # a new plottable overwrites a plotted one  using the same id
111            for plottable in self.plots.itervalues():
112                if hasattr(event.plot,"id"):
113                    if event.plot.id==plottable.id :
114                        self.graph.delete(plottable)
115           
116            self.plots[event.plot.name] = event.plot
117            self.graph.add(self.plots[event.plot.name])
118        else:
119            #replot the graph
120            self.plots[event.plot.name].x = event.plot.x   
121            self.plots[event.plot.name].y = event.plot.y   
122            self.plots[event.plot.name].dy = event.plot.dy 
123            if hasattr(event.plot, 'dx') and hasattr(self.plots[event.plot.name], 'dx'):
124                self.plots[event.plot.name].dx = event.plot.dx   
125 
126        #TODO: Should re-factor this
127        ## for all added plot the option to hide error show be displayed first
128        self.errors_hide = 0
129        ## Set axis labels
130        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
131        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
132        ## Set the view scale for all plots
133        self._onEVT_FUNC_PROPERTY()
134        ## render the graph
135        self.graph.render(self)
136        self.subplot.figure.canvas.draw_idle()
137       
138       
139    def onLeftDown(self,event): 
140        """
141            left button down and ready to drag
142            Display the position of the mouse on the statusbar
143        """
144        PlotPanel.onLeftDown(self, event)
145        ax = event.inaxes
146        if ax != None:
147            position = "x: %8.3g    y: %8.3g" % (event.xdata, event.ydata)
148            wx.PostEvent(self.parent, StatusEvent(status=position))
149
150
151    def _onRemove(self, event):
152        """
153            Remove a plottable from the graph and render the graph
154            @param event: Menu event
155        """
156        ## Check if there is a selected graph to remove
157        if not self.graph.selected_plottable == None:
158            self.graph.delete(self.plots[self.graph.selected_plottable])
159            del self.plots[self.graph.selected_plottable]
160            self.graph.render(self)
161            self.subplot.figure.canvas.draw_idle()   
162           
163
164    def onContextMenu(self, event):
165        """
166            1D plot context menu
167            @param event: wx context event
168        """
169        slicerpop = PanelMenu()
170        slicerpop.set_plots(self.plots)
171        slicerpop.set_graph(self.graph)
172               
173        # Various plot options
174        id = wx.NewId()
175        slicerpop.Append(id,'&Save image', 'Save image as PNG')
176        wx.EVT_MENU(self, id, self.onSaveImage)
177       
178        id = wx.NewId()
179        slicerpop.Append(id,'&Print image', 'Print image ')
180        wx.EVT_MENU(self, id, self.onPrint)
181         
182        id = wx.NewId()
183        slicerpop.Append(id,'&Print Preview', 'image preview for print')
184        wx.EVT_MENU(self, id, self.onPrinterPreview)
185           
186        slicerpop.AppendSeparator()
187        item_list = self.parent.get_context_menu(self.graph)
188       
189        if (not item_list==None) and (not len(item_list)==0):
190            for item in item_list:
191                try:
192                    id = wx.NewId()
193                    slicerpop.Append(id, item[0], item[1])
194                    wx.EVT_MENU(self, id, item[2])
195                except:
196                    wx.PostEvent(self.parent, StatusEvent(status=\
197                        "ModelPanel1D.onContextMenu: bad menu item  %s"%sys.exc_value))
198                    pass
199            slicerpop.AppendSeparator()
200       
201        if self.graph.selected_plottable in self.plots:
202            plot = self.plots[self.graph.selected_plottable]
203            id = wx.NewId()
204            name = plot.name
205           
206            slicerpop.Append(id, "&Save %s points" % name)
207            self.action_ids[str(id)] = plot
208            wx.EVT_MENU(self, id, self._onSave)
209           
210            id = wx.NewId()
211            slicerpop.Append(id, "&Save %s canSAS XML" % name)
212            self.action_ids[str(id)] = plot
213            wx.EVT_MENU(self, id, self._onSaveXML)
214           
215            id = wx.NewId()
216            slicerpop.Append(id, "Remove %s curve" % name)
217            self.action_ids[str(id)] = plot
218            wx.EVT_MENU(self, id, self._onRemove)
219            slicerpop.AppendSeparator()
220            # Option to hide
221            #TODO: implement functionality to hide a plottable (legend click)
222       
223        if self.graph.selected_plottable in self.plots:
224            if self.plots[self.graph.selected_plottable].name in self.err_dy.iterkeys()\
225                and self.errors_hide==1:
226               
227                id = wx.NewId()
228                slicerpop.Append(id, '&Show errors to data')
229                wx.EVT_MENU(self, id, self._on_add_errors)
230               
231            elif self.plots[self.graph.selected_plottable].__class__.__name__=="Data1D"\
232                and self.errors_hide==0:
233                   
234                    id = wx.NewId()
235                    slicerpop.Append(id, '&Hide Error bars')
236                    wx.EVT_MENU(self, id, self._on_remove_errors)
237           
238            id = wx.NewId()
239            slicerpop.Append(id, '&Linear fit')
240            wx.EVT_MENU(self, id, self.onFitting)
241               
242            slicerpop.AppendSeparator()
243       
244        id = wx.NewId()
245        slicerpop.Append(id, '&Change scale')
246        wx.EVT_MENU(self, id, self._onProperties)
247       
248        id = wx.NewId()
249        slicerpop.Append(id, '&Reset Graph')
250        wx.EVT_MENU(self, id, self.onResetGraph) 
251       
252        pos = event.GetPosition()
253        pos = self.ScreenToClient(pos)
254        self.PopupMenu(slicerpop, pos)
255       
256       
257    def _on_remove_errors(self, evt):
258        """
259            Save name and dy of data in dictionary self.err_dy
260            Create a new data1D with the same x, y
261            vector and dy with zeros.
262            post self.err_dy as event (ErrorDataEvent) for any object
263            which wants to reconstruct the initial data.
264            @param evt: Menu event
265        """
266        if not self.graph.selected_plottable == None:
267            ## store existing dy
268            name =self.plots[self.graph.selected_plottable].name
269            dy = self.plots[self.graph.selected_plottable].dy
270            self.err_dy[name]= dy
271            ## Create a new dy for a new plottable
272            import numpy
273            dy= numpy.zeros(len(self.plots[self.graph.selected_plottable].y))
274            new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
275                              self.plots[self.graph.selected_plottable].y,
276                              dy=dy)
277            new_plot.interactive = True
278            self.errors_hide = 1
279            new_plot.name = self.plots[self.graph.selected_plottable].name
280            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
281                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
282                new_plot.id = self.plots[self.graph.selected_plottable].id
283            else:
284                new_plot.group_id = str(time.time())
285                new_plot.id = str(time.time())
286            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
287            new_plot.xaxis(label, unit)
288            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
289            new_plot.yaxis(label, unit)
290            ## save the color of the selected plottable before it is deleted
291            color=self.graph.plottables[self.plots[self.graph.selected_plottable]]
292            self.graph.delete(self.plots[self.graph.selected_plottable])
293            ## add newly created plottable to the graph with the save color
294            self.graph.add(new_plot,color)
295            ## transforming the view of the new data into the same of the previous data
296            self._onEVT_FUNC_PROPERTY()
297            ## save the plot
298            self.plots[self.graph.selected_plottable]=new_plot
299            ## Render the graph
300            self.graph.render(self)
301            self.subplot.figure.canvas.draw_idle() 
302           
303            event = ErrorDataEvent(err_dy=self.err_dy)
304            wx.PostEvent(self.parent, event)
305   
306   
307    def _on_add_errors(self, evt):
308        """
309            create a new data1D witht the errors saved in self.err_dy
310            to show errors of the plot.
311            Compute reasonable errors for a data set without
312            errors and transorm the plottable to a Data1D
313            @param evt: Menu event
314        """
315        import math
316        import numpy
317        import time
318       
319        if not self.graph.selected_plottable == None:
320            ##Reset the flag to display the hide option on the context menu
321            self.errors_hide = 0
322            ## restore dy
323            length = len(self.plots[self.graph.selected_plottable].x)
324            dy = numpy.zeros(length)
325            selected_plot= self.plots[self.graph.selected_plottable]
326            try:
327                dy = self.err_dy[selected_plot.name]
328            except:
329                for i in range(length):
330                    dy[i] = math.sqrt(self.plots[self.graph.selected_plottable].y[i])     
331            ## Create a new plottable data1D
332            new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
333                              self.plots[self.graph.selected_plottable].y,
334                              dy=dy)
335            new_plot.interactive = True
336           
337            new_plot.name = self.plots[self.graph.selected_plottable].name
338            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
339                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
340                new_plot.id = self.plots[self.graph.selected_plottable].id
341            else:
342                new_plot.group_id = str(time.time())
343                new_plot.id = str(time.time())
344           
345            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
346            new_plot.xaxis(label, unit)
347            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
348            new_plot.yaxis(label, unit)
349            ## save the color of the selected plottable before it is deleted
350            color=self.graph.plottables[self.plots[self.graph.selected_plottable]]
351            self.graph.delete(self.plots[self.graph.selected_plottable])
352            ## add newly created plottable to the graph with the save color
353            self.graph.add(new_plot, color)
354            ## transforming the view of the new data into the same of the previous data
355            self._onEVT_FUNC_PROPERTY()
356            ## save the plot
357            self.plots[self.graph.selected_plottable]=new_plot
358            ## render the graph with its new content
359            self.graph.render(self)
360            self.subplot.figure.canvas.draw_idle() 
361               
362               
363    def _onSaveXML(self, evt):
364        """
365            Save 1D  Data to  XML file
366            @param evt: Menu event
367        """
368        import os
369        id = str(evt.GetId())
370        if id in self.action_ids:         
371            path = None
372            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.xml", wx.SAVE)
373            if dlg.ShowModal() == wx.ID_OK:
374                path = dlg.GetPath()
375                mypath = os.path.basename(path)
376            dlg.Destroy()
377           
378            if not path == None:
379                out = open(path, 'w')
380                from DataLoader.readers import cansas_reader
381                reader = cansas_reader.Reader()
382                datainfo= self.plots[self.graph.selected_plottable].info
383                reader.write( path, datainfo)
384            return 
385                     
386               
387               
388    def _onSave(self, evt):
389        """
390            Save a data set to a text file
391            @param evt: Menu event
392        """
393        import os
394        id = str(evt.GetId())
395        if id in self.action_ids:         
396           
397            path = None
398            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.SAVE)
399            if dlg.ShowModal() == wx.ID_OK:
400                path = dlg.GetPath()
401                mypath = os.path.basename(path)
402               
403            dlg.Destroy()
404           
405            if not path == None:
406                out = open(path, 'w')
407                has_errors = True
408                if self.action_ids[id].dy==None or self.action_ids[id].dy==[]:
409                    has_errors = False
410                   
411                # Sanity check
412                if has_errors:
413                    try:
414                        if len(self.action_ids[id].y) != len(self.action_ids[id].dy):
415   
416                            has_errors = False
417                    except:
418                        has_errors = False
419               
420                if has_errors:
421                    out.write("<X>   <Y>   <dY>\n")
422                else:
423                    out.write("<X>   <Y>\n")
424                   
425                for i in range(len(self.action_ids[id].x)):
426                    if has_errors:
427                        out.write("%g  %g  %g\n" % (self.action_ids[id].x[i], 
428                                                    self.action_ids[id].y[i],
429                                                    self.action_ids[id].dy[i]))
430                    else:
431                        out.write("%g  %g\n" % (self.action_ids[id].x[i], 
432                                                self.action_ids[id].y[i]))
433                       
434                out.close()
435   
436   
437       
Note: See TracBrowser for help on using the repository browser.