source: trunk/python/asapplotter.py@ 1547

Last change on this file since 1547 was 1547, checked in by Malte Marquarding, 16 years ago

add interactive annotation capability. Also allow creation of masks interactively

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