source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/masking.py @ 5251ec6

magnetic_scattrelease-4.2.2ticket-1009ticket-1249
Last change on this file since 5251ec6 was 5251ec6, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

improved support for py37 in sasgui

  • Property mode set to 100644
File size: 23.9 KB
RevLine 
[959eb01]1"""
2    Mask editor
3"""
4################################################################################
5# This software was developed by the University of Tennessee as part of the
6# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
7# project funded by the US National Science Foundation.
8#
9# If you use DANSE applications to do scientific research that leads to
10# publication, we ask that you acknowledge the use of the software with the
11# following sentence:
12#
13# This work benefited from DANSE software developed under NSF award DMR-0520547.
14#
15# copyright 2008, University of Tennessee
16################################################################################
17
18
19# #Todo: cleaning up, improving the maskplotpanel initialization, and testing.
20import sys
21import time
22import math
23import copy
[5251ec6]24from functools import partial
25
26import wx
[959eb01]27import numpy as np
[5251ec6]28import matplotlib.cm as cm
29
[959eb01]30from sas.sasgui.plottools.PlotPanel import PlotPanel
31from sas.sasgui.plottools.plottables import Graph
32from sas.sasgui.guiframe.dataFitting import Data1D, Data2D
33from sas.sasgui.guiframe.events import SlicerEvent
34from sas.sasgui.guiframe.events import StatusEvent
[5251ec6]35
36from .binder import BindArtist
37from .boxMask import BoxMask
38from .sector_mask import SectorMask
39from .AnnulusSlicer import CircularMask
40
[959eb01]41
42(InternalEvent, EVT_INTERNAL) = wx.lib.newevent.NewEvent()
43
44DEFAULT_CMAP = cm.get_cmap('jet')
45_BOX_WIDTH = 76
46_SCALE = 1e-6
47_STATICBOX_WIDTH = 380
48
49# SLD panel size
50if sys.platform.count("win32") > 0:
51    PANEL_SIZE = 350
52    FONT_VARIANT = 0
53else:
54    PANEL_SIZE = 300
55    FONT_VARIANT = 1
56
57from sas.sascalc.data_util.calcthread import CalcThread
58
59class CalcPlot(CalcThread):
60    """
61    Compute Resolution
62    """
63    def __init__(self,
64                 id=-1,
65                 panel=None,
66                 image=None,
67                 completefn=None,
68                 updatefn=None,
69                 elapsed=0,
70                 yieldtime=0.01,
71                 worktime=0.01):
72        """
73        """
74        CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime)
75        self.starttime = 0
76        self.id = id
77        self.panel = panel
78        self.image = image
79
80    def compute(self):
81        """
[20fa5fe]82        executing computation
[959eb01]83        """
84        elapsed = time.time() - self.starttime
85
86        self.complete(panel=self.panel, image=self.image, elapsed=elapsed)
87
88
89class MaskPanel(wx.Dialog):
90    """
91    Provides the Mask Editor GUI.
92    """
93    # # Internal nickname for the window, used by the AUI manager
94    window_name = "Mask Editor"
95    # # Name to appear on the window title bar
96    window_caption = "Mask Editor"
97    # # Flag to tell the AUI manager to put this panel in the center pane
98    CENTER_PANE = True
99    def __init__(self, parent=None, base=None,
100                 data=None, id=-1, *args, **kwds):
101        kwds["style"] = wx.DEFAULT_DIALOG_STYLE
102        kwds["size"] = wx.Size(_STATICBOX_WIDTH * 0.8, PANEL_SIZE)
103        wx.Dialog.__init__(self, parent, id=id, *args, **kwds)
104
[7432acb]105        if data is not None:
[959eb01]106            # Font size
107            kwds = []
108            self.SetWindowVariant(variant=FONT_VARIANT)
109            self.SetTitle("Mask Editor for " + data.name)
110            self.parent = base
111            self.data = data
112            self.str = self.data.__str__()
113            # # mask for 2D
114            self.mask = data.mask
115            self.default_mask = copy.deepcopy(data.mask)
116            # # masked data from GUI
117            self.slicer_mask = None
118            self.slicer = None
119            self.slicer_z = 5
120            self.data.interactive = True
121            # # when 2 data have the same id override the 1 st plotted
122            self.name = self.data.name
123            # Panel for 2D plot
124            self.plotpanel = Maskplotpanel(self, -1,
125                                           style=wx.TRANSPARENT_WINDOW)
126            self.cmap = DEFAULT_CMAP
127            # # Create Artist and bind it
128            self.subplot = self.plotpanel.subplot
129            self.connect = BindArtist(self.subplot.figure)
130            self._setup_layout()
131            self.newplot = Data2D(image=self.data.data)
132            self.newplot.setValues(self.data)
133            self.plotpanel.add_image(self.newplot)
134            self._update_mask(self.mask)
135            self.Centre()
136            self.Layout()
137            # bind evt_close to _draw in fitpage
138            self.Bind(wx.EVT_CLOSE, self.OnClose)
139
140    def ShowMessage(self, msg=''):
141        """
142        Show error message when mask covers whole data area
143        """
144        mssg = 'Erase, redraw or clear the mask. \n\r'
145        mssg += 'The data range can not be completely masked... \n\r'
146        mssg += msg
147        wx.MessageBox(mssg, 'Error', wx.OK | wx.ICON_ERROR)
148
149    def _setup_layout(self):
150        """
151        Set up the layout
152        """
153        note = "Note: This masking applies\n     only to %s." % self.data.name
154        note_txt = wx.StaticText(self, -1, note)
155        note_txt.SetForegroundColour(wx.RED)
156        shape = "Select a Shape for Masking:"
157        #  panel
158        sizer = wx.GridBagSizer(10, 10)
159        #---------inputs----------------
160        shape_txt = wx.StaticText(self, -1, shape)
161        sizer.Add(shape_txt, (1, 1), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
162        self.innersector_rb = wx.RadioButton(self, -1, "Double Wings")
163        self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=SectorMask, inside=True),
164                  id=self.innersector_rb.GetId())
165        sizer.Add(self.innersector_rb, (2, 1),
166                  flag=wx.RIGHT | wx.BOTTOM, border=5)
167        self.innercircle_rb = wx.RadioButton(self, -1, "Circular Disk")
168        self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=CircularMask, inside=True),
169                  id=self.innercircle_rb.GetId())
170        sizer.Add(self.innercircle_rb, (3, 1),
171                  flag=wx.RIGHT | wx.BOTTOM, border=5)
172        self.innerbox_rb = wx.RadioButton(self, -1, "Rectangular Disk")
173        self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=BoxMask, inside=True),
174                  id=self.innerbox_rb.GetId())
175        sizer.Add(self.innerbox_rb, (4, 1), flag=wx.RIGHT | wx.BOTTOM, border=5)
176        self.outersector_rb = wx.RadioButton(self, -1, "Double Wing Window")
177        self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=SectorMask, inside=False),
178                  id=self.outersector_rb.GetId())
179        sizer.Add(self.outersector_rb, (5, 1),
180                  flag=wx.RIGHT | wx.BOTTOM, border=5)
181        self.outercircle_rb = wx.RadioButton(self, -1, "Circular Window")
182        self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=CircularMask, inside=False),
183                  id=self.outercircle_rb.GetId())
184        sizer.Add(self.outercircle_rb, (6, 1),
185                  flag=wx.RIGHT | wx.BOTTOM, border=5)
186        self.outerbox_rb = wx.RadioButton(self, -1, "Rectangular Window")
187        self.Bind(wx.EVT_RADIOBUTTON, partial(self._on_mask, slicer=BoxMask, inside=False),
188                  id=self.outerbox_rb.GetId())
189        sizer.Add(self.outerbox_rb, (7, 1), flag=wx.RIGHT | wx.BOTTOM, border=5)
190        sizer.Add(note_txt, (8, 1), flag=wx.RIGHT | wx.BOTTOM, border=5)
191        self.innercircle_rb.SetValue(False)
192        self.outercircle_rb.SetValue(False)
193        self.innerbox_rb.SetValue(False)
194        self.outerbox_rb.SetValue(False)
195        self.innersector_rb.SetValue(False)
196        self.outersector_rb.SetValue(False)
197        sizer.Add(self.plotpanel, (0, 2), (13, 13),
198                  wx.EXPAND | wx.LEFT | wx.RIGHT, 15)
199
200        #-----Buttons------------1
201        id_button = wx.NewId()
202        button_add = wx.Button(self, id_button, "Add")
203        button_add.SetToolTipString("Add the mask drawn.")
204        button_add.Bind(wx.EVT_BUTTON, self._on_add_mask, id=button_add.GetId())
205        sizer.Add(button_add, (13, 7))
206        id_button = wx.NewId()
207        button_erase = wx.Button(self, id_button, "Erase")
208        button_erase.SetToolTipString("Erase the mask drawn.")
209        button_erase.Bind(wx.EVT_BUTTON, self._on_erase_mask,
210                          id=button_erase.GetId())
211        sizer.Add(button_erase, (13, 8))
212        id_button = wx.NewId()
213        button_reset = wx.Button(self, id_button, "Reset")
214        button_reset.SetToolTipString("Reset the mask.")
215        button_reset.Bind(wx.EVT_BUTTON, self._on_reset_mask,
216                          id=button_reset.GetId())
217        sizer.Add(button_reset, (13, 9), flag=wx.RIGHT | wx.BOTTOM, border=15)
218        id_button = wx.NewId()
219        button_reset = wx.Button(self, id_button, "Clear")
220        button_reset.SetToolTipString("Clear all mask.")
221        button_reset.Bind(wx.EVT_BUTTON, self._on_clear_mask,
222                          id=button_reset.GetId())
223        sizer.Add(button_reset, (13, 10), flag=wx.RIGHT | wx.BOTTOM, border=15)
224        sizer.AddGrowableCol(3)
225        sizer.AddGrowableRow(2)
226        self.SetSizerAndFit(sizer)
227        self.Centre()
228        self.Show(True)
229
230    def _on_mask(self, event=None, slicer=BoxMask, inside=True):
231        """
232            Draw a slicer and use it as mask
233            :param event: wx event
234            :param slicer: Slicer class to use
235            :param inside: whether we mask what's inside or outside the slicer
236        """
237        # get ready for next evt
238        event.Skip()
239        # from boxMask import BoxMask
[7432acb]240        if event is not None:
[959eb01]241            self._on_clear_slicer(event)
242        self.slicer_z += 1
243        self.slicer = slicer(self, self.subplot,
244                             zorder=self.slicer_z, side=inside)
245        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
246        self.subplot.set_xlim(self.data.xmin, self.data.xmax)
247        self.update()
248        self.slicer_mask = self.slicer.update()
249
250    def _on_add_mask(self, event):
251        """
252        Add new mask to old mask
253        """
[ac07a3a]254        if self.slicer is not None:
[959eb01]255            data = Data2D()
256            data = self.data
257            self.slicer_mask = self.slicer.update()
258            data.mask = self.data.mask & self.slicer_mask
259            self._check_display_mask(data.mask, event)
260
261    def _check_display_mask(self, mask, event):
262        """
263        check if the mask valid and update the plot
264
265        :param mask: mask data
266        """
267        # # Redraw the current image
268        self._update_mask(mask)
269
270    def _on_erase_mask(self, event):
271        """
272        Erase new mask from old mask
273        """
[45dffa69]274        if self.slicer is not None:
[959eb01]275            self.slicer_mask = self.slicer.update()
276            mask = self.data.mask
277            mask[self.slicer_mask == False] = True
278            self._check_display_mask(mask, event)
279
280    def _on_reset_mask(self, event):
281        """
282        Reset mask to the original mask
283        """
284        self.slicer_z += 1
285        self.slicer = BoxMask(self, self.subplot,
286                              zorder=self.slicer_z, side=True)
287        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
288        self.subplot.set_xlim(self.data.xmin, self.data.xmax)
289        mask = copy.deepcopy(self.default_mask)
290        self.data.mask = mask
291        # update mask plot
292        self._check_display_mask(mask, event)
293
294    def _on_clear_mask(self, event):
295        """
296        Clear mask
297        """
298        self.slicer_z += 1
299        self.slicer = BoxMask(self, self.subplot,
300                              zorder=self.slicer_z, side=True)
301        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
302        self.subplot.set_xlim(self.data.xmin, self.data.xmax)
303        mask = np.ones(len(self.data.mask), dtype=bool)
304        self.data.mask = mask
305        # update mask plot
306        self._check_display_mask(mask, event)
307
308    def _on_clear_slicer(self, event):
309        """
310        Clear the slicer on the plot
311        """
[45dffa69]312        if self.slicer is not None:
[959eb01]313            self.slicer.clear()
314            self.subplot.figure.canvas.draw()
315            self.slicer = None
316
317    def update(self, draw=True):
318        """
319        Respond to changes in the model by recalculating the
320        profiles and resetting the widgets.
321        """
322        self.plotpanel.draw()
323
324    def _set_mask(self, mask):
325        """
326        Set mask
327        """
328        self.data.mask = mask
329
330    def set_plot_unfocus(self):
331        """
332        Not implemented
333        """
334        pass
335
336    def _update_mask(self, mask):
337        """
338        Respond to changes in masking
339        """
340        # the case of liitle numbers of True points
[7432acb]341        if len(mask[mask]) < 10 and self.data is not None:
[959eb01]342            self.ShowMessage()
343            mask = copy.deepcopy(self.mask)
344            self.data.mask = mask
345        else:
346            self.mask = mask
347        # make temperary data to plot
348        temp_mask = np.zeros(len(mask))
349        temp_data = copy.deepcopy(self.data)
350        # temp_data default is None
351        # This method is to distinguish between masked point and data point = 0.
352        temp_mask = temp_mask / temp_mask
353        temp_mask[mask] = temp_data.data[mask]
354        # set temp_data value for self.mask==True, else still None
355        # temp_mask[mask] = temp_data[mask]
356
357        # TODO: refactor this horrible logic
358        temp_data.data[mask == False] = temp_mask[mask == False]
359        self.plotpanel.clear()
[7432acb]360        if self.slicer is not None:
[959eb01]361            self.slicer.clear()
362            self.slicer = None
363        # Post slicer None event
364        event = self._getEmptySlicerEvent()
365        wx.PostEvent(self, event)
366
367        # #use this method
368        # set zmax and zmin to plot: Fix it w/ data.
369        if self.plotpanel.scale == 'log_{10}':
370            zmax = math.log10(max(self.data.data[self.data.data > 0]))
371            zmin = math.log10(min(self.data.data[self.data.data > 0]))
372        else:
373            zmax = max(self.data.data[self.data.data > 0])
374            zmin = min(self.data.data[self.data.data > 0])
375        # plot
376        self.plotpanel.image(data=temp_mask,
377                             qx_data=self.data.qx_data,
378                             qy_data=self.data.qy_data,
379                             xmin=self.data.xmin,
380                             xmax=self.data.xmax,
381                             ymin=self.data.ymin,
382                             ymax=self.data.ymax,
383                             zmin=zmin,
384                             zmax=zmax,
385                             cmap=self.cmap,
386                             color=0, symbol=0, label=self.data.name)
387        # axis labels
388        self.plotpanel.axes[0].set_xlabel('$\\rm{Q}_{x}(A^{-1})$')
389        self.plotpanel.axes[0].set_ylabel('$\\rm{Q}_{y}(A^{-1})$')
390        self.plotpanel.render()
391        self.plotpanel.subplot.figure.canvas.draw_idle()
392
393    def _getEmptySlicerEvent(self):
394        """
395        create an empty slicervent
396        """
397        self.innerbox_rb.SetValue(False)
398        self.outerbox_rb.SetValue(False)
399        self.innersector_rb.SetValue(False)
400        self.outersector_rb.SetValue(False)
401        self.innercircle_rb.SetValue(False)
402        self.outercircle_rb.SetValue(False)
403        return SlicerEvent(type=None,
404                           params=None,
405                           obj_class=None)
406
407    def _draw_model(self, event):
408        """
409         on_close, update the model2d plot
410        """
411        pass
412
413    def freeze_axes(self):
414        """
415        freeze axes
416        """
417        self.plotpanel.axes_frozen = True
418
419    def thaw_axes(self):
420        """
421        thaw axes
422        """
423        self.plotpanel.axes_frozen = False
424
425    def onMouseMotion(self, event):
426        """
427        onMotion event
428        """
429        pass
430
431    def onWheel(self, event):
432        """
433        on wheel event
434        """
435        pass
436
437    def OnClose(self, event):
438        """
439            Processing close event
440        """
441        try:
442            self.parent._draw_masked_model(event)
443        except:
444            # when called by data panel
445            event.Skip()
446            pass
447
448class FloatPanel(wx.Dialog):
449    """
450    Provides the Mask Editor GUI.
451    """
452    # # Internal nickname for the window, used by the AUI manager
453    window_name = "Plot"
454    # # Name to appear on the window title bar
455    window_caption = "Plot"
456    # # Flag to tell the AUI manager to put this panel in the center pane
457    CENTER_PANE = False
458    ID = wx.NewId()
459    def __init__(self, parent=None, base=None,
460                 data=None, dimension=1, id=ID, *args, **kwds):
461        kwds["style"] = wx.DEFAULT_DIALOG_STYLE
462        kwds["size"] = wx.Size(PANEL_SIZE * 1.5, PANEL_SIZE * 1.5)
463        wx.Dialog.__init__(self, parent, id=id, *args, **kwds)
464
[7432acb]465        if data is not None:
[959eb01]466            # Font size
467            kwds = []
468            self.SetWindowVariant(variant=FONT_VARIANT)
469            self.SetTitle("Plot " + data.name)
470            self.parent = base
471            self.data = data
472            self.str = self.data.__str__()
473            # # when 2 data have the same id override the 1 st plotted
474            self.name = self.data.name
475            self.dimension = dimension
476            # Panel for 2D plot
477            self.plotpanel = Maskplotpanel(self, -1, dimension,
478                                           style=wx.TRANSPARENT_WINDOW)
479            self.plotpanel._SetInitialSize()
480            self.plotpanel.prevXtrans = "x"
481            self.plotpanel.prevYtrans = "y"
482
483            self.cmap = DEFAULT_CMAP
484            # # Create Artist and bind it
485            self.subplot = self.plotpanel.subplot
486            self._setup_layout()
487            if self.dimension == 1:
488                self.newplot = Data1D(x=data.x, y=data.y,
489                                      dx=data.dx, dy=data.dy)
490                self.newplot.name = data.name
491            else:
492                self.newplot = Data2D(image=self.data.data)
493                self.newplot.setValues(self.data)
494                    # Compute and get the image plot
495            self.get_plot()
496            # self.plotpanel.add_image(self.newplot)
497            self.Centre()
498            self.Layout()
499
500    def get_plot(self):
501        """
502        Get Plot panel
503        """
504        cal_plot = CalcPlot(panel=self.plotpanel,
505                            image=self.newplot,
506                            completefn=self.complete)
507        cal_plot.queue()
508
509    def complete(self, panel, image, elapsed=None):
510        """
511        Plot image
512
513        :param image: newplot [plotpanel]
514        """
515        wx.CallAfter(panel.add_image, image)
516
517    def _setup_layout(self):
518        """
519        Set up the layout
520        """
521        #  panel
522        sizer = wx.GridBagSizer(10, 10)
523        if self.dimension == 3:
524            note = "Note: I am very SLOW.     Please be PATIENT...\n"
525            if len(self.data.data) > 3600:
526                note += "Rotation disabled for pixels > 60x60."
527            note_txt = wx.StaticText(self, -1, note)
528            note_txt.SetForegroundColour(wx.RED)
529            sizer.Add(note_txt, (0, 2), flag=wx.RIGHT | wx.TOP, border=5)
530
531        sizer.Add(self.plotpanel, (1, 0), (9, 9),
532                  wx.EXPAND | wx.ALL, 15)
533
534        sizer.AddGrowableCol(3)
535        sizer.AddGrowableRow(2)
536
537        self.SetSizerAndFit(sizer)
538        self.Centre()
539        self.Show(True)
540
541    def set_plot_unfocus(self):
542        """
543        Not implemented
544        """
545        pass
546
547    def _draw_model(self, event):
548        """
549         on_close, update the model2d plot
550        """
551        pass
552
553    def freeze_axes(self):
554        """
555        freeze axes
556        """
557        self.plotpanel.axes_frozen = True
558
559    def thaw_axes(self):
560        """
561        thaw axes
562        """
563        self.plotpanel.axes_frozen = False
564
565    def OnClose(self, event):
566        """
567        """
568        try:
569            self.plotpanel.subplot.figure.clf()
570            self.plotpanel.Close()
571        except:
572            # when called by data panel
573            event.Skip()
574            pass
575
576class Maskplotpanel(PlotPanel):
577    """
578    PlotPanel for Quick plot and masking plot
579    """
580    def __init__(self, parent, id=-1, dimension=2, color=None, dpi=None, **kwargs):
581        """
582        """
583        PlotPanel.__init__(self, parent, id=id, color=color, dpi=dpi, **kwargs)
584
585        # Keep track of the parent Frame
586        self.parent = parent
587        # Internal list of plottable names (because graph
588        # doesn't have a dictionary of handles for the plottables)
589        self.dimension = dimension
590        self.plots = {}
591        self.graph = Graph()
592        # add axis labels
593        self.graph.xaxis('\\rm{x} ', '')
594        self.graph.yaxis('\\rm{y} ', '')
595
596    def add_toolbar(self):
597        """
598        Add toolbar
599        """
600        # Not implemented
601        pass
602
603    def on_set_focus(self, event):
604        """
605        send to the parenet the current panel on focus
606        """
607        if self.dimension == 3:
608            pass
609        else:
610            self.draw()
611
612    def add_image(self, plot):
613        """
614        Add Image
615        """
616        self.plots[plot.name] = plot
617        # init graph
618        self.graph = Graph()
619        # add plot
620        self.graph.add(plot)
621        # add axes
622        if self.dimension == 1:
623            self.xaxis_label = '\\rm{x} '
624            self.xaxis_unit = ''
625            self.yaxis_label = '\\rm{y} '
626            self.yaxis_unit = ''
627        # draw
628        # message
629        status_type = 'progress'
630        msg = 'Plotting...'
631        self._status_info(msg, status_type)
632        status_type = 'stop'
633        self.graph.render(self)
634        self.subplot.figure.canvas.resizing = False
635        if self.dimension < 3:
636            self.graph.render(self)
637            self.subplot.figure.canvas.draw()
638        elif FONT_VARIANT:
639            self.subplot.figure.canvas.draw()
640        msg = 'Plotting Completed.'
641        self._status_info(msg, status_type)
642
643    def onMouseMotion(self, event):
644        """
645        Disable dragging 2D image
646        """
647        pass
648
649    def onWheel(self, event):
650        """
651        """
652        pass
653
654    def onLeftDown(self, event):
655        """
656        Disables LeftDown
657        """
658        pass
659
660    def onPick(self, event):
661        """
662        Disables OnPick
663        """
664        pass
665
666    def draw(self):
667        """
668        Draw
669        """
670        # message
671        status_type = 'progress'
672        msg = 'Plotting...'
673        self._status_info(msg, status_type)
674        status_type = 'stop'
675
676        if not self.dimension == 3:
677            self.subplot.figure.canvas.draw_idle()
678
679        msg = 'Plotting Completed.'
680        self._status_info(msg, status_type)
681
682    def onContextMenu(self, event):
683        """
684        Default context menu for a plot panel
685        """
686        # Selective Slicer plot popup menu
687        slicerpop = wx.Menu()
688
689        id = wx.NewId()
690        slicerpop.Append(id, '&Print Image', 'Print image')
691        wx.EVT_MENU(self, id, self.onPrint)
692
693        id = wx.NewId()
694        slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
695        wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
696
697        if self.dimension == 1:
698            id = wx.NewId()
699            slicerpop.Append(id, '&Change Scale')
700            wx.EVT_MENU(self, id, self._onProperties)
701        else:
702            slicerpop.AppendSeparator()
703            id_cm = wx.NewId()
704            slicerpop.Append(id_cm, '&Toggle Linear/Log scale')
705            wx.EVT_MENU(self, id_cm, self._onToggleScale)
706
707        pos = event.GetPosition()
708        pos = self.ScreenToClient(pos)
709        self.PopupMenu(slicerpop, pos)
710
711    def _status_info(self, msg='', type="update"):
712        """
713        Status msg
714        """
[7432acb]715        if self.parent.parent.parent is not None:
[959eb01]716            wx.PostEvent(self.parent.parent.parent,
717                         StatusEvent(status=msg, type=type))
718
719class ViewerFrame(wx.Frame):
720    """
721    Add comment
722    """
723    def __init__(self, parent, id, title):
724        """
725        comment
726        :param parent: parent panel/container
727        """
728        # Initialize the Frame object
729        wx.Frame.__init__(self, parent, id, title,
730                          wx.DefaultPosition, wx.Size(950, 850))
731        # Panel for 1D plot
732        self.plotpanel = Maskplotpanel(self, -1, style=wx.RAISED_BORDER)
733
734class ViewApp(wx.App):
735    def OnInit(self):
736        frame = ViewerFrame(None, -1, 'testView')
737        frame.Show(True)
738        # self.SetTopWindow(frame)
739
740        return True
741
742if __name__ == "__main__":
743    app = ViewApp(0)
744    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.