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

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 24fc06a was 29e872e, checked in by Piotr Rozyczko <rozyczko@…>, 8 years ago

Zoomed charts now retain their zoom factor. Fixes #800

  • 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
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
27DEFAULT_QMAX = 0.05
28DEFAULT_QSTEP = 0.001
29DEFAULT_BEAM = 0.005
30BIN_WIDTH = 1
31IS_MAC = (sys.platform == 'darwin')
32
33
34def find_key(dic, val):
35    """return the key of dictionary dic given the value"""
36    return [k for k, v in dic.iteritems() if v == val][0]
37
38class ModelPanel1D(PlotPanel, PanelBase):
39    """
40    Plot panel for use with the GUI manager
41    """
42
43    ## Internal name for the AUI manager
44    window_name = "plotpanel"
45    ## Title to appear on top of the window
46    window_caption = "Graph"
47    ## Flag to tell the GUI manager that this panel is not
48    #  tied to any perspective
49    ALWAYS_ON = True
50    ## Group ID
51    group_id = None
52    _menu_ids = IdList()
53
54    def __init__(self, parent, id=-1, color=None,
55                 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
56        PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)
57        PanelBase.__init__(self, parent)
58        ## Reference to the parent window
59        self.parent = parent
60        if hasattr(parent, "parent"):
61            self.parent = self.parent.parent
62        ## Plottables
63        self.plots = {}
64        self.frame = None
65        # context menu
66        self._slicerpop = None
67        self._available_data = []
68        self._symbol_labels = self.get_symbol_label()
69        self._color_labels = self.get_color_label()
70        self.currColorIndex = ""
71        self._is_changed_legend_label = False
72        self.is_xtick = False
73        self.is_ytick = False
74
75        self.hide_menu = None
76        ## Unique ID (from gui_manager)
77        self.uid = None
78        self.x_size = None
79        ## Default locations
80        # self._default_save_location = os.getcwd()
81        self.size = None
82        self.vl_ind = 0
83        ## Graph
84        # self.graph = Graph()
85        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
86        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
87        self.graph.render(self)
88        self.cursor_id = None
89
90        # In resizing event
91        self.resizing = False
92        self.canvas.set_resizing(self.resizing)
93        self.Bind(wx.EVT_SIZE, self._OnReSize)
94        self.parent.SetFocus()
95
96        # If true, there are 3 qrange bars
97        self.is_corfunc = False
98
99
100    def get_symbol_label(self):
101        """
102        Associates label to symbol
103        """
104        _labels = {}
105        i = 0
106        _labels['Circle'] = i
107        i += 1
108        _labels['Cross X '] = i
109        i += 1
110        _labels['Triangle Down'] = i
111        i += 1
112        _labels['Triangle Up'] = i
113        i += 1
114        _labels['Triangle Left'] = i
115        i += 1
116        _labels['Triangle Right'] = i
117        i += 1
118        _labels['Cross +'] = i
119        i += 1
120        _labels['Square'] = i
121        i += 1
122        _labels['diamond'] = i
123        i += 1
124        _labels['Diamond'] = i
125        i += 1
126        _labels['Hexagon1'] = i
127        i += 1
128        _labels['Hexagon2'] = i
129        i += 1
130        _labels['Pentagon'] = i
131        i += 1
132        _labels['Line'] = i
133        i += 1
134        _labels['Dash'] = i
135        i += 1
136        _labels['Vline'] = i
137        i += 1
138        _labels['Step'] = i
139        return _labels
140
141    def get_color_label(self):
142        """
143        Associates label to a specific color
144        """
145        _labels = {}
146        i = 0
147        _labels['Blue'] = i
148        i += 1
149        _labels['Green'] = i
150        i += 1
151        _labels['Red'] = i
152        i += 1
153        _labels['Cyan'] = i
154        i += 1
155        _labels['Magenta'] = i
156        i += 1
157        _labels['Yellow'] = i
158        i += 1
159        _labels['Black'] = i
160        return _labels
161
162
163    def set_data(self, list=None):
164        """
165        """
166        pass
167
168    def _reset(self):
169        """
170        Resets internal data and graph
171        """
172        self.graph.reset()
173        self.plots = {}
174        self.is_zoomed = False
175
176    def _OnReSize(self, event):
177        """
178        On response of the resize of a panel, set axes_visiable False
179        """
180        # It was found that wx >= 2.9.3 sends an event even if no size changed.
181        # So manually recode the size (=x_size) and compare here.
182        # Massy code to work around:<
183        if self.parent._mgr != None:
184            max_panel = self.parent._mgr.GetPane(self)
185            if max_panel.IsMaximized():
186                self.parent._mgr.RestorePane(max_panel)
187                max_panel.Maximize()
188        if self.x_size != None:
189            if self.x_size == self.GetSize():
190                self.resizing = False
191                self.canvas.set_resizing(self.resizing)
192                return
193        self.x_size = self.GetSize()
194
195        # Ready for another event
196        # Do not remove this Skip. Otherwise it will get runtime error on wx>=2.9.
197        event.Skip()
198        # set the resizing flag
199        self.resizing = True
200        self.canvas.set_resizing(self.resizing)
201        self.parent.set_schedule(True)
202        pos_x, pos_y = self.GetPositionTuple()
203        if pos_x != 0 and pos_y != 0:
204            self.size, _ = self.GetClientSizeTuple()
205        self.SetSizer(self.sizer)
206        wx.CallAfter(self.parent.disable_app_menu, self)
207
208    def on_plot_qrange(self, event=None):
209        """
210        On Qmin Qmax vertical line event
211        """
212        if event == None:
213            return
214        event.Skip()
215        active_ctrl = event.active
216        if active_ctrl == None:
217            return
218        if hasattr(event, 'is_corfunc'):
219            self.is_corfunc = event.is_corfunc
220        if event.id in self.plots.keys():
221            ctrl = event.ctrl
222            self.cursor_id = event.id
223            # Set line position and color
224            colors = ['red', 'purple']
225            x_data = self.plots[self.cursor_id].x
226            values = [max(x_data.min(), float(ctrl[0].GetValue())),
227                      min(x_data.max(), float(ctrl[1].GetValue()))]
228            if len(ctrl) == 3:
229                colors.append('purple')
230                values.append(min(x_data.max(), float(ctrl[2].GetValue())))
231            if self.ly == None:
232                self.ly = []
233                for c, v in zip(colors, values):
234                    h = self.subplot.axvline(x=v, color=c, lw=2.5, alpha=0.7)
235                    h.set_rasterized(True)
236                    self.ly.append(h)
237            try:
238                # Display x,y in the status bar if possible
239                xval = float(active_ctrl.GetValue())
240                position = self.get_data_xy_vals(xval)
241                if position != None and not self.is_corfunc:
242                    wx.PostEvent(self.parent, StatusEvent(status=position))
243            except:
244                logging.error(sys.exc_value)
245            if not event.leftdown:
246                # text event
247                try:
248                    is_moved = False
249                    for h, v in zip(self.ly, values):
250                        # check if vline moved
251                        if h.get_xdata() != v:
252                            h.set_xdata(v)
253                            is_moved = True
254                    if is_moved:
255                        self.canvas.draw()
256                except:
257                    logging.error(sys.exc_value)
258                event.Skip()
259                return
260            self.q_ctrl = ctrl
261            for h, c, v in zip(self.ly, colors, values):
262                h.set_color(c)
263                h.set_xdata(v)
264            self.canvas.draw()
265        else:
266            self.q_ctrl = None
267
268    def get_data_xy_vals(self, xval):
269        """
270        Get x, y data values near x = x_val
271        """
272        try:
273            x_data = self.plots[self.cursor_id].x
274            y_data = self.plots[self.cursor_id].y
275            indx = self._find_nearest(x_data, xval)
276            pos_x = x_data[indx]
277            pos_y = y_data[indx]
278            position = str(pos_x), str(pos_y)
279            return position
280        except:
281            return None
282
283    def _find_nearest(self, array, value):
284        """
285        Find and return the nearest value in array to the value.
286        Used in cusor_line()
287        :Param array: numpy array
288        :Param value: float
289        """
290        idx = (numpy.abs(array - value)).argmin()
291        return int(idx)  # array.flat[idx]
292
293    def _check_line_positions(self, pos_x=None, nop=None):
294        """
295        Check vertical line positions
296        :Param pos_x: position of the current line [float]
297        :Param nop: number of plots [int]
298        """
299        ly = self.ly
300        ly0x = ly[0].get_xdata()
301        ly1x = ly[1].get_xdata()
302        ly2x = None
303        if self.is_corfunc: ly2x = ly[2].get_xdata()
304        self.q_ctrl[0].SetBackgroundColour('white')
305        self.q_ctrl[1].SetBackgroundColour('white')
306        if ly0x >= ly1x:
307            if self.vl_ind == 0:
308                ly[1].set_xdata(pos_x)
309                ly[1].set_zorder(nop)
310                self.q_ctrl[1].SetValue(str(pos_x))
311                self.q_ctrl[0].SetBackgroundColour('pink')
312            elif self.vl_ind == 1:
313                ly[0].set_xdata(pos_x)
314                ly[0].set_zorder(nop)
315                self.q_ctrl[0].SetValue(str(pos_x))
316                self.q_ctrl[1].SetBackgroundColour('pink')
317        elif ly2x is not None and ly1x >= ly2x:
318            if self.vl_ind == 1:
319                ly[2].set_xdata(posx)
320                ly[2].set_zorder(nop)
321                self.q_ctrl[2].SetValue(str(pos_x))
322            elif self.vl_ind == 2:
323                ly[1].set_xdata(posx)
324                ly[1].set_zorder(nop)
325                self.q_ctrl[1].SetValue(str(pos_x))
326
327
328    def _get_cusor_lines(self, event):
329        """
330        Revmove or switch cursor line if drawn
331        :Param event: LeftClick mouse event
332        """
333        ax = event.inaxes
334        if hasattr(event, "action"):
335            dclick = event.action == 'dclick'
336            if ax == None or dclick:
337                # remove the vline
338                self._check_zoom_plot()
339                self.canvas.draw()
340                self.q_ctrl = None
341                return
342        if self.ly != None and event.xdata != None:
343            # Selecting a new line if cursor lines are displayed already
344            dqmin = math.fabs(event.xdata - self.ly[0].get_xdata())
345            dqmax = math.fabs(event.xdata - self.ly[1].get_xdata())
346            if not self.is_corfunc:
347                is_qmax = dqmin > dqmax
348                if is_qmax:
349                    self.vl_ind = 1
350                else:
351                    self.vl_ind = 0
352            else:
353                dqmax2 = math.fabs(event.xdata - self.ly[2].get_xdata())
354                closest = min(dqmin, dqmax, dqmax2)
355                self.vl_ind = { dqmin: 0, dqmax: 1, dqmax2: 2 }.get(closest)
356
357    def cusor_line(self, event):
358        """
359        Move the cursor line to write Q range
360        """
361        if self.q_ctrl == None:
362            return
363        # release a q range vline
364        if self.ly != None and not self.leftdown:
365            for ly in self.ly:
366                ly.set_alpha(0.7)
367                self.canvas.draw()
368            return
369        ax = event.inaxes
370        if ax == None or not hasattr(event, 'action'):
371            return
372        end_drag = event.action != 'drag' and event.xdata != None
373        nop = len(self.plots)
374        pos_x, _ = float(event.xdata), float(event.ydata)
375        try:
376            ly = self.ly
377            ly0x = ly[0].get_xdata()
378            ly1x = ly[1].get_xdata()
379            if ly0x == ly1x:
380                if ly[0].get_zorder() > ly[1].get_zorder():
381                    self.vl_ind = 0
382                else:
383                    self.vl_ind = 1
384            vl_ind = self.vl_ind
385            x_data = self.plots[self.cursor_id].x
386            xmin = x_data.min()
387            xmax = x_data.max()
388            indx = self._find_nearest(x_data, pos_x)
389            # Need to hold LeftButton to drag
390            if end_drag:
391                if event.button:
392                    self._check_line_positions(pos_x, nop)
393                return
394            if indx >= len(x_data):
395                indx = len(x_data) - 1
396            pos_x = x_data[indx]
397            if xmin == ly1x:
398                vl_ind = 1
399            elif xmax == ly0x:
400                vl_ind = 0
401            else:
402                ly[vl_ind].set_xdata(pos_x)
403                ly[vl_ind].set_zorder(nop + 1)
404                self._check_line_positions(pos_x, nop)
405            ly[vl_ind].set_xdata(pos_x)
406            ly[vl_ind].set_alpha(1.0)
407            ly[vl_ind].set_zorder(nop + 1)
408            self.canvas.draw()
409            self.q_ctrl[vl_ind].SetValue(str(pos_x))
410        except:
411            logging.error(sys.exc_value)
412
413    def set_resizing(self, resizing=False):
414        """
415        Set the resizing (True/False)
416        """
417        self.resizing = resizing
418        # self.canvas.set_resizing(resizing)
419
420    def schedule_full_draw(self, func='append'):
421        """
422        Put self in schedule to full redraw list
423        """
424        # append/del this panel in the schedule list
425        self.parent.set_schedule_full_draw(self, func)
426
427    def remove_data_by_id(self, id):
428        """
429            Remove data from plot
430        """
431        if id in self.plots.keys():
432            data = self.plots[id]
433            self.graph.delete(data)
434            data_manager = self._manager.parent.get_data_manager()
435            data_list, theory_list = data_manager.get_by_id(id_list=[id])
436
437            if id in data_list.keys():
438                data = data_list[id]
439            if id in theory_list.keys():
440                data = theory_list[id]
441
442            del self.plots[id]
443            self.graph.render(self)
444            self.subplot.figure.canvas.draw_idle()
445            if len(self.graph.plottables) == 0:
446                # onRemove: graph is empty must be the panel must be destroyed
447                self.parent.delete_panel(self.uid)
448
449    def plot_data(self, data):
450        """
451        Data is ready to be displayed
452
453        :param event: data event
454        """
455        if data.__class__.__name__ == 'Data2D':
456            return
457        plot_keys = self.plots.keys()
458        if data.id in plot_keys:
459            # Recover panel prop.s
460            xlo, xhi = self.subplot.get_xlim()
461            ylo, yhi = self.subplot.get_ylim()
462            old_data = self.plots[data.id]
463            if self._is_changed_legend_label:
464                data.label = old_data.label
465            if old_data.__class__.__name__ == 'Data1D':
466                data.custom_color = old_data.custom_color
467                data.symbol = old_data.symbol
468                data.markersize = old_data.markersize
469                data.zorder = len(plot_keys)
470            # Replace data
471            self.graph.replace(data)
472            self.plots[data.id] = data
473            ## Set the view scale for all plots
474            try:
475                self._onEVT_FUNC_PROPERTY()
476            except Exception, exc:
477                wx.PostEvent(self.parent,
478                             StatusEvent(status="Plotting Error: %s" % str(exc), info="error"))
479            if self.is_zoomed:
480                # Recover the x,y limits
481                self.subplot.set_xlim((xlo, xhi))
482                self.subplot.set_ylim((ylo, yhi))
483        else:
484            self.plots[data.id] = data
485            self.graph.add(self.plots[data.id])
486            data.zorder = len(plot_keys)
487            ## Set the view scale for all plots
488            try:
489                self._onEVT_FUNC_PROPERTY()
490                if IS_MAC:
491                    # MAC: forcing to plot 2D avg
492                    self.canvas._onDrawIdle()
493            except Exception, exc:
494                wx.PostEvent(self.parent, StatusEvent(status=\
495                    "Plotting Error: %s" % str(exc), info="error"))
496            self.toolbar.update()
497            self.is_zoomed = False
498
499    def draw_plot(self):
500        """
501        Draw plot
502        """
503        self.draw()
504
505    def onLeftDown(self, event):
506        """
507        left button down and ready to drag
508        Display the position of the mouse on the statusbar
509        """
510        # self.parent.set_plot_unfocus()
511        self._get_cusor_lines(event)
512        ax = event.inaxes
513        PlotPanel.onLeftDown(self, event)
514        if ax != None:
515            try:
516                pos_x = float(event.xdata)  # / size_x
517                pos_y = float(event.ydata)  # / size_y
518                pos_x = "%8.3g" % pos_x
519                pos_y = "%8.3g" % pos_y
520                self.position = str(pos_x), str(pos_y)
521                wx.PostEvent(self.parent, StatusEvent(status=self.position))
522            except:
523                self.position = None
524        # unfocus all
525        self.parent.set_plot_unfocus()
526        # post nd event to notify guiframe that this panel is on focus
527        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
528
529
530    def _ontoggle_hide_error(self, event):
531        """
532        Toggle error display to hide or show
533        """
534        menu = event.GetEventObject()
535        event_id = event.GetId()
536        self.set_selected_from_menu(menu, event_id)
537        # Check zoom
538        xlo, xhi = self.subplot.get_xlim()
539        ylo, yhi = self.subplot.get_ylim()
540
541        selected_plot = self.plots[self.graph.selected_plottable]
542        if self.hide_menu.GetText() == "Hide Error Bar":
543            selected_plot.hide_error = True
544        else:
545            selected_plot.hide_error = False
546        ## increment graph color
547        self.graph.render(self)
548        self.subplot.figure.canvas.draw_idle()
549        if self.is_zoomed:
550            # Recover the x,y limits
551            self.subplot.set_xlim((xlo, xhi))
552            self.subplot.set_ylim((ylo, yhi))
553        self.graph.selected_plottable = None
554
555
556    def _onRemove(self, event):
557        """
558        Remove a plottable from the graph and render the graph
559
560        :param event: Menu event
561
562        """
563        menu = event.GetEventObject()
564        event_id = event.GetId()
565        self.set_selected_from_menu(menu, event_id)
566        ## Check if there is a selected graph to remove
567        if self.graph.selected_plottable in self.plots.keys():
568            graph_id = self.graph.selected_plottable
569            self.remove_data_by_id(graph_id)
570
571    def onContextMenu(self, event):
572        """
573        1D plot context menu
574
575        :param event: wx context event
576
577        """
578        self._slicerpop = PanelMenu()
579        self._slicerpop.set_plots(self.plots)
580        self._slicerpop.set_graph(self.graph)
581        ids = iter(self._menu_ids)
582
583        # Various plot options
584        wx_id = ids.next()
585        self._slicerpop.Append(wx_id, '&Save Image', 'Save image as PNG')
586        wx.EVT_MENU(self, wx_id, self.onSaveImage)
587        wx_id = ids.next()
588        self._slicerpop.Append(wx_id, '&Print Image', 'Print image ')
589        wx.EVT_MENU(self, wx_id, self.onPrint)
590
591        wx_id = ids.next()
592        self._slicerpop.Append(wx_id, '&Copy to Clipboard',
593                               'Copy to the clipboard')
594        wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
595
596        self._slicerpop.AppendSeparator()
597
598        for plot in self.plots.values():
599            # title = plot.title
600            name = plot.name
601            plot_menu = wx.Menu()
602            if self.graph.selected_plottable:
603                if not self.graph.selected_plottable in self.plots.keys():
604                    continue
605                if plot != self.plots[self.graph.selected_plottable]:
606                    continue
607
608            wx_id = ids.next()
609            plot_menu.Append(wx_id, "&DataInfo", name)
610            wx.EVT_MENU(self, wx_id, self. _onDataShow)
611            wx_id = ids.next()
612            plot_menu.Append(wx_id, "&Save Points as a File", name)
613            wx.EVT_MENU(self, wx_id, self._onSave)
614            plot_menu.AppendSeparator()
615
616            # add menu of other plugins
617            item_list = self.parent.get_current_context_menu(self)
618            if (not item_list == None) and (not len(item_list) == 0):
619                for item, wx_id in zip(item_list, [ids.next() for i in range(len(item_list))]):
620
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
684        if self.position != None:
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"
761        if self.parent != None:
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"
779        if self.parent != None:
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
811        if curr_color == None:
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.