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

Last change on this file since 1684 was 1632, checked in by Takeshi Nakazato, 15 years ago

New Development: No

JIRA Issue: No

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...

Bug fix.
Removed duplicated 'from asap import asaplog' lines.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.2 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 maxn = 0
616 if nstack > maxstack: maxn = maxstack
617 if n > maxpanel: maxn = maxpanel
618 msg ="Scan to be plotted contains more than %d selections.\n" \
619 "Selecting first %d selections..." % (maxn, maxn)
620 asaplog.push(msg)
621 print_log('WARN')
622 n = min(n,maxpanel)
623 nstack = min(nstack,maxstack)
624 if n > 1:
625 ganged = rcParams['plotter.ganged']
626 if self._panelling == 'i':
627 ganged = False
628 if self._rows and self._cols:
629 n = min(n,self._rows*self._cols)
630 self._plotter.set_panels(rows=self._rows,cols=self._cols,
631 nplots=n,ganged=ganged)
632 else:
633 self._plotter.set_panels(rows=n,cols=0,nplots=n,ganged=ganged)
634 else:
635 self._plotter.set_panels()
636 r=0
637 nr = scan.nrow()
638 a0,b0 = -1,-1
639 allxlim = []
640 allylim = []
641 newpanel=True
642 panelcount,stackcount = 0,0
643 while r < nr:
644 a = d[self._panelling](r)
645 b = d[self._stacking](r)
646 if a > a0 and panelcount < n:
647 if n > 1:
648 self._plotter.subplot(panelcount)
649 self._plotter.palette(0)
650 #title
651 xlab = self._abcissa and self._abcissa[panelcount] \
652 or scan._getabcissalabel()
653 ylab = self._ordinate and self._ordinate[panelcount] \
654 or scan._get_ordinate_label()
655 self._plotter.set_axes('xlabel',xlab)
656 self._plotter.set_axes('ylabel',ylab)
657 lbl = self._get_label(scan, r, self._panelling, self._title)
658 if isinstance(lbl, list) or isinstance(lbl, tuple):
659 if 0 <= panelcount < len(lbl):
660 lbl = lbl[panelcount]
661 else:
662 # get default label
663 lbl = self._get_label(scan, r, self._panelling, None)
664 self._plotter.set_axes('title',lbl)
665 newpanel = True
666 stackcount =0
667 panelcount += 1
668 if (b > b0 or newpanel) and stackcount < nstack:
669 y = []
670 if len(polmodes):
671 y = scan._getspectrum(r, polmodes[scan.getpol(r)])
672 else:
673 y = scan._getspectrum(r)
674 m = scan._getmask(r)
675 from matplotlib.numerix import logical_not, logical_and
676 if self._maskselection and len(self._usermask) == len(m):
677 if d[self._stacking](r) in self._maskselection[self._stacking]:
678 m = logical_and(m, self._usermask)
679 x = scan._getabcissa(r)
680 from matplotlib.numerix import ma, array
681 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
682 if self._minmaxx is not None:
683 s,e = self._slice_indeces(x)
684 x = x[s:e]
685 y = y[s:e]
686 if len(x) > 1024 and rcParams['plotter.decimate']:
687 fac = len(x)/1024
688 x = x[::fac]
689 y = y[::fac]
690 llbl = self._get_label(scan, r, self._stacking, self._lmap)
691 if isinstance(llbl, list) or isinstance(llbl, tuple):
692 if 0 <= stackcount < len(llbl):
693 # use user label
694 llbl = llbl[stackcount]
695 else:
696 # get default label
697 llbl = self._get_label(scan, r, self._stacking, None)
698 self._plotter.set_line(label=llbl)
699 plotit = self._plotter.plot
700 if self._hist: plotit = self._plotter.hist
701 if len(x) > 0:
702 plotit(x,y)
703 xlim= self._minmaxx or [min(x),max(x)]
704 allxlim += xlim
705 ylim= self._minmaxy or [ma.minimum(y),ma.maximum(y)]
706 allylim += ylim
707 else:
708 xlim = self._minmaxx or []
709 allxlim += xlim
710 ylim= self._minmaxy or []
711 allylim += ylim
712 stackcount += 1
713 # last in colour stack -> autoscale x
714 if stackcount == nstack and len(allxlim) > 0:
715 allxlim.sort()
716 self._plotter.subplots[panelcount-1]['axes'].set_xlim([allxlim[0],allxlim[-1]])
717 # clear
718 allxlim =[]
719
720 newpanel = False
721 a0=a
722 b0=b
723 # ignore following rows
724 if (panelcount == n) and (stackcount == nstack):
725 # last panel -> autoscale y if ganged
726 if rcParams['plotter.ganged'] and len(allylim) > 0:
727 allylim.sort()
728 self._plotter.set_limits(ylim=[allylim[0],allylim[-1]])
729 break
730 r+=1 # next row
731 #reset the selector to the scantable's original
732 scan.set_selection(savesel)
733
734 def set_selection(self, selection=None, refresh=True):
735 self._selection = isinstance(selection,selector) and selection or selector()
736 d0 = {'s': 'SCANNO', 'b': 'BEAMNO', 'i':'IFNO',
737 'p': 'POLNO', 'c': 'CYCLENO', 't' : 'TIME' }
738 order = [d0[self._panelling],d0[self._stacking]]
739 self._selection.set_order(order)
740 if self._data and refresh: self.plot(self._data)
741
742 def _get_selected_n(self, scan):
743 d1 = {'b': scan.getbeamnos, 's': scan.getscannos,
744 'i': scan.getifnos, 'p': scan.getpolnos, 't': scan.ncycle }
745 d2 = { 'b': self._selection.get_beams(),
746 's': self._selection.get_scans(),
747 'i': self._selection.get_ifs(),
748 'p': self._selection.get_pols(),
749 't': self._selection.get_cycles() }
750 n = d2[self._panelling] or d1[self._panelling]()
751 nstack = d2[self._stacking] or d1[self._stacking]()
752 return n,nstack
753
754 def _get_label(self, scan, row, mode, userlabel=None):
755 if isinstance(userlabel, list) and len(userlabel) == 0:
756 userlabel = " "
757 pms = dict(zip(self._selection.get_pols(),self._selection.get_poltypes()))
758 if len(pms):
759 poleval = scan._getpollabel(scan.getpol(row),pms[scan.getpol(row)])
760 else:
761 poleval = scan._getpollabel(scan.getpol(row),scan.poltype())
762 d = {'b': "Beam "+str(scan.getbeam(row)),
763 's': scan._getsourcename(row),
764 'i': "IF"+str(scan.getif(row)),
765 'p': poleval,
766 't': str(scan.get_time(row)) }
767 return userlabel or d[mode]
768
769 def plotazel(self, scan=None, outfile=None):
770 """
771 plot azimuth and elevation versus time of a scantable
772 """
773 import pylab as PL
774 from matplotlib.dates import DateFormatter, timezone, HourLocator, MinuteLocator, DayLocator
775 from matplotlib.ticker import MultipleLocator
776 from matplotlib.numerix import array, pi
777 self._data = scan
778 self._outfile = outfile
779 dates = self._data.get_time(asdatetime=True)
780 t = PL.date2num(dates)
781 tz = timezone('UTC')
782 PL.cla()
783 #PL.ioff()
784 PL.clf()
785 tdel = max(t) - min(t)
786 ax = PL.subplot(2,1,1)
787 el = array(self._data.get_elevation())*180./pi
788 PL.ylabel('El [deg.]')
789 dstr = dates[0].strftime('%Y/%m/%d')
790 if tdel > 1.0:
791 dstr2 = dates[len(dates)-1].strftime('%Y/%m/%d')
792 dstr = dstr + " - " + dstr2
793 majloc = DayLocator()
794 minloc = HourLocator(range(0,23,12))
795 timefmt = DateFormatter("%b%d")
796 else:
797 timefmt = DateFormatter('%H')
798 majloc = HourLocator()
799 minloc = MinuteLocator(20)
800 PL.title(dstr)
801
802 if tdel == 0.0:
803 th = (t - PL.floor(t))*24.0
804 PL.plot(th,el,'o',markersize=2, markerfacecolor='b', markeredgecolor='b')
805 else:
806 PL.plot_date(t,el,'o', markersize=2, markerfacecolor='b', markeredgecolor='b',tz=tz)
807 #ax.grid(True)
808 ax.xaxis.set_major_formatter(timefmt)
809 ax.xaxis.set_major_locator(majloc)
810 ax.xaxis.set_minor_locator(minloc)
811 ax.yaxis.grid(True)
812 yloc = MultipleLocator(30)
813 ax.set_ylim(0,90)
814 ax.yaxis.set_major_locator(yloc)
815 if tdel > 1.0:
816 labels = ax.get_xticklabels()
817 # PL.setp(labels, fontsize=10, rotation=45)
818 PL.setp(labels, fontsize=10)
819
820 # Az plot
821 az = array(self._data.get_azimuth())*180./pi
822 if min(az) < 0:
823 for irow in range(len(az)):
824 if az[irow] < 0: az[irow] += 360.0
825
826 ax = PL.subplot(2,1,2)
827 #PL.xlabel('Time (UT [hour])')
828 PL.ylabel('Az [deg.]')
829 if tdel == 0.0:
830 PL.plot(th,az,'o',markersize=2, markeredgecolor='b',markerfacecolor='b')
831 else:
832 PL.plot_date(t,az,'o', markersize=2,markeredgecolor='b',markerfacecolor='b',tz=tz)
833 ax.xaxis.set_major_formatter(timefmt)
834 ax.xaxis.set_major_locator(majloc)
835 ax.xaxis.set_minor_locator(minloc)
836 #ax.grid(True)
837 ax.set_ylim(0,360)
838 ax.yaxis.grid(True)
839 #hfmt = DateFormatter('%H')
840 #hloc = HourLocator()
841 yloc = MultipleLocator(60)
842 ax.yaxis.set_major_locator(yloc)
843 if tdel > 1.0:
844 labels = ax.get_xticklabels()
845 PL.setp(labels, fontsize=10)
846 PL.xlabel('Time (UT [day])')
847 else:
848 PL.xlabel('Time (UT [hour])')
849
850 #PL.ion()
851 PL.draw()
852 if (self._outfile is not None):
853 PL.savefig(self._outfile)
854
855 def plotpointing(self, scan=None, outfile=None):
856 """
857 plot telescope pointings
858 """
859 import pylab as PL
860 from matplotlib.dates import DateFormatter, timezone
861 from matplotlib.ticker import MultipleLocator
862 from matplotlib.numerix import array, pi, zeros
863 self._data = scan
864 self._outfile = outfile
865 dir = array(self._data.get_directionval()).transpose()
866 ra = dir[0]*180./pi
867 dec = dir[1]*180./pi
868 PL.cla()
869 #PL.ioff()
870 PL.clf()
871 ax = PL.axes([0.1,0.1,0.8,0.8])
872 ax = PL.axes([0.1,0.1,0.8,0.8])
873 ax.set_aspect('equal')
874 PL.plot(ra,dec, 'b,')
875 PL.xlabel('RA [deg.]')
876 PL.ylabel('Declination [deg.]')
877 PL.title('Telescope pointings')
878 [xmin,xmax,ymin,ymax] = PL.axis()
879 PL.axis([xmax,xmin,ymin,ymax])
880 #PL.ion()
881 PL.draw()
882 if (self._outfile is not None):
883 PL.savefig(self._outfile)
884
885 # plot total power data
886 # plotting in time is not yet implemented..
887 def plottp(self, scan=None, outfile=None):
888 if self._plotter.is_dead:
889 self._plotter = self._newplotter()
890 self._plotter.hold()
891 self._plotter.clear()
892 from asap import scantable
893 if not self._data and not scan:
894 msg = "Input is not a scantable"
895 if rcParams['verbose']:
896 #print msg
897 asaplog.push( msg )
898 print_log( 'ERROR' )
899 return
900 raise TypeError(msg)
901 if isinstance(scan, scantable):
902 if self._data is not None:
903 if scan != self._data:
904 self._data = scan
905 # reset
906 self._reset()
907 else:
908 self._data = scan
909 self._reset()
910 # ranges become invalid when abcissa changes?
911 #if self._abcunit and self._abcunit != self._data.get_unit():
912 # self._minmaxx = None
913 # self._minmaxy = None
914 # self._abcunit = self._data.get_unit()
915 # self._datamask = None
916 self._plottp(self._data)
917 if self._minmaxy is not None:
918 self._plotter.set_limits(ylim=self._minmaxy)
919 self._plotter.release()
920 self._plotter.tidy()
921 self._plotter.show(hardrefresh=False)
922 print_log()
923 return
924
925 def _plottp(self,scan):
926 """
927 private method for plotting total power data
928 """
929 from matplotlib.numerix import ma, array, arange, logical_not
930 r=0
931 nr = scan.nrow()
932 a0,b0 = -1,-1
933 allxlim = []
934 allylim = []
935 y=[]
936 self._plotter.set_panels()
937 self._plotter.palette(0)
938 #title
939 #xlab = self._abcissa and self._abcissa[panelcount] \
940 # or scan._getabcissalabel()
941 #ylab = self._ordinate and self._ordinate[panelcount] \
942 # or scan._get_ordinate_label()
943 xlab = self._abcissa or 'row number' #or Time
944 ylab = self._ordinate or scan._get_ordinate_label()
945 self._plotter.set_axes('xlabel',xlab)
946 self._plotter.set_axes('ylabel',ylab)
947 lbl = self._get_label(scan, r, 's', self._title)
948 if isinstance(lbl, list) or isinstance(lbl, tuple):
949 # if 0 <= panelcount < len(lbl):
950 # lbl = lbl[panelcount]
951 # else:
952 # get default label
953 lbl = self._get_label(scan, r, self._panelling, None)
954 self._plotter.set_axes('title',lbl)
955 y=array(scan._get_column(scan._getspectrum,-1))
956 m = array(scan._get_column(scan._getmask,-1))
957 y = ma.masked_array(y,mask=logical_not(array(m,copy=False)))
958 x = arange(len(y))
959 # try to handle spectral data somewhat...
960 l,m = y.shape
961 if m > 1:
962 y=y.mean(axis=1)
963 plotit = self._plotter.plot
964 llbl = self._get_label(scan, r, self._stacking, None)
965 self._plotter.set_line(label=llbl)
966 if len(x) > 0:
967 plotit(x,y)
968
969
970 # forwards to matplotlib.Figure.text
971 def figtext(self, *args, **kwargs):
972 """
973 Add text to figure at location x,y (relative 0-1 coords).
974 This method forwards *args and **kwargs to a Matplotlib method,
975 matplotlib.Figure.text.
976 See the method help for detailed information.
977 """
978 self._plotter.text(*args, **kwargs)
979 # end matplotlib.Figure.text forwarding function
980
Note: See TracBrowser for help on using the repository browser.