source: branches/mergetest/python/asapplotter.py@ 1782

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

New Development: Yes

JIRA Issue: No (test merging alma branch)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s):

Description:


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