source: trunk/python/asapplotter.py@ 670

Last change on this file since 670 was 652, checked in by mar637, 19 years ago

removed color loading as mpl now supports named colors. some minor corrections on pol label handling. Also added orientation option for ps output.

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