source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ 54cc36a

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 54cc36a was ffd23b5, checked in by Gervaise Alina <gervyh@…>, 15 years ago
  • Property mode set to 100644
File size: 12.7 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
20
21from SlicerParameters import SlicerEvent
22from binder import BindArtist
23(InternalEvent, EVT_INTERNAL)   = wx.lib.newevent.NewEvent()
24#from SlicerParameters import SlicerEvent
25#(InternalEvent, EVT_INTERNAL)   = wx.lib.newevent.NewEvent()
26DEFAULT_QMAX = 0.05
27
28DEFAULT_QSTEP = 0.001
29DEFAULT_BEAM = 0.005
30BIN_WIDTH =1
31import pylab
32
33class PanelMenu(wx.Menu):
34    plots = None
35    graph = None
36   
37    def set_plots(self, plots):
38        self.plots = plots
39   
40    def set_graph(self, graph):
41        self.graph = graph
42class ModelPanel1D(PlotPanel):
43    """
44        Plot panel for use with the GUI manager
45    """
46   
47    ## Internal name for the AUI manager
48    window_name = "plotpanel"
49    ## Title to appear on top of the window
50    window_caption = "Plot Panel"
51    ## Flag to tell the GUI manager that this panel is not
52    #  tied to any perspective
53    ALWAYS_ON = True
54    ## Group ID
55    group_id = None
56   
57    def __init__(self, parent, id = -1, color = None,\
58        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
59        """
60            Initialize the panel
61        """
62        PlotPanel.__init__(self, parent, id = id, style = style, **kwargs)
63       
64        ## Reference to the parent window
65        self.parent = parent
66        ## Plottables
67        self.plots = {}
68       
69        ## Unique ID (from gui_manager)
70        self.uid = None
71       
72        ## Action IDs for internal call-backs
73        self.action_ids = {}
74       
75        ## Graph       
76        self.graph = Graph()
77        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
78        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
79        self.graph.render(self)
80   
81    def _reset(self):
82        """
83            Resets internal data and graph
84        """   
85        self.graph.reset()
86        self.plots      = {}
87        self.action_ids = {}
88   
89    def _onEVT_1DREPLOT(self, event):
90        """
91            Data is ready to be displayed
92            @param event: data event
93        """
94       
95        #TODO: Check for existence of plot attribute
96
97        # Check whether this is a replot. If we ask for a replot
98        # and the plottable no longer exists, ignore the event.
99        if hasattr(event, "update") and event.update==True \
100            and event.plot.name not in self.plots.keys():
101            return
102       
103        if hasattr(event, "reset"):
104            self._reset()
105       
106        is_new = True
107        if event.plot.name in self.plots.keys():
108            # Check whether the class of plottable changed
109            if not event.plot.__class__==self.plots[event.plot.name].__class__:
110                #overwrite a plottable using the same name
111                self.graph.delete(self.plots[event.plot.name])
112            else:
113                # plottable is already draw on the panel
114                is_new = False
115       
116           
117           
118        if is_new:
119            # a new plottable overwrites a plotted one  using the same id
120            for plottable in self.plots.itervalues():
121                if event.plot.id==plottable.id :
122                    self.graph.delete(plottable)
123           
124            self.plots[event.plot.name] = event.plot
125            self.graph.add(self.plots[event.plot.name])
126        else:
127            #replot the graph
128            self.plots[event.plot.name].x = event.plot.x   
129            self.plots[event.plot.name].y = event.plot.y   
130            self.plots[event.plot.name].dy = event.plot.dy 
131            if hasattr(event.plot, 'dx') and hasattr(self.plots[event.plot.name], 'dx'):
132                self.plots[event.plot.name].dx = event.plot.dx   
133 
134       
135        # Check axis labels
136        #TODO: Should re-factor this
137        #if event.plot._xunit != self.graph.prop["xunit"]:
138       
139        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
140           
141        #if event.plot._yunit != self.graph.prop["yunit"]:
142        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
143     
144        # Set the view scale for all plots
145       
146        self._onEVT_FUNC_PROPERTY()
147   
148        self.graph.render(self)
149        self.subplot.figure.canvas.draw_idle()
150
151    def onLeftDown(self,event): 
152        """ left button down and ready to drag"""
153           
154        PlotPanel.onLeftDown(self, event)
155        ax = event.inaxes
156        if ax != None:
157            position = "x: %8.3g    y: %8.3g" % (event.xdata, event.ydata)
158            wx.PostEvent(self.parent, StatusEvent(status=position))
159
160    def _onRemove(self, event):
161        """
162        """
163        if not self.graph.selected_plottable == None:
164            print self.graph.selected_plottable
165           
166           
167            self.graph.delete(self.plots[self.graph.selected_plottable])
168            del self.plots[self.graph.selected_plottable]
169            self.graph.render(self)
170            self.subplot.figure.canvas.draw_idle()   
171           
172
173    def onContextMenu(self, event):
174        """
175            1D plot context menu
176            @param event: wx context event
177        """
178        #slicerpop = wx.Menu()
179        slicerpop = PanelMenu()
180        slicerpop.set_plots(self.plots)
181        slicerpop.set_graph(self.graph)
182               
183        # Option to save the data displayed
184       
185        #for plot in self.graph.plottables:
186        if self.graph.selected_plottable in self.plots:
187            plot = self.plots[self.graph.selected_plottable]
188            id = wx.NewId()
189            name = plot.name
190            slicerpop.Append(id, "&Save %s points" % name)
191            self.action_ids[str(id)] = plot
192            wx.EVT_MENU(self, id, self._onSave)
193               
194            # Option to delete plottable
195            id = wx.NewId()
196            slicerpop.Append(id, "Remove %s curve" % name)
197            self.action_ids[str(id)] = plot
198            wx.EVT_MENU(self, id, self._onRemove)
199           
200            # Option to hide
201            #TODO: implement functionality to hide a plottable (legend click)
202            slicerpop.AppendSeparator()
203               
204        # Various plot options
205        id = wx.NewId()
206        slicerpop.Append(id,'&Save image', 'Save image as PNG')
207        wx.EVT_MENU(self, id, self.onSaveImage)
208       
209       
210        item_list = self.parent.get_context_menu(self.graph)
211        if (not item_list==None) and (not len(item_list)==0):
212                slicerpop.AppendSeparator()
213                for item in item_list:
214                    try:
215                        id = wx.NewId()
216                        slicerpop.Append(id, item[0], item[1])
217                        wx.EVT_MENU(self, id, item[2])
218                    except:
219                        print sys.exc_value
220                        print RuntimeError, "View1DPanel.onContextMenu: bad menu item"
221       
222        slicerpop.AppendSeparator()
223       
224        if self.graph.selected_plottable in self.plots:
225            if self.plots[self.graph.selected_plottable].__class__.__name__=="Theory1D":
226                id = wx.NewId()
227                slicerpop.Append(id, '&Add errors to data')
228                #print "panel scale before  ",self.xLabel, self.yLabel
229                #print "cyllinder before adding error", self.plots[self.graph.selected_plottable].x
230                wx.EVT_MENU(self, id, self._on_add_errors)
231            else:
232                id = wx.NewId()
233                slicerpop.Append(id, '&Linear fit')
234                wx.EVT_MENU(self, id, self.onFitting)
235               
236       
237
238        id = wx.NewId()
239        slicerpop.Append(id, '&Change scale')
240        wx.EVT_MENU(self, id, self._onProperties)
241       
242        id = wx.NewId()
243        #slicerpop.AppendSeparator()
244        slicerpop.Append(id, '&Reset Graph')
245        wx.EVT_MENU(self, id, self.onResetGraph)       
246
247        pos = event.GetPosition()
248        pos = self.ScreenToClient(pos)
249        self.PopupMenu(slicerpop, pos)
250   
251   
252    def _on_add_errors(self, evt):
253        """
254            Compute reasonable errors for a data set without
255            errors and transorm the plottable to a Data1D
256        """
257        import math
258        import numpy
259        import time
260       
261        if not self.graph.selected_plottable == None:
262            length = len(self.plots[self.graph.selected_plottable].x)
263            dy = numpy.zeros(length)
264            for i in range(length):
265                dy[i] = math.sqrt(self.plots[self.graph.selected_plottable].y[i])
266               
267            new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
268                              self.plots[self.graph.selected_plottable].y,
269                              dy=dy)
270            new_plot.interactive = True
271            new_plot.name = self.plots[self.graph.selected_plottable].name
272            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
273                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
274                new_plot.id = self.plots[self.graph.selected_plottable].id
275            else:
276                new_plot.group_id = str(time.time())
277                new_plot.id = str(time.time())
278           
279            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
280            new_plot.xaxis(label, unit)
281            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
282            new_plot.yaxis(label, unit)
283            #print "panel scale ",self.xLabel, self.yLabel
284            self.graph.delete(self.plots[self.graph.selected_plottable])
285           
286            self.graph.add(new_plot)
287            # transforming the view of the new data into the same of the previous data
288            self._onEVT_FUNC_PROPERTY()
289            #print "cyllinder", self.plots[self.graph.selected_plottable].x,self.plots[self.graph.selected_plottable].view.x, new_plot.x, new_plot.view.x
290            self.plots[self.graph.selected_plottable]=new_plot
291           
292            self.graph.render(self)
293            self.subplot.figure.canvas.draw_idle()   
294   
295    def _onSave(self, evt):
296        """
297            Save a data set to a text file
298            @param evt: Menu event
299        """
300        import os
301        id = str(evt.GetId())
302        if id in self.action_ids:         
303           
304            path = None
305            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.SAVE)
306            if dlg.ShowModal() == wx.ID_OK:
307                path = dlg.GetPath()
308                mypath = os.path.basename(path)
309                print path
310            dlg.Destroy()
311           
312            if not path == None:
313                out = open(path, 'w')
314                has_errors = True
315                if self.action_ids[id].dy==None or self.action_ids[id].dy==[]:
316                    has_errors = False
317                   
318                # Sanity check
319                if has_errors:
320                    try:
321                        if len(self.action_ids[id].y) != len(self.action_ids[id].dy):
322                            print "Y and dY have different lengths"
323                            has_errors = False
324                    except:
325                        has_errors = False
326               
327                if has_errors:
328                    out.write("<X>   <Y>   <dY>\n")
329                else:
330                    out.write("<X>   <Y>\n")
331                   
332                for i in range(len(self.action_ids[id].x)):
333                    if has_errors:
334                        out.write("%g  %g  %g\n" % (self.action_ids[id].x[i], 
335                                                    self.action_ids[id].y[i],
336                                                    self.action_ids[id].dy[i]))
337                    else:
338                        out.write("%g  %g\n" % (self.action_ids[id].x[i], 
339                                                self.action_ids[id].y[i]))
340                       
341                out.close()
342   
343   
344    def _onToggleScale(self, event):
345        if self.get_yscale() == 'log':
346            self.set_yscale('linear')
347        else:
348            self.set_yscale('log')
349        self.subplot.figure.canvas.draw_idle()   
350       
Note: See TracBrowser for help on using the repository browser.