source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ ab8f936

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

override a plot update —> model can be plotted with unik name

  • Property mode set to 100644
File size: 12.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
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        #TODO: Check for existence of plot attribute
95
96        # Check whether this is a replot. If we ask for a replot
97        # and the plottable no longer exists, ignore the event.
98        if hasattr(event, "update") and event.update==True \
99            and event.plot.name not in self.plots.keys():
100            return
101       
102        if hasattr(event, "reset"):
103            self._reset()
104       
105        is_new = True
106        if event.plot.name in self.plots.keys():
107            # Check whether the class of plottable changed
108            if not event.plot.__class__==self.plots[event.plot.name].__class__:
109                #overwrite a plottable using the same name
110                self.graph.delete(self.plots[event.plot.name])
111            else:
112                # plottable is already draw on the panel
113                is_new = False
114
115           
116        if is_new:
117            # a new plottable overwrites a plotted one  using the same id
118            for plottable in self.plots.itervalues():
119                if event.plot.id==plottable.id :
120                    self.graph.delete(plottable)
121           
122            self.plots[event.plot.name] = event.plot
123            self.graph.add(self.plots[event.plot.name])
124        else:
125            #replot the graph
126            self.plots[event.plot.name].x = event.plot.x   
127            self.plots[event.plot.name].y = event.plot.y   
128            self.plots[event.plot.name].dy = event.plot.dy 
129            if hasattr(event.plot, 'dx') and hasattr(self.plots[event.plot.name], 'dx'):
130                self.plots[event.plot.name].dx = event.plot.dx   
131 
132       
133        # Check axis labels
134        #TODO: Should re-factor this
135        #if event.plot._xunit != self.graph.prop["xunit"]:
136        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
137           
138        #if event.plot._yunit != self.graph.prop["yunit"]:
139        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
140     
141        # Set the view scale for all plots
142        self._onEVT_FUNC_PROPERTY()
143     
144        self.graph.render(self)
145        self.subplot.figure.canvas.draw_idle()
146
147    def onLeftDown(self,event): 
148        """ left button down and ready to drag"""
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    def _onRemove(self, event):
157        """
158        """
159        if not self.graph.selected_plottable == None:
160            print self.graph.selected_plottable
161           
162           
163            self.graph.delete(self.plots[self.graph.selected_plottable])
164            del self.plots[self.graph.selected_plottable]
165            self.graph.render(self)
166            self.subplot.figure.canvas.draw_idle()   
167           
168
169    def onContextMenu(self, event):
170        """
171            1D plot context menu
172            @param event: wx context event
173        """
174        #slicerpop = wx.Menu()
175        slicerpop = PanelMenu()
176        slicerpop.set_plots(self.plots)
177        slicerpop.set_graph(self.graph)
178               
179        # Option to save the data displayed
180       
181        #for plot in self.graph.plottables:
182        if self.graph.selected_plottable in self.plots:
183            plot = self.plots[self.graph.selected_plottable]
184            id = wx.NewId()
185            name = plot.name
186            slicerpop.Append(id, "&Save %s points" % name)
187            self.action_ids[str(id)] = plot
188            wx.EVT_MENU(self, id, self._onSave)
189               
190            # Option to delete plottable
191            id = wx.NewId()
192            slicerpop.Append(id, "Remove %s curve" % name)
193            self.action_ids[str(id)] = plot
194            wx.EVT_MENU(self, id, self._onRemove)
195           
196            # Option to hide
197            #TODO: implement functionality to hide a plottable (legend click)
198            slicerpop.AppendSeparator()
199               
200        # Various plot options
201        id = wx.NewId()
202        slicerpop.Append(id,'&Save image', 'Save image as PNG')
203        wx.EVT_MENU(self, id, self.onSaveImage)
204       
205       
206        item_list = self.parent.get_context_menu(self.graph)
207        if (not item_list==None) and (not len(item_list)==0):
208                slicerpop.AppendSeparator()
209                for item in item_list:
210                    try:
211                        id = wx.NewId()
212                        slicerpop.Append(id, item[0], item[1])
213                        wx.EVT_MENU(self, id, item[2])
214                    except:
215                        print sys.exc_value
216                        print RuntimeError, "View1DPanel.onContextMenu: bad menu item"
217       
218        slicerpop.AppendSeparator()
219       
220        if self.graph.selected_plottable in self.plots:
221            if self.plots[self.graph.selected_plottable].__class__.__name__=="Theory1D":
222                id = wx.NewId()
223                slicerpop.Append(id, '&Add errors to data')
224                wx.EVT_MENU(self, id, self._on_add_errors)
225            else:
226                id = wx.NewId()
227                slicerpop.Append(id, '&Linear fit')
228                wx.EVT_MENU(self, id, self.onFitting)
229               
230       
231
232        id = wx.NewId()
233        slicerpop.Append(id, '&Change scale')
234        wx.EVT_MENU(self, id, self._onProperties)
235       
236        id = wx.NewId()
237        #slicerpop.AppendSeparator()
238        slicerpop.Append(id, '&Reset Graph')
239        wx.EVT_MENU(self, id, self.onResetGraph)       
240
241        pos = event.GetPosition()
242        pos = self.ScreenToClient(pos)
243        self.PopupMenu(slicerpop, pos)
244   
245   
246    def _on_add_errors(self, evt):
247        """
248            Compute reasonable errors for a data set without
249            errors and transorm the plottable to a Data1D
250        """
251        import math
252        import numpy
253        import time
254       
255        if not self.graph.selected_plottable == None:
256            length = len(self.plots[self.graph.selected_plottable].x)
257            dy = numpy.zeros(length)
258            for i in range(length):
259                dy[i] = math.sqrt(self.plots[self.graph.selected_plottable].y[i])
260               
261            new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
262                              self.plots[self.graph.selected_plottable].y,
263                              dy=dy)
264            new_plot.interactive = True
265            new_plot.name = self.plots[self.graph.selected_plottable].name
266            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
267                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
268            else:
269                new_plot.group_id = str(time.time())
270           
271            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
272            new_plot.xaxis(label, unit)
273            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
274            new_plot.yaxis(label, unit)
275           
276            self.graph.delete(self.plots[self.graph.selected_plottable])
277           
278            self.graph.add(new_plot)
279            self.plots[self.graph.selected_plottable]=new_plot
280           
281            self.graph.render(self)
282            self.subplot.figure.canvas.draw_idle()   
283   
284    def _onSave(self, evt):
285        """
286            Save a data set to a text file
287            @param evt: Menu event
288        """
289        import os
290        id = str(evt.GetId())
291        if id in self.action_ids:         
292           
293            path = None
294            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.SAVE)
295            if dlg.ShowModal() == wx.ID_OK:
296                path = dlg.GetPath()
297                mypath = os.path.basename(path)
298                print path
299            dlg.Destroy()
300           
301            if not path == None:
302                out = open(path, 'w')
303                has_errors = True
304                if self.action_ids[id].dy==None or self.action_ids[id].dy==[]:
305                    has_errors = False
306                   
307                # Sanity check
308                if has_errors:
309                    try:
310                        if len(self.action_ids[id].y) != len(self.action_ids[id].dy):
311                            print "Y and dY have different lengths"
312                            has_errors = False
313                    except:
314                        has_errors = False
315               
316                if has_errors:
317                    out.write("<X>   <Y>   <dY>\n")
318                else:
319                    out.write("<X>   <Y>\n")
320                   
321                for i in range(len(self.action_ids[id].x)):
322                    if has_errors:
323                        out.write("%g  %g  %g\n" % (self.action_ids[id].x[i], 
324                                                    self.action_ids[id].y[i],
325                                                    self.action_ids[id].dy[i]))
326                    else:
327                        out.write("%g  %g\n" % (self.action_ids[id].x[i], 
328                                                self.action_ids[id].y[i]))
329                       
330                out.close()
331   
332   
333    def _onToggleScale(self, event):
334        if self.get_yscale() == 'log':
335            self.set_yscale('linear')
336        else:
337            self.set_yscale('log')
338        self.subplot.figure.canvas.draw_idle()   
339       
Note: See TracBrowser for help on using the repository browser.