source: branches/alma/python/asapplotter.py@ 1712

Last change on this file since 1712 was 1702, checked in by Kana Sugimoto, 15 years ago

New Development: No

JIRA Issue: Yes (CAS-1077)

Ready to Release: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s):

Description: Add a note to help message and log output for set_data().

Just for user infomation.


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