source: trunk/python/asapplotter.py@ 701

Last change on this file since 701 was 700, checked in by mar637, 20 years ago

merger from Release-1-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
215 for scan in scans:
216 self._plotter.palette(0)
217 if n > 1:
218 self._plotter.subplot(scans.index(scan))
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(0)
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, orientation='landscape'):
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 orientation: optional parameter for postscript. 'landscape'
523 (default) and 'portrait' are valid.
524 """
525 self._plotter.save(filename,orientation)
526 return
527
528 def set_cursor(self, row=None,beam=None,IF=None,pol=None, refresh=True):
529 """
530 Specify a 'cursor' for plotting selected spectra. Time (rows),
531 Beam, IF, Polarisation ranges can be specified.
532 Parameters:
533 Default for all paramaters is to select all available
534 row: selects the rows (time stamps) to be plotted, this has
535 to be a vector of row indices, e.g. row=[0,2,5] or row=[2]
536 beam: select a range of beams
537 IF: select a range of IFs
538 pol: select Polarisations for plotting these can be by index
539 (raw polarisations (default)) or by names any of:
540 ["I", "Q", "U", "V"] or
541 ["I", "Plinear", "Pangle", "V"] or
542 ["XX", "YY", "Real(XY)", "Imag(XY)"] or
543 ["RR", "LL"]
544 Example:
545 plotter.set_mode('pol','time')
546 plotter.plot(myscan) # plots all raw polarisations colour stacked
547 plotter.set_cursor(pol=["I"]) # plot "I" only for all rows
548 # plot "I" only for two time stamps row=0 and row=2
549 plotter.set_cursor(row=[0,2],pol=["I"])
550
551 Note:
552 Be careful to select only exisiting polarisations.
553 """
554 if not self._data:
555 print "Can only set cursor after a first call to plot()"
556 return
557
558 n = self._data[0].nrow()
559 if row is None:
560 self._cursor["t"] = range(n)
561 else:
562 for i in row:
563 if i < 0 or i >= n:
564 print "Row index '%d' out of range" % i
565 return
566 self._cursor["t"] = row
567
568 n = self._data[0].nbeam()
569 if beam is None:
570 self._cursor["b"] = range(n)
571 else:
572 for i in beam:
573 if i < 0 or i >= n:
574 print "Beam index '%d' out of range" % i
575 return
576 self._cursor["b"] = beam
577
578 n = self._data[0].nif()
579 if IF is None:
580 self._cursor["i"] = range(n)
581 else:
582 for i in IF:
583 if i < 0 or i >= n:
584 print "IF index '%d' out of range" %i
585 return
586 self._cursor["i"] = IF
587
588 n = self._data[0].npol()
589 dstokes = {"I":0,"Q":1,"U":2,"V":3}
590 dstokes2 = {"I":0,"Plinear":1,"Pangle":2,"V":3}
591 draw = {"XX":0, "YY":1,"Real(XY)":2, "Imag(XY)":3}
592 dcirc = { "RR":0,"LL":1}#,"Real(RL)":2,"Image(RL)":3}
593
594 if pol is None:
595 self._cursor["p"] = range(n)
596 self._polmode = ["raw" for i in range(n)]
597 else:
598 if isinstance(pol,str):
599 pol = pol.split()
600 polmode = []
601 pols = []
602 for i in pol:
603 if isinstance(i,str):
604 if draw.has_key(i):
605 pols.append(draw.get(i))
606 polmode.append("raw")
607 elif dstokes.has_key(i):
608 pols.append(dstokes.get(i))
609 polmode.append("stokes")
610 elif dstokes2.has_key(i):
611 pols.append(dstokes2.get(i))
612 polmode.append("stokes2")
613 elif dcirc.has_key(i):
614 pols.append(dcirc.get(i))
615 polmode.append("circular")
616 else:
617 print "Pol type '%s' not valid" %i
618 return
619 elif 0 > i >= n:
620 print "Pol index '%d' out of range" %i
621 return
622 else:
623 pols.append(i)
624 polmode.append("raw")
625 self._cursor["p"] = pols
626 self._polmode = polmode
627 if self._data and refresh: self.plot()
628
629 def _get_pollabel(self, scan, polmode):
630 tlab = ""
631 if polmode == "stokes":
632 tlab = scan._getpolarizationlabel(0,1,0)
633 elif polmode == "stokes2":
634 tlab = scan._getpolarizationlabel(0,1,1)
635 elif polmode == "circular":
636 tlab = scan._getpolarizationlabel(0,0,0)
637 else:
638 tlab = scan._getpolarizationlabel(1,0,0)
639 return tlab
640
641if __name__ == '__main__':
642 plotter = asapplotter()
Note: See TracBrowser for help on using the repository browser.