00001 import os
00002 import matplotlib, numpy
00003 from asap.logging import asaplog, asaplog_post_dec
00004 from matplotlib.patches import Rectangle
00005 from asap.parameters import rcParams
00006 from asap import scantable
00007 from asap._asap import stmath
00008 from asap.utils import _n_bools, mask_not, mask_or
00009
00010
00011
00012
00013 class CustomToolbarCommon:
00014 def __init__(self,parent):
00015 self.plotter = parent
00016
00017
00018
00019
00020 def _select_spectrum(self,event):
00021
00022 mode = self.figmgr.toolbar.mode
00023 if not mode == '':
00024 return
00025
00026 if event.inaxes == None:
00027 return
00028
00029 if event.button != 1:
00030 return
00031
00032 xclick = event.xdata
00033 yclick = event.ydata
00034 dist2 = 1000.
00035 pickline = None
00036
00037 pflag = False
00038 for lin in event.inaxes.lines:
00039 if not lin.pickable():
00040 continue
00041 pflag = True
00042 flag,pind = lin.contains(event)
00043 if not flag:
00044 continue
00045
00046 inds = pind['ind']
00047 xlin = lin.get_xdata()
00048 ylin = lin.get_ydata()
00049 for i in inds:
00050 d2=(xlin[i]-xclick)**2+(ylin[i]-yclick)**2
00051 if dist2 >= d2:
00052 dist2 = d2
00053 pickline = lin
00054
00055 if not pflag:
00056 return
00057
00058 elif pickline is None:
00059 picked = 'No line selected.'
00060 self.figmgr.toolbar.set_message(picked)
00061 return
00062 del pind, inds, xlin, ylin
00063
00064 theplot = self.plotter._plotter
00065 thetoolbar = self.figmgr.toolbar
00066 thecanvas = self.figmgr.canvas
00067
00068
00069 thecanvas.mpl_disconnect(thetoolbar._idDrag)
00070
00071 xdata = pickline.get_xdata()
00072 ydata = pickline.get_ydata()
00073 titl = pickline.get_label()
00074 titp = event.inaxes.title.get_text()
00075 panel0 = event.inaxes
00076 picked = "Selected: '"+titl+"' in panel '"+titp+"'."
00077 thetoolbar.set_message(picked)
00078
00079
00080
00081
00082 def spec_data(event):
00083
00084 xclick = event.xdata
00085 if event.inaxes != panel0:
00086 return
00087 ipoint = len(xdata)-1
00088 for i in range(len(xdata)-1):
00089 xl = xclick - xdata[i]
00090 xr = xclick - xdata[i+1]
00091 if xl*xr <= 0.:
00092 ipoint = i
00093 break
00094
00095 posi = '[ %s, %s ]: x = %.2f value = %.2f'\
00096 %(titl,titp,xdata[ipoint],ydata[ipoint])
00097
00098 thetoolbar.set_message(posi)
00099
00100
00101 def discon(event):
00102
00103 theplot.register('motion_notify',None)
00104
00105 thetoolbar._idDrag = thecanvas.mpl_connect('motion_notify_event',
00106 thetoolbar.mouse_move)
00107 theplot.register('button_release',None)
00108 return
00109
00110
00111 theplot.register('motion_notify',spec_data)
00112
00113 theplot.register('button_release',discon)
00114
00115
00116
00117 def _mod_note(self,event):
00118
00119 if not self.figmgr.toolbar.mode == '':
00120 return
00121 if event.button == 1:
00122 self.notewin.load_textwindow(event)
00123 elif event.button == 3 and self._note_picked(event):
00124 self.notewin.load_modmenu(event)
00125 return
00126
00127 def _note_picked(self,event):
00128
00129 for textobj in self.canvas.figure.texts:
00130 if textobj.contains(event)[0]:
00131 return True
00132 for ax in self.canvas.figure.axes:
00133 for textobj in ax.texts:
00134 if textobj.contains(event)[0]:
00135 return True
00136
00137 return False
00138
00139
00140
00141
00142 def _single_mask(self,event):
00143
00144 if not self.figmgr.toolbar.mode == '':
00145 return
00146
00147 if event.inaxes == None:
00148 return
00149 if event.button == 1:
00150 exclude=False
00151 elif event.button == 3:
00152 exclude=True
00153 else:
00154 return
00155
00156 self._thisregion = {'axes': event.inaxes,'xs': event.x,
00157 'worldx': [event.xdata,event.xdata],
00158 'invert': exclude}
00159 self.xold = event.x
00160 self.xdataold = event.xdata
00161
00162 self.plotter._plotter.register('button_press',None)
00163 self.plotter._plotter.register('motion_notify', self._xspan_draw)
00164 self.plotter._plotter.register('button_press', self._xspan_end)
00165
00166 def _xspan_draw(self,event):
00167 if event.inaxes == self._thisregion['axes']:
00168 xnow = event.x
00169 self.xold = xnow
00170 self.xdataold = event.xdata
00171 else:
00172 xnow = self.xold
00173 try: self.lastspan
00174 except AttributeError: pass
00175 else:
00176 if self.lastspan: self._remove_span(self.lastspan)
00177
00178 self.lastspan = self._draw_span(self._thisregion['axes'],
00179 self._thisregion['xs'], xnow, fill="")
00180 del xnow
00181
00182 def _draw_span(self,axes,x0,x1,**kwargs):
00183 pass
00184
00185 def _remove_span(self,span):
00186 pass
00187
00188 @asaplog_post_dec
00189 def _xspan_end(self,event):
00190 if not self.figmgr.toolbar.mode == '':
00191 return
00192
00193
00194
00195 try: self.lastspan
00196 except AttributeError: pass
00197 else:
00198 self._remove_span(self.lastspan)
00199 del self.lastspan
00200 if event.inaxes == self._thisregion['axes']:
00201 xdataend = event.xdata
00202 else:
00203 xdataend = self.xdataold
00204
00205 self._thisregion['worldx'][1] = xdataend
00206
00207 self._subplot_stats(self._thisregion)
00208
00209
00210 self.plotter._plotter.register('button_press',None)
00211 self.plotter._plotter.register('motion_notify',None)
00212
00213 self._thisregion = None
00214 self.xdataold = None
00215 self.xold = None
00216
00217 self.plotter._plotter.register('button_press',self._single_mask)
00218
00219 def _subplot_stats(self,selection):
00220 statstr = ['max', 'min', 'median', 'mean', 'sum', 'std']
00221 panelstr = selection['axes'].title.get_text()
00222 ssep = "-"*70
00223 asaplog.push(ssep)
00224 asaplog.post()
00225 for line in selection['axes'].lines:
00226
00227 if line.get_label().startswith("_"):
00228 continue
00229 label = panelstr + ", "+line.get_label()
00230 x = line.get_xdata()
00231 newmsk = None
00232 selmsk = self._create_flag_from_array(x,
00233 selection['worldx'],
00234 selection['invert'])
00235 ydat = None
00236 y = line.get_ydata()
00237 if numpy.ma.isMaskedArray(y):
00238 ydat = y.data
00239 basemsk = y.mask
00240 else:
00241 ydat = y
00242 basemsk = False
00243 if not isinstance(basemsk, bool):
00244
00245 newmsk = mask_or(selmsk, basemsk)
00246 elif basemsk:
00247
00248 newmsk = basemsk
00249 else:
00250
00251 newmsk = selmsk
00252 mdata = numpy.ma.masked_array(ydat, mask=newmsk)
00253 statval = {}
00254 for stat in statstr:
00255
00256 statval[stat] = getattr(numpy.ma,stat)(mdata)
00257 self._print_stats(statval, statstr=statstr, label=label,\
00258 mask=selection['worldx'],\
00259 unmask=selection['invert'])
00260 asaplog.push(ssep)
00261 asaplog.post()
00262
00263 def _create_flag_from_array(self,x,masklist,invert):
00264
00265 if len(masklist) <= 1:
00266 asaplog.push()
00267 asaplog.post("masklist should be a list of 2 elements")
00268 asaplog.push("ERROR")
00269 n = len(x)
00270
00271 mask = _n_bools(n, True)
00272 minval = min(masklist[0:2])
00273 maxval = max(masklist[0:2])
00274 for i in range(n):
00275 if minval <= x[i] <= maxval:
00276 mask[i] = False
00277 if invert:
00278 mask = mask_not(mask)
00279 return mask
00280
00281 @asaplog_post_dec
00282 def _print_stats(self,stats,statstr=None,label="",mask=None,unmask=False):
00283 if not isinstance(stats,dict) or len(stats) == 0:
00284 asaplog.post()
00285 asaplog.push("Invalid statistic value")
00286 asaplog.post("ERROR")
00287 maskstr = "Not available"
00288 if mask:
00289 masktype = "mask"
00290 maskstr = str(mask)
00291 if unmask: masktype = "unmask"
00292
00293 sout = label + ", " + masktype + " = " + maskstr + "\n"
00294 statvals = []
00295 if not len(statstr):
00296 statstr = stats.keys()
00297 for key in statstr:
00298 sout += key.ljust(10)
00299 statvals.append(stats.pop(key))
00300 sout += "\n"
00301 sout += ("%f "*len(statstr) % tuple(statvals))
00302 asaplog.push(sout)
00303
00304
00305
00306
00307
00308 def prev_page(self):
00309 self.figmgr.toolbar.set_message('plotting the previous page')
00310
00311 self._new_page(goback=True)
00312
00313
00314
00315 def next_page(self):
00316 self.figmgr.toolbar.set_message('plotting the next page')
00317
00318 self._new_page(goback=False)
00319
00320
00321
00322 def _new_page(self,goback=False):
00323 top = None
00324 header = self.plotter._headtext
00325 reset = False
00326 doheader = (isinstance(header['textobj'],list) and \
00327 len(header['textobj']) > 0)
00328 if self.plotter._startrow <= 0:
00329 msg = "The page counter is reset due to chages of plot settings. "
00330 msg += "Plotting from the first page."
00331 asaplog.push(msg)
00332 asaplog.post('WARN')
00333 reset = True
00334 goback = False
00335 if doheader:
00336 extrastr = selstr = ''
00337 if header.has_key('extrastr'):
00338 extrastr = header['extrastr']
00339 if header.has_key('selstr'):
00340 selstr = header['selstr']
00341 self.plotter._reset_header()
00342 if doheader:
00343 top = self.plotter._plotter.figure.subplotpars.top
00344 fontsize = header['textobj'][0].get_fontproperties().get_size()
00345
00346 self.plotter._plotter.hold()
00347 if goback:
00348 self._set_prevpage_counter()
00349
00350 self.plotter._plot(self.plotter._data)
00351 self.set_pagecounter(self._get_pagenum())
00352
00353 if header['textobj']:
00354 if top and top != self.plotter._margins[3]:
00355
00356 self.plotter._plotter.figure.subplots_adjust(top=top)
00357 if reset:
00358 self.plotter.print_header(plot=True,fontsize=fontsize,selstr=selstr, extrastr=extrastr)
00359 else:
00360 self.plotter._header_plot(header['string'],fontsize=fontsize)
00361 self.plotter._plotter.release()
00362 self.plotter._plotter.tidy()
00363 self.plotter._plotter.show(hardrefresh=False)
00364 del top
00365
00366
00367 def _set_prevpage_counter(self):
00368
00369 maxpanel = 16
00370
00371 lastpanel = self.plotter._ipanel
00372
00373 currpnum = len(self.plotter._plotter.subplots)
00374
00375 prevpnum = None
00376 if self.plotter._rows and self.plotter._cols:
00377
00378 prevpnum = self.plotter._rows*self.plotter._cols
00379 else:
00380
00381 prevpnum = maxpanel
00382
00383 start_ipanel = max(lastpanel-currpnum-prevpnum+1, 0)
00384
00385 self.plotter._ipanel = start_ipanel-1
00386 if self.plotter._panelling == 'r':
00387 self.plotter._startrow = start_ipanel
00388 else:
00389
00390 self.plotter._startrow = self.plotter._panelrows[start_ipanel]
00391 del lastpanel,currpnum,prevpnum,start_ipanel
00392
00393
00394 def set_pagecounter(self,page):
00395 nwidth = int(numpy.ceil(numpy.log10(max(page,1))))+1
00396 nwidth = max(nwidth,4)
00397 formatstr = '%'+str(nwidth)+'d'
00398 self.show_pagenum(page,formatstr)
00399
00400 def show_pagenum(self,pagenum,formatstr):
00401
00402 pass
00403
00404 def _get_pagenum(self):
00405 maxpanel = 16
00406
00407 idlastpanel = self.plotter._ipanel
00408 if self.plotter._rows and self.plotter._cols:
00409 ppp = self.plotter._rows*self.plotter._cols
00410 else:
00411 ppp = maxpanel
00412 return int(idlastpanel/ppp)+1
00413
00414
00415 def _pause_buttons(self,operation="end",msg=""):
00416 pass
00417
00418
00419
00420
00421
00422
00423
00424 class NotationWindowCommon:
00425 """
00426 A base class to define the functions that the backend-based
00427 GUI notation class must implement to print/modify/delete notes on a canvas.
00428
00429 The following methods *must* be implemented in the backend-based
00430 parent class:
00431 _get_note : get text in text box
00432 _get_anchval : get anchor value selected
00433 """
00434 def __init__(self,master=None):
00435
00436 self.canvas = master
00437 self.event = None
00438 self.note = None
00439 self.anchors = ["figure","axes","data"]
00440 self.seltext = {}
00441 self.numnote = 0
00442
00443 @asaplog_post_dec
00444 def print_text(self):
00445 """
00446 Print a note on a canvas specified with the Notation window.
00447 Called when 'print' button selected on the window.
00448 """
00449 anchor = self.anchors[self._get_anchval()]
00450 notestr = self._get_note().rstrip("\n")
00451 if len(notestr.strip()) == 0:
00452
00453
00454 return
00455
00456 myaxes = None
00457 calcpos = True
00458 xpos = None
00459 ypos = None
00460 if self.seltext:
00461
00462 mycanvas = self.canvas
00463 oldanch = self.seltext['anchor']
00464 if oldanch != 'figure':
00465 myaxes = self.seltext['parent']
00466 calcpos = (anchor != oldanch)
00467 if not calcpos:
00468
00469
00470 parent = self.seltext['parent']
00471 transform = self.seltext['textobj'].get_transform()
00472 (xpos, ypos) = self.seltext['textobj'].get_position()
00473 elif anchor == "figure":
00474
00475 (x, y) = self.seltext['textobj']._get_xy_display()
00476 elif oldanch == "data":
00477
00478
00479 (x, y) = self.seltext['textobj'].get_position()
00480 else:
00481
00482
00483 pixpos = self.seltext['textobj']._get_xy_display()
00484 (w,h) = mycanvas.get_width_height()
00485 relpos = (pixpos[0]/float(w), pixpos[1]/float(h))
00486 if not myaxes:
00487 myaxes = self._get_axes_from_pos(relpos,mycanvas)
00488 if not myaxes:
00489 raise RuntimeError, "Axes resolution failed!"
00490 (x, y) = self._convert_pix2dat(relpos,myaxes)
00491 self._remove_seltext()
00492 elif self.event:
00493 mycanvas = self.event.canvas
00494 myaxes = self.event.inaxes
00495 if myaxes and (anchor != "figure"):
00496 x = self.event.xdata
00497 y = self.event.ydata
00498 else:
00499 x = self.event.x
00500 y = self.event.y
00501 else:
00502 raise RuntimeError, "No valid position to print data"
00503 return
00504
00505
00506 picker = True
00507
00508 ha = 'left'
00509
00510 va = 'top'
00511 if not calcpos:
00512
00513 pass
00514 elif anchor == "figure":
00515
00516 parent = mycanvas.figure
00517 transform = parent.transFigure
00518 (w,h) = mycanvas.get_width_height()
00519 xpos = x/float(w)
00520 ypos = y/float(h)
00521 elif myaxes:
00522
00523 parent = myaxes
00524 if anchor == "axes":
00525 transform = myaxes.transAxes
00526 lims = myaxes.get_xlim()
00527 xpos = (x-lims[0])/(lims[1]-lims[0])
00528 lims = myaxes.get_ylim()
00529 ypos = (y-lims[0])/(lims[1]-lims[0])
00530 else:
00531
00532 transform = myaxes.transData
00533 xpos = x
00534 ypos = y
00535 parent.text(xpos,ypos,notestr,transform=transform,
00536 ha=ha,va=va,picker=picker)
00537 mycanvas.draw()
00538
00539 self.numnote += 1
00540
00541
00542 msg = "Added note: '"+notestr+"'"
00543 msg += " @["+str(xpos)+", "+str(ypos)+"] ("+anchor+"-coord)"
00544 msg += "\ntotal number of notes are "+str(self.numnote)
00545 asaplog.push( msg )
00546
00547 def _get_axes_from_pos(self,pos,canvas):
00548 """helper function to get axes of a position in a plot (fig-coord)"""
00549 if len(pos) != 2:
00550 raise ValueError, "pixel position should have 2 elements"
00551 for axes in canvas.figure.axes:
00552
00553
00554
00555 try:
00556 axbox = axes.get_position().get_points()
00557 except AttributeError:
00558 axbox = self._oldpos2new(axes.get_position())
00559 if (axbox[0][0] <= pos[0] <= axbox[1][0]) and \
00560 (axbox[0][1] <= pos[1] <= axbox[1][1]):
00561 return axes
00562 return None
00563
00564
00565 def _oldpos2new(self,oldpos=None):
00566 return [[oldpos[0],oldpos[1]],[oldpos[0]+oldpos[2],oldpos[1]+oldpos[3]]]
00567
00568 def _convert_pix2dat(self,pos,axes):
00569 """
00570 helper function to convert a position in figure-coord (0-1) to
00571 data-coordinate of the axes
00572 """
00573
00574
00575 if len(pos) != 2:
00576 raise ValueError, "pixel position should have 2 elements"
00577
00578 bbox = axes.get_position()
00579 try:
00580 axpos = bbox.get_points()
00581 except AttributeError:
00582 axpos = self._oldpos2new(bbox)
00583
00584 if (pos[0] < axpos[0][0]) or (pos[1] < axpos[0][1]) \
00585 or (pos[0] > axpos[1][0]) or (pos[1] > axpos[1][1]):
00586 raise ValueError, "The position is out of the axes"
00587 xlims = axes.get_xlim()
00588 ylims = axes.get_ylim()
00589 wdat = xlims[1] - xlims[0]
00590 hdat = ylims[1] - ylims[0]
00591 xdat = xlims[0] + wdat*(pos[0] - axpos[0][0])/(axpos[1][0] - axpos[0][0])
00592 ydat = ylims[0] + hdat*(pos[1] - axpos[0][1])/(axpos[1][1] - axpos[0][1])
00593 return (xdat, ydat)
00594
00595 @asaplog_post_dec
00596 def _get_selected_text(self,event):
00597 """helper function to return a dictionary of the nearest note to the event."""
00598 (w,h) = event.canvas.get_width_height()
00599 dist2 = w*w+h*h
00600 selected = {}
00601 for textobj in self.canvas.figure.texts:
00602 if textobj.contains(event)[0]:
00603 d2 = self._get_text_dist2(event,textobj)
00604 if dist2 >= d2:
00605 dist2 = d2
00606 selected = {'anchor': 'figure', \
00607 'parent': event.canvas.figure, 'textobj': textobj}
00608 msg = "Fig loop: a text, '"+textobj.get_text()+"', at "
00609 msg += str(textobj.get_position())+" detected"
00610
00611 for ax in self.canvas.figure.axes:
00612 for textobj in ax.texts:
00613 if textobj.contains(event)[0]:
00614 d2 = self._get_text_dist2(event,textobj)
00615 if dist2 >= d2:
00616 anchor='axes'
00617 if ax.transData == textobj.get_transform():
00618 anchor = 'data'
00619 selected = {'anchor': anchor, \
00620 'parent': ax, 'textobj': textobj}
00621 msg = "Ax loop: a text, '"+textobj.get_text()+"', at "
00622 msg += str(textobj.get_position())+" detected"
00623
00624
00625 if selected:
00626 msg = "Selected (modify/delete): '"+selected['textobj'].get_text()
00627 msg += "' @"+str(selected['textobj'].get_position())
00628 msg += " ("+selected['anchor']+"-coord)"
00629 asaplog.push(msg)
00630
00631 return selected
00632
00633 def _get_text_dist2(self,event,textobj):
00634 """
00635 helper function to calculate square of distance between
00636 a event position and a text object.
00637 """
00638 (x,y) = textobj._get_xy_display()
00639 return (x-event.x)**2+(y-event.y)**2
00640
00641 def delete_note(self):
00642 """
00643 Remove selected note.
00644 """
00645
00646 self._remove_seltext()
00647 self.canvas.draw()
00648
00649 @asaplog_post_dec
00650 def _remove_seltext(self):
00651 """helper function to remove the selected note"""
00652 if len(self.seltext) < 3:
00653 raise ValueError, "Don't under stand selected text obj."
00654 return
00655 try:
00656 self.seltext['textobj'].remove()
00657 except NotImplementedError:
00658 self.seltext['parent'].texts.pop(self.seltext['parent'].texts.index(self.seltext['textobj']))
00659 self.numnote -= 1
00660
00661 textobj = self.seltext['textobj']
00662 msg = "Deleted note: '"+textobj.get_text()+"'"
00663 msg += "@"+str(textobj.get_position())\
00664 +" ("+self.seltext['anchor']+"-coord)"
00665 msg += "\ntotal number of notes are "+str(self.numnote)
00666 asaplog.push( msg )
00667
00668 self.seltext = {}
00669
00670 @asaplog_post_dec
00671 def cancel_delete(self):
00672 """
00673 Cancel deleting the selected note.
00674 Called when 'cancel' button selected on confirmation dialog.
00675 """
00676 asaplog.push( "Cancel deleting: '"+self.seltext['textobj'].get_text()+"'" )
00677 self.seltext = {}
00678
00679
00680
00681
00682
00683
00684 class CustomFlagToolbarCommon:
00685 def __init__(self,parent):
00686 self.plotter=parent
00687
00688 self._selregions = {}
00689 self._selpanels = []
00690 self._polygons = []
00691 self._thisregion = None
00692 self.xdataold=None
00693
00694
00695
00696 def _select_spectrum(self,event):
00697
00698 mode = self.figmgr.toolbar.mode
00699 if not mode == '':
00700 return
00701
00702 if event.inaxes == None:
00703 return
00704
00705 if event.button != 1:
00706 return
00707
00708 xclick = event.xdata
00709 yclick = event.ydata
00710 dist2 = 1000.
00711 pickline = None
00712
00713 pflag = False
00714 for lin in event.inaxes.lines:
00715 if not lin.pickable():
00716 continue
00717 pflag = True
00718 flag,pind = lin.contains(event)
00719 if not flag:
00720 continue
00721
00722 inds = pind['ind']
00723 xlin = lin.get_xdata()
00724 ylin = lin.get_ydata()
00725 for i in inds:
00726 d2=(xlin[i]-xclick)**2+(ylin[i]-yclick)**2
00727 if dist2 >= d2:
00728 dist2 = d2
00729 pickline = lin
00730
00731 if not pflag:
00732 return
00733
00734 elif pickline is None:
00735 picked = 'No line selected.'
00736 self.figmgr.toolbar.set_message(picked)
00737 return
00738 del pind, inds, xlin, ylin
00739
00740 theplot = self.plotter._plotter
00741 thetoolbar = self.figmgr.toolbar
00742 thecanvas = self.figmgr.canvas
00743
00744
00745 thecanvas.mpl_disconnect(thetoolbar._idDrag)
00746
00747 xdata = pickline.get_xdata()
00748 ydata = pickline.get_ydata()
00749 titl = pickline.get_label()
00750 titp = event.inaxes.title.get_text()
00751 panel0 = event.inaxes
00752 picked = "Selected: '"+titl+"' in panel '"+titp+"'."
00753 thetoolbar.set_message(picked)
00754
00755
00756
00757
00758 def spec_data(event):
00759
00760 xclick = event.xdata
00761 if event.inaxes != panel0:
00762 return
00763 ipoint = len(xdata)-1
00764 for i in range(len(xdata)-1):
00765 xl = xclick-xdata[i]
00766 xr = xclick-xdata[i+1]
00767 if xl*xr <= 0.:
00768 ipoint = i
00769 break
00770
00771 posi = '[ %s, %s ]: x = %.2f value = %.2f'\
00772 %(titl,titp,xdata[ipoint],ydata[ipoint])
00773
00774 thetoolbar.set_message(posi)
00775
00776
00777 def discon(event):
00778
00779 theplot.register('motion_notify',None)
00780
00781 thetoolbar._idDrag=thecanvas.mpl_connect('motion_notify_event',
00782 thetoolbar.mouse_move)
00783 theplot.register('button_release',None)
00784 return
00785
00786
00787 theplot.register('motion_notify',spec_data)
00788
00789 theplot.register('button_release',discon)
00790
00791
00792
00793 def _mod_note(self,event):
00794
00795 if not self.figmgr.toolbar.mode == '':
00796 return
00797 if event.button == 1:
00798 self.notewin.load_textwindow(event)
00799 elif event.button == 3 and self._note_picked(event):
00800 self.notewin.load_modmenu(event)
00801 return
00802
00803 def _note_picked(self,event):
00804
00805 for textobj in self.canvas.figure.texts:
00806 if textobj.contains(event)[0]:
00807 return True
00808 for ax in self.canvas.figure.axes:
00809 for textobj in ax.texts:
00810 if textobj.contains(event)[0]:
00811 return True
00812 return False
00813
00814
00815
00816 @asaplog_post_dec
00817 def _add_region(self,event):
00818 if not self.figmgr.toolbar.mode == '':
00819 return
00820 if event.button != 1 or event.inaxes == None:
00821 return
00822
00823 irow = int(self._getrownum(event.inaxes))
00824 if irow in self._selpanels:
00825 msg = "The whole spectrum is already selected"
00826 asaplog.post()
00827 asaplog.push(msg)
00828 asaplog.post('WARN')
00829 return
00830 self._thisregion = {'axes': event.inaxes,'xs': event.x,
00831 'worldx': [event.xdata,event.xdata]}
00832 self.plotter._plotter.register('button_press',None)
00833 self.xold = event.x
00834 self.xdataold = event.xdata
00835 self.plotter._plotter.register('motion_notify', self._xspan_draw)
00836 self.plotter._plotter.register('button_press', self._xspan_end)
00837
00838 def _xspan_draw(self,event):
00839 if event.inaxes == self._thisregion['axes']:
00840 xnow = event.x
00841 self.xold = xnow
00842 self.xdataold = event.xdata
00843 else:
00844 xnow = self.xold
00845 try: self.lastspan
00846 except AttributeError: pass
00847 else:
00848 if self.lastspan: self._remove_span(self.lastspan)
00849
00850
00851 self.lastspan = self._draw_span(self._thisregion['axes'],self._thisregion['xs'],xnow,fill="")
00852 del xnow
00853
00854 def _draw_span(self,axes,x0,x1,**kwargs):
00855 pass
00856
00857 def _remove_span(self,span):
00858 pass
00859
00860 @asaplog_post_dec
00861 def _xspan_end(self,event):
00862 if not self.figmgr.toolbar.mode == '':
00863 return
00864 if event.button != 1:
00865 return
00866
00867 try: self.lastspan
00868 except AttributeError: pass
00869 else:
00870 self._remove_span(self.lastspan)
00871 del self.lastspan
00872 if event.inaxes == self._thisregion['axes']:
00873 xdataend = event.xdata
00874 else:
00875 xdataend = self.xdataold
00876
00877 self._thisregion['worldx'][1] = xdataend
00878 lregion = self._thisregion['worldx']
00879
00880 axlimx = self._thisregion['axes'].get_xlim()
00881 pregion = self._thisregion['axes'].axvspan(lregion[0],lregion[1],
00882 facecolor='0.7')
00883 self._thisregion['axes'].set_xlim(axlimx)
00884
00885 self.plotter._plotter.canvas.draw()
00886 self._polygons.append(pregion)
00887 srow = self._getrownum(self._thisregion['axes'])
00888 irow = int(srow)
00889 if not self._selregions.has_key(srow):
00890 self._selregions[srow] = []
00891 self._selregions[srow].append(lregion)
00892 del lregion, pregion, xdataend
00893 sout = "selected region: "+str(self._thisregion['worldx'])+\
00894 "(@row "+str(self._getrownum(self._thisregion['axes']))+")"
00895 asaplog.push(sout)
00896
00897
00898 self.plotter._plotter.register('button_press',None)
00899 self.plotter._plotter.register('motion_notify',None)
00900
00901 self._thisregion = None
00902 self.xdataold = None
00903 self.xold = None
00904
00905 self.plotter._plotter.register('button_press',self._add_region)
00906
00907
00908 @asaplog_post_dec
00909 def _add_panel(self,event):
00910 if not self.figmgr.toolbar.mode == '':
00911 return
00912 if event.button != 1 or event.inaxes == None:
00913 return
00914 selax = event.inaxes
00915
00916 srow = self._getrownum(selax)
00917 irow = int(srow)
00918 if srow:
00919 self._selpanels.append(irow)
00920 shadow = Rectangle((0,0),1,1,facecolor='0.7',transform=selax.transAxes,visible=True)
00921 self._polygons.append(selax.add_patch(shadow))
00922
00923 self.plotter._plotter.canvas.draw()
00924 asaplog.push("row "+str(irow)+" is selected")
00925
00926
00927
00928
00929
00930
00931
00932 def _getrownum(self,axis):
00933
00934 plabel = axis.get_title()
00935 if plabel.startswith("row "):
00936 return plabel.strip("row ")
00937 return None
00938
00939 def _any_selection(self):
00940
00941 if len(self._selpanels) or len(self._selregions):
00942 return True
00943 return False
00944
00945 def _plot_selections(self,regions=None,panels=None):
00946
00947 if not self._any_selection() and not (regions or panels):
00948 return
00949 regions = regions or self._selregions.copy() or {}
00950 panels = panels or self._selpanels or []
00951 if not isinstance(regions,dict):
00952 asaplog.post()
00953 asaplog.push("Invalid region specification")
00954 asaplog.post('ERROR')
00955 if not isinstance(panels,list):
00956 asaplog.post()
00957 asaplog.push("Invalid panel specification")
00958 asaplog.post('ERROR')
00959 strow = self._getrownum(self.plotter._plotter.subplots[0]['axes'])
00960 enrow = self._getrownum(self.plotter._plotter.subplots[-1]['axes'])
00961 for irow in range(int(strow),int(enrow)+1):
00962 if regions.has_key(str(irow)):
00963 ax = self.plotter._plotter.subplots[irow - int(strow)]['axes']
00964 mlist = regions.pop(str(irow))
00965
00966 axlimx = ax.get_xlim()
00967 for i in range(len(mlist)):
00968 self._polygons.append(ax.axvspan(mlist[i][0],mlist[i][1],
00969 facecolor='0.7'))
00970 ax.set_xlim(axlimx)
00971 del ax,mlist,axlimx
00972 if irow in panels:
00973 ax = self.plotter._plotter.subplots[irow - int(strow)]['axes']
00974 shadow = Rectangle((0,0),1,1,facecolor='0.7',
00975 transform=ax.transAxes,visible=True)
00976 self._polygons.append(ax.add_patch(shadow))
00977 del ax,shadow
00978 self.plotter._plotter.canvas.draw()
00979 del regions,panels,strow,enrow
00980
00981 def _clear_selection_plot(self, refresh=True):
00982
00983 if len(self._polygons) > 0:
00984 for shadow in self._polygons:
00985 shadow.remove()
00986 if refresh: self.plotter._plotter.canvas.draw()
00987 self._polygons = []
00988
00989 def _clearup_selections(self, refresh=True):
00990
00991 self._selpanels = []
00992 self._selregions = {}
00993 self._clear_selection_plot(refresh=refresh)
00994
00995
00996 def cancel_select(self):
00997 self.figmgr.toolbar.set_message('selections canceled')
00998
00999 self._clearup_selections(refresh=True)
01000
01001
01002 @asaplog_post_dec
01003 def flag(self):
01004 if not self._any_selection():
01005 msg = "No selection to be Flagged"
01006 asaplog.post()
01007 asaplog.push(msg)
01008 asaplog.post('WARN')
01009 return
01010 self._pause_buttons(operation="start",msg="Flagging data...")
01011 self._flag_operation(rows=self._selpanels,
01012 regions=self._selregions,unflag=False)
01013 sout = "Flagged:\n"
01014 sout += " rows = "+str(self._selpanels)+"\n"
01015 sout += " regions: "+str(self._selregions)
01016 asaplog.push(sout)
01017 del sout
01018 self.plotter._ismodified = True
01019 self._clearup_selections(refresh=False)
01020 self._plot_page(pagemode="current")
01021 self._pause_buttons(operation="end")
01022
01023
01024 @asaplog_post_dec
01025 def unflag(self):
01026 if not self._any_selection():
01027 msg = "No selection to be Flagged"
01028 asaplog.push(msg)
01029 asaplog.post('WARN')
01030 return
01031 self._pause_buttons(operation="start",msg="Unflagging data...")
01032 self._flag_operation(rows=self._selpanels,
01033 regions=self._selregions,unflag=True)
01034 sout = "Unflagged:\n"
01035 sout += " rows = "+str(self._selpanels)+"\n"
01036 sout += " regions: "+str(self._selregions)
01037 asaplog.push(sout)
01038 del sout
01039 self.plotter._ismodified = True
01040 self._clearup_selections(refresh=False)
01041 self._plot_page(pagemode="current")
01042 self._pause_buttons(operation="end")
01043
01044
01045 @asaplog_post_dec
01046 def _flag_operation(self,rows=None,regions=None,unflag=False):
01047 scan = self.plotter._data
01048 if not scan:
01049 asaplog.post()
01050 asaplog.push("Invalid scantable")
01051 asaplog.post("ERROR")
01052 if isinstance(rows,list) and len(rows) > 0:
01053 scan.flag_row(rows=rows,unflag=unflag)
01054 if isinstance(regions,dict) and len(regions) > 0:
01055 for srow, masklist in regions.iteritems():
01056 if not isinstance(masklist,list) or len(masklist) ==0:
01057 msg = "Ignoring invalid region selection for row = "+srow
01058 asaplog.post()
01059 asaplog.push(msg)
01060 asaplog.post("WARN")
01061 continue
01062 irow = int(srow)
01063 mask = scan.create_mask(masklist,invert=False,row=irow)
01064 scan.flag(row=irow,mask=mask,unflag=unflag)
01065 del irow, mask
01066 del srow, masklist
01067 del scan
01068
01069
01070 @asaplog_post_dec
01071 def stat_cal(self):
01072 if not self._any_selection():
01073 msg = "No selection to be calculated"
01074 asaplog.push(msg)
01075 asaplog.post('WARN')
01076 return
01077 self._selected_stats(rows=self._selpanels,regions=self._selregions)
01078 self._clearup_selections(refresh=True)
01079
01080 @asaplog_post_dec
01081 def _selected_stats(self,rows=None,regions=None):
01082 scan = self.plotter._data
01083 if not scan:
01084 asaplog.post()
01085 asaplog.push("Invalid scantable")
01086 asaplog.post("ERROR")
01087 mathobj = stmath( rcParams['insitu'] )
01088 statval = {}
01089 statstr = ['max', 'min', 'mean', 'median', 'sum', 'stddev', 'rms']
01090 if isinstance(rows, list) and len(rows) > 0:
01091 for irow in rows:
01092 for stat in statstr:
01093 statval[stat] = mathobj._statsrow(scan,[],stat,irow)[0]
01094 self._print_stats(scan,irow,statval,statstr=statstr)
01095 del irow
01096 if isinstance(regions,dict) and len(regions) > 0:
01097 for srow, masklist in regions.iteritems():
01098 if not isinstance(masklist,list) or len(masklist) ==0:
01099 msg = "Ignoring invalid region selection for row = "+srow
01100 asaplog.post()
01101 asaplog.push(msg)
01102 asaplog.post("WARN")
01103 continue
01104 irow = int(srow)
01105 mask = scan.create_mask(masklist,invert=False,row=irow)
01106 for stat in statstr:
01107 statval[stat] = mathobj._statsrow(scan,mask,stat,irow)[0]
01108 self._print_stats(scan,irow,statval,statstr=statstr,
01109 mask=masklist)
01110 del irow, mask
01111 del srow, masklist
01112 del scan, statval, mathobj
01113
01114 @asaplog_post_dec
01115 def _print_stats(self,scan,row,stats,statstr=None,mask=None):
01116 if not isinstance(scan, scantable):
01117 asaplog.post()
01118 asaplog.push("Invalid scantable")
01119 asaplog.post("ERROR")
01120 if row < 0 or row > scan.nrow():
01121 asaplog.post()
01122 asaplog.push("Invalid row number")
01123 asaplog.post("ERROR")
01124 if not isinstance(stats,dict) or len(stats) == 0:
01125 asaplog.post()
01126 asaplog.push("Invalid statistic value")
01127 asaplog.post("ERROR")
01128 maskstr = "All"
01129 if mask:
01130 maskstr = str(mask)
01131 ssep = "-"*70+"\n"
01132 sout = ssep
01133 sout += ("Row=%d Scan=%d IF=%d Pol=%d Time=%s mask=%s" % \
01134 (row, scan.getscan(row), scan.getif(row), scan.getpol(row), scan.get_time(row),maskstr))
01135 sout += "\n"
01136 statvals = []
01137 if not len(statstr):
01138 statstr = stats.keys()
01139 for key in statstr:
01140 sout += key.ljust(10)
01141 statvals.append(stats.pop(key))
01142 sout += "\n"
01143 sout += ("%f "*len(statstr) % tuple(statvals))
01144 sout += "\n"+ssep
01145 asaplog.push(sout)
01146 del sout, ssep, maskstr, statvals, key, scan, row, stats, statstr, mask
01147
01148
01149
01150 def prev_page(self):
01151 self._pause_buttons(operation="start",msg='plotting the previous page')
01152 self._clear_selection_plot(refresh=False)
01153 self._plot_page(pagemode="prev")
01154 self._plot_selections()
01155 self._pause_buttons(operation="end")
01156
01157
01158 def next_page(self):
01159 self._pause_buttons(operation="start",msg='plotting the next page')
01160 self._clear_selection_plot(refresh=False)
01161 self._plot_page(pagemode="next")
01162 self._plot_selections()
01163 self._pause_buttons(operation="end")
01164
01165
01166 def _plot_page(self,pagemode="next"):
01167 if self.plotter._startrow <= 0:
01168 msg = "The page counter is reset due to chages of plot settings. "
01169 msg += "Plotting from the first page."
01170 asaplog.post()
01171 asaplog.push(msg)
01172 asaplog.post('WARN')
01173 goback = False
01174
01175 self.plotter._plotter.hold()
01176
01177 self._set_plot_counter(pagemode)
01178 self.plotter._plot(self.plotter._data)
01179 self.set_pagecounter(self._get_pagenum())
01180 self.plotter._plotter.release()
01181 self.plotter._plotter.tidy()
01182 self.plotter._plotter.show(hardrefresh=False)
01183
01184
01185
01186 def _set_plot_counter(self, pagemode):
01187
01188 availpage = ["p","c","n"]
01189 pageop = pagemode[0].lower()
01190 if not (pageop in availpage):
01191 asaplog.post()
01192 asaplog.push("Invalid page operation")
01193 asaplog.post("ERROR")
01194 if pageop == "n":
01195
01196 return
01197
01198 maxpanel = 25
01199
01200 lastpanel = self.plotter._ipanel
01201
01202 currpnum = len(self.plotter._plotter.subplots)
01203
01204
01205 start_ipanel = None
01206 if pageop == "c":
01207 start_ipanel = max(lastpanel-currpnum+1, 0)
01208 else:
01209
01210 prevpnum = None
01211 if self.plotter._rows and self.plotter._cols:
01212
01213 prevpnum = self.plotter._rows*self.plotter._cols
01214 else:
01215
01216 prevpnum = maxpanel
01217 start_ipanel = max(lastpanel-currpnum-prevpnum+1, 0)
01218 del prevpnum
01219
01220
01221 self.plotter._ipanel = start_ipanel-1
01222 if self.plotter._panelling == 'r':
01223 self.plotter._startrow = start_ipanel
01224 else:
01225
01226 self.plotter._startrow = self.plotter._panelrows[start_ipanel]
01227 del lastpanel,currpnum,start_ipanel
01228
01229
01230 def set_pagecounter(self,page):
01231 nwidth = int(numpy.ceil(numpy.log10(max(page,1))))+1
01232 nwidth = max(nwidth,4)
01233 formatstr = '%'+str(nwidth)+'d'
01234 self.show_pagenum(page,formatstr)
01235
01236 def show_pagenum(self,pagenum,formatstr):
01237
01238 pass
01239
01240 def _get_pagenum(self):
01241 maxpanel = 25
01242
01243 idlastpanel = self.plotter._ipanel
01244 if self.plotter._rows and self.plotter._cols:
01245 ppp = self.plotter._rows*self.plotter._cols
01246 else:
01247 ppp = maxpanel
01248 return int(idlastpanel/ppp)+1
01249
01250
01251 def _pause_buttons(self,operation="end",msg=""):
01252 pass