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

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

New Development: No

JIRA Issue: Yes (CAS-1077)

Ready to Release: Yes

Interface Changes: Yes

What Interface Changed: see the Description

Test Programs: run the new function or try refresh=False

Put in Release Notes: Yes

Module(s): CASA task sdplot()

Description:

  1. A new function, set_data(self, scan, refresh=True), added to the asapplotter class. This function sets a scantable (specified by scan) to be plotted.
  2. A boolean parameter refresh is added to following functions in the asapplotter class:

set_mode, set_layout, set_range, set_legend, set_title, set_ordinate,
set_abcissa, set_colors, set_histogram, set_linestyles, set_font,
set_mask, and set_selection

The plot is replotted based on the new parameter setting(s) only when refresh=True.


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