source: sasview/src/sas/guiframe/local_perspectives/plotting/masking.py @ 0ea31ca

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.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 0ea31ca was c039589, checked in by Mathieu Doucet <doucetm@…>, 10 years ago

pylint fixes

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