source: trunk/python/asapplotter.py@ 1552

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

Add some instuctions to the plot

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