source: trunk/python/asapplotter.py@ 542

Last change on this file since 542 was 541, checked in by mar637, 20 years ago
  • enabled plotting of circular pols.
  • major bug fix on recursive plot calls.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.5 KB
RevLine 
[203]1from asap.asaplot import ASAPlot
[226]2from asap import rcParams
[203]3
4class asapplotter:
[226]5 """
6 The ASAP plotter.
7 By default the plotter is set up to plot polarisations
8 'colour stacked' and scantables across panels.
9 Note:
10 Currenly it only plots 'spectra' not Tsys or
11 other variables.
12 """
[203]13 def __init__(self):
14 self._plotter = ASAPlot()
15
16 self._tdict = {'Time':'t','time':'t','t':'t','T':'t'}
17 self._bdict = {'Beam':'b','beam':'b','b':'b','B':'b'}
18 self._idict = {'IF':'i','if':'i','i':'i','I':'i'}
19 self._pdict = {'Pol':'p','pol':'p','p':'p'}
20 self._sdict = {'scan':'s','Scan':'s','s':'s','S':'s'}
[525]21 self._cdict = {'t':'len(self._cursor["t"])',
22 'b':'len(self._cursor["b"])',
23 'i':'len(self._cursor["i"])',
24 'p':'len(self._cursor["p"])',
[203]25 's':'len(scans)'}
26 self._ldict = {'b':'Beam',
27 'i':'IF',
28 'p':'Pol',
29 's':'Scan'}
30 self._dicts = [self._tdict,self._bdict,
31 self._idict,self._pdict,
32 self._sdict]
[541]33 self._panels = rcParams['plotter.panelling']
[226]34 self._stacking = rcParams['plotter.stacking']
[377]35 self._rows = None
36 self._cols = None
[203]37 self._autoplot = False
[525]38 self._minmaxx = None
39 self._minmaxy = None
[203]40 self._data = None
41 self._lmap = []
[226]42 self._title = None
[257]43 self._ordinate = None
44 self._abcissa = None
[525]45 self._cursor = {'t':None, 'b':None,
46 'i':None, 'p':None
47 }
[203]48
49 def _translate(self, name):
50 for d in self._dicts:
51 if d.has_key(name):
52 return d[name]
53 return None
54
[525]55 def plot(self, *args):
[203]56 """
57 Plot a (list of) scantables.
58 Parameters:
59 one or more comma separated scantables
60 Note:
61 If a (list) of scantables was specified in a previous call
62 to plot, no argument has to be given to 'replot'
[525]63 NO checking is done that the abcissas of the scantables
[203]64 are consistent e.g. all 'channel' or all 'velocity' etc.
65 """
66 if self._plotter.is_dead:
67 self._plotter = ASAPlot()
68 self._plotter.clear()
69 self._plotter.hold()
70 if len(args) > 0:
[525]71 if self._data is not None:
72 if list(args) != self._data:
73 self._data = list(args)
74 # reset cursor
[541]75 self.set_cursor(refresh=False)
[525]76 else:
77 self._data = list(args)
[541]78 self.set_cursor(refresh=False)
[203]79 if self._panels == 't':
[541]80 maxrows = 9
81 if self._data[0].nrow() > maxrows:
82 print "Scan to be plotted contains more than %d rows.\n" \
83 "Selecting first %d rows..." % (maxrows,maxrows)
84 self._cursor["t"] = range(maxrows)
[203]85 self._plot_time(self._data[0], self._stacking)
86 elif self._panels == 's':
87 self._plot_scans(self._data, self._stacking)
88 else:
89 self._plot_other(self._data, self._stacking)
[525]90 if self._minmaxx is not None or self._minmaxy is not None:
91 self._plotter.set_limits(xlim=self._minmaxx,ylim=self._minmaxy)
[203]92 self._plotter.release()
93 return
94
95 def _plot_time(self, scan, colmode):
96 if colmode == 't':
97 return
[525]98 n = len(self._cursor["t"])
[203]99 cdict = {'b':'scan.setbeam(j)',
100 'i':'scan.setif(j)',
101 'p':'scan.setpol(j)'}
[525]102 cdict2 = {'b':'self._cursor["b"]',
103 'i':'self._cursor["i"]',
104 'p':'self._cursor["p"]'}
105 ncol = 1
[203]106 if self._stacking is not None:
107 ncol = eval(self._cdict.get(colmode))
108 self._plotter.set_panels()
109 if n > 1:
[377]110 if self._rows and self._cols:
111 n = min(n,self._rows*self._cols)
112 self._plotter.set_panels(rows=self._rows,cols=self._cols,
113 nplots=n)
114 else:
[485]115 self._plotter.set_panels(rows=n,cols=0,nplots=n)
[525]116 rows = self._cursor["t"]
117 self._plotter.palette(1)
118 for rowsel in rows:
119 i = self._cursor["t"].index(rowsel)
[203]120 if n > 1:
[377]121 self._plotter.palette(1)
[203]122 self._plotter.subplot(i)
[525]123 colvals = eval(cdict2.get(colmode))
124 for j in colvals:
125 polmode = "raw"
126 jj = colvals.index(j)
127 savej = j
128 for k in cdict.keys():
129 sel = eval(cdict2.get(k))
130 j = sel[0]
131 if k == "p":
132 which = self._cursor["p"].index(j)
133 polmode = self._polmode[which]
134 j = which
135 eval(cdict.get(k))
136 j = savej
137 if colmode == "p":
138 polmode = self._polmode[self._cursor["p"].index(j)]
139 j = jj
[203]140 eval(cdict.get(colmode))
141 x = None
142 y = None
143 m = None
[226]144 if not self._title:
[525]145 tlab = scan._getsourcename(rowsel)
[226]146 else:
147 if len(self._title) == n:
[525]148 tlab = self._title[rowsel]
[226]149 else:
[525]150 tlab = scan._getsourcename(rowsel)
151 x,xlab = scan.get_abcissa(rowsel)
[257]152 if self._abcissa: xlab = self._abcissa
[525]153 y = None
154 if polmode == "stokes":
155 y = scan._getstokesspectrum(rowsel)
156 elif polmode == "stokes2":
157 y = scan._getstokesspectrum(rowsel,True)
[541]158 elif polmode == "circular":
159 y = scan._stokestopolspectrum(rowsel,False,-1)
[525]160 else:
161 y = scan._getspectrum(rowsel)
[257]162 if self._ordinate:
163 ylab = self._ordinate
164 else:
165 ylab = 'Flux ('+scan.get_fluxunit()+')'
[525]166 m = scan._getmask(rowsel)
[226]167 if self._lmap and len(self._lmap) > 0:
[525]168 llab = self._lmap[jj]
[203]169 else:
[525]170 if colmode == 'p':
171 if polmode == "stokes":
172 llab = scan._getpolarizationlabel(0,1,0)
173 elif polmode == "stokes2":
174 llab = scan._getpolarizationlabel(0,1,1)
[541]175 elif polmode == "circular":
176 llab = scan._getpolarizationlabel(0,0,0)
[525]177 else:
178 llab = scan._getpolarizationlabel(1,0,0)
179 else:
180 llab = self._ldict.get(colmode)+' '+str(j)
[203]181 self._plotter.set_line(label=llab)
182 self._plotter.plot(x,y,m)
183 xlim=[min(x),max(x)]
184 self._plotter.axes.set_xlim(xlim)
185 self._plotter.set_axes('xlabel',xlab)
186 self._plotter.set_axes('ylabel',ylab)
187 self._plotter.set_axes('title',tlab)
188 return
189
[525]190 def _plot_scans(self, scans, colmode):
191 print "Can only plot one row per scan."
[203]192 if colmode == 's':
193 return
194 cdict = {'b':'scan.setbeam(j)',
195 'i':'scan.setif(j)',
196 'p':'scan.setpol(j)'}
[525]197 cdict2 = {'b':'self._cursor["b"]',
198 'i':'self._cursor["i"]',
199 'p':'self._cursor["p"]'}
200
[203]201 n = len(scans)
[525]202 ncol = 1
[203]203 if self._stacking is not None:
204 scan = scans[0]
205 ncol = eval(self._cdict.get(colmode))
206 self._plotter.set_panels()
207 if n > 1:
[377]208 if self._rows and self._cols:
209 n = min(n,self._rows*self._cols)
210 self._plotter.set_panels(rows=self._rows,cols=self._cols,
211 nplots=n)
212 else:
[485]213 self._plotter.set_panels(rows=n,cols=0,nplots=n)
[203]214 for scan in scans:
[541]215 self._plotter.palette(1)
[203]216 if n > 1:
[525]217 self._plotter.subplot(scans.index(scan))
[485]218 self._plotter.palette(1)
[525]219 colvals = eval(cdict2.get(colmode))
220 rowsel = self._cursor["t"][0]
221 for j in colvals:
222 polmode = "raw"
223 jj = colvals.index(j)
224 savej = j
225 for k in cdict.keys():
226 sel = eval(cdict2.get(k))
227 j = sel[0]
228 eval(cdict.get(k))
229 if k == "p":
230 which = self._cursor["p"].index(j)
231 polmode = self._polmode[which]
232 j = which
233 j = savej
234 if colmode == "p":
235 polmode = self._polmode[self._cursor["p"].index(j)]
236 j = jj
[203]237 eval(cdict.get(colmode))
238 x = None
239 y = None
240 m = None
[226]241 tlab = self._title
242 if not self._title:
[525]243 tlab = scan._getsourcename(rowsel)
244 x,xlab = scan.get_abcissa(rowsel)
[257]245 if self._abcissa: xlab = self._abcissa
[525]246 if polmode == "stokes":
247 y = scan._getstokesspectrum(rowsel)
248 elif polmode == "stokes2":
249 y = scan._getstokesspectrum(rowsel,True)
[541]250 elif polmode == "circular":
251 y = scan._stokestopolspectrum(rowsel,False,-1)
[525]252 else:
253 y = scan._getspectrum(rowsel)
[257]254 if self._ordinate:
255 ylab = self._ordinate
256 else:
257 ylab = 'Flux ('+scan.get_fluxunit()+')'
[525]258 m = scan._getmask(rowsel)
[257]259 if self._lmap and len(self._lmap) > 0:
[525]260 llab = self._lmap[jj]
[203]261 else:
[525]262 if colmode == 'p':
263 if polmode == "stokes":
264 llab = scan._getpolarizationlabel(0,1,0)
265 elif polmode == "stokes2":
266 llab = scan._getpolarizationlabel(0,1,1)
[541]267 elif polmode == "circular":
268 llab = scan._getpolarizationlabel(0,0,0)
[525]269 else:
270 llab = scan._getpolarizationlabel(1,0,0)
271 else:
272 llab = self._ldict.get(colmode)+' '+str(j)
[203]273 self._plotter.set_line(label=llab)
274 self._plotter.plot(x,y,m)
275 xlim=[min(x),max(x)]
276 self._plotter.axes.set_xlim(xlim)
277
278 self._plotter.set_axes('xlabel',xlab)
279 self._plotter.set_axes('ylabel',ylab)
280 self._plotter.set_axes('title',tlab)
281 return
282
283 def _plot_other(self,scans,colmode):
284 if colmode == self._panels:
285 return
[525]286 cdict = {'b':'scan.setbeam(i)',
287 'i':'scan.setif(i)',
288 'p':'scan.setpol(i)'}
289 cdict2 = {'b':'self._cursor["b"]',
290 'i':'self._cursor["i"]',
291 'p':'self._cursor["p"]',
292 's': 'scans',
293 't': 'self._cursor["t"]'}
[203]294 scan = scans[0]
295 n = eval(self._cdict.get(self._panels))
[525]296 ncol=1
[203]297 if self._stacking is not None:
298 ncol = eval(self._cdict.get(colmode))
299 self._plotter.set_panels()
300 if n > 1:
[377]301 if self._rows and self._cols:
302 n = min(n,self._rows*self._cols)
303 self._plotter.set_panels(rows=self._rows,cols=self._cols,
304 nplots=n)
305 else:
[485]306 self._plotter.set_panels(rows=n,cols=0,nplots=n)
[525]307 panels = self._cursor[self._panels]
308 for i in panels:
[541]309 self._plotter.palette(1)
[525]310 polmode = "raw"
311 ii = self._cursor[self._panels].index(i)
[203]312 if n>1:
[525]313 self._plotter.subplot(ii)
314 if self._panels == "p":
315 polmode = self._polmode[ii]
316 eval(cdict.get(self._panels))
317 else:
318 eval(cdict.get(self._panels))
319 colvals = eval(cdict2.get(colmode))
320 for j in colvals:
321 rowsel = self._cursor["t"][0]
322 jj = colvals.index(j)
323 savei = i
324 for k in cdict.keys():
325 if k != self._panels:
326 sel = eval(cdict2.get(k))
327 i = sel[0]
328 if k == "p":
329 which = self._cursor["p"].index(j)
330 polmode = self._polmode[which]
331 i = which
332 eval(cdict.get(k))
333 i = savei
[203]334 if colmode == 's':
[525]335 scan = j
[203]336 elif colmode == 't':
[525]337 rowsel = j
[203]338 else:
[525]339 savei = i
340 if colmode == 'p':
341 polmode = self._polmode[self._cursor["p"].index(j)]
342 i = j
[203]343 eval(cdict.get(colmode))
[525]344 i = savei
[203]345 x = None
346 y = None
347 m = None
[525]348 x,xlab = scan.get_abcissa(rowsel)
[257]349 if self._abcissa: xlab = self._abcissa
[525]350 if polmode == "stokes":
351 y = scan._getstokesspectrum(rowsel)
352 elif polmode == "stokes2":
353 y = scan._getstokesspectrum(rowsel,True)
[541]354 elif polmode == "circular":
355 y = scan._stokestopolspectrum(rowsel,False,-1)
[525]356 else:
357 y = scan._getspectrum(rowsel)
358
[257]359 if self._ordinate:
360 ylab = self._ordinate
361 else:
362 ylab = 'Flux ('+scan.get_fluxunit()+')'
[525]363 m = scan._getmask(rowsel)
[203]364 if colmode == 's' or colmode == 't':
[525]365 if self._title and len(self._title) > 0:
366 tlab = self._title[ii]
367 else:
[226]368 tlab = self._ldict.get(self._panels)+' '+str(i)
[525]369 llab = scan._getsourcename(rowsel)
[203]370 else:
[226]371 if self._title and len(self._title) > 0:
[525]372 tlab = self._title[ii]
[226]373 else:
[257]374 tlab = self._ldict.get(self._panels)+' '+str(i)
[226]375 if self._lmap and len(self._lmap) > 0:
[525]376 llab = self._lmap[jj]
[203]377 else:
[525]378 if colmode == 'p':
379 if polmode == "stokes":
380 llab = scan._getpolarizationlabel(0,1,0)
381 elif polmode == "stokes2":
382 llab = scan._getpolarizationlabel(0,1,1)
[541]383 elif polmode == "circular":
384 llab = scan._getpolarizationlabel(0,0,0)
[525]385 else:
386 llab = scan._getpolarizationlabel(1,0,0)
387 else:
388 llab = self._ldict.get(colmode)+' '+str(j)
389 if self._panels == 'p':
390 if polmode == "stokes":
391 tlab = scan._getpolarizationlabel(0,1,0)
392 elif polmode == "stokes2":
393 tlab = scan._getpolarizationlabel(0,1,1)
[541]394 elif polmode == "circular":
395 tlab = scan._getpolarizationlabel(0,0,0)
[525]396 else:
397 tlab = scan._getpolarizationlabel(1,0,0)
[203]398 self._plotter.set_line(label=llab)
399 self._plotter.plot(x,y,m)
400 xlim=[min(x),max(x)]
401 self._plotter.axes.set_xlim(xlim)
402
403 self._plotter.set_axes('xlabel',xlab)
404 self._plotter.set_axes('ylabel',ylab)
405 self._plotter.set_axes('title',tlab)
406
407 return
408
409
[226]410 def set_mode(self, stacking=None, panelling=None):
[203]411 """
[377]412 Set the plots look and feel, i.e. what you want to see on the plot.
[203]413 Parameters:
414 stacking: tell the plotter which variable to plot
415 as line colour overlays (default 'pol')
416 panelling: tell the plotter which variable to plot
417 across multiple panels (default 'scan'
418 Note:
419 Valid modes are:
420 'beam' 'Beam' 'b': Beams
421 'if' 'IF' 'i': IFs
422 'pol' 'Pol' 'p': Polarisations
423 'scan' 'Scan' 's': Scans
424 'time' 'Time' 't': Times
425 """
426 if not self.set_panels(panelling):
427 print "Invalid mode"
[226]428 return
[203]429 if not self.set_stacking(stacking):
430 print "Invalid mode"
[226]431 return
432 if self._data: self.plot()
[203]433 return
434
[377]435 def set_panels(self, what=None):
[226]436 if not what:
437 what = rcParams['plotter.panelling']
[203]438 md = self._translate(what)
439 if md:
[226]440 self._panels = md
441 self._title = None
[203]442 return True
443 return False
444
[377]445 def set_layout(self,rows=None,cols=None):
446 """
447 Set the multi-panel layout, i.e. how many rows and columns plots
448 are visible.
449 Parameters:
450 rows: The number of rows of plots
451 cols: The number of columns of plots
452 Note:
453 If no argument is given, the potter reverts to its auto-plot
454 behaviour.
455 """
456 self._rows = rows
457 self._cols = cols
458 if self._data: self.plot()
459 return
460
[226]461 def set_stacking(self, what=None):
462 if not what:
463 what = rcParams['plotter.stacking']
[203]464 md = self._translate(what)
465 if md:
466 self._stacking = md
[226]467 self._lmap = None
[203]468 return True
469 return False
470
[525]471 def set_range(self,xstart=None,xend=None,ystart=None,yend=None):
[203]472 """
473 Set the range of interest on the abcissa of the plot
474 Parameters:
[525]475 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
[203]476 Note:
477 These become non-sensical when the unit changes.
478 use plotter.set_range() without parameters to reset
479
480 """
[525]481 if xstart is None and xend is None:
482 self._minmaxx = None
[226]483 if self._data: self.plot()
[525]484 return
485 if ystart is None and yend is None:
486 self._minmaxy = None
[226]487 if self._data: self.plot()
[525]488 return
489 self._minmaxx = [xstart,xend]
490 self._minmaxy = [ystart,yend]
491 if self._data: self.plot()
[203]492 return
493
[257]494 def set_legend(self, mp=None):
[203]495 """
496 Specify a mapping for the legend instead of using the default
497 indices:
498 Parameters:
499 mp: a list of 'strings'. This should have the same length
500 as the number of elements on the legend and then maps
501 to the indeces in order
502
503 Example:
[485]504 If the data has two IFs/rest frequencies with index 0 and 1
[203]505 for CO and SiO:
506 plotter.set_stacking('i')
507 plotter.set_legend_map(['CO','SiO'])
508 plotter.plot()
509 """
510 self._lmap = mp
[226]511 if self._data: self.plot()
512 return
513
514 def set_title(self, title=None):
515 self._title = title
516 if self._data: self.plot()
517 return
518
[257]519 def set_ordinate(self, ordinate=None):
520 self._ordinate = ordinate
521 if self._data: self.plot()
522 return
523
524 def set_abcissa(self, abcissa=None):
525 self._abcissa = abcissa
526 if self._data: self.plot()
527 return
528
[377]529 def save(self, filename=None):
530 """
531 Save the plot to a file. The know formats are 'png', 'ps', 'eps'.
532 Parameters:
533 filename: The name of the output file. This is optional
534 and autodetects the image format from the file
535 suffix. If non filename is specified a file
536 called 'yyyymmdd_hhmmss.png' is created in the
537 current directory.
538 """
539 self._plotter.save(filename)
540 return
[525]541
[541]542 def set_cursor(self, row=None,beam=None,IF=None,pol=None, refresh=True):
[525]543 """
544 Specify a 'cursor' for plotting selected spectra. Time (rows),
545 Beam, IF, Polarisation ranges can be specified.
546 Parameters:
547 Default for all paramaters is to select all available
548 row: selects the rows (time stamps) to be plotted, this has
549 to be a vector of row indices, e.g. row=[0,2,5] or row=[2]
550 beam: select a range of beams
551 IF: select a range of IFs
552 pol: select Polarisations for plotting these can be by index
553 (raw polarisations (default)) or by names any of:
554 ["I", "Q", "U", "V"] or
555 ["I", "Plinear", "Pangle", "V"] or
[541]556 ["XX", "YY", "Real(XY)", "Imag(XY)"] or
557 ["RR", "LL"]
[525]558 Example:
559 plotter.set_mode('pol','time')
560 plotter.plot(myscan) # plots all raw polarisations colour stacked
561 plotter.set_cursor(pol=["I"]) # plot "I" only for all rows
562 # plot "I" only for two time stamps row=0 and row=2
563 plotter.set_cursor(row=[0,2],pol=["I"])
[257]564
[525]565 Note:
566 Be careful to select only exisiting polarisations.
567 """
568 if not self._data:
569 print "Can only set cursor after a first call to plot()"
570 return
571
572 n = self._data[0].nrow()
573 if row is None:
574 self._cursor["t"] = range(n)
575 else:
576 for i in row:
577 if 0 > i >= n:
578 print "Row index '%d' out of range" % i
579 return
580 self._cursor["t"] = row
581
582 n = self._data[0].nbeam()
583 if beam is None:
584 self._cursor["b"] = range(n)
585 else:
586 for i in beam:
587 if 0 > i >= n:
588 print "Beam index '%d' out of range" % i
589 return
590 self._cursor["b"] = beam
591
592 n = self._data[0].nif()
593 if IF is None:
594 self._cursor["i"] = range(n)
595 else:
596 for i in IF:
597 if 0 > i >= n:
598 print "IF index '%d' out of range" %i
599 return
600 self._cursor["i"] = IF
601
602 n = self._data[0].npol()
603 dstokes = {"I":0,"Q":1,"U":2,"V":3}
604 dstokes2 = {"I":0,"Plinear":1,"Pangle":2,"V":3}
605 draw = {"XX":0, "YY":1,"Real(XY)":2, "Imag(XY)":3}
[541]606 dcirc = { "RR":0,"LL":1}#,"Real(RL)":2,"Image(RL)":3}
[525]607
608 if pol is None:
609 self._cursor["p"] = range(n)
610 self._polmode = ["raw" for i in range(n)]
611 else:
612 if isinstance(pol,str):
613 pol = pol.split()
614 polmode = []
615 pols = []
616 for i in pol:
617 if isinstance(i,str):
618 if draw.has_key(i):
619 pols.append(draw.get(i))
620 polmode.append("raw")
621 elif dstokes.has_key(i):
622 pols.append(dstokes.get(i))
623 polmode.append("stokes")
624 elif dstokes2.has_key(i):
625 pols.append(dstokes2.get(i))
626 polmode.append("stokes2")
627 elif dcirc.has_key(i):
628 pols.append(dcirc.get(i))
[541]629 polmode.append("circular")
[525]630 else:
631 "Pol type '%s' not valid" %i
632 return
633 elif 0 > i >= n:
634 print "Pol index '%d' out of range" %i
635 return
636 else:
637 pols.append(i)
638 polmode.append("raw")
639 self._cursor["p"] = pols
640 self._polmode = polmode
[541]641 if self._data and refresh: self.plot()
[525]642
643
[203]644if __name__ == '__main__':
645 plotter = asapplotter()
Note: See TracBrowser for help on using the repository browser.