source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ 8bd764d

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

context menu improve for xml

  • Property mode set to 100644
File size: 17.5 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
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        self.errors_hide=0
61       
62        ## Unique ID (from gui_manager)
63        self.uid = None
64       
65        ## Action IDs for internal call-backs
66        self.action_ids = {}
67       
68        ## Graph       
69        self.graph = Graph()
70        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
71        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
72        self.graph.render(self)
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    def _onEVT_1DREPLOT(self, event):
83        """
84            Data is ready to be displayed
85            @param event: data event
86        """
87       
88        #TODO: Check for existence of plot attribute
89
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           
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       
129        # Check axis labels
130        #TODO: Should re-factor this
131        #if event.plot._xunit != self.graph.prop["xunit"]:
132       
133        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
134           
135        #if event.plot._yunit != self.graph.prop["yunit"]:
136        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
137     
138        # Set the view scale for all plots
139       
140        self._onEVT_FUNC_PROPERTY()
141       
142        self.graph.render(self)
143       
144        self.subplot.figure.canvas.draw_idle()
145       
146    def onLeftDown(self,event): 
147        """ left button down and ready to drag"""
148           
149        PlotPanel.onLeftDown(self, event)
150        ax = event.inaxes
151        if ax != None:
152            position = "x: %8.3g    y: %8.3g" % (event.xdata, event.ydata)
153            wx.PostEvent(self.parent, StatusEvent(status=position))
154
155    def _onRemove(self, event):
156        """
157        """
158        if not self.graph.selected_plottable == None:
159            #print self.graph.selected_plottable
160            self.graph.delete(self.plots[self.graph.selected_plottable])
161            del self.plots[self.graph.selected_plottable]
162            self.graph.render(self)
163            self.subplot.figure.canvas.draw_idle()   
164           
165
166    def onContextMenu(self, event):
167        """
168            1D plot context menu
169            @param event: wx context event
170        """
171        #slicerpop = wx.Menu()
172        slicerpop = PanelMenu()
173        slicerpop.set_plots(self.plots)
174        slicerpop.set_graph(self.graph)
175               
176        # Option to save the data displayed
177       
178     
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        #print "item_list",item_list
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                    pass
204                    #print sys.exc_value
205                    #print RuntimeError, "View1DPanel.onContextMenu: bad menu item"
206            slicerpop.AppendSeparator()
207        #for plot in self.graph.plottables:
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            slicerpop.Append(id, "&Save %s points" % name)
213            self.action_ids[str(id)] = plot
214            wx.EVT_MENU(self, id, self._onSave)
215            #save as cansas
216            id = wx.NewId()
217            slicerpop.Append(id, "&Save %s canSAS XML" % name)
218            self.action_ids[str(id)] = plot
219            wx.EVT_MENU(self, id, self._onSaveXML)
220               
221            # Option to delete plottable
222            id = wx.NewId()
223            slicerpop.Append(id, "Remove %s curve" % name)
224            self.action_ids[str(id)] = plot
225            wx.EVT_MENU(self, id, self._onRemove)
226            slicerpop.AppendSeparator()
227            # Option to hide
228            #TODO: implement functionality to hide a plottable (legend click)
229           
230       
231        if self.graph.selected_plottable in self.plots:
232            if self.plots[self.graph.selected_plottable].name in self.err_dy.iterkeys()\
233                and self.errors_hide==1:
234                 
235                #if self.plots[self.graph.selected_plottable].__class__.__name__=="Theory1D":
236                id = wx.NewId()
237                slicerpop.Append(id, '&Show errors to data')
238                #print "panel scale before  ",self.xLabel, self.yLabel
239                #print "cyllinder before adding error", self.plots[self.graph.selected_plottable].x
240                wx.EVT_MENU(self, id, self._on_add_errors)
241               
242               
243            elif self.plots[self.graph.selected_plottable].__class__.__name__=="Data1D"\
244                and self.errors_hide==0:
245                    id = wx.NewId()
246                    slicerpop.Append(id, '&Hide Error bars')
247                    #print "panel scale before  ",self.xLabel, self.yLabel
248                    #print "cyllinder before adding error", self.plots[self.graph.selected_plottable].x
249                    wx.EVT_MENU(self, id, self._on_remove_errors)
250                   
251             
252            else:
253                id = wx.NewId()
254                slicerpop.Append(id, '&Linear fit')
255                wx.EVT_MENU(self, id, self.onFitting)
256               
257            slicerpop.AppendSeparator()
258        id = wx.NewId()
259        slicerpop.Append(id, '&Change scale')
260        wx.EVT_MENU(self, id, self._onProperties)
261       
262        id = wx.NewId()
263        slicerpop.Append(id, '&Reset Graph')
264        wx.EVT_MENU(self, id, self.onResetGraph) 
265        """
266        slicerpop.AppendSeparator()
267        id = wx.NewId()
268        slicerpop.Append(id,'&Printer setup', 'Set image size')
269        wx.EVT_MENU(self, id, self.onPrinterSetup)
270       
271        id = wx.NewId()
272        slicerpop.Append(id,'&Printer Preview', 'Set image size')
273        wx.EVT_MENU(self, id, self.onPrinterPreview)
274        """
275       
276
277        pos = event.GetPosition()
278        pos = self.ScreenToClient(pos)
279        self.PopupMenu(slicerpop, pos)
280       
281       
282    def _on_remove_errors(self, evt):
283        if not self.graph.selected_plottable == None:
284            name =self.plots[self.graph.selected_plottable].name
285            dy = self.plots[self.graph.selected_plottable].dy
286            self.err_dy[name]= dy
287            import numpy
288            dy= numpy.zeros(len(self.plots[self.graph.selected_plottable].y))
289            new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
290                              self.plots[self.graph.selected_plottable].y,
291                              dy=dy)
292            new_plot.interactive = True
293            self.errors_hide=1
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            #print "panel scale ",self.xLabel, self.yLabel
306            #print "color",self.graph.plottables[self.plots[self.graph.selected_plottable]]
307            color=self.graph.plottables[self.plots[self.graph.selected_plottable]]
308            self.graph.delete(self.plots[self.graph.selected_plottable])
309           
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            #print "cyllinder", self.plots[self.graph.selected_plottable].x,self.plots[self.graph.selected_plottable].view.x, new_plot.x, new_plot.view.x
314            self.plots[self.graph.selected_plottable]=new_plot
315           
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    def _on_add_errors(self, evt):
323        """
324            Compute reasonable errors for a data set without
325            errors and transorm the plottable to a Data1D
326        """
327        import math
328        import numpy
329        import time
330       
331        if not self.graph.selected_plottable == None:
332            length = len(self.plots[self.graph.selected_plottable].x)
333            dy = numpy.zeros(length)
334            selected_plot= self.plots[self.graph.selected_plottable]
335            try:
336                dy = self.err_dy[selected_plot.name]
337            except:
338                for i in range(length):
339                    dy[i] = math.sqrt(self.plots[self.graph.selected_plottable].y[i])     
340            #for i in range(length):
341            #    dy[i] = math.sqrt(self.plots[self.graph.selected_plottable].y[i])
342               
343            new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
344                              self.plots[self.graph.selected_plottable].y,
345                              dy=dy)
346            new_plot.interactive = True
347            self.errors_hide=0
348            new_plot.name = self.plots[self.graph.selected_plottable].name
349            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
350                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
351                new_plot.id = self.plots[self.graph.selected_plottable].id
352            else:
353                new_plot.group_id = str(time.time())
354                new_plot.id = str(time.time())
355           
356            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
357            new_plot.xaxis(label, unit)
358            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
359            new_plot.yaxis(label, unit)
360            #print "panel scale ",self.xLabel, self.yLabel
361            color=self.graph.plottables[self.plots[self.graph.selected_plottable]]
362            self.graph.delete(self.plots[self.graph.selected_plottable])
363            self.graph.add(new_plot, color)
364           
365            # transforming the view of the new data into the same of the previous data
366            self._onEVT_FUNC_PROPERTY()
367            #print "cyllinder", self.plots[self.graph.selected_plottable].x,self.plots[self.graph.selected_plottable].view.x, new_plot.x, new_plot.view.x
368            self.plots[self.graph.selected_plottable]=new_plot
369           
370            self.graph.render(self)
371            self.subplot.figure.canvas.draw_idle() 
372               
373    def _onSaveXML(self, evt):
374        import os
375        id = str(evt.GetId())
376        if id in self.action_ids:         
377            path = None
378            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.xml", wx.SAVE)
379            if dlg.ShowModal() == wx.ID_OK:
380                path = dlg.GetPath()
381                mypath = os.path.basename(path)
382                #print path
383            dlg.Destroy()
384           
385            if not path == None:
386                out = open(path, 'w')
387                from DataLoader.readers import cansas_reader
388                reader = cansas_reader.Reader()
389                datainfo= self.plots[self.graph.selected_plottable].info
390                reader.write( path, datainfo)
391            return 
392               
393               
394               
395               
396    def _onSave(self, evt):
397        """
398            Save a data set to a text file
399            @param evt: Menu event
400        """
401        import os
402        id = str(evt.GetId())
403        if id in self.action_ids:         
404           
405            path = None
406            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.SAVE)
407            if dlg.ShowModal() == wx.ID_OK:
408                path = dlg.GetPath()
409                mypath = os.path.basename(path)
410                #print path
411            dlg.Destroy()
412           
413            if not path == None:
414                out = open(path, 'w')
415                has_errors = True
416                if self.action_ids[id].dy==None or self.action_ids[id].dy==[]:
417                    has_errors = False
418                   
419                # Sanity check
420                if has_errors:
421                    try:
422                        if len(self.action_ids[id].y) != len(self.action_ids[id].dy):
423                            #print "Y and dY have different lengths"
424                            has_errors = False
425                    except:
426                        has_errors = False
427               
428                if has_errors:
429                    out.write("<X>   <Y>   <dY>\n")
430                else:
431                    out.write("<X>   <Y>\n")
432                   
433                for i in range(len(self.action_ids[id].x)):
434                    if has_errors:
435                        out.write("%g  %g  %g\n" % (self.action_ids[id].x[i], 
436                                                    self.action_ids[id].y[i],
437                                                    self.action_ids[id].dy[i]))
438                    else:
439                        out.write("%g  %g\n" % (self.action_ids[id].x[i], 
440                                                self.action_ids[id].y[i]))
441                       
442                out.close()
443   
444 
445
446    def _onToggleScale(self, event):
447        if self.get_yscale() == 'log':
448            self.set_yscale('linear')
449        else:
450            self.set_yscale('log')
451        self.subplot.figure.canvas.draw_idle()   
452       
Note: See TracBrowser for help on using the repository browser.