source: branches/alma/python/asapplotter.py@ 1757

Last change on this file since 1757 was 1757, checked in by Kana Sugimoto, 15 years ago

New Development: Yes

JIRA Issue: Yes (CAS-2211)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: ASAP 3.0.0 interface changes

Test Programs:

Put in Release Notes: Yes

Module(s): all the CASA sd tools and tasks are affected.

Description: Merged ATNF-ASAP 3.0.0 developments to CASA (alma) branch.

Note you also need to update casa/code/atnf.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.4 KB
Line 
1from asap import rcParams, print_log, print_log_dec
2from asap import selector, scantable
3from asap import asaplog
4import matplotlib.axes
5from matplotlib.font_manager import FontProperties
6from matplotlib.text import Text
7
8import re
9
10class asapplotter:
11 """
12 The ASAP plotter.
13 By default the plotter is set up to plot polarisations
14 'colour stacked' and scantables across panels.
15 Note:
16 Currenly it only plots 'spectra' not Tsys or
17 other variables.
18 """
19 def __init__(self, visible=None , **kwargs):
20 self._visible = rcParams['plotter.gui']
21 if visible is not None:
22 self._visible = visible
23 self._plotter = self._newplotter(**kwargs)
24 if self._visible and matplotlib.get_backend() == "TkAgg":
25 from asap.casatoolbar import CustomToolbarTkAgg
26 self._plotter.figmgr.casabar = CustomToolbarTkAgg(self)
27
28 self._panelling = None
29 self._stacking = None
30 self.set_panelling()
31 self.set_stacking()
32 self._rows = None
33 self._cols = None
34 self._autoplot = False
35 self._minmaxx = None
36 self._minmaxy = None
37 self._datamask = None
38 self._data = None
39 self._lmap = None
40 self._title = None
41 self._ordinate = None
42 self._abcissa = None
43 self._abcunit = None
44 self._usermask = []
45 self._maskselection = None
46 self._selection = selector()
47 self._hist = rcParams['plotter.histogram']
48 self._fp = FontProperties()
49 self._panellayout = self.set_panellayout(refresh=False)
50
51 def _translate(self, instr):
52 keys = "s b i p t".split()
53 if isinstance(instr, str):
54 for key in keys:
55 if instr.lower().startswith(key):
56 return key
57 return None
58
59 def _newplotter(self, **kwargs):
60 backend=matplotlib.get_backend()
61 if not self._visible:
62 from asap.asaplot import asaplot
63 elif backend == 'TkAgg':
64 from asap.asaplotgui import asaplotgui as asaplot
65 elif backend == 'Qt4Agg':
66 from asap.asaplotgui_qt4 import asaplotgui as asaplot
67 elif backend == 'GTkAgg':
68 from asap.asaplotgui_gtk import asaplotgui as asaplot
69 else:
70 from asap.asaplot import asaplot
71 return asaplot(**kwargs)
72
73 #@print_log_dec
74 def plot(self, scan=None):
75 """
76 Plot a scantable.
77 Parameters:
78 scan: a scantable
79 Note:
80 If a scantable was specified in a previous call
81 to plot, no argument has to be given to 'replot'
82 NO checking is done that the abcissas of the scantable
83 are consistent e.g. all 'channel' or all 'velocity' etc.
84 """
85 if self._plotter.is_dead:
86 self._plotter = self._newplotter()
87 self._plotter.hold()
88 self._plotter.clear()
89 if not self._data and not scan:
90 msg = "Input is not a scantable"
91 if rcParams['verbose']:
92 #print msg
93 asaplog.push( msg )
94 print_log( 'ERROR' )
95 return
96 raise TypeError(msg)
97 if scan: self.set_data(scan,refresh=False)
98 self._plot(self._data)
99 if self._minmaxy is not None:
100 self._plotter.set_limits(ylim=self._minmaxy)
101 if self._plotter.figmgr.casabar: self._plotter.figmgr.casabar.enable_button()
102 self._plotter.release()
103 self._plotter.tidy()
104 self._plotter.show(hardrefresh=False)
105 print_log()
106 return
107
108 def gca(self):
109 return self._plotter.figure.gca()
110
111 def refresh(self):
112 """Do a soft refresh"""
113 self._plotter.figure.show()
114
115 def create_mask(self, nwin=1, panel=0, color=None):
116 """
117 Interactively define a mask.It retruns a mask that is equivalent to
118 the one created manually with scantable.create_mask.
119 Parameters:
120 nwin: The number of mask windows to create interactively
121 default is 1.
122 panel: Which panel to use for mask selection. This is useful
123 if different IFs are spread over panels (default 0)
124 """
125 if self._data is None:
126 return []
127 outmask = []
128 self._plotter.subplot(panel)
129 xmin, xmax = self._plotter.axes.get_xlim()
130 marg = 0.05*(xmax-xmin)
131 self._plotter.axes.set_xlim(xmin-marg, xmax+marg)
132 self.refresh()
133
134 def cleanup(lines=False, texts=False, refresh=False):
135 if lines:
136 del self._plotter.axes.lines[-1]
137 if texts:
138 del self._plotter.axes.texts[-1]
139 if refresh:
140 self.refresh()
141
142 for w in xrange(nwin):
143 wpos = []
144 self.text(0.05,1.0, "Add start boundary",
145 coords="relative", fontsize=10)
146 point = self._plotter.get_point()
147 cleanup(texts=True)
148 if point is None:
149 continue
150 wpos.append(point[0])
151 self.axvline(wpos[0], color=color)
152 self.text(0.05,1.0, "Add end boundary", coords="relative", fontsize=10)
153 point = self._plotter.get_point()
154 cleanup(texts=True, lines=True)
155 if point is None:
156 self.refresh()
157 continue
158 wpos.append(point[0])
159 self.axvspan(wpos[0], wpos[1], alpha=0.1,
160 edgecolor=color, facecolor=color)
161 ymin, ymax = self._plotter.axes.get_ylim()
162 outmask.append(wpos)
163
164 self._plotter.axes.set_xlim(xmin, xmax)
165 self.refresh()
166 if len(outmask) > 0:
167 return self._data.create_mask(*outmask)
168 return []
169
170 # forwards to matplotlib axes
171 def text(self, *args, **kwargs):
172 if kwargs.has_key("interactive"):
173 #if kwargs.pop("interactive"):
174 # pos = self._plotter.get_point()
175 # args = tuple(pos)+args
176 kwargs.pop("interactive")
177 self._axes_callback("text", *args, **kwargs)
178
179 text.__doc__ = matplotlib.axes.Axes.text.__doc__
180
181 def arrow(self, *args, **kwargs):
182 if kwargs.has_key("interactive"):
183 #if kwargs.pop("interactive"):
184 # pos = self._plotter.get_region()
185 # dpos = (pos[0][0], pos[0][1],
186 # pos[1][0]-pos[0][0],
187 # pos[1][1] - pos[0][1])
188 # args = dpos + args
189 kwargs.pop("interactive")
190 self._axes_callback("arrow", *args, **kwargs)
191
192 arrow.__doc__ = matplotlib.axes.Axes.arrow.__doc__
193
194 def annotate(self, text, xy=None, xytext=None, **kwargs):
195 if kwargs.has_key("interactive"):
196 #if kwargs.pop("interactive"):
197 # xy = self._plotter.get_point()
198 # xytext = self._plotter.get_point()
199 kwargs.pop("interactive")
200 if not kwargs.has_key("arrowprops"):
201 kwargs["arrowprops"] = dict(arrowstyle="->")
202 self._axes_callback("annotate", text, xy, xytext, **kwargs)
203
204 annotate.__doc__ = matplotlib.axes.Axes.annotate.__doc__
205
206 def axvline(self, *args, **kwargs):
207 if kwargs.has_key("interactive"):
208 #if kwargs.pop("interactive"):
209 # pos = self._plotter.get_point()
210 # args = (pos[0],)+args
211 kwargs.pop("interactive")
212 self._axes_callback("axvline", *args, **kwargs)
213
214 axvline.__doc__ = matplotlib.axes.Axes.axvline.__doc__
215
216 def axhline(self, *args, **kwargs):
217 if kwargs.has_key("interactive"):
218 #if kwargs.pop("interactive"):
219 # pos = self._plotter.get_point()
220 # args = (pos[1],)+args
221 kwargs.pop("interactive")
222 self._axes_callback("axhline", *args, **kwargs)
223
224 axhline.__doc__ = matplotlib.axes.Axes.axhline.__doc__
225
226 def axvspan(self, *args, **kwargs):
227 if kwargs.has_key("interactive"):
228 #if kwargs.pop("interactive"):
229 # pos = self._plotter.get_region()
230 # dpos = (pos[0][0], pos[1][0])
231 # args = dpos + args
232 kwargs.pop("interactive")
233 self._axes_callback("axvspan", *args, **kwargs)
234 # hack to preventy mpl from redrawing the patch
235 # it seem to convert the patch into lines on every draw.
236 # This doesn't happen in a test script???
237 #del self._plotter.axes.patches[-1]
238
239 axvspan.__doc__ = matplotlib.axes.Axes.axvspan.__doc__
240
241 def axhspan(self, *args, **kwargs):
242 if kwargs.has_key("interactive"):
243 #if kwargs.pop("interactive"):
244 # pos = self._plotter.get_region()
245 # dpos = (pos[0][1], pos[1][1])
246 # args = dpos + args
247 kwargs.pop("interactive")
248 self._axes_callback("axhspan", *args, **kwargs)
249 # hack to preventy mpl from redrawing the patch
250 # it seem to convert the patch into lines on every draw.
251 # This doesn't happen in a test script???
252 #del self._plotter.axes.patches[-1]
253
254 axhspan.__doc__ = matplotlib.axes.Axes.axhspan.__doc__
255
256 def _axes_callback(self, axesfunc, *args, **kwargs):
257 panel = 0
258 if kwargs.has_key("panel"):
259 panel = kwargs.pop("panel")
260 coords = None
261 if kwargs.has_key("coords"):
262 coords = kwargs.pop("coords")
263 if coords.lower() == 'world':
264 kwargs["transform"] = self._plotter.axes.transData
265 elif coords.lower() == 'relative':
266 kwargs["transform"] = self._plotter.axes.transAxes
267 self._plotter.subplot(panel)
268 self._plotter.axes.set_autoscale_on(False)
269 getattr(self._plotter.axes, axesfunc)(*args, **kwargs)
270 self._plotter.show(False)
271 self._plotter.axes.set_autoscale_on(True)
272 # end matplotlib.axes fowarding functions
273
274 def set_data(self, scan, refresh=True):
275 """
276 Set a scantable to plot.
277 Parameters:
278 scan: a scantable
279 refresh: True (default) or False. If True, the plot is
280 replotted based on the new parameter setting(s).
281 Otherwise,the parameter(s) are set without replotting.
282 Note:
283 The user specified masks and data selections will be reset
284 if a new scantable is set. This method should be called before
285 setting data selections (set_selection) and/or masks (set_mask).
286 """
287 from asap import scantable
288 if isinstance(scan, scantable):
289 if self._data is not None:
290 if scan != self._data:
291 self._data = scan
292 # reset
293 self._reset()
294 msg = "A new scantable is set to the plotter. The masks and data selections are reset."
295 asaplog.push( msg )
296 print_log( 'INFO' )
297 else:
298 self._data = scan
299 self._reset()
300 else:
301 msg = "Input is not a scantable"
302 if rcParams['verbose']:
303 #print msg
304 asaplog.push( msg )
305 print_log( 'ERROR' )
306 return
307 raise TypeError(msg)
308
309 # ranges become invalid when unit changes
310 if self._abcunit and self._abcunit != self._data.get_unit():
311 self._minmaxx = None
312 self._minmaxy = None
313 self._abcunit = self._data.get_unit()
314 self._datamask = None
315 if refresh: self.plot()
316
317
318 def set_mode(self, stacking=None, panelling=None, refresh=True):
319 """
320 Set the plots look and feel, i.e. what you want to see on the plot.
321 Parameters:
322 stacking: tell the plotter which variable to plot
323 as line colour overlays (default 'pol')
324 panelling: tell the plotter which variable to plot
325 across multiple panels (default 'scan'
326 refresh: True (default) or False. If True, the plot is
327 replotted based on the new parameter setting(s).
328 Otherwise,the parameter(s) are set without replotting.
329 Note:
330 Valid modes are:
331 'beam' 'Beam' 'b': Beams
332 'if' 'IF' 'i': IFs
333 'pol' 'Pol' 'p': Polarisations
334 'scan' 'Scan' 's': Scans
335 'time' 'Time' 't': Times
336 """
337 msg = "Invalid mode"
338 if not self.set_panelling(panelling) or \
339 not self.set_stacking(stacking):
340 if rcParams['verbose']:
341 #print msg
342 asaplog.push( msg )
343 print_log( 'ERROR' )
344 return
345 else:
346 raise TypeError(msg)
347 if refresh and self._data: self.plot(self._data)
348 return
349
350 def set_panelling(self, what=None):
351 mode = what
352 if mode is None:
353 mode = rcParams['plotter.panelling']
354 md = self._translate(mode)
355 if md:
356 self._panelling = md
357 self._title = None
358 return True
359 return False
360
361 def set_layout(self,rows=None,cols=None,refresh=True):
362 """
363 Set the multi-panel layout, i.e. how many rows and columns plots
364 are visible.
365 Parameters:
366 rows: The number of rows of plots
367 cols: The number of columns of plots
368 refresh: True (default) or False. If True, the plot is
369 replotted based on the new parameter setting(s).
370 Otherwise,the parameter(s) are set without replotting.
371 Note:
372 If no argument is given, the potter reverts to its auto-plot
373 behaviour.
374 """
375 self._rows = rows
376 self._cols = cols
377 if refresh and self._data: self.plot(self._data)
378 return
379
380 def set_stacking(self, what=None):
381 mode = what
382 if mode is None:
383 mode = rcParams['plotter.stacking']
384 md = self._translate(mode)
385 if md:
386 self._stacking = md
387 self._lmap = None
388 return True
389 return False
390
391 def set_range(self,xstart=None,xend=None,ystart=None,yend=None,refresh=True):
392 """
393 Set the range of interest on the abcissa of the plot
394 Parameters:
395 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
396 refresh: True (default) or False. If True, the plot is
397 replotted based on the new parameter setting(s).
398 Otherwise,the parameter(s) are set without replotting.
399 Note:
400 These become non-sensical when the unit changes.
401 use plotter.set_range() without parameters to reset
402
403 """
404 if xstart is None and xend is None:
405 self._minmaxx = None
406 else:
407 self._minmaxx = [xstart,xend]
408 if ystart is None and yend is None:
409 self._minmaxy = None
410 else:
411 self._minmaxy = [ystart,yend]
412 if refresh and self._data: self.plot(self._data)
413 return
414
415 def set_legend(self, mp=None, fontsize = None, mode = 0, refresh=True):
416 """
417 Specify a mapping for the legend instead of using the default
418 indices:
419 Parameters:
420 mp: a list of 'strings'. This should have the same length
421 as the number of elements on the legend and then maps
422 to the indeces in order. It is possible to uses latex
423 math expression. These have to be enclosed in r'',
424 e.g. r'$x^{2}$'
425 fontsize: The font size of the label (default None)
426 mode: where to display the legend
427 Any other value for loc else disables the legend:
428 0: auto
429 1: upper right
430 2: upper left
431 3: lower left
432 4: lower right
433 5: right
434 6: center left
435 7: center right
436 8: lower center
437 9: upper center
438 10: center
439 refresh: True (default) or False. If True, the plot is
440 replotted based on the new parameter setting(s).
441 Otherwise,the parameter(s) are set without replotting.
442
443 Example:
444 If the data has two IFs/rest frequencies with index 0 and 1
445 for CO and SiO:
446 plotter.set_stacking('i')
447 plotter.set_legend(['CO','SiO'])
448 plotter.plot()
449 plotter.set_legend([r'$^{12}CO$', r'SiO'])
450 """
451 self._lmap = mp
452 self._plotter.legend(mode)
453 if isinstance(fontsize, int):
454 from matplotlib import rc as rcp
455 rcp('legend', fontsize=fontsize)
456 if refresh and self._data: self.plot(self._data)
457 return
458
459 def set_title(self, title=None, fontsize=None, refresh=True):
460 """
461 Set the title of the plot. If multiple panels are plotted,
462 multiple titles have to be specified.
463 Parameters:
464 refresh: True (default) or False. If True, the plot is
465 replotted based on the new parameter setting(s).
466 Otherwise,the parameter(s) are set without replotting.
467 Example:
468 # two panels are visible on the plotter
469 plotter.set_title(["First Panel","Second Panel"])
470 """
471 self._title = title
472 if isinstance(fontsize, int):
473 from matplotlib import rc as rcp
474 rcp('axes', titlesize=fontsize)
475 if refresh and self._data: self.plot(self._data)
476 return
477
478 def set_ordinate(self, ordinate=None, fontsize=None, refresh=True):
479 """
480 Set the y-axis label of the plot. If multiple panels are plotted,
481 multiple labels have to be specified.
482 Parameters:
483 ordinate: a list of ordinate labels. None (default) let
484 data determine the labels
485 refresh: True (default) or False. If True, the plot is
486 replotted based on the new parameter setting(s).
487 Otherwise,the parameter(s) are set without replotting.
488 Example:
489 # two panels are visible on the plotter
490 plotter.set_ordinate(["First Y-Axis","Second Y-Axis"])
491 """
492 self._ordinate = ordinate
493 if isinstance(fontsize, int):
494 from matplotlib import rc as rcp
495 rcp('axes', labelsize=fontsize)
496 rcp('ytick', labelsize=fontsize)
497 if refresh and self._data: self.plot(self._data)
498 return
499
500 def set_abcissa(self, abcissa=None, fontsize=None, refresh=True):
501 """
502 Set the x-axis label of the plot. If multiple panels are plotted,
503 multiple labels have to be specified.
504 Parameters:
505 abcissa: a list of abcissa labels. None (default) let
506 data determine the labels
507 refresh: True (default) or False. If True, the plot is
508 replotted based on the new parameter setting(s).
509 Otherwise,the parameter(s) are set without replotting.
510 Example:
511 # two panels are visible on the plotter
512 plotter.set_ordinate(["First X-Axis","Second X-Axis"])
513 """
514 self._abcissa = abcissa
515 if isinstance(fontsize, int):
516 from matplotlib import rc as rcp
517 rcp('axes', labelsize=fontsize)
518 rcp('xtick', labelsize=fontsize)
519 if refresh and self._data: self.plot(self._data)
520 return
521
522 def set_colors(self, colmap, refresh=True):
523 """
524 Set the colours to be used. The plotter will cycle through
525 these colours when lines are overlaid (stacking mode).
526 Parameters:
527 colmap: a list of colour names
528 refresh: True (default) or False. If True, the plot is
529 replotted based on the new parameter setting(s).
530 Otherwise,the parameter(s) are set without replotting.
531 Example:
532 plotter.set_colors("red green blue")
533 # If for example four lines are overlaid e.g I Q U V
534 # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
535 # and 'V' will be 'red' again.
536 """
537 if isinstance(colmap,str):
538 colmap = colmap.split()
539 self._plotter.palette(0, colormap=colmap)
540 if refresh and self._data: self.plot(self._data)
541
542 # alias for english speakers
543 set_colours = set_colors
544
545 def set_histogram(self, hist=True, linewidth=None, refresh=True):
546 """
547 Enable/Disable histogram-like plotting.
548 Parameters:
549 hist: True (default) or False. The fisrt default
550 is taken from the .asaprc setting
551 plotter.histogram
552 refresh: True (default) or False. If True, the plot is
553 replotted based on the new parameter setting(s).
554 Otherwise,the parameter(s) are set without replotting.
555 """
556 self._hist = hist
557 if isinstance(linewidth, float) or isinstance(linewidth, int):
558 from matplotlib import rc as rcp
559 rcp('lines', linewidth=linewidth)
560 if refresh and self._data: self.plot(self._data)
561
562 def set_linestyles(self, linestyles=None, linewidth=None, refresh=True):
563 """
564 Set the linestyles to be used. The plotter will cycle through
565 these linestyles when lines are overlaid (stacking mode) AND
566 only one color has been set.
567 Parameters:
568 linestyles: a list of linestyles to use.
569 'line', 'dashed', 'dotted', 'dashdot',
570 'dashdotdot' and 'dashdashdot' are
571 possible
572 refresh: True (default) or False. If True, the plot is
573 replotted based on the new parameter setting(s).
574 Otherwise,the parameter(s) are set without replotting.
575 Example:
576 plotter.set_colors("black")
577 plotter.set_linestyles("line dashed dotted dashdot")
578 # If for example four lines are overlaid e.g I Q U V
579 # 'I' will be 'solid', 'Q' will be 'dashed',
580 # U will be 'dotted' and 'V' will be 'dashdot'.
581 """
582 if isinstance(linestyles,str):
583 linestyles = linestyles.split()
584 self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
585 if isinstance(linewidth, float) or isinstance(linewidth, int):
586 from matplotlib import rc as rcp
587 rcp('lines', linewidth=linewidth)
588 if refresh and self._data: self.plot(self._data)
589
590 def set_font(self, refresh=True,**kwargs):
591 """
592 Set font properties.
593 Parameters:
594 family: one of 'sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'
595 style: one of 'normal' (or 'roman'), 'italic' or 'oblique'
596 weight: one of 'normal or 'bold'
597 size: the 'general' font size, individual elements can be adjusted
598 seperately
599 refresh: True (default) or False. If True, the plot is
600 replotted based on the new parameter setting(s).
601 Otherwise,the parameter(s) are set without replotting.
602 """
603 from matplotlib import rc as rcp
604 fdict = {}
605 for k,v in kwargs.iteritems():
606 if v:
607 fdict[k] = v
608 self._fp = FontProperties(**fdict)
609 if refresh and self._data: self.plot(self._data)
610
611 def set_panellayout(self,layout=[],refresh=True):
612 """
613 Set the layout of subplots.
614 Parameters:
615 layout: a list of subplots layout in figure coordinate (0-1),
616 i.e., fraction of the figure width or height.
617 The order of elements should be:
618 [left, bottom, right, top, horizontal space btw panels,
619 vertical space btw panels].
620 refresh: True (default) or False. If True, the plot is
621 replotted based on the new parameter setting(s).
622 Otherwise,the parameter(s) are set without replotting.
623 Note
624 * When layout is not specified, the values are reset to the defaults
625 of matplotlib.
626 * If any element is set to be None, the current value is adopted.
627 """
628 if layout == []: self._panellayout=self._reset_panellayout()
629 else:
630 self._panellayout=[None]*6
631 self._panellayout[0:len(layout)]=layout
632 #print "panel layout set to ",self._panellayout
633 if refresh and self._data: self.plot(self._data)
634
635 def _reset_panellayout(self):
636 ks=map(lambda x: 'figure.subplot.'+x,
637 ['left','bottom','right','top','hspace','wspace'])
638 return map(matplotlib.rcParams.get,ks)
639
640 def plot_lines(self, linecat=None, doppler=0.0, deltachan=10, rotate=90.0,
641 location=None):
642 """
643 Plot a line catalog.
644 Parameters:
645 linecat: the linecatalog to plot
646 doppler: the velocity shift to apply to the frequencies
647 deltachan: the number of channels to include each side of the
648 line to determine a local maximum/minimum
649 rotate: the rotation (in degrees) )for the text label (default 90.0)
650 location: the location of the line annotation from the 'top',
651 'bottom' or alternate (None - the default)
652 Notes:
653 If the spectrum is flagged no line will be drawn in that location.
654 """
655 if not self._data:
656 raise RuntimeError("No scantable has been plotted yet.")
657 from asap._asap import linecatalog
658 if not isinstance(linecat, linecatalog):
659 raise ValueError("'linecat' isn't of type linecatalog.")
660 if not self._data.get_unit().endswith("Hz"):
661 raise RuntimeError("Can only overlay linecatalogs when data is in frequency.")
662 from numpy import ma
663 for j in range(len(self._plotter.subplots)):
664 self._plotter.subplot(j)
665 lims = self._plotter.axes.get_xlim()
666 for row in range(linecat.nrow()):
667 # get_frequency returns MHz
668 base = { "GHz": 1000.0, "MHz": 1.0, "Hz": 1.0e-6 }
669 restf = linecat.get_frequency(row)/base[self._data.get_unit()]
670 c = 299792.458
671 freq = restf*(1.0-doppler/c)
672 if lims[0] < freq < lims[1]:
673 if location is None:
674 loc = 'bottom'
675 if row%2: loc='top'
676 else: loc = location
677 maxys = []
678 for line in self._plotter.axes.lines:
679 v = line._x
680 asc = v[0] < v[-1]
681
682 idx = None
683 if not asc:
684 if v[len(v)-1] <= freq <= v[0]:
685 i = len(v)-1
686 while i>=0 and v[i] < freq:
687 idx = i
688 i-=1
689 else:
690 if v[0] <= freq <= v[len(v)-1]:
691 i = 0
692 while i<len(v) and v[i] < freq:
693 idx = i
694 i+=1
695 if idx is not None:
696 lower = idx - deltachan
697 upper = idx + deltachan
698 if lower < 0: lower = 0
699 if upper > len(v): upper = len(v)
700 s = slice(lower, upper)
701 y = line._y[s]
702 maxy = ma.maximum(y)
703 if isinstance( maxy, float):
704 maxys.append(maxy)
705 if len(maxys):
706 peak = max(maxys)
707 if peak > self._plotter.axes.get_ylim()[1]:
708 loc = 'bottom'
709 else:
710 continue
711 self._plotter.vline_with_label(freq, peak,
712 linecat.get_name(row),
713 location=loc, rotate=rotate)
714 self._plotter.show(hardrefresh=False)
715
716
717 def save(self, filename=None, orientation=None, dpi=None):
718 """
719 Save the plot to a file. The know formats are 'png', 'ps', 'eps'.
720 Parameters:
721 filename: The name of the output file. This is optional
722 and autodetects the image format from the file
723 suffix. If non filename is specified a file
724 called 'yyyymmdd_hhmmss.png' is created in the
725 current directory.
726 orientation: optional parameter for postscript only (not eps).
727 'landscape', 'portrait' or None (default) are valid.
728 If None is choosen for 'ps' output, the plot is
729 automatically oriented to fill the page.
730 dpi: The dpi of the output non-ps plot
731 """
732 self._plotter.save(filename,orientation,dpi)
733 return
734
735
736 def set_mask(self, mask=None, selection=None, refresh=True):
737 """
738 Set a plotting mask for a specific polarization.
739 This is useful for masking out "noise" Pangle outside a source.
740 Parameters:
741 mask: a mask from scantable.create_mask
742 selection: the spectra to apply the mask to.
743 refresh: True (default) or False. If True, the plot is
744 replotted based on the new parameter setting(s).
745 Otherwise,the parameter(s) are set without replotting.
746 Example:
747 select = selector()
748 select.setpolstrings("Pangle")
749 plotter.set_mask(mymask, select)
750 """
751 if not self._data:
752 msg = "Can only set mask after a first call to plot()"
753 if rcParams['verbose']:
754 #print msg
755 asaplog.push( msg )
756 print_log( 'ERROR' )
757 return
758 else:
759 raise RuntimeError(msg)
760 if len(mask):
761 if isinstance(mask, list) or isinstance(mask, tuple):
762 self._usermask = array(mask)
763 else:
764 self._usermask = mask
765 if mask is None and selection is None:
766 self._usermask = []
767 self._maskselection = None
768 if isinstance(selection, selector):
769 self._maskselection = {'b': selection.get_beams(),
770 's': selection.get_scans(),
771 'i': selection.get_ifs(),
772 'p': selection.get_pols(),
773 't': [] }
774 else:
775 self._maskselection = None
776 if refresh: self.plot(self._data)
777
778 def _slice_indeces(self, data):
779 mn = self._minmaxx[0]
780 mx = self._minmaxx[1]
781 asc = data[0] < data[-1]
782 start=0
783 end = len(data)-1
784 inc = 1
785 if not asc:
786 start = len(data)-1
787 end = 0
788 inc = -1
789 # find min index
790 #while start > 0 and data[start] < mn:
791 # start+= inc
792 minind=start
793 for ind in xrange(start,end+inc,inc):
794 if data[ind] > mn: break
795 minind=ind
796 # find max index
797 #while end > 0 and data[end] > mx:
798 # end-=inc
799 #if end > 0: end +=1
800 maxind=end
801 for ind in xrange(end,start-inc,-inc):
802 if data[ind] < mx: break
803 maxind=ind
804 start=minind
805 end=maxind
806 if start > end:
807 return end,start+1
808 elif start < end:
809 return start,end+1
810 else:
811 return start,end
812
813 def _reset(self):
814 self._usermask = []
815 self._usermaskspectra = None
816 self.set_selection(None, False)
817
818 def _plot(self, scan):
819 savesel = scan.get_selection()
820 sel = savesel + self._selection
821 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
822 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
823 order = [d0[self._panelling],d0[self._stacking]]
824 sel.set_order(order)
825 scan.set_selection(sel)
826 d = {'b': scan.getbeam, 's': scan.getscan,
827 'i': scan.getif, 'p': scan.getpol, 't': scan._gettime }
828
829 polmodes = dict(zip(self._selection.get_pols(),
830 self._selection.get_poltypes()))
831 # this returns either a tuple of numbers or a length (ncycles)
832 # convert this into lengths
833 n0,nstack0 = self._get_selected_n(scan)
834 if isinstance(n0, int): n = n0
835 else: n = len(n0)
836 if isinstance(nstack0, int): nstack = nstack0
837 else: nstack = len(nstack0)
838 maxpanel, maxstack = 16,16
839 if n > maxpanel or nstack > maxstack:
840 maxn = 0
841 if nstack > maxstack: maxn = maxstack
842 if n > maxpanel: maxn = maxpanel
843 msg ="Scan to be plotted contains more than %d selections.\n" \
844 "Selecting first %d selections..." % (maxn, maxn)
845 asaplog.push(msg)
846 print_log('WARN')
847 n = min(n,maxpanel)
848 nstack = min(nstack,maxstack)
849 if n > 1:
850 ganged = rcParams['plotter.ganged']
851 if self._panelling == 'i':
852 ganged = False
853 if self._rows and self._cols:
854 n = min(n,self._rows*self._cols)
855 self._plotter.set_panels(rows=self._rows,cols=self._cols,
856# nplots=n,ganged=ganged)
857 nplots=n,layout=self._panellayout,ganged=ganged)
858 else:
859# self._plotter.set_panels(rows=n,cols=0,nplots=n,ganged=ganged)
860 self._plotter.set_panels(rows=n,cols=0,nplots=n,layout=self._panellayout,ganged=ganged)
861 else:
862# self._plotter.set_panels()
863 self._plotter.set_panels(layout=self._panellayout)
864 r=0
865 nr = scan.nrow()
866 a0,b0 = -1,-1
867 allxlim = []
868 allylim = []
869 newpanel=True
870 panelcount,stackcount = 0,0
871 while r < nr:
872 a = d[self._panelling](r)
873 b = d[self._stacking](r)
874 if a > a0 and panelcount < n:
875 if n > 1:
876 self._plotter.subplot(panelcount)
877 self._plotter.palette(0)
878 #title
879 xlab = self._abcissa and self._abcissa[panelcount] \
880 or scan._getabcissalabel()
881 ylab = self._ordinate and self._ordinate[panelcount] \
882 or scan._get_ordinate_label()
883 self._plotter.set_axes('xlabel', xlab)
884 self._plotter.set_axes('ylabel', ylab)
885 lbl = self._get_label(scan, r, self._panelling, self._title)
886 if isinstance(lbl, list) or isinstance(lbl, tuple):
887 if 0 <= panelcount < len(lbl):
888 lbl = lbl[panelcount]
889 else:
890 # get default label
891 lbl = self._get_label(scan, r, self._panelling, None)
892 self._plotter.set_axes('title',lbl)
893 newpanel = True
894 stackcount =0
895 panelcount += 1
896 if (b > b0 or newpanel) and stackcount < nstack:
897 y = []
898 if len(polmodes):
899 y = scan._getspectrum(r, polmodes[scan.getpol(r)])
900 else:
901 y = scan._getspectrum(r)
902 m = scan._getmask(r)
903 from numpy import logical_not, logical_and
904 if self._maskselection and len(self._usermask) == len(m):
905 if d[self._stacking](r) in self._maskselection[self._stacking]:
906 m = logical_and(m, self._usermask)
907 x = scan._getabcissa(r)
908 from numpy import ma, array
909 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
910 if self._minmaxx is not None:
911 s,e = self._slice_indeces(x)
912 x = x[s:e]
913 y = y[s:e]
914 if len(x) > 1024 and rcParams['plotter.decimate']:
915 fac = len(x)/1024
916 x = x[::fac]
917 y = y[::fac]
918 llbl = self._get_label(scan, r, self._stacking, self._lmap)
919 if isinstance(llbl, list) or isinstance(llbl, tuple):
920 if 0 <= stackcount < len(llbl):
921 # use user label
922 llbl = llbl[stackcount]
923 else:
924 # get default label
925 llbl = self._get_label(scan, r, self._stacking, None)
926 self._plotter.set_line(label=llbl)
927 plotit = self._plotter.plot
928 if self._hist: plotit = self._plotter.hist
929 if len(x) > 0:
930 plotit(x,y)
931 xlim= self._minmaxx or [min(x),max(x)]
932 allxlim += xlim
933 ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
934 allylim += ylim
935 else:
936 xlim = self._minmaxx or []
937 allxlim += xlim
938 ylim= self._minmaxy or []
939 allylim += ylim
940 stackcount += 1
941 # last in colour stack -> autoscale x
942 if stackcount == nstack and len(allxlim) > 0:
943 allxlim.sort()
944 self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
945 # clear
946 allxlim =[]
947
948 newpanel = False
949 a0=a
950 b0=b
951 # ignore following rows
952 if (panelcount == n) and (stackcount == nstack):
953 # last panel -> autoscale y if ganged
954 if rcParams['plotter.ganged'] and len(allylim) > 0:
955 allylim.sort()
956 self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
957 break
958 r+=1 # next row
959 #reset the selector to the scantable's original
960 scan.set_selection(savesel)
961
962 #temporary switch-off for older matplotlib
963 #if self._fp is not None:
964 if self._fp is not None and getattr(self._plotter.figure,'findobj',False):
965 for o in self._plotter.figure.findobj(Text):
966 o.set_fontproperties(self._fp)
967
968 def set_selection(self, selection=None, refresh=True, **kw):
969 """
970 Parameters:
971 selection: a selector object (default unset the selection)
972 refresh: True (default) or False. If True, the plot is
973 replotted based on the new parameter setting(s).
974 Otherwise,the parameter(s) are set without replotting.
975 """
976 if selection is None:
977 # reset
978 if len(kw) == 0:
979 self._selection = selector()
980 else:
981 # try keywords
982 for k in kw:
983 if k not in selector.fields:
984 raise KeyError("Invalid selection key '%s', valid keys are %s" % (k, selector.fields))
985 self._selection = selector(**kw)
986 elif isinstance(selection, selector):
987 self._selection = selection
988 else:
989 raise TypeError("'selection' is not of type selector")
990
991 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
992 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
993 order = [d0[self._panelling],d0[self._stacking]]
994 self._selection.set_order(order)
995 if refresh and self._data: self.plot(self._data)
996
997 def _get_selected_n(self, scan):
998 d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
999 'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle }
1000 d2 = { 'b': self._selection.get_beams(),
1001 's': self._selection.get_scans(),
1002 'i': self._selection.get_ifs(),
1003 'p': self._selection.get_pols(),
1004 't': self._selection.get_cycles() }
1005 n = d2[self._panelling] or d1[self._panelling]()
1006 nstack = d2[self._stacking] or d1[self._stacking]()
1007 return n,nstack
1008
1009 def _get_label(self, scan, row, mode, userlabel=None):
1010 if isinstance(userlabel, list) and len(userlabel) == 0:
1011 userlabel = " "
1012 pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
1013 if len(pms):
1014 poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
1015 else:
1016 poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
1017 d = {'b': "Beam "+str(scan.getbeam(row)),
1018 #'s': scan._getsourcename(row),
1019 's': "Scan "+str(scan.getscan(row))+\
1020 " ("+str(scan._getsourcename(row))+")",
1021 'i': "IF"+str(scan.getif(row)),
1022 'p': poleval,
1023 't': str(scan.get_time(row)) }
1024 return userlabel or d[mode]
1025
1026 def plotazel(self, scan=None, outfile=None):
1027 #def plotazel(self):
1028 """
1029 plot azimuth and elevation versus time of a scantable
1030 """
1031 from matplotlib import pylab as PL
1032 from matplotlib.dates import DateFormatter, timezone
1033 from matplotlib.dates import HourLocator, MinuteLocator,SecondLocator, DayLocator
1034 from matplotlib.ticker import MultipleLocator
1035 from numpy import array, pi
1036 self._data = scan
1037 self._outfile = outfile
1038 dates = self._data.get_time(asdatetime=True)
1039 t = PL.date2num(dates)
1040 tz = timezone('UTC')
1041 PL.cla()
1042 PL.ioff()
1043 PL.clf()
1044 # Adjust subplot layouts
1045 if len(self._panellayout) !=6: self.set_panellayout(refresh=False)
1046 lef, bot, rig, top, wsp, hsp = self._panellayout
1047 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1048 wspace=wsp,hspace=hsp)
1049
1050 tdel = max(t) - min(t)
1051 ax = PL.subplot(2,1,1)
1052 el = array(self._data.get_elevation())*180./pi
1053 PL.ylabel('El [deg.]')
1054 dstr = dates[0].strftime('%Y/%m/%d')
1055 if tdel > 1.0:
1056 dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
1057 dstr = dstr + " - " + dstr2
1058 majloc = DayLocator()
1059 minloc = HourLocator(range(0,23,12))
1060 timefmt = DateFormatter("%b%d")
1061 elif tdel > 24./60.:
1062 timefmt = DateFormatter('%H:%M')
1063 majloc = HourLocator()
1064 minloc = MinuteLocator(30)
1065 else:
1066 timefmt = DateFormatter('%H:%M')
1067 majloc = MinuteLocator(interval=5)
1068 minloc = SecondLocator(30)
1069
1070 PL.title(dstr)
1071 if tdel == 0.0:
1072 th = (t - PL.floor(t))*24.0
1073 PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
1074 else:
1075 PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
1076 #ax.grid(True)
1077 ax.xaxis.set_major_formatter(timefmt)
1078 ax.xaxis.set_major_locator(majloc)
1079 ax.xaxis.set_minor_locator(minloc)
1080 ax.yaxis.grid(True)
1081 yloc = MultipleLocator(30)
1082 ax.set_ylim(0,90)
1083 ax.yaxis.set_major_locator(yloc)
1084 if tdel > 1.0:
1085 labels = ax.get_xticklabels()
1086 # PL.setp(labels, fontsize=10, rotation=45)
1087 PL.setp(labels, fontsize=10)
1088
1089 # Az plot
1090 az = array(self._data.get_azimuth())*180./pi
1091 if min(az) < 0:
1092 for irow in range(len(az)):
1093 if az[irow] < 0: az[irow] += 360.0
1094
1095 ax2 = PL.subplot(2,1,2)
1096 #PL.xlabel('Time (UT [hour])')
1097 PL.ylabel('Az [deg.]')
1098 if tdel == 0.0:
1099 PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
1100 else:
1101 PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
1102 ax2.xaxis.set_major_formatter(timefmt)
1103 ax2.xaxis.set_major_locator(majloc)
1104 ax2.xaxis.set_minor_locator(minloc)
1105 #ax2.grid(True)
1106 ax2.set_ylim(0,360)
1107 ax2.yaxis.grid(True)
1108 #hfmt = DateFormatter('%H')
1109 #hloc = HourLocator()
1110 yloc = MultipleLocator(60)
1111 ax2.yaxis.set_major_locator(yloc)
1112 if tdel > 1.0:
1113 labels = ax2.get_xticklabels()
1114 PL.setp(labels, fontsize=10)
1115 PL.xlabel('Time (UT [day])')
1116 else:
1117 PL.xlabel('Time (UT [hour])')
1118
1119 PL.ion()
1120 PL.draw()
1121 if (self._outfile is not None):
1122 PL.savefig(self._outfile)
1123
1124 def plotpointing(self, scan=None, outfile=None):
1125 #def plotpointing(self):
1126 """
1127 plot telescope pointings
1128 """
1129 from matplotlib import pylab as PL
1130 from numpy import array, pi
1131 self._data = scan
1132 self._outfile = outfile
1133 dir = array(self._data.get_directionval()).transpose()
1134 ra = dir[0]*180./pi
1135 dec = dir[1]*180./pi
1136 PL.cla()
1137 #PL.ioff()
1138 PL.clf()
1139 # Adjust subplot layouts
1140 if len(self._panellayout) !=6: self.set_panellayout(refresh=False)
1141 lef, bot, rig, top, wsp, hsp = self._panellayout
1142 PL.gcf().subplots_adjust(left=lef,bottom=bot,right=rig,top=top,
1143 wspace=wsp,hspace=hsp)
1144 ax = PL.gca()
1145 #ax = PL.axes([0.1,0.1,0.8,0.8])
1146 #ax = PL.axes([0.1,0.1,0.8,0.8])
1147 ax.set_aspect('equal')
1148 PL.plot(ra, dec, 'b,')
1149 PL.xlabel('RA [deg.]')
1150 PL.ylabel('Declination [deg.]')
1151 PL.title('Telescope pointings')
1152 [xmin,xmax,ymin,ymax] = PL.axis()
1153 PL.axis([xmax,xmin,ymin,ymax])
1154 #PL.ion()
1155 PL.draw()
1156 if (self._outfile is not None):
1157 PL.savefig(self._outfile)
1158
1159 # plot total power data
1160 # plotting in time is not yet implemented..
1161 def plottp(self, scan=None, outfile=None):
1162 if self._plotter.is_dead:
1163 self._plotter = self._newplotter()
1164 self._plotter.hold()
1165 self._plotter.clear()
1166 from asap import scantable
1167 if not self._data and not scan:
1168 msg = "Input is not a scantable"
1169 if rcParams['verbose']:
1170 #print msg
1171 asaplog.push( msg )
1172 print_log( 'ERROR' )
1173 return
1174 raise TypeError(msg)
1175 if isinstance(scan, scantable):
1176 if self._data is not None:
1177 if scan != self._data:
1178 self._data = scan
1179 # reset
1180 self._reset()
1181 else:
1182 self._data = scan
1183 self._reset()
1184 # ranges become invalid when abcissa changes?
1185 #if self._abcunit and self._abcunit != self._data.get_unit():
1186 # self._minmaxx = None
1187 # self._minmaxy = None
1188 # self._abcunit = self._data.get_unit()
1189 # self._datamask = None
1190
1191 # Adjust subplot layouts
1192 if len(self._panellayout) !=6: self.set_panellayout(refresh=False)
1193 lef, bot, rig, top, wsp, hsp = self._panellayout
1194 self._plotter.figure.subplots_adjust(
1195 left=lef,bottom=bot,right=rig,top=top,wspace=wsp,hspace=hsp)
1196 if self._plotter.figmgr.casabar: self._plotter.figmgr.casabar.disable_button()
1197 self._plottp(self._data)
1198 if self._minmaxy is not None:
1199 self._plotter.set_limits(ylim=self._minmaxy)
1200 self._plotter.release()
1201 self._plotter.tidy()
1202 self._plotter.show(hardrefresh=False)
1203 print_log()
1204 return
1205
1206 def _plottp(self,scan):
1207 """
1208 private method for plotting total power data
1209 """
1210 from matplotlib.numerix import ma, array, arange, logical_not
1211 r=0
1212 nr = scan.nrow()
1213 a0,b0 = -1,-1
1214 allxlim = []
1215 allylim = []
1216 y=[]
1217 self._plotter.set_panels()
1218 self._plotter.palette(0)
1219 #title
1220 #xlab = self._abcissa and self._abcissa[panelcount] \
1221 # or scan._getabcissalabel()
1222 #ylab = self._ordinate and self._ordinate[panelcount] \
1223 # or scan._get_ordinate_label()
1224 xlab = self._abcissa or 'row number' #or Time
1225 ylab = self._ordinate or scan._get_ordinate_label()
1226 self._plotter.set_axes('xlabel',xlab)
1227 self._plotter.set_axes('ylabel',ylab)
1228 lbl = self._get_label(scan, r, 's', self._title)
1229 if isinstance(lbl, list) or isinstance(lbl, tuple):
1230 # if 0 <= panelcount < len(lbl):
1231 # lbl = lbl[panelcount]
1232 # else:
1233 # get default label
1234 lbl = self._get_label(scan, r, self._panelling, None)
1235 self._plotter.set_axes('title',lbl)
1236 y=array(scan._get_column(scan._getspectrum,-1))
1237 m = array(scan._get_column(scan._getmask,-1))
1238 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
1239 x = arange(len(y))
1240 # try to handle spectral data somewhat...
1241 l,m = y.shape
1242 if m > 1:
1243 y=y.mean(axis=1)
1244 plotit = self._plotter.plot
1245 llbl = self._get_label(scan, r, self._stacking, None)
1246 self._plotter.set_line(label=llbl)
1247 if len(x) > 0:
1248 plotit(x,y)
1249
1250
1251 # forwards to matplotlib.Figure.text
1252 def figtext(self, *args, **kwargs):
1253 """
1254 Add text to figure at location x,y (relative 0-1 coords).
1255 This method forwards *args and **kwargs to a Matplotlib method,
1256 matplotlib.Figure.text.
1257 See the method help for detailed information.
1258 """
1259 self._plotter.text(*args, **kwargs)
1260 # end matplotlib.Figure.text forwarding function
1261
1262
1263 # printing header information
1264 def print_header(self, plot=True, fontsize=9, logger=False, selstr='', extrastr=''):
1265 """
1266 print data (scantable) header on the plot and/or logger.
1267 Parameters:
1268 plot: whether or not print header info on the plot.
1269 fontsize: header font size (valid only plot=True)
1270 autoscale: whether or not autoscale the plot (valid only plot=True)
1271 logger: whether or not print header info on the logger.
1272 selstr: additional selection string (not verified)
1273 extrastr: additional string to print (not verified)
1274 """
1275 if not plot and not logger: return
1276 if not self._data: raise RuntimeError("No scantable has been set yet.")
1277 # Now header will be printed on plot and/or logger.
1278 # Get header information and format it.
1279 ssum=self._data.__str__()
1280 # Print Observation header to the upper-left corner of plot
1281 if plot:
1282 headstr=[ssum[ssum.find('Observer:'):ssum.find('Flux Unit:')]]
1283 headstr.append(ssum[ssum.find('Beams:'):ssum.find('Observer:')]
1284 +ssum[ssum.find('Rest Freqs:'):ssum.find('Abcissa:')])
1285 if extrastr != '': headstr[0]=extrastr+'\n'+headstr[0]
1286 #headstr[1]='Data File: '+(filestr or 'unknown')+'\n'+headstr[1]
1287 ssel='***Selections***\n'+(selstr+self._data.get_selection().__str__() or 'none')
1288 headstr.append(ssel)
1289 nstcol=len(headstr)
1290
1291 self._plotter.hold()
1292 for i in range(nstcol):
1293 self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1294 headstr[i],
1295 horizontalalignment='left',
1296 verticalalignment='top',
1297 fontsize=fontsize)
1298 import time
1299 self._plotter.figure.text(0.99,0.0,
1300 time.strftime("%a %d %b %Y %H:%M:%S %Z"),
1301 horizontalalignment='right',
1302 verticalalignment='bottom',fontsize=8)
1303 self._plotter.release()
1304 del headstr, ssel
1305 if logger:
1306 asaplog.push("----------------\n Plot Summary\n----------------")
1307 asaplog.push(extrastr)
1308 asaplog.push(ssum[ssum.find('Beams:'):])
1309 print_log()
1310 del ssum
1311
1312
Note: See TracBrowser for help on using the repository browser.