source: trunk/python/asapplotter.py@ 606

Last change on this file since 606 was 603, checked in by mar637, 19 years ago

Fix for asap0015

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