source: trunk/python/asapplotter.py@ 709

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

changes to reflect change in asaplot

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.0 KB
Line 
1from asap import rcParams
2from numarray import logical_and
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, visible=True):
14
15 if visible:
16 from asap.asaplotgui import asaplotgui as asaplot
17 else:
18 from asap.asaplot import asaplot
19 self._plotter = asaplot()
20
21 self._tdict = {'Time':'t','time':'t','t':'t','T':'t'}
22 self._bdict = {'Beam':'b','beam':'b','b':'b','B':'b'}
23 self._idict = {'IF':'i','if':'i','i':'i','I':'i'}
24 self._pdict = {'Pol':'p','pol':'p','p':'p'}
25 self._sdict = {'scan':'s','Scan':'s','s':'s','S':'s'}
26 self._cdict = {'t':'len(self._cursor["t"])',
27 'b':'len(self._cursor["b"])',
28 'i':'len(self._cursor["i"])',
29 'p':'len(self._cursor["p"])',
30 's':'len(scans)'}
31 self._ldict = {'b':'Beam',
32 'i':'IF',
33 'p':'Pol',
34 's':'Scan'}
35 self._dicts = [self._tdict,self._bdict,
36 self._idict,self._pdict,
37 self._sdict]
38 self._panelling = None
39 self._stacking = None
40 self.set_panelling()
41 self.set_stacking()
42 self._rows = None
43 self._cols = None
44 self._autoplot = False
45 self._minmaxx = None
46 self._minmaxy = None
47 self._datamask = None
48 self._data = None
49 self._lmap = None
50 self._title = None
51 self._ordinate = None
52 self._abcissa = None
53 self._abcunit = None
54 self._cursor = {'t':None, 'b':None,
55 'i':None, 'p':None
56 }
57
58 def _translate(self, name):
59 for d in self._dicts:
60 if d.has_key(name):
61 return d[name]
62 return None
63
64 def plot(self, *args):
65 """
66 Plot a (list of) scantables.
67 Parameters:
68 one or more comma separated scantables
69 Note:
70 If a (list) of scantables was specified in a previous call
71 to plot, no argument has to be given to 'replot'
72 NO checking is done that the abcissas of the scantables
73 are consistent e.g. all 'channel' or all 'velocity' etc.
74 """
75 if self._plotter.is_dead:
76 self._plotter = ASAPlot()
77 self._plotter.hold()
78 self._plotter.clear()
79 if len(args) > 0:
80 if self._data is not None:
81 if list(args) != self._data:
82 self._data = list(args)
83 # reset cursor
84 self.set_cursor(refresh=False)
85 else:
86 self._data = list(args)
87 self.set_cursor(refresh=False)
88 # ranges become invalid when unit changes
89 if self._abcunit != self._data[0].get_unit():
90 self._minmaxx = None
91 self._minmaxy = None
92 self._abcunit = self._data[0].get_unit()
93 self._datamask = None
94 if self._panelling == 't':
95 maxrows = 25
96 if self._data[0].nrow() > maxrows:
97 if self._cursor["t"] is None or \
98 (isinstance(self._cursor["t"],list) and \
99 len(self._cursor["t"]) > maxrows ):
100 print "Scan to be plotted contains more than %d rows.\n" \
101 "Selecting first %d rows..." % (maxrows,maxrows)
102 self._cursor["t"] = range(maxrows)
103 self._plot_time(self._data[0], self._stacking)
104 elif self._panelling == 's':
105 self._plot_scans(self._data, self._stacking)
106 else:
107 self._plot_other(self._data, self._stacking)
108 if self._minmaxy is not None:
109 self._plotter.set_limits(ylim=self._minmaxy)
110 self._plotter.release()
111 return
112
113 def _plot_time(self, scan, colmode):
114 if colmode == 't':
115 return
116 n = len(self._cursor["t"])
117 cdict = {'b':'scan.setbeam(j)',
118 'i':'scan.setif(j)',
119 'p':'scan.setpol(j)'}
120 cdict2 = {'b':'self._cursor["b"]',
121 'i':'self._cursor["i"]',
122 'p':'self._cursor["p"]'}
123 ncol = 1
124 if self._stacking is not None:
125 ncol = eval(self._cdict.get(colmode))
126 if n > 1:
127 if self._rows and self._cols:
128 n = min(n,self._rows*self._cols)
129 self._plotter.set_panels(rows=self._rows,cols=self._cols,
130 nplots=n)
131 else:
132 self._plotter.set_panels(rows=n,cols=0,nplots=n)
133 else:
134 self._plotter.set_panels()
135 rows = self._cursor["t"]
136 self._plotter.palette(0)
137 for rowsel in rows:
138 i = self._cursor["t"].index(rowsel)
139 if n > 1:
140 self._plotter.palette(0)
141 self._plotter.subplot(i)
142 colvals = eval(cdict2.get(colmode))
143 for j in colvals:
144 polmode = "raw"
145 jj = colvals.index(j)
146 savej = j
147 for k in cdict.keys():
148 sel = eval(cdict2.get(k))
149 j = sel[0]
150 if k == "p":
151 which = self._cursor["p"].index(j)
152 polmode = self._polmode[which]
153 j = which
154 eval(cdict.get(k))
155 j = savej
156 if colmode == "p":
157 polmode = self._polmode[self._cursor["p"].index(j)]
158 #j = jj
159 eval(cdict.get(colmode))
160 x = None
161 y = None
162 m = None
163 if self._title is None:
164 tlab = scan._getsourcename(rowsel)
165 else:
166 if len(self._title) >= n:
167 tlab = self._title[rowsel]
168 else:
169 tlab = scan._getsourcename(rowsel)
170 x,xlab = scan.get_abcissa(rowsel)
171 if self._abcissa: xlab = self._abcissa
172 y = None
173 if polmode == "stokes":
174 y = scan._getstokesspectrum(rowsel)
175 elif polmode == "stokes2":
176 y = scan._getstokesspectrum(rowsel,True)
177 elif polmode == "circular":
178 y = scan._stokestopolspectrum(rowsel,False,-1)
179 else:
180 y = scan._getspectrum(rowsel)
181 if self._ordinate:
182 ylab = self._ordinate
183 else:
184 ylab = scan._get_ordinate_label()
185 m = scan._getmask(rowsel)
186 if self._datamask is not None:
187 if len(m) == len(self._datamask):
188 m = logical_and(m,self._datamask)
189 if self._lmap and len(self._lmap) > 0:
190 llab = self._lmap[jj]
191 else:
192 if colmode == 'p':
193 llab = self._get_pollabel(scan, polmode)
194 else:
195 llab = self._ldict.get(colmode)+' '+str(j)
196 self._plotter.set_line(label=llab)
197 if self._minmaxx is not None:
198 s,e = self._slice_indeces(x)
199 x = x[s:e]
200 y = y[s:e]
201 m = m[s:e]
202 self._plotter.plot(x,y,m)
203 xlim=[min(x),max(x)]
204 if self._minmaxx is not None:
205 xlim = self._minmaxx
206 self._plotter.axes.set_xlim(xlim)
207 self._plotter.set_axes('xlabel',xlab)
208 self._plotter.set_axes('ylabel',ylab)
209 self._plotter.set_axes('title',tlab)
210 return
211
212 def _plot_scans(self, scans, colmode):
213 print "Can only plot one row per scan."
214 if colmode == 's':
215 return
216 cdict = {'b':'scan.setbeam(j)',
217 'i':'scan.setif(j)',
218 'p':'scan.setpol(j)'}
219 cdict2 = {'b':'self._cursor["b"]',
220 'i':'self._cursor["i"]',
221 'p':'self._cursor["p"]'}
222
223 n = len(scans)
224 ncol = 1
225 if self._stacking is not None:
226 scan = scans[0]
227 ncol = eval(self._cdict.get(colmode))
228 if n > 1:
229 if self._rows and self._cols:
230 n = min(n,self._rows*self._cols)
231 self._plotter.set_panels(rows=self._rows,cols=self._cols,
232 nplots=n)
233 else:
234 self._plotter.set_panels(rows=n,cols=0,nplots=n)
235 else:
236 self._plotter.set_panels()
237
238 for scan in scans:
239 self._plotter.palette(0)
240 if n > 1:
241 self._plotter.subplot(scans.index(scan))
242 colvals = eval(cdict2.get(colmode))
243 rowsel = self._cursor["t"][0]
244 for j in colvals:
245 polmode = "raw"
246 jj = colvals.index(j)
247 savej = j
248 for k in cdict.keys():
249 sel = eval(cdict2.get(k))
250 j = sel[0]
251 eval(cdict.get(k))
252 if k == "p":
253 which = self._cursor["p"].index(j)
254 polmode = self._polmode[which]
255 j = which
256 j = savej
257 if colmode == "p":
258 polmode = self._polmode[self._cursor["p"].index(j)]
259 #j = jj
260 eval(cdict.get(colmode))
261 x = None
262 y = None
263 m = None
264 tlab = self._title
265 if not self._title:
266 tlab = scan._getsourcename(rowsel)
267 x,xlab = scan.get_abcissa(rowsel)
268 if self._abcissa: xlab = self._abcissa
269 if polmode == "stokes":
270 y = scan._getstokesspectrum(rowsel)
271 elif polmode == "stokes2":
272 y = scan._getstokesspectrum(rowsel,True)
273 elif polmode == "circular":
274 y = scan._stokestopolspectrum(rowsel,False,-1)
275 else:
276 y = scan._getspectrum(rowsel)
277 if self._ordinate:
278 ylab = self._ordinate
279 else:
280 ylab = scan._get_ordinate_label()
281 m = scan._getmask(rowsel)
282 if self._datamask is not None:
283 if len(m) == len(self._datamask):
284 m = logical_and(m,self._datamask)
285 if self._lmap and len(self._lmap) > 0:
286 llab = self._lmap[jj]
287 else:
288 if colmode == 'p':
289 llab = self._get_pollabel(scan, polmode)
290 else:
291 llab = self._ldict.get(colmode)+' '+str(j)
292 self._plotter.set_line(label=llab)
293 if self._minmaxx is not None:
294 s,e = self._slice_indeces(x)
295 x = x[s:e]
296 y = y[s:e]
297 m = m[s:e]
298
299 self._plotter.plot(x,y,m)
300 xlim=[min(x),max(x)]
301 if self._minmaxx is not None:
302 xlim = self._minmaxx
303 self._plotter.axes.set_xlim(xlim)
304
305 self._plotter.set_axes('xlabel',xlab)
306 self._plotter.set_axes('ylabel',ylab)
307 self._plotter.set_axes('title',tlab)
308 return
309
310 def _plot_other(self,scans,colmode):
311 if colmode == self._panelling:
312 return
313 cdict = {'b':'scan.setbeam(i)',
314 'i':'scan.setif(i)',
315 'p':'scan.setpol(i)'}
316 cdict2 = {'b':'self._cursor["b"]',
317 'i':'self._cursor["i"]',
318 'p':'self._cursor["p"]',
319 's': 'scans',
320 't': 'self._cursor["t"]'}
321 scan = scans[0]
322 n = eval(self._cdict.get(self._panelling))
323 ncol=1
324 if self._stacking is not None:
325 ncol = eval(self._cdict.get(colmode))
326 if n > 1:
327 if self._rows and self._cols:
328 n = min(n,self._rows*self._cols)
329 self._plotter.set_panels(rows=self._rows,cols=self._cols,
330 nplots=n)
331 else:
332 self._plotter.set_panels(rows=n,cols=0,nplots=n)
333 else:
334 self._plotter.set_panels()
335 panels = self._cursor[self._panelling]
336 for i in panels:
337 self._plotter.palette(0)
338 polmode = "raw"
339 ii = self._cursor[self._panelling].index(i)
340 if n>1:
341 self._plotter.subplot(ii)
342 if self._panelling == "p":
343 polmode = self._polmode[ii]
344 eval(cdict.get(self._panelling))
345 else:
346 eval(cdict.get(self._panelling))
347 colvals = eval(cdict2.get(colmode))
348 for j in colvals:
349 rowsel = self._cursor["t"][0]
350 jj = colvals.index(j)
351 savei = i
352 for k in cdict.keys():
353 if k != self._panelling:
354 sel = eval(cdict2.get(k))
355 i = sel[0]
356 if k == "p":
357 which = self._cursor["p"].index(i)
358 polmode = self._polmode[which]
359 i = which
360 eval(cdict.get(k))
361 i = savei
362 if colmode == 's':
363 scan = j
364 elif colmode == 't':
365 rowsel = j
366 else:
367 savei = i
368 if colmode == 'p':
369 polmode = self._polmode[self._cursor["p"].index(j)]
370 i = j
371 eval(cdict.get(colmode))
372 i = savei
373 x = None
374 y = None
375 m = None
376 x,xlab = scan.get_abcissa(rowsel)
377 if self._abcissa: xlab = self._abcissa
378 if polmode == "stokes":
379 y = scan._getstokesspectrum(rowsel)
380 elif polmode == "stokes2":
381 y = scan._getstokesspectrum(rowsel,True)
382 elif polmode == "circular":
383 y = scan._stokestopolspectrum(rowsel,False,-1)
384 else:
385 y = scan._getspectrum(rowsel)
386
387 if self._ordinate:
388 ylab = self._ordinate
389 else:
390 ylab = scan._get_ordinate_label()
391 m = scan._getmask(rowsel)
392 if self._datamask is not None:
393 if len(m) == len(self._datamask):
394 m = logical_and(m,self._datamask)
395 if colmode == 's' or colmode == 't':
396 if self._title and len(self._title) > 0:
397 tlab = self._title[ii]
398 else:
399 if self._panelling == 'p':
400 tlab = self._get_pollabel(scan, polmode)
401 else:
402 tlab = self._ldict.get(self._panelling)+' '+str(i)
403 if self._lmap and len(self._lmap) > 0:
404 llab = self._lmap[jj]
405 else:
406 llab = scan._getsourcename(rowsel)
407 else:
408 if self._title and len(self._title) > 0:
409 tlab = self._title[ii]
410 else:
411 if self._panelling == 'p':
412 tlab = self._get_pollabel(scan, polmode)
413 else:
414 tlab = self._ldict.get(self._panelling)+' '+str(i)
415 if self._lmap and len(self._lmap) > 0:
416 llab = self._lmap[jj]
417 else:
418 if colmode == 'p':
419 llab = self._get_pollabel(scan, polmode)
420 else:
421 llab = self._ldict.get(colmode)+' '+str(j)
422 self._plotter.set_line(label=llab)
423 if self._minmaxx is not None:
424 s,e = self._slice_indeces(x)
425 x = x[s:e]
426 y = y[s:e]
427 m = m[s:e]
428
429 self._plotter.plot(x,y,m)
430 xlim=[min(x),max(x)]
431 if self._minmaxx is not None:
432 xlim = self._minmaxx
433 self._plotter.axes.set_xlim(xlim)
434
435 self._plotter.set_axes('xlabel',xlab)
436 self._plotter.set_axes('ylabel',ylab)
437 self._plotter.set_axes('title',tlab)
438
439 return
440
441
442 def set_mode(self, stacking=None, panelling=None):
443 """
444 Set the plots look and feel, i.e. what you want to see on the plot.
445 Parameters:
446 stacking: tell the plotter which variable to plot
447 as line colour overlays (default 'pol')
448 panelling: tell the plotter which variable to plot
449 across multiple panels (default 'scan'
450 Note:
451 Valid modes are:
452 'beam' 'Beam' 'b': Beams
453 'if' 'IF' 'i': IFs
454 'pol' 'Pol' 'p': Polarisations
455 'scan' 'Scan' 's': Scans
456 'time' 'Time' 't': Times
457 """
458 if not self.set_panelling(panelling):
459 print "Invalid mode"
460 return
461 if not self.set_stacking(stacking):
462 print "Invalid mode"
463 return
464 if self._data: self.plot()
465 return
466
467 def set_panelling(self, what=None):
468 mode = what
469 if mode is None:
470 mode = rcParams['plotter.panelling']
471 md = self._translate(mode)
472 if md:
473 self._panelling = md
474 self._title = None
475 return True
476 return False
477
478 def set_layout(self,rows=None,cols=None):
479 """
480 Set the multi-panel layout, i.e. how many rows and columns plots
481 are visible.
482 Parameters:
483 rows: The number of rows of plots
484 cols: The number of columns of plots
485 Note:
486 If no argument is given, the potter reverts to its auto-plot
487 behaviour.
488 """
489 self._rows = rows
490 self._cols = cols
491 if self._data: self.plot()
492 return
493
494 def set_stacking(self, what=None):
495 mode = what
496 if mode is None:
497 mode = rcParams['plotter.stacking']
498 md = self._translate(mode)
499 if md:
500 self._stacking = md
501 self._lmap = None
502 return True
503 return False
504
505 def set_range(self,xstart=None,xend=None,ystart=None,yend=None):
506 """
507 Set the range of interest on the abcissa of the plot
508 Parameters:
509 [x,y]start,[x,y]end: The start and end points of the 'zoom' window
510 Note:
511 These become non-sensical when the unit changes.
512 use plotter.set_range() without parameters to reset
513
514 """
515 if xstart is None and xend is None:
516 self._minmaxx = None
517 else:
518 self._minmaxx = [xstart,xend]
519 if ystart is None and yend is None:
520 self._minmaxy = None
521 else:
522 self._minmaxy = [ystart,yend]
523 if self._data: self.plot()
524 return
525
526 def set_legend(self, mp=None):
527 """
528 Specify a mapping for the legend instead of using the default
529 indices:
530 Parameters:
531 mp: a list of 'strings'. This should have the same length
532 as the number of elements on the legend and then maps
533 to the indeces in order
534
535 Example:
536 If the data has two IFs/rest frequencies with index 0 and 1
537 for CO and SiO:
538 plotter.set_stacking('i')
539 plotter.set_legend_map(['CO','SiO'])
540 plotter.plot()
541 """
542 self._lmap = mp
543 if self._data: self.plot()
544 return
545
546 def set_title(self, title=None):
547 self._title = title
548 if self._data: self.plot()
549 return
550
551 def set_ordinate(self, ordinate=None):
552 self._ordinate = ordinate
553 if self._data: self.plot()
554 return
555
556 def set_abcissa(self, abcissa=None):
557 self._abcissa = abcissa
558 if self._data: self.plot()
559 return
560
561 def save(self, filename=None, orientation=None,dpi=None):
562 """
563 Save the plot to a file. The know formats are 'png', 'ps', 'eps'.
564 Parameters:
565 filename: The name of the output file. This is optional
566 and autodetects the image format from the file
567 suffix. If non filename is specified a file
568 called 'yyyymmdd_hhmmss.png' is created in the
569 current directory.
570 orientation: optional parameter for postscript only (not eps).
571 'landscape', 'portrait' or None (default) are valid.
572 If None is choosen for 'ps' output, the plot is
573 automatically oriented to fill the page.
574 """
575 self._plotter.save(filename,orientation,dpi)
576 return
577
578 def set_cursor(self, row=None,beam=None,IF=None,pol=None, refresh=True):
579 """
580 Specify a 'cursor' for plotting selected spectra. Time (rows),
581 Beam, IF, Polarisation ranges can be specified.
582 Parameters:
583 Default for all paramaters is to select all available
584 row: selects the rows (time stamps) to be plotted, this has
585 to be a vector of row indices, e.g. row=[0,2,5] or row=[2]
586 beam: select a range of beams
587 IF: select a range of IFs
588 pol: select Polarisations for plotting these can be by index
589 (raw polarisations (default)) or by names any of:
590 ["I", "Q", "U", "V"] or
591 ["I", "Plinear", "Pangle", "V"] or
592 ["XX", "YY", "Real(XY)", "Imag(XY)"] or
593 ["RR", "LL"]
594 Example:
595 plotter.set_mode('pol','time')
596 plotter.plot(myscan) # plots all raw polarisations colour stacked
597 plotter.set_cursor(pol=["I"]) # plot "I" only for all rows
598 # plot "I" only for two time stamps row=0 and row=2
599 plotter.set_cursor(row=[0,2],pol=["I"])
600
601 Note:
602 Be careful to select only exisiting polarisations.
603 """
604 if not self._data:
605 print "Can only set cursor after a first call to plot()"
606 return
607
608 n = self._data[0].nrow()
609 if row is None:
610 self._cursor["t"] = range(n)
611 else:
612 for i in row:
613 if i < 0 or i >= n:
614 print "Row index '%d' out of range" % i
615 return
616 self._cursor["t"] = row
617
618 n = self._data[0].nbeam()
619 if beam is None:
620 self._cursor["b"] = range(n)
621 else:
622 for i in beam:
623 if i < 0 or i >= n:
624 print "Beam index '%d' out of range" % i
625 return
626 self._cursor["b"] = beam
627
628 n = self._data[0].nif()
629 if IF is None:
630 self._cursor["i"] = range(n)
631 else:
632 for i in IF:
633 if i < 0 or i >= n:
634 print "IF index '%d' out of range" %i
635 return
636 self._cursor["i"] = IF
637
638 n = self._data[0].npol()
639 dstokes = {"I":0,"Q":1,"U":2,"V":3}
640 dstokes2 = {"I":0,"Plinear":1,"Pangle":2,"V":3}
641 draw = {"XX":0, "YY":1,"Real(XY)":2, "Imag(XY)":3}
642 dcirc = { "RR":0,"LL":1}#,"Real(RL)":2,"Image(RL)":3}
643
644 if pol is None:
645 self._cursor["p"] = range(n)
646 self._polmode = ["raw" for i in range(n)]
647 else:
648 if isinstance(pol,str):
649 pol = pol.split()
650 polmode = []
651 pols = []
652 for i in pol:
653 if isinstance(i,str):
654 if draw.has_key(i):
655 pols.append(draw.get(i))
656 polmode.append("raw")
657 elif dstokes.has_key(i):
658 pols.append(dstokes.get(i))
659 polmode.append("stokes")
660 elif dstokes2.has_key(i):
661 pols.append(dstokes2.get(i))
662 polmode.append("stokes2")
663 elif dcirc.has_key(i):
664 pols.append(dcirc.get(i))
665 polmode.append("circular")
666 else:
667 print "Pol type '%s' not valid" %i
668 return
669 elif 0 > i >= n:
670 print "Pol index '%d' out of range" %i
671 return
672 else:
673 pols.append(i)
674 polmode.append("raw")
675 self._cursor["p"] = pols
676 self._polmode = polmode
677 if self._data and refresh: self.plot()
678
679 def _get_pollabel(self, scan, polmode):
680 tlab = ""
681 if polmode == "stokes":
682 tlab = scan._getpolarizationlabel(0,1,0)
683 elif polmode == "stokes2":
684 tlab = scan._getpolarizationlabel(0,1,1)
685 elif polmode == "circular":
686 tlab = scan._getpolarizationlabel(0,0,0)
687 else:
688 tlab = scan._getpolarizationlabel(1,0,0)
689 return tlab
690
691 def _slice_indeces(self, data):
692 mn = self._minmaxx[0]
693 mx = self._minmaxx[1]
694 asc = data[0] < data[-1]
695 start=0
696 end = len(data)-1
697 inc = 1
698 if not asc:
699 start = len(data)-1
700 end = 0
701 inc = -1
702 # find min index
703 while data[start] < mn:
704 start+= inc
705 # find max index
706 while data[end] > mx:
707 end-=inc
708 end +=1
709 if start > end:
710 return end,start
711 return start,end
712
713#if __name__ == '__main__':
714# plotter = asapplotter()
Note: See TracBrowser for help on using the repository browser.