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@…>, 5 years ago

improved support for py37 in sasgui

  • Property mode set to 100644
File size: 23.9 KB
Line 
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
24from functools import partial
25
26import wx
27import numpy as np
28import matplotlib.cm as cm
29
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
35
36from .binder import BindArtist
37from .boxMask import BoxMask
38from .sector_mask import SectorMask
39from .AnnulusSlicer import CircularMask
40
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        """
82        executing computation
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
105        if data is not None:
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
240        if event is not None:
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        """
254        if self.slicer is not None:
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        """
274        if self.slicer is not None:
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        """
312        if self.slicer is not None:
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
341        if len(mask[mask]) < 10 and self.data is not None:
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()
360        if self.slicer is not None:
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
465        if data is not None:
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        """
715        if self.parent.parent.parent is not None:
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.