source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py @ 9f25bce

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 9f25bce was 5bcb6a9, checked in by Piotr Rozyczko <rozyczko@…>, 8 years ago

Allow user to set the range of a plot (closes #245)

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