source: branches/Release-1-fixes/python/asapplotter.py @ 605

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

Fixed asap00016

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