source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py @ 377ca62f

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.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 377ca62f was 9c0f3c17, checked in by Ricardo Ferraz Leal <ricleal@…>, 8 years ago

After merge conflict

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