source: trunk/python/asapplotter.py@ 703

Last change on this file since 703 was 702, checked in by mar637, 19 years ago

merges from Release-2-fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.0 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(0)
124 for rowsel in rows:
125 i = self._cursor["t"].index(rowsel)
126 if n > 1:
127 self._plotter.palette(0)
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(0)
216 if n > 1:
217 self._plotter.subplot(scans.index(scan))
218 colvals = eval(cdict2.get(colmode))
219 rowsel = self._cursor["t"][0]
220 for j in colvals:
221 polmode = "raw"
222 jj = colvals.index(j)
223 savej = j
224 for k in cdict.keys():
225 sel = eval(cdict2.get(k))
226 j = sel[0]
227 eval(cdict.get(k))
228 if k == "p":
229 which = self._cursor["p"].index(j)
230 polmode = self._polmode[which]
231 j = which
232 j = savej
233 if colmode == "p":
234 polmode = self._polmode[self._cursor["p"].index(j)]
235 j = jj
236 eval(cdict.get(colmode))
237 x = None
238 y = None
239 m = None
240 tlab = self._title
241 if not self._title:
242 tlab = scan._getsourcename(rowsel)
243 x,xlab = scan.get_abcissa(rowsel)
244 if self._abcissa: xlab = self._abcissa
245 if polmode == "stokes":
246 y = scan._getstokesspectrum(rowsel)
247 elif polmode == "stokes2":
248 y = scan._getstokesspectrum(rowsel,True)
249 elif polmode == "circular":
250 y = scan._stokestopolspectrum(rowsel,False,-1)
251 else:
252 y = scan._getspectrum(rowsel)
253 if self._ordinate:
254 ylab = self._ordinate
255 else:
256 ylab = scan._get_ordinate_label()
257 m = scan._getmask(rowsel)
258 if self._lmap and len(self._lmap) > 0:
259 llab = self._lmap[jj]
260 else:
261 if colmode == 'p':
262 llab = self._get_pollabel(scan, polmode)
263 else:
264 llab = self._ldict.get(colmode)+' '+str(j)
265 self._plotter.set_line(label=llab)
266 self._plotter.plot(x,y,m)
267 xlim=[min(x),max(x)]
268 self._plotter.axes.set_xlim(xlim)
269
270 self._plotter.set_axes('xlabel',xlab)
271 self._plotter.set_axes('ylabel',ylab)
272 self._plotter.set_axes('title',tlab)
273 return
274
275 def _plot_other(self,scans,colmode):
276 if colmode == self._panelling:
277 return
278 cdict = {'b':'scan.setbeam(i)',
279 'i':'scan.setif(i)',
280 'p':'scan.setpol(i)'}
281 cdict2 = {'b':'self._cursor["b"]',
282 'i':'self._cursor["i"]',
283 'p':'self._cursor["p"]',
284 's': 'scans',
285 't': 'self._cursor["t"]'}
286 scan = scans[0]
287 n = eval(self._cdict.get(self._panelling))
288 ncol=1
289 if self._stacking is not None:
290 ncol = eval(self._cdict.get(colmode))
291 if n > 1:
292 if self._rows and self._cols:
293 n = min(n,self._rows*self._cols)
294 self._plotter.set_panels(rows=self._rows,cols=self._cols,
295 nplots=n)
296 else:
297 self._plotter.set_panels(rows=n,cols=0,nplots=n)
298 else:
299 self._plotter.set_panels()
300 panels = self._cursor[self._panelling]
301 for i in panels:
302 self._plotter.palette(0)
303 polmode = "raw"
304 ii = self._cursor[self._panelling].index(i)
305 if n>1:
306 self._plotter.subplot(ii)
307 if self._panelling == "p":
308 polmode = self._polmode[ii]
309 eval(cdict.get(self._panelling))
310 else:
311 eval(cdict.get(self._panelling))
312 colvals = eval(cdict2.get(colmode))
313 for j in colvals:
314 rowsel = self._cursor["t"][0]
315 jj = colvals.index(j)
316 savei = i
317 for k in cdict.keys():
318 if k != self._panelling:
319 sel = eval(cdict2.get(k))
320 i = sel[0]
321 if k == "p":
322 which = self._cursor["p"].index(i)
323 polmode = self._polmode[which]
324 i = which
325 eval(cdict.get(k))
326 i = savei
327 if colmode == 's':
328 scan = j
329 elif colmode == 't':
330 rowsel = j
331 else:
332 savei = i
333 if colmode == 'p':
334 polmode = self._polmode[self._cursor["p"].index(j)]
335 i = j
336 eval(cdict.get(colmode))
337 i = savei
338 x = None
339 y = None
340 m = None
341 x,xlab = scan.get_abcissa(rowsel)
342 if self._abcissa: xlab = self._abcissa
343 if polmode == "stokes":
344 y = scan._getstokesspectrum(rowsel)
345 elif polmode == "stokes2":
346 y = scan._getstokesspectrum(rowsel,True)
347 elif polmode == "circular":
348 y = scan._stokestopolspectrum(rowsel,False,-1)
349 else:
350 y = scan._getspectrum(rowsel)
351
352 if self._ordinate:
353 ylab = self._ordinate
354 else:
355 ylab = scan._get_ordinate_label()
356 m = scan._getmask(rowsel)
357 if colmode == 's' or colmode == 't':
358 if self._title and len(self._title) > 0:
359 tlab = self._title[ii]
360 else:
361 tlab = self._ldict.get(self._panelling)+' '+str(i)
362 if self._lmap and len(self._lmap) > 0:
363 llab = self._lmap[jj]
364 else:
365 llab = scan._getsourcename(rowsel)
366 else:
367 if self._title and len(self._title) > 0:
368 tlab = self._title[ii]
369 else:
370 if self._panelling == 'p':
371 tlab = self._get_pollabel(scan, polmode)
372 else:
373 tlab = self._ldict.get(self._panelling)+' '+str(i)
374 if self._lmap and len(self._lmap) > 0:
375 llab = self._lmap[jj]
376 else:
377 if colmode == 'p':
378 llab = self._get_pollabel(scan, polmode)
379 else:
380 llab = self._ldict.get(colmode)+' '+str(j)
381 self._plotter.set_line(label=llab)
382 self._plotter.plot(x,y,m)
383 xlim=[min(x),max(x)]
384 self._plotter.axes.set_xlim(xlim)
385
386 self._plotter.set_axes('xlabel',xlab)
387 self._plotter.set_axes('ylabel',ylab)
388 self._plotter.set_axes('title',tlab)
389
390 return
391
392
393 def set_mode(self, stacking=None, panelling=None):
394 """
395 Set the plots look and feel, i.e. what you want to see on the plot.
396 Parameters:
397 stacking: tell the plotter which variable to plot
398 as line colour overlays (default 'pol')
399 panelling: tell the plotter which variable to plot
400 across multiple panels (default 'scan'
401 Note:
402 Valid modes are:
403 'beam' 'Beam' 'b': Beams
404 'if' 'IF' 'i': IFs
405 'pol' 'Pol' 'p': Polarisations
406 'scan' 'Scan' 's': Scans
407 'time' 'Time' 't': Times
408 """
409 if not self.set_panelling(panelling):
410 print "Invalid mode"
411 return
412 if not self.set_stacking(stacking):
413 print "Invalid mode"
414 return
415 if self._data: self.plot()
416 return
417
418 def set_panelling(self, what=None):
419 mode = what
420 if mode is None:
421 mode = rcParams['plotter.panelling']
422 md = self._translate(mode)
423 if md:
424 self._panelling = md
425 self._title = None
426 return True
427 return False
428
429 def set_layout(self,rows=None,cols=None):
430 """
431 Set the multi-panel layout, i.e. how many rows and columns plots
432 are visible.
433 Parameters:
434 rows: The number of rows of plots
435 cols: The number of columns of plots
436 Note:
437 If no argument is given, the potter reverts to its auto-plot
438 behaviour.
439 """
440 self._rows = rows
441 self._cols = cols
442 if self._data: self.plot()
443 return
444
445 def set_stacking(self, what=None):
446 mode = what
447 if mode is None:
448 mode = rcParams['plotter.stacking']
449 md = self._translate(mode)
450 if md:
451 self._stacking = md
452 self._lmap = None
453 return True
454 return False
455
456 def set_range(self,xstart=None,xend=None,ystart=None,yend=None):
457 """
458 Set the range of interest on the abcissa of the plot
459 Parameters:
460 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
461 Note:
462 These become non-sensical when the unit changes.
463 use plotter.set_range() without parameters to reset
464
465 """
466 if xstart is None and xend is None:
467 self._minmaxx = None
468 else:
469 self._minmaxx = [xstart,xend]
470 if ystart is None and yend is None:
471 self._minmaxy = None
472 else:
473 self._minmaxy = [ystart,yend]
474 if self._data: self.plot()
475 return
476
477 def set_legend(self, mp=None):
478 """
479 Specify a mapping for the legend instead of using the default
480 indices:
481 Parameters:
482 mp: a list of 'strings'. This should have the same length
483 as the number of elements on the legend and then maps
484 to the indeces in order
485
486 Example:
487 If the data has two IFs/rest frequencies with index 0 and 1
488 for CO and SiO:
489 plotter.set_stacking('i')
490 plotter.set_legend_map(['CO','SiO'])
491 plotter.plot()
492 """
493 self._lmap = mp
494 if self._data: self.plot()
495 return
496
497 def set_title(self, title=None):
498 self._title = title
499 if self._data: self.plot()
500 return
501
502 def set_ordinate(self, ordinate=None):
503 self._ordinate = ordinate
504 if self._data: self.plot()
505 return
506
507 def set_abcissa(self, abcissa=None):
508 self._abcissa = abcissa
509 if self._data: self.plot()
510 return
511
512 def save(self, filename=None, orientation='landscape'):
513 """
514 Save the plot to a file. The know formats are 'png', 'ps', 'eps'.
515 Parameters:
516 filename: The name of the output file. This is optional
517 and autodetects the image format from the file
518 suffix. If non filename is specified a file
519 called 'yyyymmdd_hhmmss.png' is created in the
520 current directory.
521 orientation: optional parameter for postscript. 'landscape'
522 (default) and 'portrait' are valid.
523 """
524 self._plotter.save(filename,orientation)
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 print "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.