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

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

New Development: No

JIRA Issue: Yes (CAS2065)

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: run sdplot and make sure the additional tool bar appears and works.

Put in Release Notes: No

Module(s): sdplot and ASAP plotter running on TkAgg

Description: A bit of refactoring (created a new method _newcasabar to load the additional tool bar)


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