source: branches/casa-prerelease/pre-asap/python/asapplotter.py@ 2052

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

merged a bug fix in trunk(r2051)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.9 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._headstring = None
58 self._headsize = None
59
60 def _translate(self, instr):
61 keys = "s b i p t r".split()
62 if isinstance(instr, str):
63 for key in keys:
64 if instr.lower().startswith(key):
65 return key
66 return None
67
68 def _newplotter(self, **kwargs):
69 backend=matplotlib.get_backend()
70 if not self._visible:
71 from asap.asaplot import asaplot
72 elif backend == 'TkAgg':
73 from asap.asaplotgui import asaplotgui as asaplot
74 elif backend == 'Qt4Agg':
75 from asap.asaplotgui_qt4 import asaplotgui as asaplot
76 elif backend == 'GTkAgg':
77 from asap.asaplotgui_gtk import asaplotgui as asaplot
78 else:
79 from asap.asaplot import asaplot
80 return asaplot(**kwargs)
81
82 def _newcasabar(self):
83 backend=matplotlib.get_backend()
84 if self._visible and backend == "TkAgg":
85 from asap.casatoolbar import CustomToolbarTkAgg
86 return CustomToolbarTkAgg(self)
87 #from asap.casatoolbar import CustomFlagToolbarTkAgg
88 #return CustomFlagToolbarTkAgg(self)
89 return None
90
91 @asaplog_post_dec
92 def plot(self, scan=None):
93 """
94 Plot a scantable.
95 Parameters:
96 scan: a scantable
97 Note:
98 If a scantable was specified in a previous call
99 to plot, no argument has to be given to 'replot'
100 NO checking is done that the abcissas of the scantable
101 are consistent e.g. all 'channel' or all 'velocity' etc.
102 """
103 self._startrow = 0
104 self._ipanel = -1
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 self._data = scan
307 # reset
308 self._reset()
309 msg = "A new scantable is set to the plotter. "\
310 "The masks and data selections are reset."
311 asaplog.push( msg )
312 else:
313 self._data = scan
314 self._reset()
315 else:
316 msg = "Input is not a scantable"
317 raise TypeError(msg)
318
319 # ranges become invalid when unit changes
320 if self._abcunit and self._abcunit != self._data.get_unit():
321 self._minmaxx = None
322 self._minmaxy = None
323 self._abcunit = self._data.get_unit()
324 self._datamask = None
325 if refresh: self.plot()
326
327 @asaplog_post_dec
328 def set_mode(self, stacking=None, panelling=None, refresh=True):
329 """
330 Set the plots look and feel, i.e. what you want to see on the plot.
331 Parameters:
332 stacking: tell the plotter which variable to plot
333 as line colour overlays (default 'pol')
334 panelling: tell the plotter which variable to plot
335 across multiple panels (default 'scan'
336 refresh: True (default) or False. If True, the plot is
337 replotted based on the new parameter setting(s).
338 Otherwise,the parameter(s) are set without replotting.
339 Note:
340 Valid modes are:
341 'beam' 'Beam' 'b': Beams
342 'if' 'IF' 'i': IFs
343 'pol' 'Pol' 'p': Polarisations
344 'scan' 'Scan' 's': Scans
345 'time' 'Time' 't': Times
346 'row' 'Row' 'r': Rows
347 When either 'stacking' or 'panelling' is set to 'row',
348 the other parameter setting is ignored.
349 """
350 msg = "Invalid mode"
351 if not self.set_panelling(panelling) or \
352 not self.set_stacking(stacking):
353 raise TypeError(msg)
354 #if self._panelling == 'r':
355 # self._stacking = '_r'
356 #if self._stacking == 'r':
357 # self._panelling = '_r'
358 if refresh and self._data: self.plot(self._data)
359 return
360
361 def set_panelling(self, what=None):
362 """Set the 'panelling' mode i.e. which type of spectra should be
363 spread across different panels.
364 """
365
366 mode = what
367 if mode is None:
368 mode = rcParams['plotter.panelling']
369 md = self._translate(mode)
370 if md:
371 self._panelling = md
372 self._title = None
373 #if md == 'r':
374 # self._stacking = '_r'
375 # you need to reset counters for multi page plotting
376 self._reset_counters()
377 return True
378 return False
379
380 def set_layout(self,rows=None,cols=None,refresh=True):
381 """
382 Set the multi-panel layout, i.e. how many rows and columns plots
383 are visible.
384 Parameters:
385 rows: The number of rows of plots
386 cols: The number of columns of plots
387 refresh: True (default) or False. If True, the plot is
388 replotted based on the new parameter setting(s).
389 Otherwise,the parameter(s) are set without replotting.
390 Note:
391 If no argument is given, the potter reverts to its auto-plot
392 behaviour.
393 """
394 self._rows = rows
395 self._cols = cols
396 if refresh and self._data: self.plot(self._data)
397 return
398
399 def set_stacking(self, what=None):
400 """Set the 'stacking' mode i.e. which type of spectra should be
401 overlayed.
402 """
403 mode = what
404 if mode is None:
405 mode = rcParams['plotter.stacking']
406 md = self._translate(mode)
407 if md:
408 self._stacking = md
409 self._lmap = None
410 #if md == 'r':
411 # self._panelling = '_r'
412 # you need to reset counters for multi page plotting
413 self._reset_counters()
414 return True
415 return False
416
417 def _reset_counters(self):
418 self._startrow = 0
419 self._ipanel = -1
420 self._panelrows = []
421
422 def set_range(self,xstart=None,xend=None,ystart=None,yend=None,refresh=True, offset=None):
423 """
424 Set the range of interest on the abcissa of the plot
425 Parameters:
426 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
427 refresh: True (default) or False. If True, the plot is
428 replotted based on the new parameter setting(s).
429 Otherwise,the parameter(s) are set without replotting.
430 offset: shift the abcissa by the given amount. The abcissa label will
431 have '(relative)' appended to it.
432 Note:
433 These become non-sensical when the unit changes.
434 use plotter.set_range() without parameters to reset
435
436 """
437 self._offset = offset
438 if xstart is None and xend is None:
439 self._minmaxx = None
440 else:
441 self._minmaxx = [xstart,xend]
442 if ystart is None and yend is None:
443 self._minmaxy = None
444 else:
445 self._minmaxy = [ystart,yend]
446 if refresh and self._data: self.plot(self._data)
447 return
448
449 def set_legend(self, mp=None, fontsize = None, mode = 0, refresh=True):
450 """
451 Specify a mapping for the legend instead of using the default
452 indices:
453 Parameters:
454 mp: a list of 'strings'. This should have the same length
455 as the number of elements on the legend and then maps
456 to the indeces in order. It is possible to uses latex
457 math expression. These have to be enclosed in r'',
458 e.g. r'$x^{2}$'
459 fontsize: The font size of the label (default None)
460 mode: where to display the legend
461 Any other value for loc else disables the legend:
462 0: auto
463 1: upper right
464 2: upper left
465 3: lower left
466 4: lower right
467 5: right
468 6: center left
469 7: center right
470 8: lower center
471 9: upper center
472 10: center
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
477 Example:
478 If the data has two IFs/rest frequencies with index 0 and 1
479 for CO and SiO:
480 plotter.set_stacking('i')
481 plotter.set_legend(['CO','SiO'])
482 plotter.plot()
483 plotter.set_legend([r'$^{12}CO$', r'SiO'])
484 """
485 self._lmap = mp
486 self._plotter.legend(mode)
487 if isinstance(fontsize, int):
488 from matplotlib import rc as rcp
489 rcp('legend', fontsize=fontsize)
490 if refresh and self._data: self.plot(self._data)
491 return
492
493 def set_title(self, title=None, fontsize=None, refresh=True):
494 """
495 Set the title of the plot. If multiple panels are plotted,
496 multiple titles have to be specified.
497 Parameters:
498 refresh: True (default) or False. If True, the plot is
499 replotted based on the new parameter setting(s).
500 Otherwise,the parameter(s) are set without replotting.
501 Example:
502 # two panels are visible on the plotter
503 plotter.set_title(["First Panel","Second Panel"])
504 """
505 self._title = title
506 if isinstance(fontsize, int):
507 from matplotlib import rc as rcp
508 rcp('axes', titlesize=fontsize)
509 if refresh and self._data: self.plot(self._data)
510 return
511
512 def set_ordinate(self, ordinate=None, fontsize=None, refresh=True):
513 """
514 Set the y-axis label of the plot. If multiple panels are plotted,
515 multiple labels have to be specified.
516 Parameters:
517 ordinate: a list of ordinate labels. None (default) let
518 data determine the labels
519 refresh: True (default) or False. If True, the plot is
520 replotted based on the new parameter setting(s).
521 Otherwise,the parameter(s) are set without replotting.
522 Example:
523 # two panels are visible on the plotter
524 plotter.set_ordinate(["First Y-Axis","Second Y-Axis"])
525 """
526 self._ordinate = ordinate
527 if isinstance(fontsize, int):
528 from matplotlib import rc as rcp
529 rcp('axes', labelsize=fontsize)
530 rcp('ytick', labelsize=fontsize)
531 if refresh and self._data: self.plot(self._data)
532 return
533
534 def set_abcissa(self, abcissa=None, fontsize=None, refresh=True):
535 """
536 Set the x-axis label of the plot. If multiple panels are plotted,
537 multiple labels have to be specified.
538 Parameters:
539 abcissa: a list of abcissa labels. None (default) let
540 data determine the labels
541 refresh: True (default) or False. If True, the plot is
542 replotted based on the new parameter setting(s).
543 Otherwise,the parameter(s) are set without replotting.
544 Example:
545 # two panels are visible on the plotter
546 plotter.set_ordinate(["First X-Axis","Second X-Axis"])
547 """
548 self._abcissa = abcissa
549 if isinstance(fontsize, int):
550 from matplotlib import rc as rcp
551 rcp('axes', labelsize=fontsize)
552 rcp('xtick', labelsize=fontsize)
553 if refresh and self._data: self.plot(self._data)
554 return
555
556 def set_colors(self, colmap, refresh=True):
557 """
558 Set the colours to be used. The plotter will cycle through
559 these colours when lines are overlaid (stacking mode).
560 Parameters:
561 colmap: a list of colour names
562 refresh: True (default) or False. If True, the plot is
563 replotted based on the new parameter setting(s).
564 Otherwise,the parameter(s) are set without replotting.
565 Example:
566 plotter.set_colors("red green blue")
567 # If for example four lines are overlaid e.g I Q U V
568 # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
569 # and 'V' will be 'red' again.
570 """
571 if isinstance(colmap,str):
572 colmap = colmap.split()
573 self._plotter.palette(0, colormap=colmap)
574 if refresh and self._data: self.plot(self._data)
575
576 # alias for english speakers
577 set_colours = set_colors
578
579 def set_histogram(self, hist=True, linewidth=None, refresh=True):
580 """
581 Enable/Disable histogram-like plotting.
582 Parameters:
583 hist: True (default) or False. The fisrt default
584 is taken from the .asaprc setting
585 plotter.histogram
586 refresh: True (default) or False. If True, the plot is
587 replotted based on the new parameter setting(s).
588 Otherwise,the parameter(s) are set without replotting.
589 """
590 self._hist = hist
591 if isinstance(linewidth, float) or isinstance(linewidth, int):
592 from matplotlib import rc as rcp
593 rcp('lines', linewidth=linewidth)
594 if refresh and self._data: self.plot(self._data)
595
596 def set_linestyles(self, linestyles=None, linewidth=None, refresh=True):
597 """
598 Set the linestyles to be used. The plotter will cycle through
599 these linestyles when lines are overlaid (stacking mode) AND
600 only one color has been set.
601 Parameters:
602 linestyles: a list of linestyles to use.
603 'line', 'dashed', 'dotted', 'dashdot',
604 'dashdotdot' and 'dashdashdot' are
605 possible
606 refresh: True (default) or False. If True, the plot is
607 replotted based on the new parameter setting(s).
608 Otherwise,the parameter(s) are set without replotting.
609 Example:
610 plotter.set_colors("black")
611 plotter.set_linestyles("line dashed dotted dashdot")
612 # If for example four lines are overlaid e.g I Q U V
613 # 'I' will be 'solid', 'Q' will be 'dashed',
614 # U will be 'dotted' and 'V' will be 'dashdot'.
615 """
616 if isinstance(linestyles,str):
617 linestyles = linestyles.split()
618 self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
619 if isinstance(linewidth, float) or isinstance(linewidth, int):
620 from matplotlib import rc as rcp
621 rcp('lines', linewidth=linewidth)
622 if refresh and self._data: self.plot(self._data)
623
624 def set_font(self, refresh=True,**kwargs):
625 """
626 Set font properties.
627 Parameters:
628 family: one of 'sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'
629 style: one of 'normal' (or 'roman'), 'italic' or 'oblique'
630 weight: one of 'normal or 'bold'
631 size: the 'general' font size, individual elements can be adjusted
632 seperately
633 refresh: True (default) or False. If True, the plot is
634 replotted based on the new parameter setting(s).
635 Otherwise,the parameter(s) are set without replotting.
636 """
637 from matplotlib import rc as rcp
638 fdict = {}
639 for k,v in kwargs.iteritems():
640 if v:
641 fdict[k] = v
642 self._fp = FontProperties(**fdict)
643 if refresh and self._data: self.plot(self._data)
644
645 def set_margin(self,margin=[],refresh=True):
646 """
647 Set margins between subplots and plot edges.
648 Parameters:
649 margin: a list of margins in figure coordinate (0-1),
650 i.e., fraction of the figure width or height.
651 The order of elements should be:
652 [left, bottom, right, top, horizontal space btw panels,
653 vertical space btw panels].
654 refresh: True (default) or False. If True, the plot is
655 replotted based on the new parameter setting(s).
656 Otherwise,the parameter(s) are set without replotting.
657 Note
658 * When margin is not specified, the values are reset to the defaults
659 of matplotlib.
660 * If any element is set to be None, the current value is adopted.
661 """
662 if margin == []: self._margins=self._reset_margin()
663 else:
664 self._margins=[None]*6
665 self._margins[0:len(margin)]=margin
666 #print "panel margin set to ",self._margins
667 if refresh and self._data: self.plot(self._data)
668
669 def _reset_margin(self):
670 ks=map(lambda x: 'figure.subplot.'+x,
671 ['left','bottom','right','top','hspace','wspace'])
672 return map(matplotlib.rcParams.get,ks)
673
674 def plot_lines(self, linecat=None, doppler=0.0, deltachan=10, rotate=90.0,
675 location=None):
676 """
677 Plot a line catalog.
678 Parameters:
679 linecat: the linecatalog to plot
680 doppler: the velocity shift to apply to the frequencies
681 deltachan: the number of channels to include each side of the
682 line to determine a local maximum/minimum
683 rotate: the rotation (in degrees) for the text label (default 90.0)
684 location: the location of the line annotation from the 'top',
685 'bottom' or alternate (None - the default)
686 Notes:
687 If the spectrum is flagged no line will be drawn in that location.
688 """
689 if not self._data:
690 raise RuntimeError("No scantable has been plotted yet.")
691 from asap._asap import linecatalog
692 if not isinstance(linecat, linecatalog):
693 raise ValueError("'linecat' isn't of type linecatalog.")
694 if not self._data.get_unit().endswith("Hz"):
695 raise RuntimeError("Can only overlay linecatalogs when data is in frequency.")
696 from numpy import ma
697 for j in range(len(self._plotter.subplots)):
698 self._plotter.subplot(j)
699 lims = self._plotter.axes.get_xlim()
700 for row in range(linecat.nrow()):
701 # get_frequency returns MHz
702 base = { "GHz": 1000.0, "MHz": 1.0, "Hz": 1.0e-6 }
703 restf = linecat.get_frequency(row)/base[self._data.get_unit()]
704 c = 299792.458
705 freq = restf*(1.0-doppler/c)
706 if lims[0] < freq < lims[1]:
707 if location is None:
708 loc = 'bottom'
709 if row%2: loc='top'
710 else: loc = location
711 maxys = []
712 for line in self._plotter.axes.lines:
713 v = line._x
714 asc = v[0] < v[-1]
715
716 idx = None
717 if not asc:
718 if v[len(v)-1] <= freq <= v[0]:
719 i = len(v)-1
720 while i>=0 and v[i] < freq:
721 idx = i
722 i-=1
723 else:
724 if v[0] <= freq <= v[len(v)-1]:
725 i = 0
726 while i<len(v) and v[i] < freq:
727 idx = i
728 i+=1
729 if idx is not None:
730 lower = idx - deltachan
731 upper = idx + deltachan
732 if lower < 0: lower = 0
733 if upper > len(v): upper = len(v)
734 s = slice(lower, upper)
735 y = line._y[s]
736 maxy = ma.maximum(y)
737 if isinstance( maxy, float):
738 maxys.append(maxy)
739 if len(maxys):
740 peak = max(maxys)
741 if peak > self._plotter.axes.get_ylim()[1]:
742 loc = 'bottom'
743 else:
744 continue
745 self._plotter.vline_with_label(freq, peak,
746 linecat.get_name(row),
747 location=loc, rotate=rotate)
748 self._plotter.show(hardrefresh=False)
749
750
751 def save(self, filename=None, orientation=None, dpi=None):
752 """
753 Save the plot to a file. The known formats are 'png', 'ps', 'eps'.
754 Parameters:
755 filename: The name of the output file. This is optional
756 and autodetects the image format from the file
757 suffix. If non filename is specified a file
758 called 'yyyymmdd_hhmmss.png' is created in the
759 current directory.
760 orientation: optional parameter for postscript only (not eps).
761 'landscape', 'portrait' or None (default) are valid.
762 If None is choosen for 'ps' output, the plot is
763 automatically oriented to fill the page.
764 dpi: The dpi of the output non-ps plot
765 """
766 self._plotter.save(filename,orientation,dpi)
767 return
768
769 @asaplog_post_dec
770 def set_mask(self, mask=None, selection=None, refresh=True):
771 """
772 Set a plotting mask for a specific polarization.
773 This is useful for masking out "noise" Pangle outside a source.
774 Parameters:
775 mask: a mask from scantable.create_mask
776 selection: the spectra to apply the mask to.
777 refresh: True (default) or False. If True, the plot is
778 replotted based on the new parameter setting(s).
779 Otherwise,the parameter(s) are set without replotting.
780 Example:
781 select = selector()
782 select.setpolstrings("Pangle")
783 plotter.set_mask(mymask, select)
784 """
785 if not self._data:
786 msg = "Can only set mask after a first call to plot()"
787 raise RuntimeError(msg)
788 if len(mask):
789 if isinstance(mask, list) or isinstance(mask, tuple):
790 self._usermask = array(mask)
791 else:
792 self._usermask = mask
793 if mask is None and selection is None:
794 self._usermask = []
795 self._maskselection = None
796 if isinstance(selection, selector):
797 self._maskselection = {'b': selection.get_beams(),
798 's': selection.get_scans(),
799 'i': selection.get_ifs(),
800 'p': selection.get_pols(),
801 't': [] }
802 else:
803 self._maskselection = None
804 if refresh: self.plot(self._data)
805
806 def _slice_indeces(self, data):
807 mn = self._minmaxx[0]
808 mx = self._minmaxx[1]
809 asc = data[0] < data[-1]
810 start=0
811 end = len(data)-1
812 inc = 1
813 if not asc:
814 start = len(data)-1
815 end = 0
816 inc = -1
817 # find min index
818 #while start > 0 and data[start] < mn:
819 # start+= inc
820 minind=start
821 for ind in xrange(start,end+inc,inc):
822 if data[ind] > mn: break
823 minind=ind
824 # find max index
825 #while end > 0 and data[end] > mx:
826 # end-=inc
827 #if end > 0: end +=1
828 maxind=end
829 for ind in xrange(end,start-inc,-inc):
830 if data[ind] < mx: break
831 maxind=ind
832 start=minind
833 end=maxind
834 if start > end:
835 return end,start+1
836 elif start < end:
837 return start,end+1
838 else:
839 return start,end
840
841 def _reset(self):
842 self._usermask = []
843 self._usermaskspectra = None
844 self._offset = None
845 self.set_selection(None, False)
846 self._reset_header()
847
848 def _reset_header(self):
849 self._headsize = None
850 self._headstring = 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=None, logger=False, selstr='', extrastr=''):
1387 """
1388 print data (scantable) header on the plot and/or logger.
1389 Parameters:
1390 plot: whether or not print header info on the plot.
1391 fontsize: header font size (valid only plot=True) default: 9
1392 logger: whether or not print header info on the logger.
1393 selstr: additional selection string (not verified)
1394 extrastr: additional string to print (not verified)
1395 """
1396 if not plot and not logger:
1397 return
1398 if not self._data:
1399 raise RuntimeError("No scantable has been set yet.")
1400 # Now header will be printed on plot and/or logger.
1401 # Get header information and format it.
1402 ssum=self._data.__str__()
1403 # Print Observation header to the upper-left corner of plot
1404 if self._headstring:
1405 headstr = self._headstring
1406 if extrastr != '': headstr[0]=extrastr+'\n'+headstr[0]
1407 if selstr != '': headstr[2] += selstr
1408 fontsize = fontsize or self._headsize
1409 else:
1410 headstr=[ssum[ssum.find('Observer:'):ssum.find('Flux Unit:')]]
1411 headstr.append(ssum[ssum.find('Beams:'):ssum.find('Observer:')]
1412 +ssum[ssum.find('Rest Freqs:'):ssum.find('Abcissa:')])
1413 if extrastr != '': headstr[0]=extrastr+'\n'+headstr[0]
1414 ssel='***Selections***\n'+(selstr+self._data.get_selection().__str__() or 'none')
1415 headstr.append(ssel)
1416 del ssel
1417 fontsize = fontsize or 9
1418 self._headsize = fontsize
1419 self._headstring = headstr
1420
1421 if plot:
1422 self._plotter.hold()
1423 nstcol=len(headstr)
1424 for i in range(nstcol):
1425 self._plotter.figure.text(0.03+float(i)/nstcol,0.98,
1426 headstr[i],
1427 horizontalalignment='left',
1428 verticalalignment='top',
1429 fontsize=fontsize)
1430 import time
1431 self._plotter.figure.text(0.99,0.0,
1432 time.strftime("%a %d %b %Y %H:%M:%S %Z"),
1433 horizontalalignment='right',
1434 verticalalignment='bottom',fontsize=8)
1435 self._plotter.release()
1436 if logger:
1437 sextra = headstr[0][0:headstr[0].find('Observer:')].rstrip('\n')
1438 selstr = "Selections: "+(headstr[2].lstrip('***Selections***\n') or 'none')+"\n \n"
1439
1440 asaplog.push("----------------\n Plot Summary\n----------------")
1441 asaplog.push(sextra)
1442 asaplog.push(ssum[ssum.find('Beams:'):ssum.find('Selection:')]\
1443 + selstr + ssum[ssum.find('Scan Source'):])
1444 del ssum, headstr
1445
1446# def clear_header(self):
1447# if not self._headstring or len(self._plotter.figure.texts) == 0:
1448# asaplog.push("No header has been plotted. Exit without any operation")
1449# asaplog.post("WARN")
1450# else:
1451# self._plotter.hold()
1452# for textobj in self._plotter.figure.texts:
1453# if textobj.get_text() in self._headstring:
1454# try:
1455# textobj.remove()
1456# except NotImplementedError:
1457# self._plotter.figure.texts.pop(self._plotter.figure.texts.index(textobj))
1458# self._plotter.release()
1459# self._reset_header()
Note: See TracBrowser for help on using the repository browser.