source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ 0b16ee3

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

hide and show error ,fix ,color change and toggle between hide and show

  • Property mode set to 100644
File size: 18.4 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            selected_plot= self.plots[self.graph.selected_plottable]
226            #if self.plots[self.graph.selected_plottable].name in self.err_dy.iterkeys()\
227            #    and self.errors_hide:
228            if selected_plot.__class__.__name__=="Data1D":
229                if selected_plot.dy ==None or selected_plot.dy== []:
230                    id = wx.NewId()
231                    slicerpop.Append(id, '&Show errors to data')
232                    wx.EVT_MENU(self, id, self._on_add_errors)
233                elif numpy.all(selected_plot.dy==0):
234                    id = wx.NewId()
235                    slicerpop.Append(id, '&Show errors to data')
236                    wx.EVT_MENU(self, id, self._on_add_errors)
237                else:
238                    id = wx.NewId()
239                    slicerpop.Append(id, '&Hide Error bars')
240                    wx.EVT_MENU(self, id, self._on_remove_errors)
241           
242            id = wx.NewId()
243            slicerpop.Append(id, '&Linear fit')
244            wx.EVT_MENU(self, id, self.onFitting)
245               
246            slicerpop.AppendSeparator()
247       
248        id = wx.NewId()
249        slicerpop.Append(id, '&Change scale')
250        wx.EVT_MENU(self, id, self._onProperties)
251       
252        id = wx.NewId()
253        slicerpop.Append(id, '&Reset Graph')
254        wx.EVT_MENU(self, id, self.onResetGraph) 
255       
256        pos = event.GetPosition()
257        pos = self.ScreenToClient(pos)
258        self.PopupMenu(slicerpop, pos)
259       
260       
261    def _on_remove_errors(self, evt):
262        """
263            Save name and dy of data in dictionary self.err_dy
264            Create a new data1D with the same x, y
265            vector and dy with zeros.
266            post self.err_dy as event (ErrorDataEvent) for any object
267            which wants to reconstruct the initial data.
268            @param evt: Menu event
269        """
270        if not self.graph.selected_plottable == None:
271            ## store existing dy
272            name =self.plots[self.graph.selected_plottable].name
273            dy = self.plots[self.graph.selected_plottable].dy
274            self.err_dy[name]= dy
275            ## Create a new dy for a new plottable
276            import numpy
277            dy= numpy.zeros(len(self.plots[self.graph.selected_plottable].y))
278            selected_plot= self.plots[self.graph.selected_plottable]
279           
280            if selected_plot.__class__.__name__=="Data1D":
281                new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
282                              self.plots[self.graph.selected_plottable].y,
283                              dy=dy)
284            else:
285                 new_plot = Theory1D(self.plots[self.graph.selected_plottable].x,
286                          self.plots[self.graph.selected_plottable].y,
287                          dy=dy)
288            new_plot.interactive = True
289            self.errors_hide = True
290            new_plot.name = self.plots[self.graph.selected_plottable].name
291            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
292                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
293                new_plot.id = self.plots[self.graph.selected_plottable].id
294            else:
295                new_plot.group_id = str(time.time())
296                new_plot.id = str(time.time())
297            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
298            new_plot.xaxis(label, unit)
299            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
300            new_plot.yaxis(label, unit)
301            ## save the color of the selected plottable before it is deleted
302            color=self.graph.plottables[self.plots[self.graph.selected_plottable]]
303            self.graph.delete(self.plots[self.graph.selected_plottable])
304            ## add newly created plottable to the graph with the save color
305            self.graph.color += color
306            self.graph.add(new_plot,color)
307            ## transforming the view of the new data into the same of the previous data
308            self._onEVT_FUNC_PROPERTY()
309            ## save the plot
310            self.plots[self.graph.selected_plottable]=new_plot
311            ## Render the graph
312            self.graph.render(self)
313            self.subplot.figure.canvas.draw_idle() 
314           
315            event = ErrorDataEvent(err_dy=self.err_dy)
316            wx.PostEvent(self.parent, event)
317   
318   
319    def _on_add_errors(self, evt):
320        """
321            create a new data1D witht the errors saved in self.err_dy
322            to show errors of the plot.
323            Compute reasonable errors for a data set without
324            errors and transorm the plottable to a Data1D
325            @param evt: Menu event
326        """
327        import math
328        import numpy
329        import time
330       
331        if not self.graph.selected_plottable == None:
332            ##Reset the flag to display the hide option on the context menu
333            self.errors_hide = False
334            ## restore dy
335            length = len(self.plots[self.graph.selected_plottable].x)
336            dy = numpy.zeros(length)
337            selected_plot= self.plots[self.graph.selected_plottable]
338           
339            try:
340                dy = self.err_dy[selected_plot.name]
341               
342            except:
343                #for i in range(length):
344                #dy[i] = math.sqrt(self.plots[self.graph.selected_plottable].y[i])     
345                if hasattr(selected_plot,"dy"):
346                    dy= selected_plot.dy
347                else:
348                    dy = numpy.zeros(selected_plot.dy)
349                   
350            ## Create a new plottable data1D
351            if selected_plot.__class__.__name__=="Data1D":
352                new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
353                          self.plots[self.graph.selected_plottable].y,
354                          dy=dy)
355            else:
356                ## Create a new plottable Theory1D
357                new_plot = Theory1D(self.plots[self.graph.selected_plottable].x,
358                          self.plots[self.graph.selected_plottable].y,
359                          dy=dy)
360            new_plot.interactive = True
361           
362            new_plot.name = self.plots[self.graph.selected_plottable].name
363            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
364                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
365                new_plot.id = self.plots[self.graph.selected_plottable].id
366            else:
367                new_plot.group_id = str(time.time())
368                new_plot.id = str(time.time())
369           
370            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
371            new_plot.xaxis(label, unit)
372            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
373            new_plot.yaxis(label, unit)
374            ## save the color of the selected plottable before it is deleted
375            color=self.graph.plottables[self.plots[self.graph.selected_plottable]]
376            self.graph.delete(self.plots[self.graph.selected_plottable])
377            self.graph.color += color
378            ## add newly created plottable to the graph with the save color
379            self.graph.add(new_plot, color)
380            ## transforming the view of the new data into the same of the previous data
381            self._onEVT_FUNC_PROPERTY()
382            ## save the plot
383            self.plots[self.graph.selected_plottable]=new_plot
384            ## render the graph with its new content
385            self.graph.render(self)
386            self.subplot.figure.canvas.draw_idle() 
387               
388               
389    def _onSaveXML(self, path):
390        """
391            Save 1D  Data to  XML file
392            @param evt: Menu event
393        """
394        if not path == None:
395            out = open(path, 'w')
396            from DataLoader.readers import cansas_reader
397            reader = cansas_reader.Reader()
398            datainfo= self.plots[self.graph.selected_plottable].info
399            reader.write( path, datainfo)
400           
401            try:
402                self._default_save_location = os.path.dirname(path)
403            except:
404                pass
405       
406        return 
407   
408   
409    def _onsaveTXT(self, path):
410        """
411            Save file as txt
412        """
413        data = self.plots[self.graph.selected_plottable]
414       
415        if not path == None:
416            out = open(path, 'w')
417            has_errors = True
418            if data.dy==None or data.dy==[]:
419                has_errors = False
420               
421            # Sanity check
422            if has_errors:
423                try:
424                    if len(data.y) != len(data.dy):
425
426                        has_errors = False
427                except:
428                    has_errors = False
429           
430            if has_errors:
431                out.write("<X>   <Y>   <dY>\n")
432            else:
433                out.write("<X>   <Y>\n")
434               
435            for i in range(len(data.x)):
436                if has_errors:
437                    out.write("%g  %g  %g\n" % (data.x[i], 
438                                                data.y[i],
439                                               data.dy[i]))
440                else:
441                    out.write("%g  %g\n" % (data.x[i], 
442                                            data.y[i]))
443                   
444            out.close()                 
445            try:
446                self._default_save_location = os.path.dirname(path)
447            except:
448                pass   
449               
450    def _onSave(self, evt):
451        """
452            Save a data set to a text file
453            @param evt: Menu event
454        """
455        import os
456        id = str(evt.GetId())
457        if id in self.action_ids:         
458           
459            path = None
460            wildcard = "Text files (*.txt)|*.txt|"\
461            "CanSAS 1D files(*.xml)|*.xml" 
462            dlg = wx.FileDialog(self, "Choose a file",
463                                self._default_save_location, "",wildcard , wx.SAVE)
464           
465            if dlg.ShowModal() == wx.ID_OK:
466                path = dlg.GetPath()
467                mypath = os.path.basename(path)
468                if os.path.splitext(mypath)[1].lower() ==".txt":
469                    self._onsaveTXT(path)
470                if os.path.splitext(mypath)[1].lower() ==".xml":
471                    self._onSaveXML(path)
472           
473            dlg.Destroy()
474           
475           
476   
477   
478   
479       
Note: See TracBrowser for help on using the repository browser.