source: sasview/guiframe/local_perspectives/plotting/plotting.py @ 96f13a9

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 96f13a9 was 96f13a9, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Fixed problem with context menu. Added item to reset plot.

  • Property mode set to 100644
File size: 11.3 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
14from sans.guitools.PlotPanel import PlotPanel
15from sans.guitools.plottables import Graph
16from sans.guicomm.events import EVT_NEW_PLOT
17
18class PanelMenu(wx.Menu):
19    plots = None
20   
21    def set_plots(self, plots):
22        self.plots = plots
23   
24
25class View1DPanel(PlotPanel):
26    """
27        Plot panel for use with the GUI manager
28    """
29   
30    ## Internal name for the AUI manager
31    window_name = "plotpanel"
32    ## Title to appear on top of the window
33    window_caption = "Plot Panel"
34    ## Flag to tell the GUI manager that this panel is not
35    #  tied to any perspective
36    ALWAYS_ON = True
37    ## Group ID
38    group_id = None
39   
40    def __init__(self, parent, id = -1, color = None,\
41        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
42        """
43            Initialize the panel
44        """
45        PlotPanel.__init__(self, parent, id = id, style = style, **kwargs)
46       
47        ## Reference to the parent window
48        self.parent = parent
49        ## Plottables
50        self.plots = {}
51       
52        ## Unique ID (from gui_manager)
53        self.uid = None
54       
55        ## Action IDs for internal call-backs
56        self.action_ids = {}
57       
58        ## Graph       
59        self.graph = Graph()
60        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
61        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
62        self.graph.render(self)
63       
64    def _onEVT_1DREPLOT(self, event):
65        """
66            Data is ready to be displayed
67            @param event: data event
68        """
69        #TODO: Check for existence of plot attribute
70       
71        is_new = True
72        if event.plot.name in self.plots.keys():
73            is_new = False
74       
75        if is_new:
76            self.plots[event.plot.name] = event.plot
77            self.graph.add(self.plots[event.plot.name])
78        else:
79            self.plots[event.plot.name].x = event.plot.x   
80            self.plots[event.plot.name].y = event.plot.y   
81            self.plots[event.plot.name].dy = event.plot.dy 
82            if hasattr(event.plot, 'dx') and hasattr(self.plots[event.plot.name], 'dx'):
83                self.plots[event.plot.name].dx = event.plot.dx   
84 
85       
86        # Check axis labels
87        #TODO: Should re-factor this
88        #if event.plot._xunit != self.graph.prop["xunit"]:
89        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
90           
91        #if event.plot._yunit != self.graph.prop["yunit"]:
92        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
93     
94        self.graph.render(self)
95        self.subplot.figure.canvas.draw_idle()
96
97    def onContextMenu(self, event):
98        """
99            1D plot context menu
100            @param event: wx context event
101        """
102        #slicerpop = wx.Menu()
103        slicerpop = PanelMenu()
104        slicerpop.set_plots(self.plots)
105               
106        # Option to save the data displayed
107        for plot in self.graph.plottables:
108            id = wx.NewId()
109            name = plot.name
110            slicerpop.Append(id, "&Save %s points" % name)
111            self.action_ids[str(id)] = plot
112            wx.EVT_MENU(self, id, self._onSave)
113               
114        # Various plot options
115        id = wx.NewId()
116        slicerpop.Append(id,'&Save image', 'Save image as PNG')
117        wx.EVT_MENU(self, id, self.onSaveImage)
118       
119        slicerpop.AppendSeparator()
120        item_list = self.parent.get_context_menu(self.graph)
121        if not item_list==None:
122            for item in item_list:
123                try:
124                    id = wx.NewId()
125                    slicerpop.Append(id, item[0], item[1])
126                    wx.EVT_MENU(self, id, item[2])
127                except:
128                    print sys.exc_value
129                    print RuntimeError, "View1DPanel.onContextMenu: bad menu item"
130       
131        slicerpop.AppendSeparator()
132       
133        #id = wx.NewId()
134        #slicerpop.Append(id, '&Toggle Linear/Log scale')
135        #wx.EVT_MENU(self, id, self._onToggleScale)
136
137        id = wx.NewId()
138        slicerpop.Append(id, '&Change scale')
139        wx.EVT_MENU(self, id, self._onProperties)
140       
141        id = wx.NewId()
142        slicerpop.AppendSeparator()
143        slicerpop.Append(id, '&Reset Graph')
144        wx.EVT_MENU(self, id, self.onResetGraph)       
145
146        pos = event.GetPosition()
147        pos = self.ScreenToClient(pos)
148        self.PopupMenu(slicerpop, pos)
149   
150    def _onSave(self, evt):
151        """
152            Save a data set to a text file
153            @param evt: Menu event
154        """
155        import os
156        id = str(evt.GetId())
157        if id in self.action_ids:         
158           
159            path = None
160            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.SAVE)
161            if dlg.ShowModal() == wx.ID_OK:
162                path = dlg.GetPath()
163                mypath = os.path.basename(path)
164                print path
165            dlg.Destroy()
166           
167            if not path == None:
168                out = open(path, 'w')
169                has_errors = True
170                if self.action_ids[id].dy==None or self.action_ids[id].dy==[]:
171                    has_errors = False
172                   
173                # Sanity check
174                if has_errors:
175                    try:
176                        if len(self.action_ids[id].y) != len(self.action_ids[id].dy):
177                            print "Y and dY have different lengths"
178                            has_errors = False
179                    except:
180                        has_errors = False
181               
182                if has_errors:
183                    out.write("<X>   <Y>   <dY>\n")
184                else:
185                    out.write("<X>   <Y>\n")
186                   
187                for i in range(len(self.action_ids[id].x)):
188                    if has_errors:
189                        out.write("%g  %g  %g\n" % (self.action_ids[id].x[i], 
190                                                    self.action_ids[id].y[i],
191                                                    self.action_ids[id].dy[i]))
192                    else:
193                        out.write("%g  %g\n" % (self.action_ids[id].x[i], 
194                                                self.action_ids[id].y[i]))
195                       
196                out.close()
197   
198   
199    def _onToggleScale(self, event):
200        if self.get_yscale() == 'log':
201            self.set_yscale('linear')
202        else:
203            self.set_yscale('log')
204        self.subplot.figure.canvas.draw_idle()   
205   
206class Plugin:
207    """
208        Plug-in class to be instantiated by the GUI manager
209    """
210   
211    def __init__(self):
212        """
213            Initialize the plug-in
214        """
215        ## Plug-in name
216        self.sub_menu = "Plotting"
217       
218        ## Reference to the parent window
219        self.parent = None
220       
221        ## List of panels for the simulation perspective (names)
222        self.perspective = []
223       
224        ## Plot panels
225        self.plot_panels = []
226       
227
228    def populate_menu(self, id, parent):
229        """
230            Create a 'Plot' menu to list the panels
231            available for displaying
232            @param id: next available unique ID for wx events
233            @param parent: parent window
234        """
235        self.menu = wx.Menu()
236        return [(id, self.menu, "Plot")]
237   
238       
239    def get_panels(self, parent):
240        """
241            Create and return a list of panel objects
242        """
243        ## Save a reference to the parent
244        self.parent = parent
245        # Connect to plotting events
246        self.parent.Bind(EVT_NEW_PLOT, self._on_plot_event)
247       
248        # We have no initial panels for this plug-in
249        return []
250   
251    def get_perspective(self):
252        """
253            Get the list of panel names for this perspective
254        """
255        return self.perspective
256   
257    def on_perspective(self, event):
258        """
259            Call back function for the perspective menu item.
260            We notify the parent window that the perspective
261            has changed.
262            @param event: menu event
263        """
264        self.parent.set_perspective(self.perspective)
265   
266    def post_init(self):
267        """
268            Post initialization call back to close the loose ends
269            [Somehow openGL needs this call]
270        """
271        pass
272   
273    def _on_show_panel(self, event):
274        print "_on_show_panel"
275   
276    def _on_plot_event(self, event):
277        """
278            A new plottable is being shipped to the plotting plug-in.
279            Check whether we have a panel to put in on, or create
280            a new one
281            @param event: EVT_NEW_PLOT event
282        """
283        # Check whether we already have a graph with the same units
284        # as the plottable we just received.
285        is_available = False
286        for panel in self.plot_panels:
287            if event.plot._xunit == panel.graph.prop["xunit"] \
288            and event.plot._yunit == panel.graph.prop["yunit"]:
289                if hasattr(event.plot, "group_id"):
290                    if not event.plot.group_id==None \
291                        and event.plot.group_id==panel.group_id:
292                        is_available = True
293                        panel._onEVT_1DREPLOT(event)
294                        self.parent.show_panel(panel.uid)
295                else:
296                    # Check that the plot panel has no group ID
297                    if panel.group_id==None:
298                        is_available = True
299                        panel._onEVT_1DREPLOT(event)
300                        self.parent.show_panel(panel.uid)
301       
302        # Create a new plot panel if none was available       
303        if not is_available:
304            new_panel = View1DPanel(self.parent, -1, style=wx.RAISED_BORDER)
305            # Set group ID if available
306            group_id_str = ''
307            if hasattr(event.plot, "group_id"):
308                if not event.plot.group_id==None:
309                    new_panel.group_id = event.plot.group_id
310                    group_id_str = ' [%s]' % event.plot.group_id
311           
312            if hasattr(event, "title"):
313                new_panel.window_caption = event.title
314                new_panel.window_name = event.title
315                #new_panel.window_caption = event.title+group_id_str
316                #new_panel.window_name = event.title+group_id_str
317           
318            event_id = self.parent.popup_panel(new_panel)
319            self.menu.Append(event_id, new_panel.window_caption, 
320                             "Show %s plot panel" % new_panel.window_caption)
321           
322            # Set UID to allow us to reference the panel later
323            new_panel.uid = event_id
324           
325            # Ship the plottable to its panel
326            new_panel._onEVT_1DREPLOT(event)
327            self.plot_panels.append(new_panel)       
328           
329        return
330       
Note: See TracBrowser for help on using the repository browser.