source: trunk/python/asapplotter.py@ 1550

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

add alittle bit of room, so masks can be created past the first/last channel

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