source: trunk/python/asapplotter.py@ 1555

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

handle timeouts and general None returns in ginput

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