source: trunk/python/asapplotter.py@ 1549

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

add alittle bit of room, so masks can be created past the first/last channel

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