source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ bb5c1c7

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 bb5c1c7 was bb5c1c7, checked in by Gervaise Alina <gervyh@…>, 15 years ago

add error doesn't add sqrt of y if dy=[] anymore

  • Property mode set to 100644
File size: 17.3 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, os
14import pylab, time,numpy
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=False
63        ## Unique ID (from gui_manager)
64        self.uid = None
65        ## Action IDs for internal call-backs
66        self.action_ids = {}
67        ## Default locations
68        self._default_save_location = os.getcwd()       
69        ## Graph       
70        self.graph = Graph()
71        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
72        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
73        self.graph.render(self)
74   
75   
76    def _reset(self):
77        """
78            Resets internal data and graph
79        """   
80        self.graph.reset()
81        self.plots      = {}
82        self.action_ids = {}
83   
84   
85    def _onEVT_1DREPLOT(self, event):
86        """
87            Data is ready to be displayed
88            @param event: data event
89        """
90       
91        #TODO: Check for existence of plot attribute
92        # Check whether this is a replot. If we ask for a replot
93        # and the plottable no longer exists, ignore the event.
94        if hasattr(event, "update") and event.update==True \
95            and event.plot.name not in self.plots.keys():
96            return
97       
98        if hasattr(event, "reset"):
99            self._reset()
100       
101        is_new = True
102        if event.plot.name in self.plots.keys():
103            # Check whether the class of plottable changed
104            if not event.plot.__class__==self.plots[event.plot.name].__class__:
105                #overwrite a plottable using the same name
106                self.graph.delete(self.plots[event.plot.name])
107            else:
108                # plottable is already draw on the panel
109                is_new = False
110       
111        if is_new:
112            # a new plottable overwrites a plotted one  using the same id
113            for plottable in self.plots.itervalues():
114                if hasattr(event.plot,"id"):
115                    if event.plot.id==plottable.id :
116                        self.graph.delete(plottable)
117           
118            self.plots[event.plot.name] = event.plot
119            self.graph.add(self.plots[event.plot.name])
120        else:
121            #replot the graph
122            self.plots[event.plot.name].x = event.plot.x   
123            self.plots[event.plot.name].y = event.plot.y   
124            self.plots[event.plot.name].dy = event.plot.dy 
125            if hasattr(event.plot, 'dx') and hasattr(self.plots[event.plot.name], 'dx'):
126                self.plots[event.plot.name].dx = event.plot.dx   
127         
128        #TODO: Should re-factor this
129        ## for all added plot the option to hide error show be displayed first
130        #self.errors_hide = 0
131        ## Set axis labels
132        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
133        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
134        ## Set the view scale for all plots
135        self._onEVT_FUNC_PROPERTY()
136        ## render the graph
137        self.graph.render(self)
138        self.subplot.figure.canvas.draw_idle()
139        if self.errors_hide:
140            self._on_remove_errors(evt=None)
141        else:
142            self._on_add_errors( evt=None)
143        return
144   
145    def onLeftDown(self,event): 
146        """
147            left button down and ready to drag
148            Display the position of the mouse on the statusbar
149        """
150        PlotPanel.onLeftDown(self, event)
151        ax = event.inaxes
152        if ax != None:
153            position = "x: %8.3g    y: %8.3g" % (event.xdata, event.ydata)
154            wx.PostEvent(self.parent, StatusEvent(status=position))
155
156
157    def _onRemove(self, event):
158        """
159            Remove a plottable from the graph and render the graph
160            @param event: Menu event
161        """
162        ## Check if there is a selected graph to remove
163        if not self.graph.selected_plottable == None:
164            self.graph.delete(self.plots[self.graph.selected_plottable])
165            del self.plots[self.graph.selected_plottable]
166            self.graph.render(self)
167            self.subplot.figure.canvas.draw_idle()   
168           
169
170    def onContextMenu(self, event):
171        """
172            1D plot context menu
173            @param event: wx context event
174        """
175        slicerpop = PanelMenu()
176        slicerpop.set_plots(self.plots)
177        slicerpop.set_graph(self.graph)
178               
179        # Various plot options
180        id = wx.NewId()
181        slicerpop.Append(id,'&Save image', 'Save image as PNG')
182        wx.EVT_MENU(self, id, self.onSaveImage)
183       
184        id = wx.NewId()
185        slicerpop.Append(id,'&Print image', 'Print image ')
186        wx.EVT_MENU(self, id, self.onPrint)
187         
188        id = wx.NewId()
189        slicerpop.Append(id,'&Print Preview', 'image preview for print')
190        wx.EVT_MENU(self, id, self.onPrinterPreview)
191           
192        slicerpop.AppendSeparator()
193        item_list = self.parent.get_context_menu(self.graph)
194       
195        if (not item_list==None) and (not len(item_list)==0):
196            for item in item_list:
197                try:
198                    id = wx.NewId()
199                    slicerpop.Append(id, item[0], item[1])
200                    wx.EVT_MENU(self, id, item[2])
201                except:
202                    wx.PostEvent(self.parent, StatusEvent(status=\
203                        "ModelPanel1D.onContextMenu: bad menu item  %s"%sys.exc_value))
204                    pass
205            slicerpop.AppendSeparator()
206       
207        if self.graph.selected_plottable in self.plots:
208            plot = self.plots[self.graph.selected_plottable]
209            id = wx.NewId()
210            name = plot.name
211           
212            slicerpop.Append(id, "&Save points" )
213            self.action_ids[str(id)] = plot
214            wx.EVT_MENU(self, id, self._onSave)
215         
216            id = wx.NewId()
217            slicerpop.Append(id, "Remove %s curve" % name)
218            self.action_ids[str(id)] = plot
219            wx.EVT_MENU(self, id, self._onRemove)
220            slicerpop.AppendSeparator()
221            # Option to hide
222            #TODO: implement functionality to hide a plottable (legend click)
223       
224        if self.graph.selected_plottable in self.plots:
225            if self.plots[self.graph.selected_plottable].name in self.err_dy.iterkeys()\
226                and self.errors_hide:
227               
228                id = wx.NewId()
229                slicerpop.Append(id, '&Show errors to data')
230                wx.EVT_MENU(self, id, self._on_add_errors)
231               
232            elif self.plots[self.graph.selected_plottable].__class__.__name__=="Data1D"\
233                and not self.errors_hide:
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 = True
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.color = color
295            self.graph.add(new_plot,color)
296            ## transforming the view of the new data into the same of the previous data
297            self._onEVT_FUNC_PROPERTY()
298            ## save the plot
299            self.plots[self.graph.selected_plottable]=new_plot
300            ## Render the graph
301            self.graph.render(self)
302            self.subplot.figure.canvas.draw_idle() 
303           
304            event = ErrorDataEvent(err_dy=self.err_dy)
305            wx.PostEvent(self.parent, event)
306   
307   
308    def _on_add_errors(self, evt):
309        """
310            create a new data1D witht the errors saved in self.err_dy
311            to show errors of the plot.
312            Compute reasonable errors for a data set without
313            errors and transorm the plottable to a Data1D
314            @param evt: Menu event
315        """
316        import math
317        import numpy
318        import time
319       
320        if not self.graph.selected_plottable == None:
321            ##Reset the flag to display the hide option on the context menu
322            self.errors_hide = False
323            ## restore dy
324            length = len(self.plots[self.graph.selected_plottable].x)
325            dy = numpy.zeros(length)
326            selected_plot= self.plots[self.graph.selected_plottable]
327            try:
328                dy = self.err_dy[selected_plot.name]
329            except:
330                #for i in range(length):
331                #dy[i] = math.sqrt(self.plots[self.graph.selected_plottable].y[i])     
332                dy= selected_plot.dy
333            ## Create a new plottable data1D
334            new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
335                              self.plots[self.graph.selected_plottable].y,
336                              dy=dy)
337            new_plot.interactive = True
338           
339            new_plot.name = self.plots[self.graph.selected_plottable].name
340            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
341                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
342                new_plot.id = self.plots[self.graph.selected_plottable].id
343            else:
344                new_plot.group_id = str(time.time())
345                new_plot.id = str(time.time())
346           
347            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
348            new_plot.xaxis(label, unit)
349            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
350            new_plot.yaxis(label, unit)
351            ## save the color of the selected plottable before it is deleted
352            color=self.graph.plottables[self.plots[self.graph.selected_plottable]]
353            self.graph.delete(self.plots[self.graph.selected_plottable])
354            self.graph.color = color
355            ## add newly created plottable to the graph with the save color
356            self.graph.add(new_plot, color)
357            ## transforming the view of the new data into the same of the previous data
358            self._onEVT_FUNC_PROPERTY()
359            ## save the plot
360            self.plots[self.graph.selected_plottable]=new_plot
361            ## render the graph with its new content
362            self.graph.render(self)
363            self.subplot.figure.canvas.draw_idle() 
364               
365               
366    def _onSaveXML(self, path):
367        """
368            Save 1D  Data to  XML file
369            @param evt: Menu event
370        """
371        if not path == None:
372            out = open(path, 'w')
373            from DataLoader.readers import cansas_reader
374            reader = cansas_reader.Reader()
375            datainfo= self.plots[self.graph.selected_plottable].info
376            reader.write( path, datainfo)
377           
378            try:
379                self._default_save_location = os.path.dirname(path)
380            except:
381                pass
382       
383        return 
384   
385   
386    def _onsaveTXT(self, path):
387        """
388            Save file as txt
389        """
390        data = self.plots[self.graph.selected_plottable]
391       
392        if not path == None:
393            out = open(path, 'w')
394            has_errors = True
395            if data.dy==None or data.dy==[]:
396                has_errors = False
397               
398            # Sanity check
399            if has_errors:
400                try:
401                    if len(data.y) != len(data.dy):
402
403                        has_errors = False
404                except:
405                    has_errors = False
406           
407            if has_errors:
408                out.write("<X>   <Y>   <dY>\n")
409            else:
410                out.write("<X>   <Y>\n")
411               
412            for i in range(len(data.x)):
413                if has_errors:
414                    out.write("%g  %g  %g\n" % (data.x[i], 
415                                                data.y[i],
416                                               data.dy[i]))
417                else:
418                    out.write("%g  %g\n" % (data.x[i], 
419                                            data.y[i]))
420                   
421            out.close()                 
422            try:
423                self._default_save_location = os.path.dirname(path)
424            except:
425                pass   
426               
427    def _onSave(self, evt):
428        """
429            Save a data set to a text file
430            @param evt: Menu event
431        """
432        import os
433        id = str(evt.GetId())
434        if id in self.action_ids:         
435           
436            path = None
437            wildcard = "Text files (*.txt)|*.txt|"\
438            "CanSAS 1D files(*.xml)|*.xml" 
439            dlg = wx.FileDialog(self, "Choose a file",
440                                self._default_save_location, "",wildcard , wx.SAVE)
441           
442            if dlg.ShowModal() == wx.ID_OK:
443                path = dlg.GetPath()
444                mypath = os.path.basename(path)
445                if os.path.splitext(mypath)[1].lower() ==".txt":
446                    self._onsaveTXT(path)
447                if os.path.splitext(mypath)[1].lower() ==".xml":
448                    self._onSaveXML(path)
449           
450            dlg.Destroy()
451           
452           
453   
454   
455   
456       
Note: See TracBrowser for help on using the repository browser.