source: trunk/python/asapplotter.py@ 638

Last change on this file since 638 was 626, checked in by mar637, 20 years ago

fix for asap0019 from Release-1

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