source: trunk/python/asapplotter.py@ 541

Last change on this file since 541 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
Line 
1from asap.asaplot import ASAPlot
2from asap import rcParams
3
4class asapplotter:
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 """
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'}
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"])',
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]
33 self._panels = rcParams['plotter.panelling']
34 self._stacking = rcParams['plotter.stacking']
35 self._rows = None
36 self._cols = None
37 self._autoplot = False
38 self._minmaxx = None
39 self._minmaxy = None
40 self._data = None
41 self._lmap = []
42 self._title = None
43 self._ordinate = None
44 self._abcissa = None
45 self._cursor = {'t':None, 'b':None,
46 'i':None, 'p':None
47 }
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
55 def plot(self, *args):
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'
63 NO checking is done that the abcissas of the scantables
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:
71 if self._data is not None:
72 if list(args) != self._data:
73 self._data = list(args)
74 # reset cursor
75 self.set_cursor(refresh=False)
76 else:
77 self._data = list(args)
78 self.set_cursor(refresh=False)
79 if self._panels == 't':
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)
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)
90 if self._minmaxx is not None or self._minmaxy is not None:
91 self._plotter.set_limits(xlim=self._minmaxx,ylim=self._minmaxy)
92 self._plotter.release()
93 return
94
95 def _plot_time(self, scan, colmode):
96 if colmode == 't':
97 return
98 n = len(self._cursor["t"])
99 cdict = {'b':'scan.setbeam(j)',
100 'i':'scan.setif(j)',
101 'p':'scan.setpol(j)'}
102 cdict2 = {'b':'self._cursor["b"]',
103 'i':'self._cursor["i"]',
104 'p':'self._cursor["p"]'}
105 ncol = 1
106 if self._stacking is not None:
107 ncol = eval(self._cdict.get(colmode))
108 self._plotter.set_panels()
109 if n > 1:
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:
115 self._plotter.set_panels(rows=n,cols=0,nplots=n)
116 rows = self._cursor["t"]
117 self._plotter.palette(1)
118 for rowsel in rows:
119 i = self._cursor["t"].index(rowsel)
120 if n > 1:
121 self._plotter.palette(1)
122 self._plotter.subplot(i)
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
140 eval(cdict.get(colmode))
141 x = None
142 y = None
143 m = None
144 if not self._title:
145 tlab = scan._getsourcename(rowsel)
146 else:
147 if len(self._title) == n:
148 tlab = self._title[rowsel]
149 else:
150 tlab = scan._getsourcename(rowsel)
151 x,xlab = scan.get_abcissa(rowsel)
152 if self._abcissa: xlab = self._abcissa
153 y = None
154 if polmode == "stokes":
155 y = scan._getstokesspectrum(rowsel)
156 elif polmode == "stokes2":
157 y = scan._getstokesspectrum(rowsel,True)
158 elif polmode == "circular":
159 y = scan._stokestopolspectrum(rowsel,False,-1)
160 else:
161 y = scan._getspectrum(rowsel)
162 if self._ordinate:
163 ylab = self._ordinate
164 else:
165 ylab = 'Flux ('+scan.get_fluxunit()+')'
166 m = scan._getmask(rowsel)
167 if self._lmap and len(self._lmap) > 0:
168 llab = self._lmap[jj]
169 else:
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)
175 elif polmode == "circular":
176 llab = scan._getpolarizationlabel(0,0,0)
177 else:
178 llab = scan._getpolarizationlabel(1,0,0)
179 else:
180 llab = self._ldict.get(colmode)+' '+str(j)
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
190 def _plot_scans(self, scans, colmode):
191 print "Can only plot one row per scan."
192 if colmode == 's':
193 return
194 cdict = {'b':'scan.setbeam(j)',
195 'i':'scan.setif(j)',
196 'p':'scan.setpol(j)'}
197 cdict2 = {'b':'self._cursor["b"]',
198 'i':'self._cursor["i"]',
199 'p':'self._cursor["p"]'}
200
201 n = len(scans)
202 ncol = 1
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:
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:
213 self._plotter.set_panels(rows=n,cols=0,nplots=n)
214 for scan in scans:
215 self._plotter.palette(1)
216 if n > 1:
217 self._plotter.subplot(scans.index(scan))
218 self._plotter.palette(1)
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
237 eval(cdict.get(colmode))
238 x = None
239 y = None
240 m = None
241 tlab = self._title
242 if not self._title:
243 tlab = scan._getsourcename(rowsel)
244 x,xlab = scan.get_abcissa(rowsel)
245 if self._abcissa: xlab = self._abcissa
246 if polmode == "stokes":
247 y = scan._getstokesspectrum(rowsel)
248 elif polmode == "stokes2":
249 y = scan._getstokesspectrum(rowsel,True)
250 elif polmode == "circular":
251 y = scan._stokestopolspectrum(rowsel,False,-1)
252 else:
253 y = scan._getspectrum(rowsel)
254 if self._ordinate:
255 ylab = self._ordinate
256 else:
257 ylab = 'Flux ('+scan.get_fluxunit()+')'
258 m = scan._getmask(rowsel)
259 if self._lmap and len(self._lmap) > 0:
260 llab = self._lmap[jj]
261 else:
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)
267 elif polmode == "circular":
268 llab = scan._getpolarizationlabel(0,0,0)
269 else:
270 llab = scan._getpolarizationlabel(1,0,0)
271 else:
272 llab = self._ldict.get(colmode)+' '+str(j)
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
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"]'}
294 scan = scans[0]
295 n = eval(self._cdict.get(self._panels))
296 ncol=1
297 if self._stacking is not None:
298 ncol = eval(self._cdict.get(colmode))
299 self._plotter.set_panels()
300 if n > 1:
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:
306 self._plotter.set_panels(rows=n,cols=0,nplots=n)
307 panels = self._cursor[self._panels]
308 for i in panels:
309 self._plotter.palette(1)
310 polmode = "raw"
311 ii = self._cursor[self._panels].index(i)
312 if n>1:
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
334 if colmode == 's':
335 scan = j
336 elif colmode == 't':
337 rowsel = j
338 else:
339 savei = i
340 if colmode == 'p':
341 polmode = self._polmode[self._cursor["p"].index(j)]
342 i = j
343 eval(cdict.get(colmode))
344 i = savei
345 x = None
346 y = None
347 m = None
348 x,xlab = scan.get_abcissa(rowsel)
349 if self._abcissa: xlab = self._abcissa
350 if polmode == "stokes":
351 y = scan._getstokesspectrum(rowsel)
352 elif polmode == "stokes2":
353 y = scan._getstokesspectrum(rowsel,True)
354 elif polmode == "circular":
355 y = scan._stokestopolspectrum(rowsel,False,-1)
356 else:
357 y = scan._getspectrum(rowsel)
358
359 if self._ordinate:
360 ylab = self._ordinate
361 else:
362 ylab = 'Flux ('+scan.get_fluxunit()+')'
363 m = scan._getmask(rowsel)
364 if colmode == 's' or colmode == 't':
365 if self._title and len(self._title) > 0:
366 tlab = self._title[ii]
367 else:
368 tlab = self._ldict.get(self._panels)+' '+str(i)
369 llab = scan._getsourcename(rowsel)
370 else:
371 if self._title and len(self._title) > 0:
372 tlab = self._title[ii]
373 else:
374 tlab = self._ldict.get(self._panels)+' '+str(i)
375 if self._lmap and len(self._lmap) > 0:
376 llab = self._lmap[jj]
377 else:
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)
383 elif polmode == "circular":
384 llab = scan._getpolarizationlabel(0,0,0)
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)
394 elif polmode == "circular":
395 tlab = scan._getpolarizationlabel(0,0,0)
396 else:
397 tlab = scan._getpolarizationlabel(1,0,0)
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
410 def set_mode(self, stacking=None, panelling=None):
411 """
412 Set the plots look and feel, i.e. what you want to see on the plot.
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"
428 return
429 if not self.set_stacking(stacking):
430 print "Invalid mode"
431 return
432 if self._data: self.plot()
433 return
434
435 def set_panels(self, what=None):
436 if not what:
437 what = rcParams['plotter.panelling']
438 md = self._translate(what)
439 if md:
440 self._panels = md
441 self._title = None
442 return True
443 return False
444
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
461 def set_stacking(self, what=None):
462 if not what:
463 what = rcParams['plotter.stacking']
464 md = self._translate(what)
465 if md:
466 self._stacking = md
467 self._lmap = None
468 return True
469 return False
470
471 def set_range(self,xstart=None,xend=None,ystart=None,yend=None):
472 """
473 Set the range of interest on the abcissa of the plot
474 Parameters:
475 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
476 Note:
477 These become non-sensical when the unit changes.
478 use plotter.set_range() without parameters to reset
479
480 """
481 if xstart is None and xend is None:
482 self._minmaxx = None
483 if self._data: self.plot()
484 return
485 if ystart is None and yend is None:
486 self._minmaxy = None
487 if self._data: self.plot()
488 return
489 self._minmaxx = [xstart,xend]
490 self._minmaxy = [ystart,yend]
491 if self._data: self.plot()
492 return
493
494 def set_legend(self, mp=None):
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:
504 If the data has two IFs/rest frequencies with index 0 and 1
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
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
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
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
541
542 def set_cursor(self, row=None,beam=None,IF=None,pol=None, refresh=True):
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
556 ["XX", "YY", "Real(XY)", "Imag(XY)"] or
557 ["RR", "LL"]
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"])
564
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}
606 dcirc = { "RR":0,"LL":1}#,"Real(RL)":2,"Image(RL)":3}
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))
629 polmode.append("circular")
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
641 if self._data and refresh: self.plot()
642
643
644if __name__ == '__main__':
645 plotter = asapplotter()
Note: See TracBrowser for help on using the repository browser.