source: branches/casa-prerelease/pre-asap/python/casatoolbar.py@ 2156

Last change on this file since 2156 was 2119, checked in by Kana Sugimoto, 14 years ago

merged modifications in trunk (r2118)

File size: 16.6 KB
RevLine 
[1724]1import os
[1981]2import matplotlib, numpy
3from asap.logging import asaplog, asaplog_post_dec
[1884]4
[1724]5######################################
6## Add CASA custom toolbar ##
7######################################
8class CustomToolbarCommon:
9 def __init__(self,parent):
[2119]10 self.plotter = parent
[1724]11 #self.figmgr=self.plotter._plotter.figmgr
12
13 ### select the nearest spectrum in pick radius
[1826]14 ### and display spectral value on the toolbar.
[1724]15 def _select_spectrum(self,event):
16 # Do not fire event when in zooming/panning mode
17 mode = self.figmgr.toolbar.mode
[1826]18 if not mode == '':
19 return
20 # When selected point is out of panels
[1724]21 if event.inaxes == None:
[1826]22 return
[1724]23 # If not left button
24 if event.button != 1:
[1826]25 return
[1724]26
[2119]27 xclick = event.xdata
28 yclick = event.ydata
29 dist2 = 1000.
30 pickline = None
[1826]31 # If the pannel has picable objects
[2119]32 pflag = False
[1724]33 for lin in event.inaxes.lines:
[1826]34 if not lin.pickable():
35 continue
[2119]36 pflag = True
[1826]37 flag,pind = lin.contains(event)
38 if not flag:
39 continue
40 # Get nearest point
41 inds = pind['ind']
42 xlin = lin.get_xdata()
43 ylin = lin.get_ydata()
44 for i in inds:
45 d2=(xlin[i]-xclick)**2+(ylin[i]-yclick)**2
46 if dist2 >= d2:
47 dist2 = d2
48 pickline = lin
49 # No pickcable line in the pannel
50 if not pflag:
51 return
52 # Pickable but too far from mouse position
53 elif pickline is None:
[2119]54 picked = 'No line selected.'
[1826]55 self.figmgr.toolbar.set_message(picked)
56 return
[1724]57 del pind, inds, xlin, ylin
[1826]58 # Spectra are Picked
[1724]59 theplot = self.plotter._plotter
[1826]60 thetoolbar = self.figmgr.toolbar
61 thecanvas = self.figmgr.canvas
62 # Disconnect the default motion notify event
63 # Notice! the other buttons are also diabled!!!
64 thecanvas.mpl_disconnect(thetoolbar._idDrag)
[1724]65 # Get picked spectrum
66 xdata = pickline.get_xdata()
67 ydata = pickline.get_ydata()
[2119]68 titl = pickline.get_label()
69 titp = event.inaxes.title.get_text()
70 panel0 = event.inaxes
71 picked = "Selected: '"+titl+"' in panel '"+titp+"'."
[1826]72 thetoolbar.set_message(picked)
73 # Generate a navigation window
[1724]74 #naviwin=Navigationwindow(titp,titl)
75 #------------------------------------------------------#
76 # Show spectrum data at mouse position
77 def spec_data(event):
[1826]78 # Getting spectrum data of neiboring point
[2119]79 xclick = event.xdata
[1826]80 if event.inaxes != panel0:
81 return
[2119]82 ipoint = len(xdata)-1
[1826]83 for i in range(len(xdata)-1):
[2119]84 xl = xclick - xdata[i]
85 xr = xclick - xdata[i+1]
[1826]86 if xl*xr <= 0.:
87 ipoint = i
88 break
89 # Output spectral value on the navigation window
[2119]90 posi = '[ %s, %s ]: x = %.2f value = %.2f'\
91 %(titl,titp,xdata[ipoint],ydata[ipoint])
[1826]92 #naviwin.posi.set(posi)
93 thetoolbar.set_message(posi)
[1724]94 #------------------------------------------------------#
95 # Disconnect from mouse events
96 def discon(event):
[1826]97 #naviwin.window.destroy()
98 theplot.register('motion_notify',None)
99 # Re-activate the default motion_notify_event
[2119]100 thetoolbar._idDrag = thecanvas.mpl_connect('motion_notify_event',
101 thetoolbar.mouse_move)
[1826]102 theplot.register('button_release',None)
103 return
[1724]104 #------------------------------------------------------#
105 # Show data value along with mouse movement
[1826]106 theplot.register('motion_notify',spec_data)
[1724]107 # Finish events when mouse button is released
108 theplot.register('button_release',discon)
109
110
[1826]111 ### Calculate statistics of the selected area.
[1724]112 def _single_mask(self,event):
113 # Do not fire event when in zooming/panning mode
[1826]114 if not self.figmgr.toolbar.mode == '':
115 return
[1724]116 # When selected point is out of panels
117 if event.inaxes == None:
[1826]118 return
[2119]119 if event.button == 1:
[1826]120 baseinv=True
121 elif event.button == 3:
122 baseinv=False
123 else:
124 return
[1724]125
[1826]126 def _calc_stats():
127 msk=mymask.get_mask()
[2119]128 statstr = ['max', 'min', 'mean', 'median', 'sum', 'stddev', 'rms']
129 for stat in statstr:
130 mymask.scan.stats(stat=stat,mask=msk)
[1724]131
[1826]132 # Interactive mask definition
[1724]133 from asap.interactivemask import interactivemask
[2119]134 mymask = interactivemask(plotter=self.plotter,scan=self.plotter._data)
[1826]135 # Create initial mask
136 mymask.set_basemask(invert=baseinv)
137 # Inherit event
138 mymask.set_startevent(event)
139 # Set callback func
140 mymask.set_callback(_calc_stats)
141 # Selected mask
142 mymask.select_mask(once=True,showmask=False)
[1724]143
[1884]144 def _mod_note(self,event):
145 # Do not fire event when in zooming/panning mode
146 if not self.figmgr.toolbar.mode == '':
147 return
[2119]148 if event.button == 1:
[1884]149 self.notewin.load_textwindow(event)
150 elif event.button == 3 and self._note_picked(event):
[1885]151 self.notewin.load_modmenu(event)
[1884]152 return
153
154 def _note_picked(self,event):
155 # just briefly check if any texts are picked
156 for textobj in self.canvas.figure.texts:
157 if textobj.contains(event)[0]:
158 return True
159 for ax in self.canvas.figure.axes:
160 for textobj in ax.texts:
161 if textobj.contains(event)[0]:
162 return True
163 #print "No text picked"
164 return False
165
[1983]166 ### Page chages
167 ### go to the previous page
168 def prev_page(self):
169 self.figmgr.toolbar.set_message('plotting the previous page')
[2119]170 #self._pause_buttons(operation="start",msg='plotting the previous page')
[1983]171 self._new_page(goback=True)
[2119]172 #self._pause_buttons(operation="end")
[1983]173
174 ### go to the next page
175 def next_page(self):
176 self.figmgr.toolbar.set_message('plotting the next page')
[2119]177 #self._pause_buttons(operation="start",msg='plotting the next page')
[1983]178 self._new_page(goback=False)
[2119]179 #self._pause_buttons(operation="end")
[1983]180
181 ### actual plotting of the new page
182 def _new_page(self,goback=False):
[2052]183 top = None
[2054]184 header = self.plotter._headtext
185 reset = False
186 doheader = (isinstance(header['textobj'],list) and \
187 len(header['textobj']) > 0)
[1981]188 if self.plotter._startrow <= 0:
189 msg = "The page counter is reset due to chages of plot settings. "
190 msg += "Plotting from the first page."
191 asaplog.push(msg)
192 asaplog.post('WARN')
[2054]193 reset = True
[1983]194 goback = False
[2054]195 if doheader:
196 extrastr = selstr = ''
197 if header.has_key('extrastr'):
198 extrastr = header['extrastr']
199 if header.has_key('selstr'):
200 selstr = header['selstr']
201 self.plotter._reset_header()
202 if doheader:
[2052]203 top = self.plotter._plotter.figure.subplotpars.top
[2054]204 fontsize = header['textobj'][0].get_fontproperties().get_size()
[2052]205
[1913]206 self.plotter._plotter.hold()
[1983]207 if goback:
[1981]208 self._set_prevpage_counter()
[1945]209 #self.plotter._plotter.clear()
[1982]210 self.plotter._plot(self.plotter._data)
[1983]211 self.set_pagecounter(self._get_pagenum())
[2054]212 # Plot header information
213 if header['textobj']:
[2052]214 if top and top != self.plotter._margins[3]:
215 # work around for sdplot in CASA. complete checking in future?
216 self.plotter._plotter.figure.subplots_adjust(top=top)
[2054]217 if reset:
218 self.plotter.print_header(plot=True,fontsize=fontsize,selstr=selstr, extrastr=extrastr)
219 else:
220 self.plotter._header_plot(header['string'],fontsize=fontsize)
221 self.plotter._plotter.release()
222 self.plotter._plotter.tidy()
[1913]223 self.plotter._plotter.show(hardrefresh=False)
[2052]224 del top
[1913]225
[1983]226 ### calculate the panel ID and start row to plot the previous page
[1981]227 def _set_prevpage_counter(self):
228 # set row and panel counters to those of the 1st panel of previous page
229 maxpanel = 16
230 # the ID of the last panel in current plot
231 lastpanel = self.plotter._ipanel
232 # the number of current subplots
233 currpnum = len(self.plotter._plotter.subplots)
234 # the nuber of previous subplots
235 prevpnum = None
236 if self.plotter._rows and self.plotter._cols:
237 # when user set layout
238 prevpnum = self.plotter._rows*self.plotter._cols
239 else:
240 # no user specification
241 prevpnum = maxpanel
[2119]242
[1981]243 start_ipanel = max(lastpanel-currpnum-prevpnum+1, 0)
244 # set the pannel ID of the last panel of prev-prev page
245 self.plotter._ipanel = start_ipanel-1
246 if self.plotter._panelling == 'r':
247 self.plotter._startrow = start_ipanel
248 else:
249 # the start row number of the next panel
250 self.plotter._startrow = self.plotter._panelrows[start_ipanel]
251 del lastpanel,currpnum,prevpnum,start_ipanel
[1979]252
[1983]253 ### refresh the page counter
254 ### refresh the page counter
255 def set_pagecounter(self,page):
256 nwidth = int(numpy.ceil(numpy.log10(max(page,1))))+1
257 nwidth = max(nwidth,4)
258 formatstr = '%'+str(nwidth)+'d'
259 self.show_pagenum(page,formatstr)
260
261 def show_pagenum(self,pagenum,formatstr):
262 # passed to backend dependent class
263 pass
264
[1981]265 def _get_pagenum(self):
266 maxpanel = 16
[1982]267 # get the ID of last panel in the current page
268 idlastpanel = self.plotter._ipanel
[1981]269 if self.plotter._rows and self.plotter._cols:
270 ppp = self.plotter._rows*self.plotter._cols
271 else:
272 ppp = maxpanel
[1982]273 return int(idlastpanel/ppp)+1
[1981]274
[2119]275 # pause buttons for slow operations. implemented at a backend dependent class
276 def _pause_buttons(self,operation="end",msg=""):
277 pass
278
279
[1724]280#####################################
281## Backend dependent Classes ##
282#####################################
283### TkAgg
[1826]284if matplotlib.get_backend() == 'TkAgg':
285 import Tkinter as Tk
[1884]286 from notationwindow import NotationWindowTkAgg
[1826]287
[1768]288class CustomToolbarTkAgg(CustomToolbarCommon, Tk.Frame):
[1724]289 def __init__(self,parent):
290 from asap.asapplotter import asapplotter
[1826]291 if not isinstance(parent,asapplotter):
292 return False
293 if not parent._plotter:
294 return False
[1981]295 self._p = parent._plotter
296 self.figmgr = self._p.figmgr
297 self.canvas = self.figmgr.canvas
298 self.mode = ''
299 self.button = True
[1983]300 self.pagecount = None
301 CustomToolbarCommon.__init__(self,parent)
[2119]302 self.notewin = NotationWindowTkAgg(master=self.canvas)
[1724]303 self._add_custom_toolbar()
304
305 def _add_custom_toolbar(self):
[1768]306 Tk.Frame.__init__(self,master=self.figmgr.window)
[2119]307 #self.bSpec = self._NewButton(master=self,
308 # text='spec value',
309 # command=self.spec_show)
310 self.bNote = self._NewButton(master=self,
311 text='notation',
312 command=self.modify_note)
[1981]313
[2119]314 self.bStat = self._NewButton(master=self,
315 text='statistics',
316 command=self.stat_cal)
317 self.bQuit = self._NewButton(master=self,
318 text='Quit',
319 command=self.quit,
320 side=Tk.RIGHT)
[1983]321
[1981]322 # page change oparations
[1983]323 frPage = Tk.Frame(master=self,borderwidth=2,relief=Tk.GROOVE)
324 frPage.pack(ipadx=2,padx=10,side=Tk.RIGHT)
325 self.lPagetitle = Tk.Label(master=frPage,text='Page:',padx=5)
[1981]326 self.lPagetitle.pack(side=Tk.LEFT)
[1983]327 self.pagecount = Tk.StringVar(master=frPage)
328 self.lPagecount = Tk.Label(master=frPage,
329 textvariable=self.pagecount,
330 padx=5,bg='white')
331 self.lPagecount.pack(side=Tk.LEFT,padx=3)
[1981]332
[2119]333 self.bNext = self._NewButton(master=frPage,
334 text=' + ',
335 command=self.next_page)
336 self.bPrev = self._NewButton(master=frPage,
337 text=' - ',
338 command=self.prev_page)
[1981]339
[1914]340 if os.uname()[0] != 'Darwin':
[1981]341 self.bPrev.config(padx=5)
[1914]342 self.bNext.config(padx=5)
[1983]343
[1768]344 self.pack(side=Tk.BOTTOM,fill=Tk.BOTH)
[1983]345 self.pagecount.set(' '*4)
[1768]346
[1724]347 self.disable_button()
[1768]348 return #self
[1724]349
350 def _NewButton(self, master, text, command, side=Tk.LEFT):
[1826]351 if os.uname()[0] == 'Darwin':
[1724]352 b = Tk.Button(master=master, text=text, command=command)
353 else:
[1826]354 b = Tk.Button(master=master, text=text, padx=2, pady=2,
355 command=command)
[1724]356 b.pack(side=side)
357 return b
[1826]358
[1983]359 def show_pagenum(self,pagenum,formatstr):
360 self.pagecount.set(formatstr % (pagenum))
361
[1724]362 def spec_show(self):
363 if not self.figmgr.toolbar.mode == '' or not self.button: return
364 self.figmgr.toolbar.set_message('spec value: drag on a spec')
365 if self.mode == 'spec': return
[1979]366 #self.bStat.config(relief='raised')
367 #self.bSpec.config(relief='sunken')
368 #self.bNote.config(relief='raised')
[2119]369 self.mode = 'spec'
[1885]370 self.notewin.close_widgets()
[1724]371 self.__disconnect_event()
372 self._p.register('button_press',self._select_spectrum)
373
374 def stat_cal(self):
375 if not self.figmgr.toolbar.mode == '' or not self.button: return
376 self.figmgr.toolbar.set_message('statistics: select a region')
[1979]377 if self.mode == 'stat':
378 # go back to spec mode
379 self.bStat.config(relief='raised')
380 self.spec_show()
381 return
382 #self.bSpec.config(relief='raised')
[1724]383 self.bStat.config(relief='sunken')
[1884]384 self.bNote.config(relief='raised')
[2119]385 self.mode = 'stat'
[1885]386 self.notewin.close_widgets()
[1724]387 self.__disconnect_event()
388 self._p.register('button_press',self._single_mask)
389
[1884]390 def modify_note(self):
[1890]391 if not self.figmgr.toolbar.mode == '': return
[1884]392 self.figmgr.toolbar.set_message('text: select a position/text')
[1979]393 if self.mode == 'note':
394 self.bNote.config(relief='raised')
[2119]395 self.mode = 'none'
[1979]396 self.spec_show()
397 return
398 #self.bSpec.config(relief='raised')
[1884]399 self.bStat.config(relief='raised')
400 self.bNote.config(relief='sunken')
[2119]401 self.mode = 'note'
[1884]402 self.__disconnect_event()
403 self._p.register('button_press',self._mod_note)
404
[1724]405 def quit(self):
406 self.__disconnect_event()
[1765]407 #self.delete_bar()
408 self.disable_button()
[1724]409 self.figmgr.window.wm_withdraw()
410
411 def enable_button(self):
412 if self.button: return
[1979]413 #self.bSpec.config(state=Tk.NORMAL)
[1724]414 self.bStat.config(state=Tk.NORMAL)
[2119]415 self.button = True
[1724]416 self.spec_show()
[1826]417
[1724]418 def disable_button(self):
419 if not self.button: return
[1981]420 #self.bSpec.config(relief='raised', state=Tk.DISABLED)
[1826]421 self.bStat.config(relief='raised', state=Tk.DISABLED)
[1981]422 #self.bNext.config(state=Tk.DISABLED)
[1921]423 #self.bPrev.config(state=Tk.DISABLED)
[2119]424 self.button = False
425 self.mode = ''
[1724]426 self.__disconnect_event()
427
[1913]428 def enable_next(self):
429 self.bNext.config(state=Tk.NORMAL)
430
431 def disable_next(self):
432 self.bNext.config(state=Tk.DISABLED)
433
434 def enable_prev(self):
[1981]435 self.bPrev.config(state=Tk.NORMAL)
[1913]436
437 def disable_prev(self):
[1981]438 self.bPrev.config(state=Tk.DISABLED)
[1913]439
[2119]440 # pause buttons for slow operations
441 def _pause_buttons(self,operation="end",msg=""):
442 buttons = ["bStat","bNote","bQuit"]
443 if operation == "start":
444 state = Tk.DISABLED
445 else:
446 state = Tk.NORMAL
447 for btn in buttons:
448 getattr(self,btn).config(state=state)
449 self.figmgr.toolbar.set_message(msg)
450
[1724]451 def delete_bar(self):
452 self.__disconnect_event()
[1768]453 self.destroy()
[1724]454
455 def __disconnect_event(self):
456 self._p.register('button_press',None)
457 self._p.register('button_release',None)
Note: See TracBrowser for help on using the repository browser.