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

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

working on freeze

  • Property mode set to 100644
File size: 14.0 KB
Line 
1
2################################################################################
3#This software was developed by the University of Tennessee as part of the
4#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5#project funded by the US National Science Foundation.
6#
7#See the license text in license.txt
8#
9#copyright 2008, University of Tennessee
10################################################################################
11
12
13import wx
14import sys
15import os
16import pylab
17import math
18import numpy
19import time
20
21from danse.common.plottools.PlotPanel import PlotPanel
22from danse.common.plottools.plottables import Graph
23from sans.guiframe import dataFitting
24from sans.guiframe.events import EVT_NEW_PLOT
25from sans.guiframe.events import StatusEvent
26from sans.guiframe.events import NewPlotEvent
27from sans.guiframe.events import SlicerEvent
28from sans.guiframe.events import RemoveDataEvent
29from sans.guiframe.events import PanelOnFocusEvent
30from sans.guiframe.events import EVT_NEW_LOADED_DATA
31from sans.guiframe.utils import PanelMenu
32from sans.guiframe.dataFitting import Data1D
33from sans.guiframe.panel_base import PanelBase
34from binder import BindArtist
35
36DEFAULT_QMAX = 0.05
37DEFAULT_QSTEP = 0.001
38DEFAULT_BEAM = 0.005
39BIN_WIDTH = 1
40
41
42class ModelPanel1D(PlotPanel, PanelBase):
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        PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)
60        PanelBase.__init__(self, parent)
61        ## Reference to the parent window
62        self.parent = parent
63        ## Plottables
64        self.plots = {}
65        #context menu
66        self._slicerpop = None
67       
68        self._available_data = []
69        self._menu_add_ids = []
70        self._symbol_labels = self.get_symbol_label()
71     
72        self.hide_menu = None
73        ## Unique ID (from gui_manager)
74        self.uid = None
75       
76        ## Default locations
77        self._default_save_location = os.getcwd()       
78        ## Graph       
79        self.graph = Graph()
80        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
81        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
82        self.graph.render(self)
83       
84    def get_symbol_label(self):
85        """
86        Associates label to symbol
87        """
88        _labels = {}
89        i = 0
90        _labels['Points'] = i
91        i += 1
92        _labels['X '] = i
93        i += 1
94        _labels['Triangle Down'] = i
95        i += 1
96        _labels['Triangle Up'] = i
97        i += 1
98        _labels['Triangle Left'] = i
99        i += 1
100        _labels['Triangle Right'] = i
101        i += 1
102        _labels['Plus'] = i
103        i += 1
104        _labels['Square'] = i
105        i += 1
106        _labels['Thin Diamond'] = i
107        i += 1
108        _labels['Diamond'] = i
109        i += 1
110        _labels['Hexagon1'] = i
111        i += 1
112        _labels['Hexagon2'] = i
113        i += 1
114        _labels['Pentagon'] = i
115        i += 1
116        _labels['Curve'] = i
117        return _labels
118
119   
120    def set_data(self, list=None):
121        """
122        """
123        pass
124   
125    def _reset(self):
126        """
127        Resets internal data and graph
128        """   
129        self.graph.reset()
130        self.plots      = {}
131   
132    def remove_data_by_id(self, id):
133        """'
134        remove data from plot
135        """
136        if id in self.plots.keys():
137            data =  self.plots[id]
138            self.graph.delete(data)
139            data_manager = self._manager.parent.get_data_manager()
140            data_list = data_manager.get_by_id(id_list=[id])
141            data = data_list.values()[0].data
142            data.group_id.remove(self.group_id)
143            del self.plots[id]
144                 
145            self.graph.render(self)
146            self.subplot.figure.canvas.draw_idle()   
147            if len(self.graph.plottables) == 0:
148                print "_onRemove: graph is empty must be destroyed"
149           
150        else:
151            msg = "Attempt to remove an unexisting plot with ID %s " % str(id)
152            raise ValueError, msg
153       
154    def plot_data(self, data):
155        """
156        Data is ready to be displayed
157       
158        :param event: data event
159        """
160        if data.id in self.plots.keys():
161            #replace
162            self.graph.replace(data)
163            self.plots[data.id] = data
164        else:
165            self.plots[data.id] = data
166            self.graph.add(self.plots[data.id]) 
167       
168        x_label, x_unit = data.get_xaxis()
169        y_label, y_unit = data.get_yaxis()
170        self.graph.xaxis(x_unit, x_label)
171        self.graph.yaxis(y_unit, y_label)
172        ## Set the view scale for all plots
173        self._onEVT_FUNC_PROPERTY()
174        ## render the graph
175        self.graph.render(self)
176        self.subplot.figure.canvas.draw_idle()
177
178       
179    def onLeftDown(self,event): 
180        """
181        left button down and ready to drag
182        Display the position of the mouse on the statusbar
183        """
184        PlotPanel.onLeftDown(self, event)
185        ax = event.inaxes
186        if ax != None:
187            position = "x: %8.3g    y: %8.3g" % (event.xdata, event.ydata)
188            wx.PostEvent(self.parent, StatusEvent(status=position))
189           
190        #post nd event to notify guiframe that this panel is on focus
191        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
192        self._manager.set_panel_on_focus(self)
193       
194    def _ontoggle_hide_error(self, event):
195        """
196        Toggle error display to hide or show
197        """
198       
199        selected_plot = self.plots[self.graph.selected_plottable]
200        if self.hide_menu.GetText() == "Hide Error":
201            selected_plot.hide_error = True
202        else:
203            selected_plot.hide_error = False
204        ## increment graph color
205        self.graph.render(self)
206        self.subplot.figure.canvas.draw_idle() 
207         
208    def _onRemove(self, event):
209        """
210        Remove a plottable from the graph and render the graph
211       
212        :param event: Menu event
213       
214        """
215        ## Check if there is a selected graph to remove
216        if self.graph.selected_plottable in self.plots.keys():
217            selected_plot = self.plots[self.graph.selected_plottable]
218            id = self.graph.selected_plottable
219            self.remove_data_by_id( id)
220            event = RemoveDataEvent(data=selected_plot)
221            wx.PostEvent(self.parent, event)
222            self.graph.delete(selected_plot)
223            del selected_plot
224       
225    def onContextMenu(self, event):
226        """
227        1D plot context menu
228       
229        :param event: wx context event
230       
231        """
232        self._slicerpop = PanelMenu()
233        self._slicerpop.set_plots(self.plots)
234        self._slicerpop.set_graph(self.graph)     
235        # Various plot options
236        id = wx.NewId()
237        self._slicerpop.Append(id, '&Save image', 'Save image as PNG')
238        wx.EVT_MENU(self, id, self.onSaveImage)
239        id = wx.NewId()
240        self._slicerpop.Append(id, '&Print image', 'Print image ')
241        wx.EVT_MENU(self, id, self.onPrint)
242        id = wx.NewId()
243        self._slicerpop.Append(id, '&Print Preview', 'image preview for print')
244        wx.EVT_MENU(self, id, self.onPrinterPreview)
245       
246        symbol_menu = wx.Menu()
247        for label in self._symbol_labels:
248            id = wx.NewId()
249            symbol_menu.Append(id, str(label), str(label))
250            wx.EVT_MENU(self, id, self.onChangeSymbol)
251        id = wx.NewId()
252        self._slicerpop.AppendMenu(id,'&Modify Symbol',  symbol_menu)
253        self._slicerpop.AppendSeparator()
254       
255        #add menu of other plugins
256        item_list = self.parent.get_context_menu(self)
257        if (not item_list == None) and (not len(item_list) == 0):
258            for item in item_list:
259                try:
260                    id = wx.NewId()
261                    self._slicerpop.Append(id, item[0], item[1])
262                    wx.EVT_MENU(self, id, item[2])
263                except:
264                    msg = "ModelPanel1D.onContextMenu: "
265                    msg += "bad menu item  %s" % sys.exc_value
266                    wx.PostEvent(self.parent, StatusEvent(status=msg))
267                    pass
268            self._slicerpop.AppendSeparator()
269        id = wx.NewId()
270       
271        self._slicerpop.Append(id, '&Print image', 'Print image')
272        if self.graph.selected_plottable in self.plots:
273            plot = self.plots[self.graph.selected_plottable]
274            if not plot.is_data:
275                id = wx.NewId()
276                self._slicerpop.Append(id, '&Freeze', 'Freeze')
277                wx.EVT_MENU(self, id, self.onFreeze)
278            id = wx.NewId()
279            name = plot.name
280            self._slicerpop.Append(id, "&Save points")
281            wx.EVT_MENU(self, id, self._onSave)
282            id = wx.NewId()
283            self._slicerpop.Append(id, "Remove %s curve" % name)
284            wx.EVT_MENU(self, id, self._onRemove)
285            id = wx.NewId()
286            self.hide_menu = self._slicerpop.Append(id, "Hide Error")
287            if plot.dy is not None or plot.dy != []:
288                if plot.hide_error :
289                    self.hide_menu.SetText('Show Error')
290                else:
291                    self.hide_menu.SetText('Hide Error')
292            else:
293                self.hide_menu.Disable()
294            wx.EVT_MENU(self, id, self._ontoggle_hide_error)
295           
296            self._slicerpop.AppendSeparator()
297            # Option to hide
298            #TODO: implement functionality to hide a plottable (legend click)
299        id = wx.NewId()
300        self._slicerpop.Append(id, '&Linear Fit')
301        wx.EVT_MENU(self, id, self.onFitting)
302       
303        id = wx.NewId()
304        self._slicerpop.Append(id, '&Change scale')
305        wx.EVT_MENU(self, id, self._onProperties)
306        id = wx.NewId()
307        self._slicerpop.Append(id, '&Reset Graph')
308        wx.EVT_MENU(self, id, self.onResetGraph) 
309        pos = event.GetPosition()
310        pos = self.ScreenToClient(pos)
311        self.PopupMenu(self._slicerpop, pos)
312     
313    def onFreeze(self, event):
314        """
315        """
316        plot = self.plots[self.graph.selected_plottable]
317        self.parent.onfreeze([plot.id])
318       
319    def onChangeSymbol(self, event):
320        """
321        """
322        menu = event.GetEventObject()
323        id = event.GetId()
324        label =  menu.GetLabel(id)
325        selected_plot = self.plots[self.graph.selected_plottable]
326        selected_plot.symbol = self._symbol_labels[label]
327        ## Set the view scale for all plots
328        self._onEVT_FUNC_PROPERTY()
329        ## render the graph
330        self.graph.render(self)
331        self.subplot.figure.canvas.draw_idle()
332       
333    def _onsaveTXT(self, path):
334        """
335        Save file as txt
336           
337        :TODO: Refactor and remove this method. See TODO in _onSave.
338       
339        """
340        data = self.plots[self.graph.selected_plottable]
341       
342        if not path == None:
343            out = open(path, 'w')
344            has_errors = True
345            if data.dy == None or data.dy == []:
346                has_errors = False
347            # Sanity check
348            if has_errors:
349                try:
350                    if len(data.y) != len(data.dy):
351                        has_errors = False
352                except:
353                    has_errors = False
354            if has_errors:
355                out.write("<X>   <Y>   <dY>\n")
356            else:
357                out.write("<X>   <Y>\n")
358               
359            for i in range(len(data.x)):
360                if has_errors:
361                    out.write("%g  %g  %g\n" % (data.x[i], 
362                                                data.y[i],
363                                               data.dy[i]))
364                else:
365                    out.write("%g  %g\n" % (data.x[i], 
366                                            data.y[i]))
367            out.close()                 
368            try:
369                self._default_save_location = os.path.dirname(path)
370            except:
371                pass   
372               
373    def _onSave(self, evt):
374        """
375        Save a data set to a text file
376       
377        :param evt: Menu event
378       
379        """
380       
381        path = None
382        wildcard = "Text files (*.txt)|*.txt|"\
383        "CanSAS 1D files(*.xml)|*.xml" 
384        dlg = wx.FileDialog(self, "Choose a file",
385                            self._default_save_location,
386                             "", wildcard , wx.SAVE)
387       
388        if dlg.ShowModal() == wx.ID_OK:
389            path = dlg.GetPath()
390            mypath = os.path.basename(path)
391           
392            #TODO: This is bad design. The DataLoader is designed
393            #to recognize extensions.
394            # It should be a simple matter of calling the .
395            #save(file, data, '.xml') method
396            # of the DataLoader.loader.Loader class.
397            from DataLoader.loader import  Loader
398            #Instantiate a loader
399            loader = Loader() 
400            data = self.plots[self.graph.selected_plottable]
401            format = ".txt"
402            if os.path.splitext(mypath)[1].lower() == format:
403                 self._onsaveTXT( path)
404            format = ".xml"
405            if os.path.splitext(mypath)[1].lower() == format:
406                loader.save(path, data, format)
407            try:
408                self._default_save_location = os.path.dirname(path)
409            except:
410                pass   
411        dlg.Destroy()
Note: See TracBrowser for help on using the repository browser.