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

Last change on this file since f5f8553 was 5251ec6, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

improved support for py37 in sasgui

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