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

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

New Development: No

JIRA Issue: Yes (CAS-1298)

Ready to Release: Yes

Interface Changes: No

What Interface Changed:

Test Programs: run sdplot() with wrong 'sprange' or 'flrange' selections

Put in Release Notes: No

Module(s): tools and tasks which calls sd.plotter.plot()

Description:

Methods plot() and _slice_indeces() are modified to fix bugs in ASAP plotter.
The method _slice_indeces() is modified to avoid index referencing error and
to return precise 'slice indices'.
The method plot() is modified to avoid invalid index referencing when setting
plot range. The y-range of the plot will be set to the default plot range of
Matplotlib, i.e., [0,1], if flrange is not set and the selected sprange is out
of range.


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