source: trunk/python/asapplotter.py @ 557

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

bug fix in mode == 'p' indexing

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