source: sasview/sansguiframe/src/sans/guiframe/local_perspectives/plotting/Plotter1D.py @ 3e001f9

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 3e001f9 was 3e001f9, checked in by Jae Cho <jhjcho@…>, 11 years ago

Added tools, imageviwer and qrange cursors

  • Property mode set to 100644
File size: 33.4 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
[6d52f21d]22from danse.common.plottools.SizeDialog import SizeDialog
23from danse.common.plottools.LabelDialog import LabelDialog
[9f5c8bb]24#from danse.common.plottools.plottables import Graph
[3b69ca6]25from sans.guiframe import dataFitting
[df7046f]26from sans.guiframe.events import EVT_NEW_PLOT
27from sans.guiframe.events import StatusEvent
28from sans.guiframe.events import NewPlotEvent
[2636188]29from sans.guiframe.events import NewColorEvent
[df7046f]30from sans.guiframe.events import SlicerEvent
[a45037aa]31from sans.guiframe.events import PanelOnFocusEvent
[52b8b74]32from sans.guiframe.events import EVT_NEW_LOADED_DATA
[0d9dae8]33from sans.guiframe.utils import PanelMenu
[4ac8556]34from sans.guiframe.dataFitting import Data1D
[691643c]35from sans.guiframe.panel_base import PanelBase
[6e75ed0]36from sans.guiframe.gui_style import GUIFRAME_ICON
[0899c82]37from danse.common.plottools.binder import BindArtist
[f8be87d]38from appearanceDialog import appearanceDialog
[8f59e95]39from graphAppearance import graphAppearance
[1bf33c1]40
[0d9dae8]41DEFAULT_QMAX = 0.05
[1bf33c1]42DEFAULT_QSTEP = 0.001
43DEFAULT_BEAM = 0.005
[32c0841]44BIN_WIDTH = 1
[940aca7]45IS_MAC = (sys.platform == 'darwin')
[0d9dae8]46
[8f59e95]47
48def find_key(dic, val):
49    """return the key of dictionary dic given the value"""
50    return [k for k, v in dic.iteritems() if v == val][0]
51
52
53
[691643c]54class ModelPanel1D(PlotPanel, PanelBase):
[1bf33c1]55    """
[d955bf19]56    Plot panel for use with the GUI manager
[1bf33c1]57    """
58   
59    ## Internal name for the AUI manager
60    window_name = "plotpanel"
61    ## Title to appear on top of the window
[37c36d9]62    window_caption = "Graph"
[1bf33c1]63    ## Flag to tell the GUI manager that this panel is not
64    #  tied to any perspective
65    ALWAYS_ON = True
66    ## Group ID
67    group_id = None
68   
[32c0841]69    def __init__(self, parent, id=-1, color = None,
70                 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
71        PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)
[a45037aa]72        PanelBase.__init__(self, parent)
[1bf33c1]73        ## Reference to the parent window
74        self.parent = parent
75        ## Plottables
76        self.plots = {}
[52b8b74]77        #context menu
78        self._slicerpop = None
[a07e72f]79       
[52b8b74]80        self._available_data = []
81        self._menu_add_ids = []
[a07e72f]82        self._symbol_labels = self.get_symbol_label()
[2636188]83        self._color_labels = self.get_color_label()
84        self.currColorIndex = ""
[36288ca]85        self._is_changed_legend_label = False
[657e52c]86        self.is_xtick = False
87        self.is_ytick = False
[a07e72f]88     
89        self.hide_menu = None
[1bf33c1]90        ## Unique ID (from gui_manager)
91        self.uid = None
[66718a1]92        self.x_size = None
[6063b16]93        ## Default locations
[c553b18]94        #self._default_save_location = os.getcwd()
[3e001f9]95        self.size = None 
96        self.vl_ind = 0     
[1bf33c1]97        ## Graph       
[9f5c8bb]98        #self.graph = Graph()
[1bf33c1]99        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
[32c0841]100        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
[1bf33c1]101        self.graph.render(self)
[3e001f9]102        self.cursor_id = None
[ef4a4ea]103       
[6d727ae]104        # In resizing event
105        self.resizing = False
106        self.canvas.set_resizing(self.resizing)
107        self.Bind(wx.EVT_SIZE, self._OnReSize)
[c5a769e]108        self._add_more_tool()
[6e75ed0]109        self.parent.SetFocus()
110       
[140fad00]111       
[a07e72f]112    def get_symbol_label(self):
[52b8b74]113        """
[a07e72f]114        Associates label to symbol
[52b8b74]115        """
[a07e72f]116        _labels = {}
117        i = 0
[6d727ae]118        _labels['Circle'] = i
[a07e72f]119        i += 1
[6d727ae]120        _labels['Cross X '] = i
[a07e72f]121        i += 1
122        _labels['Triangle Down'] = i
123        i += 1
124        _labels['Triangle Up'] = i
125        i += 1
126        _labels['Triangle Left'] = i
127        i += 1
128        _labels['Triangle Right'] = i
129        i += 1
[6d727ae]130        _labels['Cross +'] = i
[a07e72f]131        i += 1
132        _labels['Square'] = i
133        i += 1
[318b5bbb]134        _labels['diamond'] = i
[a07e72f]135        i += 1
136        _labels['Diamond'] = i
137        i += 1
138        _labels['Hexagon1'] = i
139        i += 1
140        _labels['Hexagon2'] = i
141        i += 1
142        _labels['Pentagon'] = i
143        i += 1
[6d727ae]144        _labels['Line'] = i
[6c4130a]145        i += 1
146        _labels['Dash'] = i
147        i += 1
148        _labels['Vline'] = i
149        i += 1
150        _labels['Step'] = i
[a07e72f]151        return _labels
[2636188]152   
153    def get_color_label(self):
154        """
155        Associates label to a specific color
156        """
157        _labels = {}
158        i = 0
159        _labels['Blue'] = i
160        i += 1
161        _labels['Green'] = i
162        i += 1
163        _labels['Red'] = i
164        i += 1
165        _labels['Cyan'] = i
166        i += 1
167        _labels['Magenta'] = i
168        i += 1
169        _labels['Yellow'] = i
[ad019b83]170        i += 1
171        _labels['Black'] = i
[2636188]172        return _labels
[a07e72f]173
[52b8b74]174   
[32c0841]175    def set_data(self, list=None):
[3c44c66]176        """
177        """
178        pass
179   
[1bf33c1]180    def _reset(self):
181        """
[d955bf19]182        Resets internal data and graph
[1bf33c1]183        """   
184        self.graph.reset()
185        self.plots      = {}
[7022fdc]186        if self.is_zoomed:
[fd51a7c]187            self.is_zoomed = False
[6d727ae]188       
189    def _OnReSize(self, event):   
190        """
191        On response of the resize of a panel, set axes_visiable False
192        """
[66718a1]193        # It was found that wx >= 2.9.3 sends an event even if no size changed.
[294efd5]194        # So manually recode the size (=x_size) and compare here.
[940aca7]195        # Massy code to work around:<
196        if self.parent._mgr != None:
197            max_panel = self.parent._mgr.GetPane(self)
198            if max_panel.IsMaximized():
199                self.parent._mgr.RestorePane(max_panel)
200                max_panel.Maximize()
[66718a1]201        if self.x_size != None:
202            if self.x_size == self.GetSize():
[71fa9bb9]203                self.resizing = False
204                self.canvas.set_resizing(self.resizing)
[66718a1]205                return
[294efd5]206        self.x_size = self.GetSize()
207
[ad9e5e1]208        # Ready for another event
[4520830]209        # Do not remove this Skip. Otherwise it will get runtime error on wx>=2.9.
[ad9e5e1]210        event.Skip() 
[6d727ae]211        # set the resizing flag
212        self.resizing = True
213        self.canvas.set_resizing(self.resizing)
214        self.parent.set_schedule(True)
[adf44c2]215        pos_x, pos_y = self.GetPositionTuple()
216        if pos_x != 0 and pos_y != 0:
[294efd5]217            self.size, _ = self.GetClientSizeTuple()
[2b29bb4]218        self.SetSizer(self.sizer)
[7fb69f26]219        wx.CallAfter(self.parent.disable_app_menu,self)
[5112838]220       
[3e001f9]221    def on_plot_qrange(self, event=None):
222        """
223        On Qmin Qmax vertical line event
224        """
225        if event == None:
226            return
227        event.Skip() 
228        active_ctrl = event.active
229        if active_ctrl == None:
230            return
231        if event.id in self.plots.keys():
232            # Set line position and color
233            colors = ['red', 'purple']
234            self.cursor_id = event.id
235            ctrl = event.ctrl
236            if self.ly == None:
237                self.ly = []
238                for ind_ly in range(len(colors)):
239                    self.ly.append(self.subplot.axvline(color=colors[ind_ly], 
240                                                        lw=2.5, alpha=0.7))
241                    self.ly[ind_ly].set_rasterized(True)     
242            try:
243                # Display x,y in the status bar if possible
244                xval = float(active_ctrl.GetValue())
245                position = self.get_data_xy_vals(xval)
246                if position != None:
247                    wx.PostEvent(self.parent, StatusEvent(status=position))
248            except:
249                pass
250            if not event.leftdown:
251                # text event
252                try:
253                    is_moved = False
254                    for idx in range(len(self.ly)):
255                        val = float(ctrl[idx].GetValue())
256                        # check if vline moved
257                        if self.ly[idx].get_xdata() != val:
258                            self.ly[idx].set_xdata(val)
259                            is_moved = True
260                    if is_moved:
261                        self.canvas.draw() 
262                except:
263                    pass
264                event.Skip() 
265                return
266            self.q_ctrl = ctrl
267            try:
268                pos_x_min = float(self.q_ctrl[0].GetValue())
269            except:
270                pos_x_min = xmin
271            try:
272                pos_x_max = float(self.q_ctrl[1].GetValue())
273            except:
274                pos_x_max = xmax
275            pos_x = [pos_x_min, pos_x_max]
276            for ind_ly in range(len(colors)):
277                self.ly[ind_ly].set_color(colors[ind_ly])
278                self.ly[ind_ly].set_xdata(pos_x[ind_ly])
279            self.canvas.draw()
280        else:
281            self.q_ctrl = None
282   
283    def get_data_xy_vals(self, xval):
284        """
285        Get x, y data values near x = x_val
286        """
287        try:
288            x_data = self.plots[self.cursor_id].x
289            y_data = self.plots[self.cursor_id].y
290            indx = self._find_nearest(x_data, xval)
291            pos_x = x_data[indx]
292            pos_y = y_data[indx]
293            position = str(pos_x), str(pos_y)
294            return position
295        except:
296            return None
297           
298    def _find_nearest(self, array, value):
299        """
300        Find and return the nearest value in array to the value.
301        Used in cusor_line()
302        :Param array: numpy array
303        :Param value: float
304        """
305        idx = (numpy.abs(array - value)).argmin()
306        return int(idx)#array.flat[idx]
307   
308    def _check_line_positions(self, pos_x=None, nop=None):
309        """
310        Check vertical line positions
311        :Param pos_x: position of the current line [float]
312        :Param nop: number of plots [int]
313        """
314        ly = self.ly
315        ly0x = ly[0].get_xdata()
316        ly1x = ly[1].get_xdata()
317        self.q_ctrl[0].SetBackgroundColour('white')
318        self.q_ctrl[1].SetBackgroundColour('white')
319        if ly0x >= ly1x:
320            if self.vl_ind == 0:
321                ly[1].set_xdata(pos_x)
322                ly[1].set_zorder(nop)
323                self.q_ctrl[1].SetValue(str(pos_x))
324                self.q_ctrl[0].SetBackgroundColour('pink')
325            elif self.vl_ind == 1:
326                ly[0].set_xdata(pos_x)
327                ly[0].set_zorder(nop)
328                self.q_ctrl[0].SetValue(str(pos_x))
329                self.q_ctrl[1].SetBackgroundColour('pink')
330               
331    def _get_cusor_lines(self, event):
332        """
333        Revmove or switch cursor line if drawn
334        :Param event: LeftClick mouse event
335        """ 
336        ax = event.inaxes
337        dclick = event.action == 'dclick'
338        if ax == None or dclick:
339            # remove the vline
340            self._check_zoom_plot()
341            self.canvas.draw()
342            self.q_ctrl = None
343            return 
344        if self.ly != None and event.xdata != None:
345            # Selecting a new line if cursor lines are displayed already
346            dqmin = math.fabs(event.xdata - self.ly[0].get_xdata())
347            dqmax = math.fabs(event.xdata - self.ly[1].get_xdata())
348            is_qmax = dqmin > dqmax
349            if is_qmax:
350                self.vl_ind = 1
351            else:
352                self.vl_ind = 0 
353                     
354    def cusor_line(self, event):
355        """
356        Move the cursor line to write Q range
357        """
358        if self.q_ctrl == None:
359            return
360        #release a q range vline
361        if self.ly != None and not self.leftdown:
362            for ly in self.ly:
363                ly.set_alpha(0.7)
364                self.canvas.draw()
365            return
366        ax = event.inaxes
367        if ax == None or not hasattr(event, 'action'):
368            return
369        end_drag = event.action != 'drag' and event.xdata != None
370        nop = len(self.plots)
371        pos_x, pos_y = float(event.xdata), float(event.ydata)
372        try:
373            ly = self.ly
374            ly0x = ly[0].get_xdata()
375            ly1x = ly[1].get_xdata()
376            if ly0x == ly1x:
377                if ly[0].get_zorder() > ly[1].get_zorder():
378                    self.vl_ind = 0
379                else:
380                    self.vl_ind = 1
381            vl_ind = self.vl_ind
382            x_data = self.plots[self.cursor_id].x
383            y_data = self.plots[self.cursor_id].y
384            xmin = x_data.min()
385            xmax = x_data.max()
386            indx = self._find_nearest(x_data, pos_x)
387            #pos_x = self._find_nearest(x_data, pos_x)
388            #indx = int(numpy.searchsorted(x_data, [pos_x])[0])
389            # Need to hold LeftButton to drag
390            if end_drag:
391                if event.button:
392                    self._check_line_positions(pos_x, nop)
393                return   
394            if indx >= len(x_data):
395                indx = len(x_data) - 1
396            pos_x = x_data[indx]
397            pos_y = y_data[indx]
398            if xmin == ly1x:
399                vl_ind = 1
400            elif xmax == ly0x:
401                vl_ind = 0
402            else:
403                ly[vl_ind].set_xdata(pos_x)
404                ly[vl_ind].set_zorder(nop + 1)
405                self._check_line_positions(pos_x, nop)
406            ly[vl_ind].set_xdata(pos_x)
407            ly[vl_ind].set_alpha(1.0)
408            ly[vl_ind].set_zorder(nop + 1)
409            self.canvas.draw()
410            self.q_ctrl[vl_ind].SetValue(str(pos_x))
411        except:
412            pass
413               
[6d727ae]414    def set_resizing(self, resizing=False):
415        """
416        Set the resizing (True/False)
417        """
418        self.resizing = resizing
419        #self.canvas.set_resizing(resizing)
[1bf33c1]420   
[6d727ae]421    def schedule_full_draw(self, func='append'):   
422        """
423        Put self in schedule to full redraw list
424        """
425        # append/del this panel in the schedule list
426        self.parent.set_schedule_full_draw(self, func)
427       
428
[a07e72f]429    def remove_data_by_id(self, id):
430        """'
431        remove data from plot
432        """
433        if id in self.plots.keys():
434            data =  self.plots[id]
435            self.graph.delete(data)
436            data_manager = self._manager.parent.get_data_manager()
[df22224]437            data_list, theory_list = data_manager.get_by_id(id_list=[id])
438           
439            if id in data_list.keys():
440                data = data_list[id]
[248b918]441            if id in theory_list.keys():
[df22224]442                data = theory_list[id]
[53a6d09]443            # Update Graph menu and help string       
444            h_id = self.parent._window_menu.FindItem(self.window_caption)
[e032dfc]445            if data != None:
[78919f45]446                if data.__class__.__name__ == 'list':
447                    label = data[0].label
448                else:
449                    label = data.label
[e032dfc]450            else:
451                label = '???'
[53a6d09]452            helpString = self.parent._window_menu.GetHelpString(h_id) 
[e032dfc]453            d_string = (' ' + str(label) +';')
[53a6d09]454            new_tip = helpString.replace(d_string, '')
455            self.parent._window_menu.SetHelpString(h_id, new_tip) 
456
[a07e72f]457            del self.plots[id]
458            self.graph.render(self)
459            self.subplot.figure.canvas.draw_idle()   
460            if len(self.graph.plottables) == 0:
[df22224]461                #onRemove: graph is empty must be the panel must be destroyed
462                self.parent.delete_panel(self.uid)
[53a6d09]463           
[a07e72f]464       
465    def plot_data(self, data):
[1bf33c1]466        """
[d955bf19]467        Data is ready to be displayed
468       
469        :param event: data event
[1bf33c1]470        """
[b837e1f]471        if data.__class__.__name__ == 'Data2D':
472            return
[6c4130a]473        plot_keys = self.plots.keys()
474        if data.id in plot_keys:
[e4a703a]475            #Recover panel prop.s
476            xlo, xhi = self.subplot.get_xlim()
477            ylo, yhi = self.subplot.get_ylim()
[5eede4e]478            old_data = self.plots[data.id]
[36288ca]479            if self._is_changed_legend_label:
480                data.label = old_data.label
[c9579e0]481            if old_data.__class__.__name__ == 'Data1D':
482                data.custom_color = old_data.custom_color
483                data.symbol = old_data.symbol
484                data.markersize = old_data.markersize
[6c4130a]485                data.zorder = len(plot_keys)
[e4a703a]486            # Replace data
[a07e72f]487            self.graph.replace(data)
488            self.plots[data.id] = data
[e4a703a]489            ## Set the view scale for all plots
[a4964b8e]490            try:
491                self._onEVT_FUNC_PROPERTY()
492            except:
[4904062]493                msg=" Encountered singular points..."
494                wx.PostEvent(self.parent, StatusEvent(status=\
[91a3860]495                    "Plotting Error: %s"% msg, info="error")) 
[7022fdc]496            # Check if zoomed
497            toolbar_zoomed = self.toolbar.GetToolEnabled(self.toolbar._NTB2_BACK)
498            if self.is_zoomed or toolbar_zoomed:
499                # Recover the x,y limits
500                self.subplot.set_xlim((xlo, xhi))     
501                self.subplot.set_ylim((ylo, yhi)) 
[a07e72f]502        else:
503            self.plots[data.id] = data
504            self.graph.add(self.plots[data.id]) 
[6c4130a]505            data.zorder = len(plot_keys)
[e4a703a]506            ## Set the view scale for all plots
[a4964b8e]507            try:
508                self._onEVT_FUNC_PROPERTY()
[940aca7]509                if IS_MAC:
510                    # MAC: forcing to plot 2D avg
511                    self.canvas._onDrawIdle()
[a4964b8e]512            except:
[4904062]513                msg=" Encountered singular points..."
514                wx.PostEvent(self.parent, StatusEvent(status=\
[91a3860]515                    "Plotting Error: %s"% msg, info="error")) 
[fe48fcc]516            self.toolbar.update()
[7022fdc]517            if self.is_zoomed:
518                self.is_zoomed = False
[d6e39a8e]519            # Update Graph menu and help string       
520            pos = self.parent._window_menu.FindItem(self.window_caption)
521            helpString = 'Show/Hide Graph: '
522            for plot in  self.plots.itervalues():
523                helpString += (' ' + str(plot.label) +';')
524            self.parent._window_menu.SetHelpString(pos, helpString)     
[e4a703a]525         
[6d727ae]526    def draw_plot(self):
527        """
528        Draw plot
529        """
530        self.draw() 
531
[1bf33c1]532    def onLeftDown(self,event): 
[6c0568b]533        """
[d955bf19]534        left button down and ready to drag
535        Display the position of the mouse on the statusbar
[6c0568b]536        """
[3e001f9]537        self._get_cusor_lines(event)
[e85e2bc]538        ax = event.inaxes
[3e001f9]539        PlotPanel.onLeftDown(self, event)
540
[e85e2bc]541        if ax != None:
[902f373]542            try:
543                pos_x = float(event.xdata)# / size_x
544                pos_y = float(event.ydata)# / size_y
545                pos_x = "%8.3g"% pos_x
546                pos_y = "%8.3g"% pos_y
547                self.position = str(pos_x), str(pos_y)
548                wx.PostEvent(self.parent, StatusEvent(status=self.position))
549            except:
550                self.position = None 
[0275276]551        # unfocus all
552        self.parent.set_plot_unfocus() 
[4ed210f4]553        #post nd event to notify guiframe that this panel is on focus
[a45037aa]554        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
[df68da1]555
[4ed210f4]556       
[a07e72f]557    def _ontoggle_hide_error(self, event):
558        """
559        Toggle error display to hide or show
560        """
[70ec588d]561        menu = event.GetEventObject()
562        id = event.GetId()
563        self.set_selected_from_menu(menu, id)
[ebf422a]564        # Check zoom
565        xlo, xhi = self.subplot.get_xlim()
566        ylo, yhi = self.subplot.get_ylim()
567
[a07e72f]568        selected_plot = self.plots[self.graph.selected_plottable]
[5637362]569        if self.hide_menu.GetText() == "Hide Error Bar":
[a07e72f]570            selected_plot.hide_error = True
571        else:
572            selected_plot.hide_error = False
573        ## increment graph color
574        self.graph.render(self)
575        self.subplot.figure.canvas.draw_idle() 
[ebf422a]576        # Check if zoomed
577        toolbar_zoomed = self.toolbar.GetToolEnabled(self.toolbar._NTB2_BACK)
578        if self.is_zoomed or toolbar_zoomed:
579            # Recover the x,y limits
580            self.subplot.set_xlim((xlo, xhi))     
581            self.subplot.set_ylim((ylo, yhi)) 
582
[a07e72f]583         
[1bf33c1]584    def _onRemove(self, event):
585        """
[d955bf19]586        Remove a plottable from the graph and render the graph
587       
588        :param event: Menu event
589       
[1bf33c1]590        """
[70ec588d]591        menu = event.GetEventObject()
592        id = event.GetId()
593        self.set_selected_from_menu(menu, id)
[6c0568b]594        ## Check if there is a selected graph to remove
[a07e72f]595        if self.graph.selected_plottable in self.plots.keys():
596            selected_plot = self.plots[self.graph.selected_plottable]
597            id = self.graph.selected_plottable
[df22224]598            self.remove_data_by_id(id)
599           
[1bf33c1]600    def onContextMenu(self, event):
601        """
[d955bf19]602        1D plot context menu
603       
604        :param event: wx context event
605       
[1bf33c1]606        """
[52b8b74]607        self._slicerpop = PanelMenu()
608        self._slicerpop.set_plots(self.plots)
[70ec588d]609        self._slicerpop.set_graph(self.graph)   
610        if not self.graph.selected_plottable in self.plots: 
611            # Various plot options
612            id = wx.NewId()
613            self._slicerpop.Append(id, '&Save Image', 'Save image as PNG')
614            wx.EVT_MENU(self, id, self.onSaveImage)
615            id = wx.NewId()
616            self._slicerpop.Append(id, '&Print Image', 'Print image ')
617            wx.EVT_MENU(self, id, self.onPrint)
618            id = wx.NewId()
619            self._slicerpop.Append(id, '&Print Preview', 'Print preview')
620            wx.EVT_MENU(self, id, self.onPrinterPreview)
[a436b2e]621           
[6d727ae]622            id = wx.NewId()
[f866fb5]623            self._slicerpop.Append(id, '&Copy to Clipboard', 
624                                   'Copy to the clipboard')
[70ec588d]625            wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
626                   
627            self._slicerpop.AppendSeparator()
628
629        for plot in self.plots.values():
630            #title = plot.title
[6d727ae]631            name = plot.name
[70ec588d]632            plot_menu = wx.Menu()
[242aff5]633            if self.graph.selected_plottable:
[4a9bce1]634                if not self.graph.selected_plottable in self.plots.keys():
635                    continue
[242aff5]636                if plot != self.plots[self.graph.selected_plottable]:
637                    continue
[940aca7]638               
639            id = wx.NewId()
640            plot_menu.Append(id, "&DataInfo", name)
641            wx.EVT_MENU(self, id, self. _onDataShow)
642            id = wx.NewId()
643            plot_menu.Append(id, "&Save Points as a File", name)
644            wx.EVT_MENU(self, id, self._onSave)
645            plot_menu.AppendSeparator()
646           
[70ec588d]647            #add menu of other plugins
[940aca7]648            item_list = self.parent.get_current_context_menu(self)
[242aff5]649             
[70ec588d]650            if (not item_list == None) and (not len(item_list) == 0):
651                for item in item_list:
[242aff5]652
[70ec588d]653                    try:
654                        id = wx.NewId()
655                        plot_menu.Append(id, item[0], name)
656                        wx.EVT_MENU(self, id, item[2])
657                    except:
658                        msg = "ModelPanel1D.onContextMenu: "
659                        msg += "bad menu item  %s" % sys.exc_value
660                        wx.PostEvent(self.parent, StatusEvent(status=msg))
661                        pass
662                plot_menu.AppendSeparator()
[940aca7]663           
[73eb92fc]664            if self.parent.ClassName.count('wxDialog') == 0: 
[e6a93df]665                id = wx.NewId()
[70ec588d]666                plot_menu.Append(id, '&Linear Fit', name)
[a436b2e]667                wx.EVT_MENU(self, id, self.onFitting)
[70ec588d]668                plot_menu.AppendSeparator()
[a436b2e]669   
[a3c96f7a]670                id = wx.NewId()
[70ec588d]671                plot_menu.Append(id, "Remove", name)
[a436b2e]672                wx.EVT_MENU(self, id, self._onRemove)
673                if not plot.is_data:
674                    id = wx.NewId()
[70ec588d]675                    plot_menu.Append(id, '&Freeze', name)
[a436b2e]676                    wx.EVT_MENU(self, id, self.onFreeze)
[70ec588d]677                plot_menu.AppendSeparator()   
[a436b2e]678                symbol_menu = wx.Menu()
[2636188]679               
[70ec588d]680                if plot.is_data:
[f8be87d]681                    id = wx.NewId()
[70ec588d]682                    self.hide_menu = plot_menu.Append(id, 
683                                                    "Hide Error Bar", name)
684       
685                    if plot.dy is not None and plot.dy != []:
686                        if plot.hide_error :
687                            self.hide_menu.SetText('Show Error Bar')
688                        else:
689                            self.hide_menu.SetText('Hide Error Bar')
[a436b2e]690                    else:
[70ec588d]691                        self.hide_menu.Enable(False)
692                    wx.EVT_MENU(self, id, self._ontoggle_hide_error)
[a436b2e]693               
[f8be87d]694                    plot_menu.AppendSeparator()
695
[e1714a9]696                id = wx.NewId()
[f866fb5]697                plot_menu.Append(id, '&Modify Plot Property', name)
[f8be87d]698                wx.EVT_MENU(self, id, self.createAppDialog)
699
700
701
[70ec588d]702            id = wx.NewId()
703            #plot_menu.SetTitle(name)
704            self._slicerpop.AppendMenu(id, '&%s'% name, plot_menu)
[f866fb5]705            # Option to hide
706            #TODO: implement functionality to hide a plottable (legend click)
[70ec588d]707        if not self.graph.selected_plottable in self.plots: 
708            self._slicerpop.AppendSeparator()
709            loc_menu = wx.Menu()
710            for label in self._loc_labels:
711                id = wx.NewId()
712                loc_menu.Append(id, str(label), str(label))
713                wx.EVT_MENU(self, id, self.onChangeLegendLoc)
714           
[ef4a4ea]715            id = wx.NewId()
[f866fb5]716            self._slicerpop.Append(id, '&Modify Graph Appearance',
717                                   'Modify graph appearance')
[8f59e95]718            wx.EVT_MENU(self, id, self.modifyGraphAppearance)
[70ec588d]719            self._slicerpop.AppendSeparator()
[8f59e95]720
[70ec588d]721           
722            if self.position != None:
723                id = wx.NewId()
724                self._slicerpop.Append(id, '&Add Text')
725                wx.EVT_MENU(self, id, self._on_addtext)
726                id = wx.NewId()
727                self._slicerpop.Append(id, '&Remove Text')
728                wx.EVT_MENU(self, id, self._on_removetext)
729                self._slicerpop.AppendSeparator()
[ef4a4ea]730            id = wx.NewId()
[70ec588d]731            self._slicerpop.Append(id, '&Change Scale')
732            wx.EVT_MENU(self, id, self._onProperties)
[857d00f]733            self._slicerpop.AppendSeparator()
[70ec588d]734            id = wx.NewId()
735            self._slicerpop.Append(id, '&Reset Graph Range')
736            wx.EVT_MENU(self, id, self.onResetGraph) 
737           
738            if self.parent.ClassName.count('wxDialog') == 0:   
739                self._slicerpop.AppendSeparator()
740                id = wx.NewId()
741                self._slicerpop.Append(id, '&Window Title')
742                wx.EVT_MENU(self, id, self.onChangeCaption)
[dc51a7f]743        try:
744            pos_evt = event.GetPosition()
745            pos = self.ScreenToClient(pos_evt)
746        except:
747            pos_x, pos_y = self.toolbar.GetPositionTuple()
748            pos = (pos_x, pos_y + 5)
[52b8b74]749        self.PopupMenu(self._slicerpop, pos)
[70ec588d]750           
[e6a93df]751    def onFreeze(self, event):
752        """
[f866fb5]753        on Freeze data
[e6a93df]754        """
[70ec588d]755        menu = event.GetEventObject()
756        id = event.GetId()
757        self.set_selected_from_menu(menu, id)
[e6a93df]758        plot = self.plots[self.graph.selected_plottable]
759        self.parent.onfreeze([plot.id])
[d7d1255e]760       
[176fbf1]761                       
[1bf33c1]762    def _onSave(self, evt):
763        """
[d955bf19]764        Save a data set to a text file
765       
766        :param evt: Menu event
767       
[1bf33c1]768        """
[70ec588d]769        menu = evt.GetEventObject()
770        id = evt.GetId()
771        self.set_selected_from_menu(menu, id)
[176fbf1]772        data = self.plots[self.graph.selected_plottable]
773        default_name = data.label
[c553b18]774        if default_name.count('.') > 0:
775            default_name = default_name.split('.')[0]
776        default_name += "_out"
777        if self.parent != None:
[176fbf1]778            self.parent.save_data1d(data, default_name)
[c5a769e]779
[0aca693]780                       
781    def _onDataShow(self, evt):
782        """
783        Show the data set in text
784       
785        :param evt: Menu event
786       
787        """
788        menu = evt.GetEventObject()
789        id = evt.GetId()
790        self.set_selected_from_menu(menu, id)
791        data = self.plots[self.graph.selected_plottable]
792        default_name = data.label
793        if default_name.count('.') > 0:
794            default_name = default_name.split('.')[0]
795        #default_name += "_out"
796        if self.parent != None:
797            self.parent.show_data1d(data, default_name)
798           
[c5a769e]799    def _add_more_tool(self):
800        """
[6e75ed0]801        Add refresh, add/hide button in the tool bar
[c5a769e]802        """
803        if self.parent.__class__.__name__ != 'ViewerFrame':
804            return
805        self.toolbar.AddSeparator()
[d6e39a8e]806        id_hide = wx.NewId()
807        hide = wx.Bitmap(GUIFRAME_ICON.HIDE_ID_PATH, wx.BITMAP_TYPE_PNG)
808        self.toolbar.AddSimpleTool(id_hide, hide, 'Hide', 'Hide')
[c5a769e]809        self.toolbar.Realize()
[d6e39a8e]810        wx.EVT_TOOL(self, id_hide,  self._on_hide)
[c5a769e]811       
[6e75ed0]812    def _on_hide(self, event):
813        """
814        Hides the plot when button is pressed
815        """     
[c5a769e]816        if self.parent is not None:
[6e75ed0]817            self.parent.hide_panel(self.uid)
[f8be87d]818
819    def createAppDialog(self, event):
820        """
821        Create the custom dialog for fit appearance modification
822        """
823        menu = event.GetEventObject()
824        id = event.GetId()
[f866fb5]825        self.set_selected_from_menu(menu, id)
826        self.appearance_selected_plot = \
827                        self.plots[self.graph.selected_plottable]
[f8be87d]828        # find current properties
829        curr_color = self.appearance_selected_plot.custom_color
830        curr_symbol = self.appearance_selected_plot.symbol
831        curr_size = self.appearance_selected_plot.markersize
832        curr_label = self.appearance_selected_plot.label
833
834        if curr_color == None:
835            curr_color = self._color_labels['Blue']
836            curr_symbol = 13
837
[9f51c2c]838        self.appD = appearanceDialog(self, 'Modify Plot Property')
839        icon = self.parent.GetIcon()
840        self.appD.SetIcon(icon)
[f866fb5]841        self.appD.set_defaults(float(curr_size), int(curr_color), 
842                    str(appearanceDialog.find_key(self.get_symbol_label(), 
843                    int(curr_symbol))), curr_label)
[9f51c2c]844        self.appD.Bind(wx.EVT_CLOSE, self.on_AppDialog_close)   
845
[f866fb5]846    def on_AppDialog_close(self, event):
847        """
848        on_Modify Plot Property_close
849        """
[9f51c2c]850        if(self.appD.okay_clicked == True):
[f866fb5]851            # returns (size,color,symbol,datalabel)
852            info = self.appD.get_current_values() 
853            self.appearance_selected_plot.custom_color = \
854                        self._color_labels[info[1].encode('ascii', 'ignore')]
[9f51c2c]855
856            self.appearance_selected_plot.markersize = float(info[0])
[f866fb5]857            self.appearance_selected_plot.symbol = \
858                        self.get_symbol_label()[info[2]] 
[9f51c2c]859            self.appearance_selected_plot.label = str(info[3])
860
861            pos = self.parent._window_menu.FindItem(self.window_caption)
862            helpString = 'Show/Hide Graph: '
863            for plot in  self.plots.itervalues():
[f866fb5]864                helpString += (' ' + str(plot.label) + ';')
[9f51c2c]865                self.parent._window_menu.SetHelpString(pos, helpString)
866                self._is_changed_legend_label = True
[f8be87d]867               
868        self.appD.Destroy()
869        self._check_zoom_plot()
[8f59e95]870
871
[f866fb5]872    def modifyGraphAppearance(self, event):
873        """
874        On Modify Graph Appearance
875        """
876        self.graphApp = graphAppearance(self, 'Modify Graph Appearance')
[9f51c2c]877        icon = self.parent.GetIcon()
878        self.graphApp.SetIcon(icon)
[f866fb5]879        self.graphApp.setDefaults(self.grid_on, self.legend_on, 
880                                  self.xaxis_label, self.yaxis_label, 
881                                  self.xaxis_unit, self.yaxis_unit, 
882                                  self.xaxis_font, self.yaxis_font, 
883                                  find_key(self.get_loc_label(), 
884                                  self.legendLoc), 
[657e52c]885                                  self.xcolor, self.ycolor, 
886                                  self.is_xtick, self.is_ytick)
[9f51c2c]887        self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)
[8f59e95]888   
889
[9f51c2c]890    def on_graphApp_close(self, event):
[83d9120]891        """
892        Gets values from graph appearance dialog and sends them off
893        to modify the plot
894        """
895        graph_app = self.graphApp
896        toggle_grid = graph_app.get_togglegrid()
897        legend_loc = graph_app.get_legend_loc()
898        toggle_legend = graph_app.get_togglelegend()
899       
900        self.onGridOnOff(toggle_grid )
901        self.ChangeLegendLoc(legend_loc)
902        self.onLegend(toggle_legend)
[8a687cfd]903
[83d9120]904        self.xaxis_label = graph_app.get_xlab()
905        self.yaxis_label = graph_app.get_ylab()
906        self.xaxis_unit = graph_app.get_xunit()
907        self.yaxis_unit = graph_app.get_yunit()
[657e52c]908        self.xaxis_font = graph_app.get_xfont()
909        self.yaxis_font = graph_app.get_yfont()
910        self.is_xtick =  graph_app.get_xtick_check()
911        self.is_ytick =  graph_app.get_ytick_check()
912        if self.is_xtick:
913            self.xaxis_tick = self.xaxis_font
914        if self.is_ytick:
915            self.yaxis_tick = self.yaxis_font
[8a687cfd]916
[83d9120]917        self.xaxis(self.xaxis_label, self.xaxis_unit, 
[657e52c]918                   graph_app.get_xfont(), graph_app.get_xcolor(), 
919                   self.xaxis_tick)
[83d9120]920        self.yaxis(self.yaxis_label, self.yaxis_unit, 
[657e52c]921                   graph_app.get_yfont(), graph_app.get_ycolor(),
922                   self.yaxis_tick)
[8f59e95]923
[83d9120]924        graph_app.Destroy()
Note: See TracBrowser for help on using the repository browser.