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
RevLine 
[203]1from asap.asaplot import ASAPlot
[226]2from asap import rcParams
[203]3
4class asapplotter:
[226]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    """
[203]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'}
[525]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"])',
[203]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]
[541]33        self._panels = rcParams['plotter.panelling']
[226]34        self._stacking = rcParams['plotter.stacking']
[377]35        self._rows = None
36        self._cols = None
[203]37        self._autoplot = False
[525]38        self._minmaxx = None
39        self._minmaxy = None
[203]40        self._data = None
41        self._lmap = []
[226]42        self._title = None
[257]43        self._ordinate = None
44        self._abcissa = None
[525]45        self._cursor = {'t':None, 'b':None,
46                        'i':None, 'p':None
47                        }
[203]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       
[525]55    def plot(self, *args):
[203]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'
[525]63            NO checking is done that the abcissas of the scantables
[203]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:
[525]71            if self._data is not None:               
72                if list(args) != self._data:
73                    self._data = list(args)
74                    # reset cursor
[541]75                    self.set_cursor(refresh=False)
[525]76            else:
77                self._data = list(args)
[541]78                self.set_cursor(refresh=False)
[203]79        if self._panels == 't':
[541]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)
[203]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)
[525]90        if self._minmaxx is not None or self._minmaxy is not None:
91            self._plotter.set_limits(xlim=self._minmaxx,ylim=self._minmaxy)
[203]92        self._plotter.release()
93        return
94
95    def _plot_time(self, scan, colmode):
96        if colmode == 't':
97            return
[525]98        n = len(self._cursor["t"])
[203]99        cdict = {'b':'scan.setbeam(j)',
100                 'i':'scan.setif(j)',
101                 'p':'scan.setpol(j)'}
[525]102        cdict2 = {'b':'self._cursor["b"]',
103                  'i':'self._cursor["i"]',
104                  'p':'self._cursor["p"]'}
105        ncol = 1
[203]106        if self._stacking is not None:
107            ncol = eval(self._cdict.get(colmode))
108        self._plotter.set_panels()
109        if n > 1:
[377]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:
[485]115                self._plotter.set_panels(rows=n,cols=0,nplots=n)
[525]116        rows = self._cursor["t"]
117        self._plotter.palette(1)
118        for rowsel in rows:
119            i = self._cursor["t"].index(rowsel)
[203]120            if n > 1:
[377]121                self._plotter.palette(1)
[203]122                self._plotter.subplot(i)
[525]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
[203]140                eval(cdict.get(colmode))
141                x = None
142                y = None
143                m = None
[226]144                if not self._title:
[525]145                    tlab = scan._getsourcename(rowsel)                   
[226]146                else:
147                    if len(self._title) == n:
[525]148                        tlab = self._title[rowsel]
[226]149                    else:
[525]150                        tlab = scan._getsourcename(rowsel)
151                x,xlab = scan.get_abcissa(rowsel)
[257]152                if self._abcissa: xlab = self._abcissa
[525]153                y = None
154                if polmode == "stokes":
155                    y = scan._getstokesspectrum(rowsel)
156                elif polmode == "stokes2":
157                    y = scan._getstokesspectrum(rowsel,True)
[541]158                elif polmode == "circular":
159                    y = scan._stokestopolspectrum(rowsel,False,-1)
[525]160                else:
161                    y = scan._getspectrum(rowsel)
[257]162                if self._ordinate:
163                    ylab = self._ordinate
164                else:
165                    ylab = 'Flux ('+scan.get_fluxunit()+')'
[525]166                m = scan._getmask(rowsel)
[226]167                if self._lmap and len(self._lmap) > 0:
[525]168                    llab = self._lmap[jj]
[203]169                else:
[525]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)
[541]175                        elif polmode == "circular":
176                            llab = scan._getpolarizationlabel(0,0,0)
[525]177                        else:
178                            llab = scan._getpolarizationlabel(1,0,0)
179                    else:                   
180                        llab = self._ldict.get(colmode)+' '+str(j)
[203]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
[525]190    def _plot_scans(self, scans, colmode):
191        print "Can only plot one row per scan."
[203]192        if colmode == 's':
193            return
194        cdict = {'b':'scan.setbeam(j)',
195                 'i':'scan.setif(j)',
196                 'p':'scan.setpol(j)'}
[525]197        cdict2 = {'b':'self._cursor["b"]',
198                  'i':'self._cursor["i"]',
199                  'p':'self._cursor["p"]'}
200       
[203]201        n = len(scans)
[525]202        ncol = 1
[203]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:
[377]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:
[485]213                self._plotter.set_panels(rows=n,cols=0,nplots=n)
[203]214        for scan in scans:
[541]215            self._plotter.palette(1)
[203]216            if n > 1:
[525]217                self._plotter.subplot(scans.index(scan))
[485]218                self._plotter.palette(1)
[525]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
[203]237                eval(cdict.get(colmode))
238                x = None
239                y = None
240                m = None
[226]241                tlab = self._title
242                if not self._title:
[525]243                    tlab = scan._getsourcename(rowsel)
244                x,xlab = scan.get_abcissa(rowsel)
[257]245                if self._abcissa: xlab = self._abcissa
[525]246                if polmode == "stokes":
247                    y = scan._getstokesspectrum(rowsel)
248                elif polmode == "stokes2":
249                    y = scan._getstokesspectrum(rowsel,True)
[541]250                elif polmode == "circular":
251                    y = scan._stokestopolspectrum(rowsel,False,-1)
[525]252                else:
253                    y = scan._getspectrum(rowsel)
[257]254                if self._ordinate:
255                    ylab = self._ordinate
256                else:
257                    ylab = 'Flux ('+scan.get_fluxunit()+')'
[525]258                m = scan._getmask(rowsel)
[257]259                if self._lmap and len(self._lmap) > 0:
[525]260                    llab = self._lmap[jj]
[203]261                else:
[525]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)
[541]267                        elif polmode == "circular":
268                            llab = scan._getpolarizationlabel(0,0,0)
[525]269                        else:
270                            llab = scan._getpolarizationlabel(1,0,0)
271                    else:
272                        llab = self._ldict.get(colmode)+' '+str(j)
[203]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
[525]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"]'}
[203]294        scan = scans[0]
295        n = eval(self._cdict.get(self._panels))
[525]296        ncol=1
[203]297        if self._stacking is not None:           
298            ncol = eval(self._cdict.get(colmode))
299        self._plotter.set_panels()
300        if n > 1:
[377]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:
[485]306                self._plotter.set_panels(rows=n,cols=0,nplots=n)
[525]307        panels = self._cursor[self._panels]       
308        for i in panels:
[541]309            self._plotter.palette(1)
[525]310            polmode = "raw"
311            ii = self._cursor[self._panels].index(i)
[203]312            if n>1:
[525]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
[203]334                if colmode == 's':
[525]335                    scan = j
[203]336                elif colmode == 't':
[525]337                    rowsel = j                   
[203]338                else:
[525]339                    savei = i
340                    if colmode == 'p':
341                        polmode = self._polmode[self._cursor["p"].index(j)]
342                    i = j
[203]343                    eval(cdict.get(colmode))
[525]344                    i = savei
[203]345                x = None
346                y = None
347                m = None
[525]348                x,xlab = scan.get_abcissa(rowsel)
[257]349                if self._abcissa: xlab = self._abcissa
[525]350                if polmode == "stokes":
351                    y = scan._getstokesspectrum(rowsel)
352                elif polmode == "stokes2":
353                    y = scan._getstokesspectrum(rowsel,True)
[541]354                elif polmode == "circular":
355                    y = scan._stokestopolspectrum(rowsel,False,-1)
[525]356                else:
357                    y = scan._getspectrum(rowsel)
358
[257]359                if self._ordinate:
360                    ylab = self._ordinate
361                else:
362                    ylab = 'Flux ('+scan.get_fluxunit()+')'
[525]363                m = scan._getmask(rowsel)
[203]364                if colmode == 's' or colmode == 't':
[525]365                    if self._title and len(self._title) > 0:
366                        tlab = self._title[ii]
367                    else:                       
[226]368                        tlab = self._ldict.get(self._panels)+' '+str(i)
[525]369                    llab = scan._getsourcename(rowsel)
[203]370                else:
[226]371                    if self._title and len(self._title) > 0:
[525]372                        tlab = self._title[ii]
[226]373                    else:
[257]374                        tlab = self._ldict.get(self._panels)+' '+str(i)
[226]375                    if self._lmap and len(self._lmap) > 0:
[525]376                        llab = self._lmap[jj]
[203]377                    else:
[525]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)
[541]383                            elif polmode == "circular":
384                                llab = scan._getpolarizationlabel(0,0,0)
[525]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)
[541]394                    elif polmode == "circular":
395                        tlab = scan._getpolarizationlabel(0,0,0)
[525]396                    else:
397                        tlab = scan._getpolarizationlabel(1,0,0)
[203]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
[226]410    def set_mode(self, stacking=None, panelling=None):
[203]411        """
[377]412        Set the plots look and feel, i.e. what you want to see on the plot.
[203]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"
[226]428            return
[203]429        if not self.set_stacking(stacking):
430            print "Invalid mode"
[226]431            return
432        if self._data: self.plot()
[203]433        return
434
[377]435    def set_panels(self, what=None):
[226]436        if not what:
437             what = rcParams['plotter.panelling']
[203]438        md = self._translate(what)
439        if md:
[226]440            self._panels = md
441            self._title = None
[203]442            return True
443        return False
444
[377]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
[226]461    def set_stacking(self, what=None): 
462        if not what:
463             what = rcParams['plotter.stacking']       
[203]464        md = self._translate(what)
465        if md:
466            self._stacking = md
[226]467            self._lmap = None
[203]468            return True
469        return False
470
[525]471    def set_range(self,xstart=None,xend=None,ystart=None,yend=None):
[203]472        """
473        Set the range of interest on the abcissa of the plot
474        Parameters:
[525]475            [x,y]start,[x,y]end:  The start and end points of the 'zoom' window
[203]476        Note:
477            These become non-sensical when the unit changes.
478            use plotter.set_range() without parameters to reset
479
480        """
[525]481        if xstart is None and xend is None:
482            self._minmaxx = None
[226]483            if self._data: self.plot()
[525]484            return
485        if ystart is None and yend is None:
486            self._minmaxy = None
[226]487            if self._data: self.plot()
[525]488            return
489        self._minmaxx = [xstart,xend]
490        self._minmaxy = [ystart,yend]
491        if self._data: self.plot()
[203]492        return
493   
[257]494    def set_legend(self, mp=None):
[203]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:
[485]504             If the data has two IFs/rest frequencies with index 0 and 1
[203]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
[226]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
[257]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
[377]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
[525]541   
[541]542    def set_cursor(self, row=None,beam=None,IF=None,pol=None, refresh=True):
[525]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
[541]556                    ["XX", "YY", "Real(XY)", "Imag(XY)"] or
557                    ["RR", "LL"]
[525]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"])
[257]564
[525]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}
[541]606        dcirc = { "RR":0,"LL":1}#,"Real(RL)":2,"Image(RL)":3}
[525]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))
[541]629                        polmode.append("circular")
[525]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
[541]641        if self._data and refresh: self.plot()
[525]642
643           
[203]644if __name__ == '__main__':
645    plotter = asapplotter()
Note: See TracBrowser for help on using the repository browser.