source: trunk/python/asapplotter.py@ 1590

Last change on this file since 1590 was 1582, checked in by Malte Marquarding, 15 years ago

Increased maxstack to 16; added simple selection to plotter (refer to #169)

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