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

Last change on this file since 1612 was 1612, checked in by Takeshi Nakazato, 16 years ago

New Development: No

JIRA Issue: Yes CAS-729, CAS-1147

Ready to Release: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes

Module(s): Module Names change impacts.

Description: Describe your changes here...

I have changed that almost all log messages are output to casapy.log,
not to the terminal window. After this change, asap becomes to depend on casapy
and is not running in standalone, because asap have to import taskinit module
to access casalogger.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.1 KB
Line 
1from asap import rcParams, print_log, selector
2from taskinit import *
3import matplotlib.axes
4import re
5
6class asapplotter:
7 """
8 The ASAP plotter.
9 By default the plotter is set up to plot polarisations
10 'colour stacked' and scantables across panels.
11 Note:
12 Currenly it only plots 'spectra' not Tsys or
13 other variables.
14 """
15 def __init__(self, visible=None):
16 self._visible = rcParams['plotter.gui']
17 if visible is not None:
18 self._visible = visible
19 self._plotter = self._newplotter()
20
21 self._panelling = None
22 self._stacking = None
23 self.set_panelling()
24 self.set_stacking()
25 self._rows = None
26 self._cols = None
27 self._autoplot = False
28 self._minmaxx = None
29 self._minmaxy = None
30 self._datamask = None
31 self._data = None
32 self._lmap = None
33 self._title = None
34 self._ordinate = None
35 self._abcissa = None
36 self._abcunit = None
37 self._usermask = []
38 self._maskselection = None
39 self._selection = selector()
40 self._hist = rcParams['plotter.histogram']
41
42 def _translate(self, instr):
43 keys = "s b i p t".split()
44 if isinstance(instr, str):
45 for key in keys:
46 if instr.lower().startswith(key):
47 return key
48 return None
49
50 def _newplotter(self):
51 if self._visible:
52 from asap.asaplotgui import asaplotgui as asaplot
53 else:
54 from asap.asaplot import asaplot
55 return asaplot()
56
57
58 def plot(self, scan=None):
59 """
60 Plot a scantable.
61 Parameters:
62 scan: a scantable
63 Note:
64 If a scantable was specified in a previous call
65 to plot, no argument has to be given to 'replot'
66 NO checking is done that the abcissas of the scantable
67 are consistent e.g. all 'channel' or all 'velocity' etc.
68 """
69 if self._plotter.is_dead:
70 self._plotter = self._newplotter()
71 self._plotter.hold()
72 self._plotter.clear()
73 from asap import scantable
74 if not self._data and not scan:
75 msg = "Input is not a scantable"
76 if rcParams['verbose']:
77 #print msg
78 casalog.post( msg, 'WARN' )
79 return
80 raise TypeError(msg)
81 if isinstance(scan, scantable):
82 if self._data is not None:
83 if scan != self._data:
84 self._data = scan
85 # reset
86 self._reset()
87 else:
88 self._data = scan
89 self._reset()
90 # ranges become invalid when unit changes
91 if self._abcunit and self._abcunit != self._data.get_unit():
92 self._minmaxx = None
93 self._minmaxy = None
94 self._abcunit = self._data.get_unit()
95 self._datamask = None
96 self._plot(self._data)
97 if self._minmaxy is not None:
98 self._plotter.set_limits(ylim=self._minmaxy)
99 self._plotter.release()
100 self._plotter.tidy()
101 self._plotter.show(hardrefresh=False)
102 print_log()
103 return
104
105
106 # forwards to matplotlib axes
107 def text(self, *args, **kwargs):
108 self._axes_callback("text", *args, **kwargs)
109 text.__doc__ = matplotlib.axes.Axes.text.__doc__
110 def arrow(self, *args, **kwargs):
111 self._axes_callback("arrow", *args, **kwargs)
112 arrow.__doc__ = matplotlib.axes.Axes.arrow.__doc__
113 def axvline(self, *args, **kwargs):
114 self._axes_callback("axvline", *args, **kwargs)
115 axvline.__doc__ = matplotlib.axes.Axes.axvline.__doc__
116 def axhline(self, *args, **kwargs):
117 self._axes_callback("axhline", *args, **kwargs)
118 axhline.__doc__ = matplotlib.axes.Axes.axhline.__doc__
119 def axvspan(self, *args, **kwargs):
120 self._axes_callback("axvspan", *args, **kwargs)
121 # hack to preventy mpl from redrawing the patch
122 # it seem to convert the patch into lines on every draw.
123 # This doesn't happen in a test script???
124 del self._plotter.axes.patches[-1]
125 axvspan.__doc__ = matplotlib.axes.Axes.axvspan.__doc__
126
127 def axhspan(self, *args, **kwargs):
128 self._axes_callback("axhspan", *args, **kwargs)
129 # hack to preventy mpl from redrawing the patch
130 # it seem to convert the patch into lines on every draw.
131 # This doesn't happen in a test script???
132 del self._plotter.axes.patches[-1]
133 axhspan.__doc__ = matplotlib.axes.Axes.axhspan.__doc__
134
135 def _axes_callback(self, axesfunc, *args, **kwargs):
136 panel = 0
137 if kwargs.has_key("panel"):
138 panel = kwargs.pop("panel")
139 coords = None
140 if kwargs.has_key("coords"):
141 coords = kwargs.pop("coords")
142 if coords.lower() == 'world':
143 kwargs["transform"] = self._plotter.axes.transData
144 elif coords.lower() == 'relative':
145 kwargs["transform"] = self._plotter.axes.transAxes
146 self._plotter.subplot(panel)
147 self._plotter.axes.set_autoscale_on(False)
148 getattr(self._plotter.axes, axesfunc)(*args, **kwargs)
149 self._plotter.show(False)
150 self._plotter.axes.set_autoscale_on(True)
151 # end matplotlib.axes fowarding functions
152
153 def set_mode(self, stacking=None, panelling=None):
154 """
155 Set the plots look and feel, i.e. what you want to see on the plot.
156 Parameters:
157 stacking: tell the plotter which variable to plot
158 as line colour overlays (default 'pol')
159 panelling: tell the plotter which variable to plot
160 across multiple panels (default 'scan'
161 Note:
162 Valid modes are:
163 'beam' 'Beam' 'b': Beams
164 'if' 'IF' 'i': IFs
165 'pol' 'Pol' 'p': Polarisations
166 'scan' 'Scan' 's': Scans
167 'time' 'Time' 't': Times
168 """
169 msg = "Invalid mode"
170 if not self.set_panelling(panelling) or \
171 not self.set_stacking(stacking):
172 if rcParams['verbose']:
173 #print msg
174 casalog.post( msg, 'WARN' )
175 return
176 else:
177 raise TypeError(msg)
178 if self._data: self.plot(self._data)
179 return
180
181 def set_panelling(self, what=None):
182 mode = what
183 if mode is None:
184 mode = rcParams['plotter.panelling']
185 md = self._translate(mode)
186 if md:
187 self._panelling = md
188 self._title = None
189 return True
190 return False
191
192 def set_layout(self,rows=None,cols=None):
193 """
194 Set the multi-panel layout, i.e. how many rows and columns plots
195 are visible.
196 Parameters:
197 rows: The number of rows of plots
198 cols: The number of columns of plots
199 Note:
200 If no argument is given, the potter reverts to its auto-plot
201 behaviour.
202 """
203 self._rows = rows
204 self._cols = cols
205 if self._data: self.plot(self._data)
206 return
207
208 def set_stacking(self, what=None):
209 mode = what
210 if mode is None:
211 mode = rcParams['plotter.stacking']
212 md = self._translate(mode)
213 if md:
214 self._stacking = md
215 self._lmap = None
216 return True
217 return False
218
219 def set_range(self,xstart=None,xend=None,ystart=None,yend=None):
220 """
221 Set the range of interest on the abcissa of the plot
222 Parameters:
223 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
224 Note:
225 These become non-sensical when the unit changes.
226 use plotter.set_range() without parameters to reset
227
228 """
229 if xstart is None and xend is None:
230 self._minmaxx = None
231 else:
232 self._minmaxx = [xstart,xend]
233 if ystart is None and yend is None:
234 self._minmaxy = None
235 else:
236 self._minmaxy = [ystart,yend]
237 if self._data: self.plot(self._data)
238 return
239
240 def set_legend(self, mp=None, fontsize = None, mode = 0):
241 """
242 Specify a mapping for the legend instead of using the default
243 indices:
244 Parameters:
245 mp: a list of 'strings'. This should have the same length
246 as the number of elements on the legend and then maps
247 to the indeces in order. It is possible to uses latex
248 math expression. These have to be enclosed in r'',
249 e.g. r'$x^{2}$'
250 fontsize: The font size of the label (default None)
251 mode: where to display the legend
252 Any other value for loc else disables the legend:
253 0: auto
254 1: upper right
255 2: upper left
256 3: lower left
257 4: lower right
258 5: right
259 6: center left
260 7: center right
261 8: lower center
262 9: upper center
263 10: center
264
265 Example:
266 If the data has two IFs/rest frequencies with index 0 and 1
267 for CO and SiO:
268 plotter.set_stacking('i')
269 plotter.set_legend(['CO','SiO'])
270 plotter.plot()
271 plotter.set_legend([r'$^{12}CO$', r'SiO'])
272 """
273 self._lmap = mp
274 self._plotter.legend(mode)
275 if isinstance(fontsize, int):
276 from matplotlib import rc as rcp
277 rcp('legend', fontsize=fontsize)
278 if self._data:
279 self.plot(self._data)
280 return
281
282 def set_title(self, title=None, fontsize=None):
283 """
284 Set the title of the plot. If multiple panels are plotted,
285 multiple titles have to be specified.
286 Example:
287 # two panels are visible on the plotter
288 plotter.set_title(["First Panel","Second Panel"])
289 """
290 self._title = title
291 if isinstance(fontsize, int):
292 from matplotlib import rc as rcp
293 rcp('axes', titlesize=fontsize)
294 if self._data: self.plot(self._data)
295 return
296
297 def set_ordinate(self, ordinate=None, fontsize=None):
298 """
299 Set the y-axis label of the plot. If multiple panels are plotted,
300 multiple labels have to be specified.
301 Parameters:
302 ordinate: a list of ordinate labels. None (default) let
303 data determine the labels
304 Example:
305 # two panels are visible on the plotter
306 plotter.set_ordinate(["First Y-Axis","Second Y-Axis"])
307 """
308 self._ordinate = ordinate
309 if isinstance(fontsize, int):
310 from matplotlib import rc as rcp
311 rcp('axes', labelsize=fontsize)
312 rcp('ytick', labelsize=fontsize)
313 if self._data: self.plot(self._data)
314 return
315
316 def set_abcissa(self, abcissa=None, fontsize=None):
317 """
318 Set the x-axis label of the plot. If multiple panels are plotted,
319 multiple labels have to be specified.
320 Parameters:
321 abcissa: a list of abcissa labels. None (default) let
322 data determine the labels
323 Example:
324 # two panels are visible on the plotter
325 plotter.set_ordinate(["First X-Axis","Second X-Axis"])
326 """
327 self._abcissa = abcissa
328 if isinstance(fontsize, int):
329 from matplotlib import rc as rcp
330 rcp('axes', labelsize=fontsize)
331 rcp('xtick', labelsize=fontsize)
332 if self._data: self.plot(self._data)
333 return
334
335 def set_colors(self, colmap):
336 """
337 Set the colours to be used. The plotter will cycle through
338 these colours when lines are overlaid (stacking mode).
339 Parameters:
340 colmap: a list of colour names
341 Example:
342 plotter.set_colors("red green blue")
343 # If for example four lines are overlaid e.g I Q U V
344 # 'I' will be 'red', 'Q' will be 'green', U will be 'blue'
345 # and 'V' will be 'red' again.
346 """
347 if isinstance(colmap,str):
348 colmap = colmap.split()
349 self._plotter.palette(0, colormap=colmap)
350 if self._data: self.plot(self._data)
351
352 # alias for english speakers
353 set_colours = set_colors
354
355 def set_histogram(self, hist=True, linewidth=None):
356 """
357 Enable/Disable histogram-like plotting.
358 Parameters:
359 hist: True (default) or False. The fisrt default
360 is taken from the .asaprc setting
361 plotter.histogram
362 """
363 self._hist = hist
364 if isinstance(linewidth, float) or isinstance(linewidth, int):
365 from matplotlib import rc as rcp
366 rcp('lines', linewidth=linewidth)
367 if self._data: self.plot(self._data)
368
369 def set_linestyles(self, linestyles=None, linewidth=None):
370 """
371 Set the linestyles to be used. The plotter will cycle through
372 these linestyles when lines are overlaid (stacking mode) AND
373 only one color has been set.
374 Parameters:
375 linestyles: a list of linestyles to use.
376 'line', 'dashed', 'dotted', 'dashdot',
377 'dashdotdot' and 'dashdashdot' are
378 possible
379
380 Example:
381 plotter.set_colors("black")
382 plotter.set_linestyles("line dashed dotted dashdot")
383 # If for example four lines are overlaid e.g I Q U V
384 # 'I' will be 'solid', 'Q' will be 'dashed',
385 # U will be 'dotted' and 'V' will be 'dashdot'.
386 """
387 if isinstance(linestyles,str):
388 linestyles = linestyles.split()
389 self._plotter.palette(color=0,linestyle=0,linestyles=linestyles)
390 if isinstance(linewidth, float) or isinstance(linewidth, int):
391 from matplotlib import rc as rcp
392 rcp('lines', linewidth=linewidth)
393 if self._data: self.plot(self._data)
394
395 def set_font(self, family=None, style=None, weight=None, size=None):
396 """
397 Set font properties.
398 Parameters:
399 family: one of 'sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'
400 style: one of 'normal' (or 'roman'), 'italic' or 'oblique'
401 weight: one of 'normal or 'bold'
402 size: the 'general' font size, individual elements can be adjusted
403 seperately
404 """
405 from matplotlib import rc as rcp
406 if isinstance(family, str):
407 rcp('font', family=family)
408 if isinstance(style, str):
409 rcp('font', style=style)
410 if isinstance(weight, str):
411 rcp('font', weight=weight)
412 if isinstance(size, float) or isinstance(size, int):
413 rcp('font', size=size)
414 if self._data: self.plot(self._data)
415
416 def plot_lines(self, linecat=None, doppler=0.0, deltachan=10, rotate=90.0,
417 location=None):
418 """
419 Plot a line catalog.
420 Parameters:
421 linecat: the linecatalog to plot
422 doppler: the velocity shift to apply to the frequencies
423 deltachan: the number of channels to include each side of the
424 line to determine a local maximum/minimum
425 rotate: the rotation (in degrees) )for the text label (default 90.0)
426 location: the location of the line annotation from the 'top',
427 'bottom' or alternate (None - the default)
428 Notes:
429 If the spectrum is flagged no line will be drawn in that location.
430 """
431 if not self._data:
432 raise RuntimeError("No scantable has been plotted yet.")
433 from asap._asap import linecatalog
434 if not isinstance(linecat, linecatalog):
435 raise ValueError("'linecat' isn't of type linecatalog.")
436 if not self._data.get_unit().endswith("Hz"):
437 raise RuntimeError("Can only overlay linecatalogs when data is in frequency.")
438 from matplotlib.numerix import ma
439 for j in range(len(self._plotter.subplots)):
440 self._plotter.subplot(j)
441 lims = self._plotter.axes.get_xlim()
442 for row in range(linecat.nrow()):
443 # get_frequency returns MHz
444 base = { "GHz": 1000.0, "MHz": 1.0, "Hz": 1.0e-6 }
445 restf = linecat.get_frequency(row)/base[self._data.get_unit()]
446 c = 299792.458
447 freq = restf*(1.0-doppler/c)
448 if lims[0] < freq < lims[1]:
449 if location is None:
450 loc = 'bottom'
451 if row%2: loc='top'
452 else: loc = location
453 maxys = []
454 for line in self._plotter.axes.lines:
455 v = line._x
456 asc = v[0] < v[-1]
457
458 idx = None
459 if not asc:
460 if v[len(v)-1] <= freq <= v[0]:
461 i = len(v)-1
462 while i>=0 and v[i] < freq:
463 idx = i
464 i-=1
465 else:
466 if v[0] <= freq <= v[len(v)-1]:
467 i = 0
468 while i<len(v) and v[i] < freq:
469 idx = i
470 i+=1
471 if idx is not None:
472 lower = idx - deltachan
473 upper = idx + deltachan
474 if lower < 0: lower = 0
475 if upper > len(v): upper = len(v)
476 s = slice(lower, upper)
477 y = line._y[s]
478 maxy = ma.maximum(y)
479 if isinstance( maxy, float):
480 maxys.append(maxy)
481 if len(maxys):
482 peak = max(maxys)
483 if peak > self._plotter.axes.get_ylim()[1]:
484 loc = 'bottom'
485 else:
486 continue
487 self._plotter.vline_with_label(freq, peak,
488 linecat.get_name(row),
489 location=loc, rotate=rotate)
490 self._plotter.show(hardrefresh=False)
491
492
493 def save(self, filename=None, orientation=None, dpi=None):
494 """
495 Save the plot to a file. The know formats are 'png', 'ps', 'eps'.
496 Parameters:
497 filename: The name of the output file. This is optional
498 and autodetects the image format from the file
499 suffix. If non filename is specified a file
500 called 'yyyymmdd_hhmmss.png' is created in the
501 current directory.
502 orientation: optional parameter for postscript only (not eps).
503 'landscape', 'portrait' or None (default) are valid.
504 If None is choosen for 'ps' output, the plot is
505 automatically oriented to fill the page.
506 dpi: The dpi of the output non-ps plot
507 """
508 self._plotter.save(filename,orientation,dpi)
509 return
510
511
512 def set_mask(self, mask=None, selection=None):
513 """
514 Set a plotting mask for a specific polarization.
515 This is useful for masking out "noise" Pangle outside a source.
516 Parameters:
517 mask: a mask from scantable.create_mask
518 selection: the spectra to apply the mask to.
519 Example:
520 select = selector()
521 select.setpolstrings("Pangle")
522 plotter.set_mask(mymask, select)
523 """
524 if not self._data:
525 msg = "Can only set mask after a first call to plot()"
526 if rcParams['verbose']:
527 #print msg
528 casalog.post( msg, 'WARN' )
529 return
530 else:
531 raise RuntimeError(msg)
532 if len(mask):
533 if isinstance(mask, list) or isinstance(mask, tuple):
534 self._usermask = array(mask)
535 else:
536 self._usermask = mask
537 if mask is None and selection is None:
538 self._usermask = []
539 self._maskselection = None
540 if isinstance(selection, selector):
541 self._maskselection = {'b': selection.get_beams(),
542 's': selection.get_scans(),
543 'i': selection.get_ifs(),
544 'p': selection.get_pols(),
545 't': [] }
546 else:
547 self._maskselection = None
548 self.plot(self._data)
549
550 def _slice_indeces(self, data):
551 mn = self._minmaxx[0]
552 mx = self._minmaxx[1]
553 asc = data[0] < data[-1]
554 start=0
555 end = len(data)-1
556 inc = 1
557 if not asc:
558 start = len(data)-1
559 end = 0
560 inc = -1
561 # find min index
562 #while start > 0 and data[start] < mn:
563 # start+= inc
564 minind=start
565 for ind in xrange(start,end+inc,inc):
566 if data[ind] > mn: break
567 minind=ind
568 # find max index
569 #while end > 0 and data[end] > mx:
570 # end-=inc
571 #if end > 0: end +=1
572 maxind=end
573 for ind in xrange(end,start-inc,-inc):
574 if data[ind] < mx: break
575 maxind=ind
576 start=minind
577 end=maxind
578 if start > end:
579 return end,start+1
580 elif start < end:
581 return start,end+1
582 else:
583 return start,end
584
585 def _reset(self):
586 self._usermask = []
587 self._usermaskspectra = None
588 self.set_selection(None, False)
589
590 def _plot(self, scan):
591 savesel = scan.get_selection()
592 sel = savesel + self._selection
593 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
594 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
595 order = [d0[self._panelling],d0[self._stacking]]
596 sel.set_order(order)
597 scan.set_selection(sel)
598 d = {'b': scan.getbeam, 's': scan.getscan,
599 'i': scan.getif, 'p': scan.getpol, 't': scan._gettime }
600
601 polmodes = dict(zip(self._selection.get_pols(),
602 self._selection.get_poltypes()))
603 # this returns either a tuple of numbers or a length (ncycles)
604 # convert this into lengths
605 n0,nstack0 = self._get_selected_n(scan)
606 if isinstance(n0, int): n = n0
607 else: n = len(n0)
608 if isinstance(nstack0, int): nstack = nstack0
609 else: nstack = len(nstack0)
610 maxpanel, maxstack = 16,8
611 if n > maxpanel or nstack > maxstack:
612 from asap import asaplog
613 maxn = 0
614 if nstack > maxstack: maxn = maxstack
615 if n > maxpanel: maxn = maxpanel
616 msg ="Scan to be plotted contains more than %d selections.\n" \
617 "Selecting first %d selections..." % (maxn, maxn)
618 asaplog.push(msg)
619 print_log()
620 n = min(n,maxpanel)
621 nstack = min(nstack,maxstack)
622 if n > 1:
623 ganged = rcParams['plotter.ganged']
624 if self._panelling == 'i':
625 ganged = False
626 if self._rows and self._cols:
627 n = min(n,self._rows*self._cols)
628 self._plotter.set_panels(rows=self._rows,cols=self._cols,
629 nplots=n,ganged=ganged)
630 else:
631 self._plotter.set_panels(rows=n,cols=0,nplots=n,ganged=ganged)
632 else:
633 self._plotter.set_panels()
634 r=0
635 nr = scan.nrow()
636 a0,b0 = -1,-1
637 allxlim = []
638 allylim = []
639 newpanel=True
640 panelcount,stackcount = 0,0
641 while r < nr:
642 a = d[self._panelling](r)
643 b = d[self._stacking](r)
644 if a > a0 and panelcount < n:
645 if n > 1:
646 self._plotter.subplot(panelcount)
647 self._plotter.palette(0)
648 #title
649 xlab = self._abcissa and self._abcissa[panelcount] \
650 or scan._getabcissalabel()
651 ylab = self._ordinate and self._ordinate[panelcount] \
652 or scan._get_ordinate_label()
653 self._plotter.set_axes('xlabel',xlab)
654 self._plotter.set_axes('ylabel',ylab)
655 lbl = self._get_label(scan, r, self._panelling, self._title)
656 if isinstance(lbl, list) or isinstance(lbl, tuple):
657 if 0 <= panelcount < len(lbl):
658 lbl = lbl[panelcount]
659 else:
660 # get default label
661 lbl = self._get_label(scan, r, self._panelling, None)
662 self._plotter.set_axes('title',lbl)
663 newpanel = True
664 stackcount =0
665 panelcount += 1
666 if (b > b0 or newpanel) and stackcount < nstack:
667 y = []
668 if len(polmodes):
669 y = scan._getspectrum(r, polmodes[scan.getpol(r)])
670 else:
671 y = scan._getspectrum(r)
672 m = scan._getmask(r)
673 from matplotlib.numerix import logical_not, logical_and
674 if self._maskselection and len(self._usermask) == len(m):
675 if d[self._stacking](r) in self._maskselection[self._stacking]:
676 m = logical_and(m, self._usermask)
677 x = scan._getabcissa(r)
678 from matplotlib.numerix import ma, array
679 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
680 if self._minmaxx is not None:
681 s,e = self._slice_indeces(x)
682 x = x[s:e]
683 y = y[s:e]
684 if len(x) > 1024 and rcParams['plotter.decimate']:
685 fac = len(x)/1024
686 x = x[::fac]
687 y = y[::fac]
688 llbl = self._get_label(scan, r, self._stacking, self._lmap)
689 if isinstance(llbl, list) or isinstance(llbl, tuple):
690 if 0 <= stackcount < len(llbl):
691 # use user label
692 llbl = llbl[stackcount]
693 else:
694 # get default label
695 llbl = self._get_label(scan, r, self._stacking, None)
696 self._plotter.set_line(label=llbl)
697 plotit = self._plotter.plot
698 if self._hist: plotit = self._plotter.hist
699 if len(x) > 0:
700 plotit(x,y)
701 xlim= self._minmaxx or [min(x),max(x)]
702 allxlim += xlim
703 ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
704 allylim += ylim
705 else:
706 xlim = self._minmaxx or []
707 allxlim += xlim
708 ylim= self._minmaxy or []
709 allylim += ylim
710 stackcount += 1
711 # last in colour stack -> autoscale x
712 if stackcount == nstack and len(allxlim) > 0:
713 allxlim.sort()
714 self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
715 # clear
716 allxlim =[]
717
718 newpanel = False
719 a0=a
720 b0=b
721 # ignore following rows
722 if (panelcount == n) and (stackcount == nstack):
723 # last panel -> autoscale y if ganged
724 if rcParams['plotter.ganged'] and len(allylim) > 0:
725 allylim.sort()
726 self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
727 break
728 r+=1 # next row
729 #reset the selector to the scantable's original
730 scan.set_selection(savesel)
731
732 def set_selection(self, selection=None, refresh=True):
733 self._selection = isinstance(selection,selector) and selection or selector()
734 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
735 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
736 order = [d0[self._panelling],d0[self._stacking]]
737 self._selection.set_order(order)
738 if self._data and refresh: self.plot(self._data)
739
740 def _get_selected_n(self, scan):
741 d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
742 'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle }
743 d2 = { 'b': self._selection.get_beams(),
744 's': self._selection.get_scans(),
745 'i': self._selection.get_ifs(),
746 'p': self._selection.get_pols(),
747 't': self._selection.get_cycles() }
748 n = d2[self._panelling] or d1[self._panelling]()
749 nstack = d2[self._stacking] or d1[self._stacking]()
750 return n,nstack
751
752 def _get_label(self, scan, row, mode, userlabel=None):
753 if isinstance(userlabel, list) and len(userlabel) == 0:
754 userlabel = " "
755 pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
756 if len(pms):
757 poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
758 else:
759 poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
760 d = {'b': "Beam "+str(scan.getbeam(row)),
761 's': scan._getsourcename(row),
762 'i': "IF"+str(scan.getif(row)),
763 'p': poleval,
764 't': str(scan.get_time(row)) }
765 return userlabel or d[mode]
766
767 def plotazel(self, scan=None, outfile=None):
768 """
769 plot azimuth and elevation versus time of a scantable
770 """
771 import pylab as PL
772 from matplotlib.dates import DateFormatter, timezone, HourLocator, MinuteLocator, DayLocator
773 from matplotlib.ticker import MultipleLocator
774 from matplotlib.numerix import array, pi
775 self._data = scan
776 self._outfile = outfile
777 dates = self._data.get_time(asdatetime=True)
778 t = PL.date2num(dates)
779 tz = timezone('UTC')
780 PL.cla()
781 #PL.ioff()
782 PL.clf()
783 tdel = max(t) - min(t)
784 ax = PL.subplot(2,1,1)
785 el = array(self._data.get_elevation())*180./pi
786 PL.ylabel('El [deg.]')
787 dstr = dates[0].strftime('%Y/%m/%d')
788 if tdel > 1.0:
789 dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
790 dstr = dstr + " - " + dstr2
791 majloc = DayLocator()
792 minloc = HourLocator(range(0,23,12))
793 timefmt = DateFormatter("%b%d")
794 else:
795 timefmt = DateFormatter('%H')
796 majloc = HourLocator()
797 minloc = MinuteLocator(20)
798 PL.title(dstr)
799
800 if tdel == 0.0:
801 th = (t - PL.floor(t))*24.0
802 PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
803 else:
804 PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
805 #ax.grid(True)
806 ax.xaxis.set_major_formatter(timefmt)
807 ax.xaxis.set_major_locator(majloc)
808 ax.xaxis.set_minor_locator(minloc)
809 ax.yaxis.grid(True)
810 yloc = MultipleLocator(30)
811 ax.set_ylim(0,90)
812 ax.yaxis.set_major_locator(yloc)
813 if tdel > 1.0:
814 labels = ax.get_xticklabels()
815 # PL.setp(labels, fontsize=10, rotation=45)
816 PL.setp(labels, fontsize=10)
817
818 # Az plot
819 az = array(self._data.get_azimuth())*180./pi
820 if min(az) < 0:
821 for irow in range(len(az)):
822 if az[irow] < 0: az[irow] += 360.0
823
824 ax = PL.subplot(2,1,2)
825 #PL.xlabel('Time (UT [hour])')
826 PL.ylabel('Az [deg.]')
827 if tdel == 0.0:
828 PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
829 else:
830 PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
831 ax.xaxis.set_major_formatter(timefmt)
832 ax.xaxis.set_major_locator(majloc)
833 ax.xaxis.set_minor_locator(minloc)
834 #ax.grid(True)
835 ax.set_ylim(0,360)
836 ax.yaxis.grid(True)
837 #hfmt = DateFormatter('%H')
838 #hloc = HourLocator()
839 yloc = MultipleLocator(60)
840 ax.yaxis.set_major_locator(yloc)
841 if tdel > 1.0:
842 labels = ax.get_xticklabels()
843 PL.setp(labels, fontsize=10)
844 PL.xlabel('Time (UT [day])')
845 else:
846 PL.xlabel('Time (UT [hour])')
847
848 #PL.ion()
849 PL.draw()
850 if (self._outfile is not None):
851 PL.savefig(self._outfile)
852
853 def plotpointing(self, scan=None, outfile=None):
854 """
855 plot telescope pointings
856 """
857 import pylab as PL
858 from matplotlib.dates import DateFormatter, timezone
859 from matplotlib.ticker import MultipleLocator
860 from matplotlib.numerix import array, pi, zeros
861 self._data = scan
862 self._outfile = outfile
863 dir = array(self._data.get_directionval()).transpose()
864 ra = dir[0]*180./pi
865 dec = dir[1]*180./pi
866 PL.cla()
867 #PL.ioff()
868 PL.clf()
869 ax = PL.axes([0.1,0.1,0.8,0.8])
870 ax = PL.axes([0.1,0.1,0.8,0.8])
871 ax.set_aspect('equal')
872 PL.plot(ra,dec, 'b,')
873 PL.xlabel('RA [deg.]')
874 PL.ylabel('Declination [deg.]')
875 PL.title('Telescope pointings')
876 [xmin,xmax,ymin,ymax] = PL.axis()
877 PL.axis([xmax,xmin,ymin,ymax])
878 #PL.ion()
879 PL.draw()
880 if (self._outfile is not None):
881 PL.savefig(self._outfile)
882
883 # plot total power data
884 # plotting in time is not yet implemented..
885 def plottp(self, scan=None, outfile=None):
886 if self._plotter.is_dead:
887 self._plotter = self._newplotter()
888 self._plotter.hold()
889 self._plotter.clear()
890 from asap import scantable
891 if not self._data and not scan:
892 msg = "Input is not a scantable"
893 if rcParams['verbose']:
894 #print msg
895 casalog.post( msg, 'WARN' )
896 return
897 raise TypeError(msg)
898 if isinstance(scan, scantable):
899 if self._data is not None:
900 if scan != self._data:
901 self._data = scan
902 # reset
903 self._reset()
904 else:
905 self._data = scan
906 self._reset()
907 # ranges become invalid when abcissa changes?
908 #if self._abcunit and self._abcunit != self._data.get_unit():
909 # self._minmaxx = None
910 # self._minmaxy = None
911 # self._abcunit = self._data.get_unit()
912 # self._datamask = None
913 self._plottp(self._data)
914 if self._minmaxy is not None:
915 self._plotter.set_limits(ylim=self._minmaxy)
916 self._plotter.release()
917 self._plotter.tidy()
918 self._plotter.show(hardrefresh=False)
919 print_log()
920 return
921
922 def _plottp(self,scan):
923 """
924 private method for plotting total power data
925 """
926 from matplotlib.numerix import ma, array, arange, logical_not
927 r=0
928 nr = scan.nrow()
929 a0,b0 = -1,-1
930 allxlim = []
931 allylim = []
932 y=[]
933 self._plotter.set_panels()
934 self._plotter.palette(0)
935 #title
936 #xlab = self._abcissa and self._abcissa[panelcount] \
937 # or scan._getabcissalabel()
938 #ylab = self._ordinate and self._ordinate[panelcount] \
939 # or scan._get_ordinate_label()
940 xlab = self._abcissa or 'row number' #or Time
941 ylab = self._ordinate or scan._get_ordinate_label()
942 self._plotter.set_axes('xlabel',xlab)
943 self._plotter.set_axes('ylabel',ylab)
944 lbl = self._get_label(scan, r, 's', self._title)
945 if isinstance(lbl, list) or isinstance(lbl, tuple):
946 # if 0 <= panelcount < len(lbl):
947 # lbl = lbl[panelcount]
948 # else:
949 # get default label
950 lbl = self._get_label(scan, r, self._panelling, None)
951 self._plotter.set_axes('title',lbl)
952 y=array(scan._get_column(scan._getspectrum,-1))
953 m = array(scan._get_column(scan._getmask,-1))
954 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
955 x = arange(len(y))
956 # try to handle spectral data somewhat...
957 l,m = y.shape
958 if m > 1:
959 y=y.mean(axis=1)
960 plotit = self._plotter.plot
961 llbl = self._get_label(scan, r, self._stacking, None)
962 self._plotter.set_line(label=llbl)
963 if len(x) > 0:
964 plotit(x,y)
965
966
967 # forwards to matplotlib.Figure.text
968 def figtext(self, *args, **kwargs):
969 """
970 Add text to figure at location x,y (relative 0-1 coords).
971 This method forwards *args and **kwargs to a Matplotlib method,
972 matplotlib.Figure.text.
973 See the method help for detailed information.
974 """
975 self._plotter.text(*args, **kwargs)
976 # end matplotlib.Figure.text forwarding function
977
Note: See TracBrowser for help on using the repository browser.