source: trunk/python/asapplotter.py @ 652

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

removed color loading as mpl now supports named colors. some minor corrections on pol label handling. Also added orientation option for ps output.

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