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

Last change on this file since 1619 was 1614, checked in by Takeshi Nakazato, 15 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: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

  1. Added level parameter to print_log()
  2. Replaced casalog.post() to asaplog.push() + print_log().


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