source: trunk/python/asapplotter.py @ 541

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