source: trunk/python/asapplotter.py @ 709

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

changes to reflect change in asaplot

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