source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ 552b3d5

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

disable linear fit for line plot

  • 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, theory_list = data_manager.get_by_id(id_list=[id])
141           
142            if id in data_list.keys():
143                data = data_list[id]
144            else:
145                data = theory_list[id]
146           
147            del self.plots[id]
148            self.graph.render(self)
149            self.subplot.figure.canvas.draw_idle()   
150            event = RemoveDataEvent(data=data)
151            wx.PostEvent(self.parent, event)
152            if len(self.graph.plottables) == 0:
153                #onRemove: graph is empty must be the panel must be destroyed
154                self.parent.delete_panel(self.uid)
155        else:
156            msg = "Attempt to remove an unexisting plot with ID %s " % str(id)
157            raise ValueError, msg
158       
159    def plot_data(self, data):
160        """
161        Data is ready to be displayed
162       
163        :param event: data event
164        """
165        if data.id in self.plots.keys():
166            #replace
167            self.graph.replace(data)
168            self.plots[data.id] = data
169        else:
170            self.plots[data.id] = data
171            self.graph.add(self.plots[data.id]) 
172       
173        x_label, x_unit = data.get_xaxis()
174        y_label, y_unit = data.get_yaxis()
175        self.graph.xaxis(x_unit, x_label)
176        self.graph.yaxis(y_unit, y_label)
177        ## Set the view scale for all plots
178        self._onEVT_FUNC_PROPERTY()
179        ## render the graph
180        self.graph.render(self)
181        self.subplot.figure.canvas.draw_idle()
182
183       
184    def onLeftDown(self,event): 
185        """
186        left button down and ready to drag
187        Display the position of the mouse on the statusbar
188        """
189        PlotPanel.onLeftDown(self, event)
190        ax = event.inaxes
191        if ax != None:
192            position = "x: %8.3g    y: %8.3g" % (event.xdata, event.ydata)
193            wx.PostEvent(self.parent, StatusEvent(status=position))
194           
195        #post nd event to notify guiframe that this panel is on focus
196        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
197        self._manager.set_panel_on_focus(self)
198       
199    def _ontoggle_hide_error(self, event):
200        """
201        Toggle error display to hide or show
202        """
203       
204        selected_plot = self.plots[self.graph.selected_plottable]
205        if self.hide_menu.GetText() == "Hide Error":
206            selected_plot.hide_error = True
207        else:
208            selected_plot.hide_error = False
209        ## increment graph color
210        self.graph.render(self)
211        self.subplot.figure.canvas.draw_idle() 
212         
213    def _onRemove(self, event):
214        """
215        Remove a plottable from the graph and render the graph
216       
217        :param event: Menu event
218       
219        """
220        ## Check if there is a selected graph to remove
221        if self.graph.selected_plottable in self.plots.keys():
222            selected_plot = self.plots[self.graph.selected_plottable]
223            id = self.graph.selected_plottable
224            self.remove_data_by_id(id)
225           
226    def onContextMenu(self, event):
227        """
228        1D plot context menu
229       
230        :param event: wx context event
231       
232        """
233        self._slicerpop = PanelMenu()
234        self._slicerpop.set_plots(self.plots)
235        self._slicerpop.set_graph(self.graph)     
236        # Various plot options
237        id = wx.NewId()
238        self._slicerpop.Append(id, '&Save image', 'Save image as PNG')
239        wx.EVT_MENU(self, id, self.onSaveImage)
240        id = wx.NewId()
241        self._slicerpop.Append(id, '&Print image', 'Print image ')
242        wx.EVT_MENU(self, id, self.onPrint)
243        id = wx.NewId()
244        self._slicerpop.Append(id, '&Print Preview', 'image preview for print')
245        wx.EVT_MENU(self, id, self.onPrinterPreview)
246       
247        symbol_menu = wx.Menu()
248        for label in self._symbol_labels:
249            id = wx.NewId()
250            symbol_menu.Append(id, str(label), str(label))
251            wx.EVT_MENU(self, id, self.onChangeSymbol)
252        id = wx.NewId()
253        self._slicerpop.AppendMenu(id,'&Modify Symbol',  symbol_menu)
254        self._slicerpop.AppendSeparator()
255       
256        #add menu of other plugins
257        item_list = self.parent.get_context_menu(self)
258        if (not item_list == None) and (not len(item_list) == 0):
259            for item in item_list:
260                try:
261                    id = wx.NewId()
262                    self._slicerpop.Append(id, item[0], item[1])
263                    wx.EVT_MENU(self, id, item[2])
264                except:
265                    msg = "ModelPanel1D.onContextMenu: "
266                    msg += "bad menu item  %s" % sys.exc_value
267                    wx.PostEvent(self.parent, StatusEvent(status=msg))
268                    pass
269            self._slicerpop.AppendSeparator()
270        id = wx.NewId()
271       
272        self._slicerpop.Append(id, '&Print image', 'Print image')
273        if self.graph.selected_plottable in self.plots:
274            plot = self.plots[self.graph.selected_plottable]
275            if not plot.is_data:
276                id = wx.NewId()
277                self._slicerpop.Append(id, '&Freeze', 'Freeze')
278                wx.EVT_MENU(self, id, self.onFreeze)
279            #else:
280            id = wx.NewId()
281            self._slicerpop.Append(id, '&Linear Fit')
282            wx.EVT_MENU(self, id, self.onFitting)
283            id = wx.NewId()
284            name = plot.name
285            self._slicerpop.Append(id, "&Save points")
286            wx.EVT_MENU(self, id, self._onSave)
287            id = wx.NewId()
288            self._slicerpop.Append(id, "Remove %s curve" % name)
289            wx.EVT_MENU(self, id, self._onRemove)
290            id = wx.NewId()
291            self.hide_menu = self._slicerpop.Append(id, "Hide Error")
292            if plot.dy is not None or plot.dy != []:
293                if plot.hide_error :
294                    self.hide_menu.SetText('Show Error')
295                else:
296                    self.hide_menu.SetText('Hide Error')
297            else:
298                self.hide_menu.Disable()
299            wx.EVT_MENU(self, id, self._ontoggle_hide_error)
300           
301            self._slicerpop.AppendSeparator()
302            # Option to hide
303            #TODO: implement functionality to hide a plottable (legend click)
304       
305       
306        id = wx.NewId()
307        self._slicerpop.Append(id, '&Change scale')
308        wx.EVT_MENU(self, id, self._onProperties)
309        id = wx.NewId()
310        self._slicerpop.Append(id, '&Reset Graph')
311        wx.EVT_MENU(self, id, self.onResetGraph) 
312        pos = event.GetPosition()
313        pos = self.ScreenToClient(pos)
314        self.PopupMenu(self._slicerpop, pos)
315     
316    def onFreeze(self, event):
317        """
318        """
319        plot = self.plots[self.graph.selected_plottable]
320        self.parent.onfreeze([plot.id])
321       
322    def onChangeSymbol(self, event):
323        """
324        """
325        menu = event.GetEventObject()
326        id = event.GetId()
327        label =  menu.GetLabel(id)
328        selected_plot = self.plots[self.graph.selected_plottable]
329        selected_plot.symbol = self._symbol_labels[label]
330        ## Set the view scale for all plots
331        self._onEVT_FUNC_PROPERTY()
332        ## render the graph
333        self.graph.render(self)
334        self.subplot.figure.canvas.draw_idle()
335       
336    def _onsaveTXT(self, path):
337        """
338        Save file as txt
339           
340        :TODO: Refactor and remove this method. See TODO in _onSave.
341       
342        """
343        data = self.plots[self.graph.selected_plottable]
344       
345        if not path == None:
346            out = open(path, 'w')
347            has_errors = True
348            if data.dy == None or data.dy == []:
349                has_errors = False
350            # Sanity check
351            if has_errors:
352                try:
353                    if len(data.y) != len(data.dy):
354                        has_errors = False
355                except:
356                    has_errors = False
357            if has_errors:
358                out.write("<X>   <Y>   <dY>\n")
359            else:
360                out.write("<X>   <Y>\n")
361               
362            for i in range(len(data.x)):
363                if has_errors:
364                    out.write("%g  %g  %g\n" % (data.x[i], 
365                                                data.y[i],
366                                               data.dy[i]))
367                else:
368                    out.write("%g  %g\n" % (data.x[i], 
369                                            data.y[i]))
370            out.close()                 
371            try:
372                self._default_save_location = os.path.dirname(path)
373            except:
374                pass   
375               
376    def _onSave(self, evt):
377        """
378        Save a data set to a text file
379       
380        :param evt: Menu event
381       
382        """
383       
384        path = None
385        wildcard = "Text files (*.txt)|*.txt|"\
386        "CanSAS 1D files(*.xml)|*.xml" 
387        dlg = wx.FileDialog(self, "Choose a file",
388                            self._default_save_location,
389                             "", wildcard , wx.SAVE)
390       
391        if dlg.ShowModal() == wx.ID_OK:
392            path = dlg.GetPath()
393            mypath = os.path.basename(path)
394           
395            #TODO: This is bad design. The DataLoader is designed
396            #to recognize extensions.
397            # It should be a simple matter of calling the .
398            #save(file, data, '.xml') method
399            # of the DataLoader.loader.Loader class.
400            from DataLoader.loader import  Loader
401            #Instantiate a loader
402            loader = Loader() 
403            data = self.plots[self.graph.selected_plottable]
404            format = ".txt"
405            if os.path.splitext(mypath)[1].lower() == format:
406                 self._onsaveTXT( path)
407            format = ".xml"
408            if os.path.splitext(mypath)[1].lower() == format:
409                loader.save(path, data, format)
410            try:
411                self._default_save_location = os.path.dirname(path)
412            except:
413                pass   
414        dlg.Destroy()
Note: See TracBrowser for help on using the repository browser.