source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter1D.py @ 2ae3edb

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 2ae3edb was fa81e94, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Initial commit of the P(r) inversion perspective.
Code merged from Jeff Krzywon's ESS_GUI_Pr branch.
Also, minor 2to3 mods to sascalc/sasgui to enble error free setup.

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