source: sasview/src/sans/guiframe/local_perspectives/plotting/masking.py @ 8f52edd

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 8f52edd was 8f52edd, checked in by Mathieu Doucet <doucetm@…>, 10 years ago

Update guiframe imports for latest move

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