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

Last change on this file since 2956 was 622, checked in by mar637, 19 years ago

fixed a typo introduced in last revision.
fixed asap0019

  • 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 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 = scan._get_ordinate_label()
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 llab = self._get_pollabel(scan, polmode)
264 else:
265 llab = self._ldict.get(colmode)+' '+str(j)
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):
277 if colmode == self._panelling:
278 return
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"]'}
287 scan = scans[0]
288 n = eval(self._cdict.get(self._panelling))
289 ncol=1
290 if self._stacking is not None:
291 ncol = eval(self._cdict.get(colmode))
292 if n > 1:
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:
298 self._plotter.set_panels(rows=n,cols=0,nplots=n)
299 else:
300 self._plotter.set_panels()
301 panels = self._cursor[self._panelling]
302 for i in panels:
303 self._plotter.palette(1)
304 polmode = "raw"
305 ii = self._cursor[self._panelling].index(i)
306 if n>1:
307 self._plotter.subplot(ii)
308 if self._panelling == "p":
309 polmode = self._polmode[ii]
310 eval(cdict.get(self._panelling))
311 else:
312 eval(cdict.get(self._panelling))
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():
319 if k != self._panelling:
320 sel = eval(cdict2.get(k))
321 i = sel[0]
322 if k == "p":
323 which = self._cursor["p"].index(i)
324 polmode = self._polmode[which]
325 i = which
326 eval(cdict.get(k))
327 i = savei
328 if colmode == 's':
329 scan = j
330 elif colmode == 't':
331 rowsel = j
332 else:
333 savei = i
334 if colmode == 'p':
335 polmode = self._polmode[self._cursor["p"].index(j)]
336 i = j
337 eval(cdict.get(colmode))
338 i = savei
339 x = None
340 y = None
341 m = None
342 x,xlab = scan.get_abcissa(rowsel)
343 if self._abcissa: xlab = self._abcissa
344 if polmode == "stokes":
345 y = scan._getstokesspectrum(rowsel)
346 elif polmode == "stokes2":
347 y = scan._getstokesspectrum(rowsel,True)
348 elif polmode == "circular":
349 y = scan._stokestopolspectrum(rowsel,False,-1)
350 else:
351 y = scan._getspectrum(rowsel)
352
353 if self._ordinate:
354 ylab = self._ordinate
355 else:
356 ylab = scan._get_ordinate_label()
357 m = scan._getmask(rowsel)
358 if colmode == 's' or colmode == 't':
359 if self._title and len(self._title) > 0:
360 tlab = self._title[ii]
361 else:
362 tlab = self._ldict.get(self._panelling)+' '+str(i)
363 if self._lmap and len(self._lmap) > 0:
364 llab = self._lmap[jj]
365 else:
366 llab = scan._getsourcename(rowsel)
367 else:
368 if self._title and len(self._title) > 0:
369 tlab = self._title[ii]
370 else:
371 if self._panelling == 'p':
372 tlab = self._get_pollabel(scan, polmode)
373 else:
374 tlab = self._ldict.get(self._panelling)+' '+str(i)
375 if self._lmap and len(self._lmap) > 0:
376 llab = self._lmap[jj]
377 else:
378 if colmode == 'p':
379 llab = self._get_pollabel(scan, polmode)
380 else:
381 llab = self._ldict.get(colmode)+' '+str(j)
382 self._plotter.set_line(label=llab)
383 self._plotter.plot(x,y,m)
384 xlim=[min(x),max(x)]
385 self._plotter.axes.set_xlim(xlim)
386
387 self._plotter.set_axes('xlabel',xlab)
388 self._plotter.set_axes('ylabel',ylab)
389 self._plotter.set_axes('title',tlab)
390
391 return
392
393
394 def set_mode(self, stacking=None, panelling=None):
395 """
396 Set the plots look and feel, i.e. what you want to see on the plot.
397 Parameters:
398 stacking: tell the plotter which variable to plot
399 as line colour overlays (default 'pol')
400 panelling: tell the plotter which variable to plot
401 across multiple panels (default 'scan'
402 Note:
403 Valid modes are:
404 'beam' 'Beam' 'b': Beams
405 'if' 'IF' 'i': IFs
406 'pol' 'Pol' 'p': Polarisations
407 'scan' 'Scan' 's': Scans
408 'time' 'Time' 't': Times
409 """
410 if not self.set_panelling(panelling):
411 print "Invalid mode"
412 return
413 if not self.set_stacking(stacking):
414 print "Invalid mode"
415 return
416 if self._data: self.plot()
417 return
418
419 def set_panelling(self, what=None):
420 mode = what
421 if mode is None:
422 mode = rcParams['plotter.panelling']
423 md = self._translate(mode)
424 if md:
425 self._panelling = md
426 self._title = None
427 return True
428 return False
429
430 def set_layout(self,rows=None,cols=None):
431 """
432 Set the multi-panel layout, i.e. how many rows and columns plots
433 are visible.
434 Parameters:
435 rows: The number of rows of plots
436 cols: The number of columns of plots
437 Note:
438 If no argument is given, the potter reverts to its auto-plot
439 behaviour.
440 """
441 self._rows = rows
442 self._cols = cols
443 if self._data: self.plot()
444 return
445
446 def set_stacking(self, what=None):
447 mode = what
448 if mode is None:
449 mode = rcParams['plotter.stacking']
450 md = self._translate(mode)
451 if md:
452 self._stacking = md
453 self._lmap = None
454 return True
455 return False
456
457 def set_range(self,xstart=None,xend=None,ystart=None,yend=None):
458 """
459 Set the range of interest on the abcissa of the plot
460 Parameters:
461 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
462 Note:
463 These become non-sensical when the unit changes.
464 use plotter.set_range() without parameters to reset
465
466 """
467 if xstart is None and xend is None:
468 self._minmaxx = None
469 else:
470 self._minmaxx = [xstart,xend]
471 if ystart is None and yend is None:
472 self._minmaxy = None
473 else:
474 self._minmaxy = [ystart,yend]
475 if self._data: self.plot()
476 return
477
478 def set_legend(self, mp=None):
479 """
480 Specify a mapping for the legend instead of using the default
481 indices:
482 Parameters:
483 mp: a list of 'strings'. This should have the same length
484 as the number of elements on the legend and then maps
485 to the indeces in order
486
487 Example:
488 If the data has two IFs/rest frequencies with index 0 and 1
489 for CO and SiO:
490 plotter.set_stacking('i')
491 plotter.set_legend_map(['CO','SiO'])
492 plotter.plot()
493 """
494 self._lmap = mp
495 if self._data: self.plot()
496 return
497
498 def set_title(self, title=None):
499 self._title = title
500 if self._data: self.plot()
501 return
502
503 def set_ordinate(self, ordinate=None):
504 self._ordinate = ordinate
505 if self._data: self.plot()
506 return
507
508 def set_abcissa(self, abcissa=None):
509 self._abcissa = abcissa
510 if self._data: self.plot()
511 return
512
513 def save(self, filename=None):
514 """
515 Save the plot to a file. The know formats are 'png', 'ps', 'eps'.
516 Parameters:
517 filename: The name of the output file. This is optional
518 and autodetects the image format from the file
519 suffix. If non filename is specified a file
520 called 'yyyymmdd_hhmmss.png' is created in the
521 current directory.
522 """
523 self._plotter.save(filename)
524 return
525
526 def set_cursor(self, row=None,beam=None,IF=None,pol=None, refresh=True):
527 """
528 Specify a 'cursor' for plotting selected spectra. Time (rows),
529 Beam, IF, Polarisation ranges can be specified.
530 Parameters:
531 Default for all paramaters is to select all available
532 row: selects the rows (time stamps) to be plotted, this has
533 to be a vector of row indices, e.g. row=[0,2,5] or row=[2]
534 beam: select a range of beams
535 IF: select a range of IFs
536 pol: select Polarisations for plotting these can be by index
537 (raw polarisations (default)) or by names any of:
538 ["I", "Q", "U", "V"] or
539 ["I", "Plinear", "Pangle", "V"] or
540 ["XX", "YY", "Real(XY)", "Imag(XY)"] or
541 ["RR", "LL"]
542 Example:
543 plotter.set_mode('pol','time')
544 plotter.plot(myscan) # plots all raw polarisations colour stacked
545 plotter.set_cursor(pol=["I"]) # plot "I" only for all rows
546 # plot "I" only for two time stamps row=0 and row=2
547 plotter.set_cursor(row=[0,2],pol=["I"])
548
549 Note:
550 Be careful to select only exisiting polarisations.
551 """
552 if not self._data:
553 print "Can only set cursor after a first call to plot()"
554 return
555
556 n = self._data[0].nrow()
557 if row is None:
558 self._cursor["t"] = range(n)
559 else:
560 for i in row:
561 if i < 0 or i >= n:
562 print "Row index '%d' out of range" % i
563 return
564 self._cursor["t"] = row
565
566 n = self._data[0].nbeam()
567 if beam is None:
568 self._cursor["b"] = range(n)
569 else:
570 for i in beam:
571 if i < 0 or i >= n:
572 print "Beam index '%d' out of range" % i
573 return
574 self._cursor["b"] = beam
575
576 n = self._data[0].nif()
577 if IF is None:
578 self._cursor["i"] = range(n)
579 else:
580 for i in IF:
581 if i < 0 or i >= n:
582 print "IF index '%d' out of range" %i
583 return
584 self._cursor["i"] = IF
585
586 n = self._data[0].npol()
587 dstokes = {"I":0,"Q":1,"U":2,"V":3}
588 dstokes2 = {"I":0,"Plinear":1,"Pangle":2,"V":3}
589 draw = {"XX":0, "YY":1,"Real(XY)":2, "Imag(XY)":3}
590 dcirc = { "RR":0,"LL":1}#,"Real(RL)":2,"Image(RL)":3}
591
592 if pol is None:
593 self._cursor["p"] = range(n)
594 self._polmode = ["raw" for i in range(n)]
595 else:
596 if isinstance(pol,str):
597 pol = pol.split()
598 polmode = []
599 pols = []
600 for i in pol:
601 if isinstance(i,str):
602 if draw.has_key(i):
603 pols.append(draw.get(i))
604 polmode.append("raw")
605 elif dstokes.has_key(i):
606 pols.append(dstokes.get(i))
607 polmode.append("stokes")
608 elif dstokes2.has_key(i):
609 pols.append(dstokes2.get(i))
610 polmode.append("stokes2")
611 elif dcirc.has_key(i):
612 pols.append(dcirc.get(i))
613 polmode.append("circular")
614 else:
615 "Pol type '%s' not valid" %i
616 return
617 elif 0 > i >= n:
618 print "Pol index '%d' out of range" %i
619 return
620 else:
621 pols.append(i)
622 polmode.append("raw")
623 self._cursor["p"] = pols
624 self._polmode = polmode
625 if self._data and refresh: self.plot()
626
627 def _get_pollabel(self, scan, polmode):
628 tlab = ""
629 if polmode == "stokes":
630 tlab = scan._getpolarizationlabel(0,1,0)
631 elif polmode == "stokes2":
632 tlab = scan._getpolarizationlabel(0,1,1)
633 elif polmode == "circular":
634 tlab = scan._getpolarizationlabel(0,0,0)
635 else:
636 tlab = scan._getpolarizationlabel(1,0,0)
637 return tlab
638
639if __name__ == '__main__':
640 plotter = asapplotter()
Note: See TracBrowser for help on using the repository browser.