source: branches/Release-1-fixes/python/asapplotter.py@ 598

Last change on this file since 598 was 597, checked in by mar637, 19 years ago

Fixed asap0008 and asap0014

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