source: trunk/python/asapplotter.py@ 1557

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

Fix for ticket #158; can' use rc parameters to set fonts dynamically

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