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

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

remove other type of data into sansview

  • Property mode set to 100644
File size: 13.6 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            id = wx.NewId()
275            name = plot.name
276            self._slicerpop.Append(id, "&Save points")
277            wx.EVT_MENU(self, id, self._onSave)
278            id = wx.NewId()
279            self._slicerpop.Append(id, "Remove %s curve" % name)
280            wx.EVT_MENU(self, id, self._onRemove)
281            id = wx.NewId()
282            self.hide_menu = self._slicerpop.Append(id, "Hide Error")
283            if plot.dy is not None or plot.dy != []:
284                if plot.hide_error :
285                    self.hide_menu.SetText('Show Error')
286                else:
287                    self.hide_menu.SetText('Hide Error')
288            else:
289                self.hide_menu.Disable()
290            wx.EVT_MENU(self, id, self._ontoggle_hide_error)
291           
292            self._slicerpop.AppendSeparator()
293            # Option to hide
294            #TODO: implement functionality to hide a plottable (legend click)
295        id = wx.NewId()
296        self._slicerpop.Append(id, '&Linear Fit')
297        wx.EVT_MENU(self, id, self.onFitting)
298       
299        id = wx.NewId()
300        self._slicerpop.Append(id, '&Change scale')
301        wx.EVT_MENU(self, id, self._onProperties)
302        id = wx.NewId()
303        self._slicerpop.Append(id, '&Reset Graph')
304        wx.EVT_MENU(self, id, self.onResetGraph) 
305        pos = event.GetPosition()
306        pos = self.ScreenToClient(pos)
307        self.PopupMenu(self._slicerpop, pos)
308     
309    def onChangeSymbol(self, event):
310        """
311        """
312        menu = event.GetEventObject()
313        id = event.GetId()
314        label =  menu.GetLabel(id)
315        selected_plot = self.plots[self.graph.selected_plottable]
316        selected_plot.symbol = self._symbol_labels[label]
317        ## Set the view scale for all plots
318        self._onEVT_FUNC_PROPERTY()
319        ## render the graph
320        self.graph.render(self)
321        self.subplot.figure.canvas.draw_idle()
322       
323    def _onsaveTXT(self, path):
324        """
325        Save file as txt
326           
327        :TODO: Refactor and remove this method. See TODO in _onSave.
328       
329        """
330        data = self.plots[self.graph.selected_plottable]
331       
332        if not path == None:
333            out = open(path, 'w')
334            has_errors = True
335            if data.dy == None or data.dy == []:
336                has_errors = False
337            # Sanity check
338            if has_errors:
339                try:
340                    if len(data.y) != len(data.dy):
341                        has_errors = False
342                except:
343                    has_errors = False
344            if has_errors:
345                out.write("<X>   <Y>   <dY>\n")
346            else:
347                out.write("<X>   <Y>\n")
348               
349            for i in range(len(data.x)):
350                if has_errors:
351                    out.write("%g  %g  %g\n" % (data.x[i], 
352                                                data.y[i],
353                                               data.dy[i]))
354                else:
355                    out.write("%g  %g\n" % (data.x[i], 
356                                            data.y[i]))
357            out.close()                 
358            try:
359                self._default_save_location = os.path.dirname(path)
360            except:
361                pass   
362               
363    def _onSave(self, evt):
364        """
365        Save a data set to a text file
366       
367        :param evt: Menu event
368       
369        """
370       
371        path = None
372        wildcard = "Text files (*.txt)|*.txt|"\
373        "CanSAS 1D files(*.xml)|*.xml" 
374        dlg = wx.FileDialog(self, "Choose a file",
375                            self._default_save_location,
376                             "", wildcard , wx.SAVE)
377       
378        if dlg.ShowModal() == wx.ID_OK:
379            path = dlg.GetPath()
380            mypath = os.path.basename(path)
381           
382            #TODO: This is bad design. The DataLoader is designed
383            #to recognize extensions.
384            # It should be a simple matter of calling the .
385            #save(file, data, '.xml') method
386            # of the DataLoader.loader.Loader class.
387            from DataLoader.loader import  Loader
388            #Instantiate a loader
389            loader = Loader() 
390            data = self.plots[self.graph.selected_plottable]
391            format = ".txt"
392            if os.path.splitext(mypath)[1].lower() == format:
393                 self._onsaveTXT( path)
394            format = ".xml"
395            if os.path.splitext(mypath)[1].lower() == format:
396                loader.save(path, data, format)
397            try:
398                self._default_save_location = os.path.dirname(path)
399            except:
400                pass   
401        dlg.Destroy()
Note: See TracBrowser for help on using the repository browser.