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

Last change on this file since 1453 was 1446, checked in by TakTsutsumi, 16 years ago

Merged recent updates (since 2007) from nrao-asap

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