source: trunk/python/asapplotter.py@ 590

Last change on this file since 590 was 557, checked in by mar637, 20 years ago

bug fix in mode == 'p' indexing

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