source: sasview/guiframe/local_perspectives/plotting/Plotter1D.py @ 504dd9f5

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

working on freeze

  • Property mode set to 100644
File size: 14.0 KB
RevLine 
[1bf33c1]1
[d955bf19]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################################################################################
[1bf33c1]11
12
13import wx
[4ac8556]14import sys
15import os
16import pylab
17import math
18import numpy
19import time
[a07e72f]20
[1bf33c1]21from danse.common.plottools.PlotPanel import PlotPanel
[e5664f2]22from danse.common.plottools.plottables import Graph
[3b69ca6]23from sans.guiframe import dataFitting
[df7046f]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
[a45037aa]29from sans.guiframe.events import PanelOnFocusEvent
[52b8b74]30from sans.guiframe.events import EVT_NEW_LOADED_DATA
[0d9dae8]31from sans.guiframe.utils import PanelMenu
[4ac8556]32from sans.guiframe.dataFitting import Data1D
[691643c]33from sans.guiframe.panel_base import PanelBase
[1bf33c1]34from binder import BindArtist
35
[0d9dae8]36DEFAULT_QMAX = 0.05
[1bf33c1]37DEFAULT_QSTEP = 0.001
38DEFAULT_BEAM = 0.005
[32c0841]39BIN_WIDTH = 1
[1bf33c1]40
[0d9dae8]41
[691643c]42class ModelPanel1D(PlotPanel, PanelBase):
[1bf33c1]43    """
[d955bf19]44    Plot panel for use with the GUI manager
[1bf33c1]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   
[32c0841]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)
[a45037aa]60        PanelBase.__init__(self, parent)
[1bf33c1]61        ## Reference to the parent window
62        self.parent = parent
63        ## Plottables
64        self.plots = {}
[52b8b74]65        #context menu
66        self._slicerpop = None
[a07e72f]67       
[52b8b74]68        self._available_data = []
69        self._menu_add_ids = []
[a07e72f]70        self._symbol_labels = self.get_symbol_label()
71     
72        self.hide_menu = None
[1bf33c1]73        ## Unique ID (from gui_manager)
74        self.uid = None
[a07e72f]75       
[6063b16]76        ## Default locations
77        self._default_save_location = os.getcwd()       
[1bf33c1]78        ## Graph       
79        self.graph = Graph()
80        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
[32c0841]81        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
[1bf33c1]82        self.graph.render(self)
[a07e72f]83       
84    def get_symbol_label(self):
[52b8b74]85        """
[a07e72f]86        Associates label to symbol
[52b8b74]87        """
[a07e72f]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
[52b8b74]119   
[32c0841]120    def set_data(self, list=None):
[3c44c66]121        """
122        """
123        pass
124   
[1bf33c1]125    def _reset(self):
126        """
[d955bf19]127        Resets internal data and graph
[1bf33c1]128        """   
129        self.graph.reset()
130        self.plots      = {}
131   
[a07e72f]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):
[1bf33c1]155        """
[d955bf19]156        Data is ready to be displayed
157       
158        :param event: data event
[1bf33c1]159        """
[a07e72f]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]) 
[ffd23b5]167       
[a07e72f]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)
[6c0568b]172        ## Set the view scale for all plots
[1bf33c1]173        self._onEVT_FUNC_PROPERTY()
[6c0568b]174        ## render the graph
[1bf33c1]175        self.graph.render(self)
176        self.subplot.figure.canvas.draw_idle()
[a07e72f]177
178       
[1bf33c1]179    def onLeftDown(self,event): 
[6c0568b]180        """
[d955bf19]181        left button down and ready to drag
182        Display the position of the mouse on the statusbar
[6c0568b]183        """
[1bf33c1]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))
[4ed210f4]189           
190        #post nd event to notify guiframe that this panel is on focus
[a45037aa]191        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
[a07e72f]192        self._manager.set_panel_on_focus(self)
[4ed210f4]193       
[a07e72f]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         
[1bf33c1]208    def _onRemove(self, event):
209        """
[d955bf19]210        Remove a plottable from the graph and render the graph
211       
212        :param event: Menu event
213       
[1bf33c1]214        """
[6c0568b]215        ## Check if there is a selected graph to remove
[a07e72f]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)
[32c0841]220            event = RemoveDataEvent(data=selected_plot)
[1debb29]221            wx.PostEvent(self.parent, event)
[32c0841]222            self.graph.delete(selected_plot)
223            del selected_plot
[a07e72f]224       
[1bf33c1]225    def onContextMenu(self, event):
226        """
[d955bf19]227        1D plot context menu
228       
229        :param event: wx context event
230       
[1bf33c1]231        """
[52b8b74]232        self._slicerpop = PanelMenu()
233        self._slicerpop.set_plots(self.plots)
234        self._slicerpop.set_graph(self.graph)     
[9a585d0]235        # Various plot options
236        id = wx.NewId()
[52b8b74]237        self._slicerpop.Append(id, '&Save image', 'Save image as PNG')
[9a585d0]238        wx.EVT_MENU(self, id, self.onSaveImage)
239        id = wx.NewId()
[52b8b74]240        self._slicerpop.Append(id, '&Print image', 'Print image ')
[18eba35]241        wx.EVT_MENU(self, id, self.onPrint)
242        id = wx.NewId()
[52b8b74]243        self._slicerpop.Append(id, '&Print Preview', 'image preview for print')
[18eba35]244        wx.EVT_MENU(self, id, self.onPrinterPreview)
[52b8b74]245       
[a07e72f]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)
[52b8b74]253        self._slicerpop.AppendSeparator()
[a07e72f]254       
[52b8b74]255        #add menu of other plugins
[a07e72f]256        item_list = self.parent.get_context_menu(self)
[32c0841]257        if (not item_list == None) and (not len(item_list) == 0):
[9a585d0]258            for item in item_list:
259                try:
260                    id = wx.NewId()
[52b8b74]261                    self._slicerpop.Append(id, item[0], item[1])
[9a585d0]262                    wx.EVT_MENU(self, id, item[2])
263                except:
[32c0841]264                    msg = "ModelPanel1D.onContextMenu: "
[a07e72f]265                    msg += "bad menu item  %s" % sys.exc_value
[32c0841]266                    wx.PostEvent(self.parent, StatusEvent(status=msg))
[9a585d0]267                    pass
[52b8b74]268            self._slicerpop.AppendSeparator()
269        id = wx.NewId()
[a07e72f]270       
[52b8b74]271        self._slicerpop.Append(id, '&Print image', 'Print image')
[1bf33c1]272        if self.graph.selected_plottable in self.plots:
273            plot = self.plots[self.graph.selected_plottable]
[e6a93df]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)
[1bf33c1]278            id = wx.NewId()
279            name = plot.name
[52b8b74]280            self._slicerpop.Append(id, "&Save points")
[1bf33c1]281            wx.EVT_MENU(self, id, self._onSave)
282            id = wx.NewId()
[52b8b74]283            self._slicerpop.Append(id, "Remove %s curve" % name)
[1bf33c1]284            wx.EVT_MENU(self, id, self._onRemove)
[a07e72f]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           
[52b8b74]296            self._slicerpop.AppendSeparator()
[1bf33c1]297            # Option to hide
298            #TODO: implement functionality to hide a plottable (legend click)
[a07e72f]299        id = wx.NewId()
300        self._slicerpop.Append(id, '&Linear Fit')
301        wx.EVT_MENU(self, id, self.onFitting)
302       
[1bf33c1]303        id = wx.NewId()
[52b8b74]304        self._slicerpop.Append(id, '&Change scale')
[1bf33c1]305        wx.EVT_MENU(self, id, self._onProperties)
306        id = wx.NewId()
[52b8b74]307        self._slicerpop.Append(id, '&Reset Graph')
[d468daa]308        wx.EVT_MENU(self, id, self.onResetGraph) 
[1bf33c1]309        pos = event.GetPosition()
310        pos = self.ScreenToClient(pos)
[52b8b74]311        self.PopupMenu(self._slicerpop, pos)
[a07e72f]312     
[e6a93df]313    def onFreeze(self, event):
314        """
315        """
316        plot = self.plots[self.graph.selected_plottable]
317        self.parent.onfreeze([plot.id])
318       
[a07e72f]319    def onChangeSymbol(self, event):
[6c0568b]320        """
321        """
[a07e72f]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()
[c81140c]332       
[42d27f2]333    def _onsaveTXT(self, path):
334        """
[d955bf19]335        Save file as txt
[1abcb04]336           
[d955bf19]337        :TODO: Refactor and remove this method. See TODO in _onSave.
338       
[42d27f2]339        """
340        data = self.plots[self.graph.selected_plottable]
341       
342        if not path == None:
343            out = open(path, 'w')
344            has_errors = True
[32c0841]345            if data.dy == None or data.dy == []:
[42d27f2]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()                 
[6063b16]368            try:
369                self._default_save_location = os.path.dirname(path)
370            except:
371                pass   
[8bd764d]372               
[1bf33c1]373    def _onSave(self, evt):
374        """
[d955bf19]375        Save a data set to a text file
376       
377        :param evt: Menu event
378       
[1bf33c1]379        """
[a07e72f]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)
[1bf33c1]391           
[a07e72f]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.