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

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 9a5097c was 9a5097c, checked in by andyfaff, 7 years ago

MAINT: import numpy as np

  • Property mode set to 100644
File size: 31.6 KB
Line 
1
2################################################################################
3# This software was developed by the University of Tennessee as part of the
4# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5# project funded by the US National Science Foundation.
6#
7# See the license text in license.txt
8#
9# copyright 2008, University of Tennessee
10################################################################################
11
12
13import wx
14import sys
15import math
16import numpy as np
17import logging
18from sas.sasgui.plottools.PlotPanel import PlotPanel
19from sas.sasgui.guiframe.events import StatusEvent
20from sas.sasgui.guiframe.events import PanelOnFocusEvent
21from sas.sasgui.guiframe.utils import PanelMenu, IdList
22from sas.sasgui.guiframe.panel_base import PanelBase
23from sas.sasgui.guiframe.gui_style import GUIFRAME_ICON
24from appearanceDialog import appearanceDialog
25from graphAppearance import graphAppearance
26
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 = (np.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.