source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ 12dbb14d

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

hide and show error ,store dxl and dxw value

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