source: sasview/sansguiframe/src/sans/guiframe/local_perspectives/plotting/masking.py @ cce182ae

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 cce182ae was 046af80, checked in by Jae Cho <jhjcho@…>, 13 years ago

simple axis labels

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