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

Last change on this file since 604 was 601, checked in by mar637, 20 years ago

Fixed asap00015, extracted pol_lablelling into separate function

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