source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ 31482fc

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

hide and show error bar previous status remembered

  • Property mode set to 100644
File size: 17.1 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.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 = False
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, path):
364        """
365            Save 1D  Data to  XML file
366            @param evt: Menu event
367        """
368        if not path == None:
369            out = open(path, 'w')
370            from DataLoader.readers import cansas_reader
371            reader = cansas_reader.Reader()
372            datainfo= self.plots[self.graph.selected_plottable].info
373            reader.write( path, datainfo)
374           
375            try:
376                self._default_save_location = os.path.dirname(path)
377            except:
378                pass
379       
380        return 
381   
382   
383    def _onsaveTXT(self, path):
384        """
385            Save file as txt
386        """
387        data = self.plots[self.graph.selected_plottable]
388       
389        if not path == None:
390            out = open(path, 'w')
391            has_errors = True
392            if data.dy==None or data.dy==[]:
393                has_errors = False
394               
395            # Sanity check
396            if has_errors:
397                try:
398                    if len(data.y) != len(data.dy):
399
400                        has_errors = False
401                except:
402                    has_errors = False
403           
404            if has_errors:
405                out.write("<X>   <Y>   <dY>\n")
406            else:
407                out.write("<X>   <Y>\n")
408               
409            for i in range(len(data.x)):
410                if has_errors:
411                    out.write("%g  %g  %g\n" % (data.x[i], 
412                                                data.y[i],
413                                               data.dy[i]))
414                else:
415                    out.write("%g  %g\n" % (data.x[i], 
416                                            data.y[i]))
417                   
418            out.close()                 
419            try:
420                self._default_save_location = os.path.dirname(path)
421            except:
422                pass   
423               
424    def _onSave(self, evt):
425        """
426            Save a data set to a text file
427            @param evt: Menu event
428        """
429        import os
430        id = str(evt.GetId())
431        if id in self.action_ids:         
432           
433            path = None
434            wildcard = "Text files (*.txt)|*.txt|"\
435            "CanSAS 1D files(*.xml)|*.xml" 
436            dlg = wx.FileDialog(self, "Choose a file",
437                                self._default_save_location, "",wildcard , wx.SAVE)
438           
439            if dlg.ShowModal() == wx.ID_OK:
440                path = dlg.GetPath()
441                mypath = os.path.basename(path)
442                if os.path.splitext(mypath)[1].lower() ==".txt":
443                    self._onsaveTXT(path)
444                if os.path.splitext(mypath)[1].lower() ==".xml":
445                    self._onSaveXML(path)
446           
447            dlg.Destroy()
448           
449           
450   
451   
452   
453       
Note: See TracBrowser for help on using the repository browser.