source: sasview/guiframe/local_perspectives/plotting/plotting.py @ ab6098f

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 ab6098f was 278cc25, checked in by Mathieu Doucet <doucetm@…>, 17 years ago

Allow adding base perspectives to an app (as opposed of only dynamically finding them out).
Modified plot label update

  • Property mode set to 100644
File size: 11.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
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        id = wx.NewId()
108        for plot in self.graph.plottables:
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()
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        pos = event.GetPosition()
138        pos = self.ScreenToClient(pos)
139        self.PopupMenu(slicerpop, pos)
140   
141    def _onSave(self, evt):
142        """
143            Save a data set to a text file
144            @param evt: Menu event
145        """
146        import os
147        id = str(evt.GetId())
148        if id in self.action_ids:         
149           
150            path = None
151            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.SAVE)
152            if dlg.ShowModal() == wx.ID_OK:
153                path = dlg.GetPath()
154                mypath = os.path.basename(path)
155                print path
156            dlg.Destroy()
157           
158            if not path == None:
159                out = open(path, 'w')
160                has_errors = True
161                if self.action_ids[id].dy==None or self.action_ids[id].dy==[]:
162                    has_errors = False
163                   
164                # Sanity check
165                if has_errors:
166                    try:
167                        if len(self.action_ids[id].y) != len(self.action_ids[id].dy):
168                            print "Y and dY have different lengths"
169                            has_errors = False
170                    except:
171                        has_errors = False
172               
173                if has_errors:
174                    out.write("<X>   <Y>   <dY>\n")
175                else:
176                    out.write("<X>   <Y>\n")
177                   
178                for i in range(len(self.action_ids[id].x)):
179                    if has_errors:
180                        out.write("%g  %g  %g\n" % (self.action_ids[id].x[i], 
181                                                    self.action_ids[id].y[i],
182                                                    self.action_ids[id].dy[i]))
183                    else:
184                        out.write("%g  %g\n" % (self.action_ids[id].x[i], 
185                                                self.action_ids[id].y[i]))
186                       
187                out.close()
188   
189   
190    def _onToggleScale(self, event):
191        if self.get_yscale() == 'log':
192            self.set_yscale('linear')
193        else:
194            self.set_yscale('log')
195        self.subplot.figure.canvas.draw_idle()   
196   
197class Plugin:
198    """
199        Plug-in class to be instantiated by the GUI manager
200    """
201   
202    def __init__(self):
203        """
204            Initialize the plug-in
205        """
206        ## Plug-in name
207        self.sub_menu = "Plotting"
208       
209        ## Reference to the parent window
210        self.parent = None
211       
212        ## List of panels for the simulation perspective (names)
213        self.perspective = []
214       
215        ## Plot panels
216        self.plot_panels = []
217       
218
219    def populate_menu(self, id, parent):
220        """
221            Create a 'Plot' menu to list the panels
222            available for displaying
223            @param id: next available unique ID for wx events
224            @param parent: parent window
225        """
226        self.menu = wx.Menu()
227        return [(id, self.menu, "Plot")]
228   
229       
230    def get_panels(self, parent):
231        """
232            Create and return a list of panel objects
233        """
234        ## Save a reference to the parent
235        self.parent = parent
236        # Connect to plotting events
237        self.parent.Bind(EVT_NEW_PLOT, self._on_plot_event)
238       
239        # We have no initial panels for this plug-in
240        return []
241   
242    def get_perspective(self):
243        """
244            Get the list of panel names for this perspective
245        """
246        return self.perspective
247   
248    def on_perspective(self, event):
249        """
250            Call back function for the perspective menu item.
251            We notify the parent window that the perspective
252            has changed.
253            @param event: menu event
254        """
255        self.parent.set_perspective(self.perspective)
256   
257    def post_init(self):
258        """
259            Post initialization call back to close the loose ends
260            [Somehow openGL needs this call]
261        """
262        pass
263   
264    def _on_show_panel(self, event):
265        print "_on_show_panel"
266   
267    def _on_plot_event(self, event):
268        """
269            A new plottable is being shipped to the plotting plug-in.
270            Check whether we have a panel to put in on, or create
271            a new one
272            @param event: EVT_NEW_PLOT event
273        """
274        # Check whether we already have a graph with the same units
275        # as the plottable we just received.
276        is_available = False
277        for panel in self.plot_panels:
278            if event.plot._xunit == panel.graph.prop["xunit"] \
279            and event.plot._yunit == panel.graph.prop["yunit"]:
280                if hasattr(event.plot, "group_id"):
281                    if not event.plot.group_id==None \
282                        and event.plot.group_id==panel.group_id:
283                        is_available = True
284                        panel._onEVT_1DREPLOT(event)
285                        self.parent.show_panel(panel.uid)
286                else:
287                    # Check that the plot panel has no group ID
288                    if panel.group_id==None:
289                        is_available = True
290                        panel._onEVT_1DREPLOT(event)
291                        self.parent.show_panel(panel.uid)
292       
293        # Create a new plot panel if none was available       
294        if not is_available:
295            new_panel = View1DPanel(self.parent, -1, style=wx.RAISED_BORDER)
296            # Set group ID if available
297            group_id_str = ''
298            if hasattr(event.plot, "group_id"):
299                if not event.plot.group_id==None:
300                    new_panel.group_id = event.plot.group_id
301                    group_id_str = ' [%s]' % event.plot.group_id
302           
303            if hasattr(event, "title"):
304                new_panel.window_caption = event.title
305                new_panel.window_name = event.title
306                #new_panel.window_caption = event.title+group_id_str
307                #new_panel.window_name = event.title+group_id_str
308           
309            event_id = self.parent.popup_panel(new_panel)
310            self.menu.Append(event_id, new_panel.window_caption, 
311                             "Show %s plot panel" % new_panel.window_caption)
312           
313            # Set UID to allow us to reference the panel later
314            new_panel.uid = event_id
315           
316            # Ship the plottable to its panel
317            new_panel._onEVT_1DREPLOT(event)
318            self.plot_panels.append(new_panel)       
319           
320        return
321       
Note: See TracBrowser for help on using the repository browser.