source: sasview/guiframe/local_perspectives/plotting/DataPanel.py @ ce64735

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

small changes not committed

  • Property mode set to 100644
File size: 19.0 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 danse.common.plottools
15from danse.common.plottools.PlotPanel import PlotPanel
16from danse.common.plottools.plottables import Graph,Data1D
17from sans.guicomm.events import EVT_NEW_PLOT
18from sans.guicomm.events import StatusEvent ,NewPlotEvent
19
20class PanelMenu(wx.Menu):
21    plots = None
22    graph = None
23   
24    def set_plots(self, plots):
25        self.plots = plots
26   
27    def set_graph(self, graph):
28        self.graph = graph
29class View1DPanel1D(PlotPanel):
30    """
31        Plot panel for use with the GUI manager
32    """
33   
34    ## Internal name for the AUI manager
35    window_name = "plotpanel"
36    ## Title to appear on top of the window
37    window_caption = "Plot Panel"
38    ## Flag to tell the GUI manager that this panel is not
39    #  tied to any perspective
40    ALWAYS_ON = True
41    ## Group ID
42    group_id = None
43   
44    def __init__(self, parent, id = -1, color = None,\
45        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
46        """
47            Initialize the panel
48        """
49        PlotPanel.__init__(self, parent, id = id, style = style, **kwargs)
50       
51        ## Reference to the parent window
52        self.parent = parent
53        ## Plottables
54        self.plots = {}
55       
56        ## Unique ID (from gui_manager)
57        self.uid = None
58       
59        ## Action IDs for internal call-backs
60        self.action_ids = {}
61       
62        ## Graph       
63        self.graph = Graph()
64        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
65        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
66        self.graph.render(self)
67   
68    def _reset(self):
69        """
70            Resets internal data and graph
71        """   
72        self.graph.reset()
73        self.plots      = {}
74        self.action_ids = {}
75   
76    def _onEVT_1DREPLOT(self, event):
77        """
78            Data is ready to be displayed
79            @param event: data event
80        """
81        #TODO: Check for existence of plot attribute
82
83        # Check whether this is a replot. If we ask for a replot
84        # and the plottable no longer exists, ignore the event.
85        if hasattr(event, "update") and event.update==True \
86            and event.plot.name not in self.plots.keys():
87            return
88       
89        if hasattr(event, "reset"):
90            self._reset()
91       
92        is_new = True
93        print "model panel name",event.plot.name
94        if event.plot.name in self.plots.keys():
95            # Check whether the class of plottable changed
96            print "model panel",event.plot.name,event.plot.__class__
97            if not event.plot.__class__==self.plots[event.plot.name].__class__:
98                self.graph.delete(self.plots[event.plot.name])
99            else:
100                is_new = False
101       
102        if is_new:
103            self.plots[event.plot.name] = event.plot
104            self.graph.add(self.plots[event.plot.name])
105        else:
106            self.plots[event.plot.name].x = event.plot.x   
107            self.plots[event.plot.name].y = event.plot.y   
108            self.plots[event.plot.name].dy = event.plot.dy 
109            if hasattr(event.plot, 'dx') and hasattr(self.plots[event.plot.name], 'dx'):
110                self.plots[event.plot.name].dx = event.plot.dx   
111 
112       
113        # Check axis labels
114        #TODO: Should re-factor this
115        #if event.plot._xunit != self.graph.prop["xunit"]:
116        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
117           
118        #if event.plot._yunit != self.graph.prop["yunit"]:
119        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
120     
121        # Set the view scale for all plots
122        self._onEVT_FUNC_PROPERTY()
123     
124        self.graph.render(self)
125        self.subplot.figure.canvas.draw_idle()
126
127    def onLeftDown(self,event): 
128        """ left button down and ready to drag"""
129           
130        PlotPanel.onLeftDown(self, event)
131        ax = event.inaxes
132        if ax != None:
133            position = "x: %8.3g    y: %8.3g" % (event.xdata, event.ydata)
134            wx.PostEvent(self.parent, StatusEvent(status=position))
135
136    def _onRemove(self, event):
137        """
138        """
139        if not self.graph.selected_plottable == None:
140            print self.graph.selected_plottable
141           
142           
143            self.graph.delete(self.plots[self.graph.selected_plottable])
144            del self.plots[self.graph.selected_plottable]
145            self.graph.render(self)
146            self.subplot.figure.canvas.draw_idle()   
147           
148
149    def onContextMenu(self, event):
150        """
151            1D plot context menu
152            @param event: wx context event
153        """
154        #slicerpop = wx.Menu()
155        slicerpop = PanelMenu()
156        slicerpop.set_plots(self.plots)
157        slicerpop.set_graph(self.graph)
158               
159        # Option to save the data displayed
160       
161        #for plot in self.graph.plottables:
162        if self.graph.selected_plottable in self.plots:
163            plot = self.plots[self.graph.selected_plottable]
164            id = wx.NewId()
165            name = plot.name
166            slicerpop.Append(id, "&Save %s points" % name)
167            self.action_ids[str(id)] = plot
168            wx.EVT_MENU(self, id, self._onSave)
169               
170            # Option to delete plottable
171            id = wx.NewId()
172            slicerpop.Append(id, "Remove %s curve" % name)
173            self.action_ids[str(id)] = plot
174            wx.EVT_MENU(self, id, self._onRemove)
175           
176            # Option to hide
177            #TODO: implement functionality to hide a plottable (legend click)
178            slicerpop.AppendSeparator()
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       
186        item_list = self.parent.get_context_menu(self.graph)
187        if (not item_list==None) and (not len(item_list)==0):
188                slicerpop.AppendSeparator()
189                for item in item_list:
190                    try:
191                        id = wx.NewId()
192                        slicerpop.Append(id, item[0], item[1])
193                        wx.EVT_MENU(self, id, item[2])
194                    except:
195                        print sys.exc_value
196                        print RuntimeError, "View1DPanel.onContextMenu: bad menu item"
197       
198        slicerpop.AppendSeparator()
199       
200        if self.graph.selected_plottable in self.plots:
201            if self.plots[self.graph.selected_plottable].__class__.__name__=="Theory1D":
202                id = wx.NewId()
203                slicerpop.Append(id, '&Add errors to data')
204                wx.EVT_MENU(self, id, self._on_add_errors)
205            else:
206                id = wx.NewId()
207                slicerpop.Append(id, '&Linear fit')
208                wx.EVT_MENU(self, id, self.onFitting)
209               
210       
211
212        id = wx.NewId()
213        slicerpop.Append(id, '&Change scale')
214        wx.EVT_MENU(self, id, self._onProperties)
215       
216        id = wx.NewId()
217        #slicerpop.AppendSeparator()
218        slicerpop.Append(id, '&Reset Graph')
219        wx.EVT_MENU(self, id, self.onResetGraph)       
220
221        pos = event.GetPosition()
222        pos = self.ScreenToClient(pos)
223        self.PopupMenu(slicerpop, pos)
224   
225   
226    def _on_add_errors(self, evt):
227        """
228            Compute reasonable errors for a data set without
229            errors and transorm the plottable to a Data1D
230        """
231        import math
232        import numpy
233        import time
234       
235        if not self.graph.selected_plottable == None:
236            length = len(self.plots[self.graph.selected_plottable].x)
237            dy = numpy.zeros(length)
238            for i in range(length):
239                dy[i] = math.sqrt(self.plots[self.graph.selected_plottable].y[i])
240               
241            new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
242                              self.plots[self.graph.selected_plottable].y,
243                              dy=dy)
244            new_plot.interactive = True
245            new_plot.name = self.plots[self.graph.selected_plottable].name
246            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
247                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
248            else:
249                new_plot.group_id = str(time.time())
250           
251            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
252            new_plot.xaxis(label, unit)
253            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
254            new_plot.yaxis(label, unit)
255           
256            self.graph.delete(self.plots[self.graph.selected_plottable])
257           
258            self.graph.add(new_plot)
259            self.plots[self.graph.selected_plottable]=new_plot
260           
261            self.graph.render(self)
262            self.subplot.figure.canvas.draw_idle()   
263   
264    def _onSave(self, evt):
265        """
266            Save a data set to a text file
267            @param evt: Menu event
268        """
269        import os
270        id = str(evt.GetId())
271        if id in self.action_ids:         
272           
273            path = None
274            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.SAVE)
275            if dlg.ShowModal() == wx.ID_OK:
276                path = dlg.GetPath()
277                mypath = os.path.basename(path)
278                print path
279            dlg.Destroy()
280           
281            if not path == None:
282                out = open(path, 'w')
283                has_errors = True
284                if self.action_ids[id].dy==None or self.action_ids[id].dy==[]:
285                    has_errors = False
286                   
287                # Sanity check
288                if has_errors:
289                    try:
290                        if len(self.action_ids[id].y) != len(self.action_ids[id].dy):
291                            print "Y and dY have different lengths"
292                            has_errors = False
293                    except:
294                        has_errors = False
295               
296                if has_errors:
297                    out.write("<X>   <Y>   <dY>\n")
298                else:
299                    out.write("<X>   <Y>\n")
300                   
301                for i in range(len(self.action_ids[id].x)):
302                    if has_errors:
303                        out.write("%g  %g  %g\n" % (self.action_ids[id].x[i], 
304                                                    self.action_ids[id].y[i],
305                                                    self.action_ids[id].dy[i]))
306                    else:
307                        out.write("%g  %g\n" % (self.action_ids[id].x[i], 
308                                                self.action_ids[id].y[i]))
309                       
310                out.close()
311   
312   
313    def _onToggleScale(self, event):
314        if self.get_yscale() == 'log':
315            self.set_yscale('linear')
316        else:
317            self.set_yscale('log')
318        self.subplot.figure.canvas.draw_idle()   
319       
320class View1DPanel2D( View1DPanel1D):
321    """
322        Plot panel for use with the GUI manager
323    """
324   
325    ## Internal name for the AUI manager
326    window_name = "plotpanel"
327    ## Title to appear on top of the window
328    window_caption = "Plot Panel"
329    ## Flag to tell the GUI manager that this panel is not
330    #  tied to any perspective
331    ALWAYS_ON = True
332    ## Group ID
333    group_id = None
334   
335    def __init__(self, parent, id = -1,data2d=None, color = None,\
336        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
337        """
338            Initialize the panel
339        """
340        View1DPanel1D.__init__(self, parent, id = id, style = style, **kwargs)
341       
342        ## Reference to the parent window
343        self.parent = parent
344        ## Plottables
345        self.plots = {}
346        self.data = data2d
347        ## Unique ID (from gui_manager)
348        self.uid = None
349       
350        ## Action IDs for internal call-backs
351        self.action_ids = {}
352       
353        ## Graph       
354        self.graph = Graph()
355        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
356        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
357        self.graph.render(self)
358 
359    def _onEVT_1DREPLOT(self, event):
360        """
361            Data is ready to be displayed
362            @param event: data event
363        """
364        #TODO: Check for existence of plot attribute
365        # Check whether this is a replot. If we ask for a replot
366        # and the plottable no longer exists, ignore the event.
367        if hasattr(event, "update") and event.update==True \
368            and event.plot.name not in self.plots.keys():
369            return
370        if hasattr(event, "reset"):
371            self._reset()
372        is_new = True
373        if event.plot.name in self.plots.keys():
374            # Check whether the class of plottable changed
375            if not event.plot.__class__==self.plots[event.plot.name].__class__:
376                self.graph.delete(self.plots[event.plot.name])
377            else:
378                is_new = False
379        self.plots[event.plot.name] = event.plot
380        #if is_new:
381        self.graph.add(self.plots[event.plot.name])
382       
383
384        # Check axis labels
385        #TODO: Should re-factor this
386        #if event.plot._xunit != self.graph.prop["xunit"]:
387       
388        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
389        #if event.plot._yunit != self.graph.prop["yunit"]:
390        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
391        self.graph.render(self)
392        self.subplot.figure.canvas.draw_idle()
393
394
395    def onContextMenu(self, event):
396        """
397            2D plot context menu
398            @param event: wx context event
399        """
400       
401        #slicerpop = wx.Menu()
402        slicerpop = PanelMenu()
403        slicerpop.set_plots(self.plots)
404        slicerpop.set_graph(self.graph)
405               
406        # Option to save the data displayed
407   
408        # Various plot options
409        id = wx.NewId()
410        slicerpop.Append(id,'&Save image', 'Save image as PNG')
411        wx.EVT_MENU(self, id, self.onSaveImage)
412       
413       
414        item_list = self.parent.get_context_menu(self.graph)
415        if (not item_list==None) and (not len(item_list)==0):
416                slicerpop.AppendSeparator()
417                for item in item_list:
418                    try:
419                        id = wx.NewId()
420                        slicerpop.Append(id, item[0], item[1])
421                        wx.EVT_MENU(self, id, item[2])
422                    except:
423                        print sys.exc_value
424                        print RuntimeError, "View1DPanel2D.onContextMenu: bad menu item"
425       
426        slicerpop.AppendSeparator()
427     
428        id = wx.NewId()
429        slicerpop.Append(id, '&Toggle Linear/Log scale')
430        wx.EVT_MENU(self, id, self._onToggleScale) 
431
432        pos = event.GetPosition()
433        pos = self.ScreenToClient(pos)
434        self.PopupMenu(slicerpop, pos)
435   
436    def _onToggleScale(self, event):
437        """
438            toggle axis and replot image
439        """
440        if self.scale == 'log':
441            self.scale = 'linear'
442        else:
443            self.scale = 'log'
444        self.image(self.data,self.xmin_2D,self.xmax_2D,self.ymin_2D,
445                   self.ymax_2D,self.zmin_2D ,self.zmax_2D )
446        wx.PostEvent(self.parent, StatusEvent(status="Image is in %s scale"%self.scale))
447       
448class View1DModelPanel2D( View1DPanel2D):
449    """
450        Plot panel for use with the GUI manager
451    """
452   
453    ## Internal name for the AUI manager
454    window_name = "plotpanel"
455    ## Title to appear on top of the window
456    window_caption = "Plot Panel"
457    ## Flag to tell the GUI manager that this panel is not
458    #  tied to any perspective
459    ALWAYS_ON = True
460    ## Group ID
461    group_id = None
462   
463    def __init__(self, parent, id = -1,color = None,\
464        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
465        """
466            Initialize the panel
467        """
468        View1DPanel2D.__init__(self, parent, id = id, style = style, **kwargs)
469        ## Reference to the parent window
470        self.parent = parent
471        ## Plottables
472        self.plots = {}
473        print "Model 2d panel"
474       
475        ## Unique ID (from gui_manager)
476        self.uid = None
477       
478        ## Action IDs for internal call-backs
479        self.action_ids = {}
480       
481        ## Graph       
482        self.graph = Graph()
483        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
484        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
485        self.graph.render(self)
486    def onContextMenu(self, event):
487        # Slicer plot popup menu
488         #slicerpop = wx.Menu()
489        slicerpop = PanelMenu()
490        slicerpop.set_plots(self.plots)
491        slicerpop.set_graph(self.graph)
492               
493        # Option to save the data displayed
494   
495        # Various plot options
496        id = wx.NewId()
497        slicerpop.Append(id,'&Save image', 'Save image as PNG')
498        wx.EVT_MENU(self, id, self.onSaveImage)
499       
500       
501        item_list = self.parent.get_context_menu(self.graph)
502        if (not item_list==None) and (not len(item_list)==0):
503                slicerpop.AppendSeparator()
504                for item in item_list:
505                    try:
506                        id = wx.NewId()
507                        slicerpop.Append(id, item[0], item[1])
508                        wx.EVT_MENU(self, id, item[2])
509                    except:
510                        print sys.exc_value
511                        print RuntimeError, "View1DPanel2D.onContextMenu: bad menu item"
512       
513        slicerpop.AppendSeparator()
514     
515        id = wx.NewId()
516        slicerpop.Append(id, '&sector averaging')
517        wx.EVT_MENU(self, id, self.onSectorSlicer) 
518       
519   
520       
521        pos = event.GetPosition()
522        pos = self.ScreenToClient(pos)
523        self.PopupMenu(slicerpop, pos)
524   
525
526    def onSectorSlicer(self, event):
527        print "onLineSlicer"
528        import math
529        from DataLoader.manipulations import SectorPhi
530        for item in self.graph.plottables:
531            r= SectorPhi(005,.01, 0.0, math.pi/2.0)
532            print r(item)
533            data=r(item)
534        new_plot= Data1D(x=data.x,y=data.y,dy=data.dy )
535        new_plot.name = "sector"
536        new_plot.group_id= "sector"
537        #wx.PostEvent(self.parent, NewPlotEvent(plot=r(item), title="Analytical model"))
538        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Analytical model"))
539       
540       
541       
Note: See TracBrowser for help on using the repository browser.