source: branches/parallelCasa3.3/python/asapplotter.py@ 2390

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

merged a bug fix in trun (r2123)

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