source: trunk/python/asapplotter.py@ 1560

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

added forward for axes.annotate and added useful default plus interactive mode

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