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

magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249unittest-saveload
Last change on this file since bb80b84 was 2469df7, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

lint: update 'if x==True/False?' to 'if x/not x:'

  • Property mode set to 100644
File size: 30.8 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 is not 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 is not 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 is None:
215            return
216        event.Skip()
217        active_ctrl = event.active
218        if active_ctrl is 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 is 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 is not 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 is 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 is not None and event.xdata is not 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 is None:
364            return
365        # release a q range vline
366        if self.ly is not 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 is None or not hasattr(event, 'action'):
373            return
374        end_drag = event.action != 'drag' and event.xdata is not 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 is not 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 (item_list is not None) and (len(item_list)):
621                for item, wx_id in zip(item_list, [ids.next() for i in range(len(item_list))]):
622                    try:
623                        plot_menu.Append(wx_id, item[0], name)
624                        wx.EVT_MENU(self, wx_id, item[2])
625                    except:
626                        msg = "ModelPanel1D.onContextMenu: "
627                        msg += "bad menu item  %s" % sys.exc_value
628                        wx.PostEvent(self.parent, StatusEvent(status=msg))
629                plot_menu.AppendSeparator()
630
631            if self.parent.ClassName.count('wxDialog') == 0:
632                if plot.id != 'fit':
633                    wx_id = ids.next()
634                    plot_menu.Append(wx_id, '&Linear Fit', name)
635                    wx.EVT_MENU(self, wx_id, self.onFitting)
636                    plot_menu.AppendSeparator()
637
638                wx_id = ids.next()
639                plot_menu.Append(wx_id, "Remove", name)
640                wx.EVT_MENU(self, wx_id, self._onRemove)
641                if not plot.is_data:
642                    wx_id = ids.next()
643                    plot_menu.Append(wx_id, '&Freeze', name)
644                    wx.EVT_MENU(self, wx_id, self.onFreeze)
645                plot_menu.AppendSeparator()
646
647                if plot.is_data:
648                    wx_id = ids.next()
649                    self.hide_menu = plot_menu.Append(wx_id, "Hide Error Bar", name)
650
651                    if plot.dy is not None and plot.dy != []:
652                        if plot.hide_error:
653                            self.hide_menu.SetText('Show Error Bar')
654                        else:
655                            self.hide_menu.SetText('Hide Error Bar')
656                    else:
657                        self.hide_menu.Enable(False)
658                    wx.EVT_MENU(self, wx_id, self._ontoggle_hide_error)
659
660                    plot_menu.AppendSeparator()
661
662                wx_id = ids.next()
663                plot_menu.Append(wx_id, '&Modify Plot Property', name)
664                wx.EVT_MENU(self, wx_id, self.createAppDialog)
665            wx_id = ids.next()
666            # plot_menu.SetTitle(name)
667            self._slicerpop.AppendMenu(wx_id, '&%s' % name, plot_menu)
668            # Option to hide
669            # TODO: implement functionality to hide a plottable (legend click)
670
671        self._slicerpop.AppendSeparator()
672        loc_menu = wx.Menu()
673        for label in self._loc_labels:
674            wx_id = ids.next()
675            loc_menu.Append(wx_id, str(label), str(label))
676            wx.EVT_MENU(self, wx_id, self.onChangeLegendLoc)
677
678        wx_id = ids.next()
679        self._slicerpop.Append(wx_id, '&Modify Graph Appearance',
680                               'Modify graph appearance')
681        wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance)
682        self._slicerpop.AppendSeparator()
683
684
685        if self.position is not None:
686            wx_id = ids.next()
687            self._slicerpop.Append(wx_id, '&Add Text')
688            wx.EVT_MENU(self, wx_id, self._on_addtext)
689            wx_id = ids.next()
690            self._slicerpop.Append(wx_id, '&Remove Text')
691            wx.EVT_MENU(self, wx_id, self._on_removetext)
692            self._slicerpop.AppendSeparator()
693        wx_id = ids.next()
694        self._slicerpop.Append(wx_id, '&Change Scale')
695        wx.EVT_MENU(self, wx_id, self._onProperties)
696        self._slicerpop.AppendSeparator()
697        wx_id = ids.next()
698        self._slicerpop.Append(wx_id, '&Set Graph Range')
699        wx.EVT_MENU(self, wx_id, self.onSetRange)
700        wx_id = ids.next()
701        self._slicerpop.Append(wx_id, '&Reset Graph Range')
702        wx.EVT_MENU(self, wx_id, self.onResetGraph)
703
704        if self.parent.ClassName.count('wxDialog') == 0:
705            self._slicerpop.AppendSeparator()
706            wx_id = ids.next()
707            self._slicerpop.Append(wx_id, '&Window Title')
708            wx.EVT_MENU(self, wx_id, self.onChangeCaption)
709        try:
710            pos_evt = event.GetPosition()
711            pos = self.ScreenToClient(pos_evt)
712        except:
713            pos_x, pos_y = self.toolbar.GetPositionTuple()
714            pos = (pos_x, pos_y + 5)
715        self.PopupMenu(self._slicerpop, pos)
716
717    def onSetRange(self, event):
718        # Display dialog
719        # self.subplot.set_xlim((low, high))
720        # self.subplot.set_ylim((low, high))
721        from sas.sasgui.plottools.RangeDialog import RangeDialog
722        d = RangeDialog(self, -1)
723        xlim = self.subplot.get_xlim()
724        ylim = self.subplot.get_ylim()
725        d.SetXRange(xlim)
726        d.SetYRange(ylim)
727        if d.ShowModal() == wx.ID_OK:
728            x_range = d.GetXRange()
729            y_range = d.GetYRange()
730            if x_range is not None and y_range is not None:
731                self.subplot.set_xlim(x_range)
732                self.subplot.set_ylim(y_range)
733                self.subplot.figure.canvas.draw_idle()
734                self.is_zoomed = True
735        d.Destroy()
736
737    def onFreeze(self, event):
738        """
739        on Freeze data
740        """
741        menu = event.GetEventObject()
742        wx_id = event.GetId()
743        self.set_selected_from_menu(menu, wx_id)
744        plot = self.plots[self.graph.selected_plottable]
745        self.parent.onfreeze([plot.id])
746
747    def _onSave(self, evt):
748        """
749        Save a data set to a text file
750
751        :param evt: Menu event
752
753        """
754        menu = evt.GetEventObject()
755        event_id = evt.GetId()
756        self.set_selected_from_menu(menu, event_id)
757        data = self.plots[self.graph.selected_plottable]
758        default_name = data.label
759        if default_name.count('.') > 0:
760            default_name = default_name.split('.')[0]
761        default_name += "_out"
762        if self.parent is not None:
763            self.parent.save_data1d(data, default_name)
764
765    def _onDataShow(self, evt):
766        """
767        Show the data set in text
768
769        :param evt: Menu event
770
771        """
772        menu = evt.GetEventObject()
773        event_id = evt.GetId()
774        self.set_selected_from_menu(menu, event_id)
775        data = self.plots[self.graph.selected_plottable]
776        default_name = data.label
777        if default_name.count('.') > 0:
778            default_name = default_name.split('.')[0]
779        # default_name += "_out"
780        if self.parent is not None:
781            self.parent.show_data1d(data, default_name)
782
783    def _on_hide(self, event):
784        """
785        Hides the plot when button is pressed
786        """
787        if self.parent is not None:
788            self.parent.hide_panel(self.uid)
789
790    def on_close(self, event):
791        """
792        On Close Event
793        """
794        ID = self.uid
795        self.parent.delete_panel(ID)
796
797    def createAppDialog(self, event):
798        """
799        Create the custom dialog for fit appearance modification
800        """
801        menu = event.GetEventObject()
802        event_id = event.GetId()
803        self.set_selected_from_menu(menu, event_id)
804        self.appearance_selected_plot = \
805                        self.plots[self.graph.selected_plottable]
806        # find current properties
807        curr_color = self.appearance_selected_plot.custom_color
808        curr_symbol = self.appearance_selected_plot.symbol
809        curr_size = self.appearance_selected_plot.markersize
810        curr_label = self.appearance_selected_plot.label
811
812        if curr_color is None:
813            curr_color = self._color_labels['Blue']
814            curr_symbol = 13
815
816        self.appD = appearanceDialog(self, 'Modify Plot Property')
817        icon = self.parent.GetIcon()
818        self.appD.SetIcon(icon)
819        self.appD.set_defaults(float(curr_size), int(curr_color),
820                               str(appearanceDialog.find_key(self.get_symbol_label(),
821                                                             int(curr_symbol))), curr_label)
822        self.appD.Bind(wx.EVT_CLOSE, self.on_AppDialog_close)
823        self.graph.selected_plottable = None
824
825    def on_AppDialog_close(self, event):
826        """
827        on_Modify Plot Property_close
828        """
829        if self.appD.okay_clicked:
830            info = self.appD.get_current_values()
831            self.appearance_selected_plot.custom_color = \
832                        self._color_labels[info[1].encode('ascii', 'ignore')]
833
834            self.appearance_selected_plot.markersize = float(info[0])
835            self.appearance_selected_plot.symbol = \
836                        self.get_symbol_label()[info[2]]
837            self.appearance_selected_plot.label = str(info[3])
838        self.appD.Destroy()
839        self._check_zoom_plot()
840
841    def modifyGraphAppearance(self, event):
842        """
843        On Modify Graph Appearance
844        """
845        self.graphApp = graphAppearance(self, 'Modify Graph Appearance')
846        icon = self.parent.GetIcon()
847        self.graphApp.SetIcon(icon)
848        self.graphApp.setDefaults(self.grid_on, self.legend_on,
849                                  self.xaxis_label, self.yaxis_label,
850                                  self.xaxis_unit, self.yaxis_unit,
851                                  self.xaxis_font, self.yaxis_font,
852                                  find_key(self.get_loc_label(), self.legendLoc),
853                                  self.xcolor, self.ycolor,
854                                  self.is_xtick, self.is_ytick)
855        self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)
856
857    def on_graphApp_close(self, event):
858        """
859        Gets values from graph appearance dialog and sends them off
860        to modify the plot
861        """
862        graph_app = self.graphApp
863        toggle_grid = graph_app.get_togglegrid()
864        legend_loc = graph_app.get_legend_loc()
865        toggle_legend = graph_app.get_togglelegend()
866
867        self.onGridOnOff(toggle_grid)
868        self.ChangeLegendLoc(legend_loc)
869        self.onLegend(toggle_legend)
870
871        self.xaxis_label = graph_app.get_xlab()
872        self.yaxis_label = graph_app.get_ylab()
873        self.xaxis_unit = graph_app.get_xunit()
874        self.yaxis_unit = graph_app.get_yunit()
875        self.xaxis_font = graph_app.get_xfont()
876        self.yaxis_font = graph_app.get_yfont()
877        self.is_xtick = graph_app.get_xtick_check()
878        self.is_ytick = graph_app.get_ytick_check()
879        if self.is_xtick:
880            self.xaxis_tick = self.xaxis_font
881        if self.is_ytick:
882            self.yaxis_tick = self.yaxis_font
883
884        self.xaxis(self.xaxis_label, self.xaxis_unit,
885                   graph_app.get_xfont(), graph_app.get_xcolor(),
886                   self.xaxis_tick)
887        self.yaxis(self.yaxis_label, self.yaxis_unit,
888                   graph_app.get_yfont(), graph_app.get_ycolor(),
889                   self.yaxis_tick)
890
891        graph_app.Destroy()
Note: See TracBrowser for help on using the repository browser.