source: trunk/python/scantable.py @ 267

Last change on this file since 267 was 256, checked in by mar637, 19 years ago
  • rewrote save to avoid using empty filenames
  • rewrote stat,tsys output and formatting
  • renmaing of function names
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.7 KB
RevLine 
[102]1from asap._asap import sdtable
[226]2from asap import rcParams
[189]3from numarray import ones,zeros
[102]4import sys
5
6class scantable(sdtable):
7    """
8        The ASAP container for scans
9    """
[113]10   
[102]11    def __init__(self, filename):
12        """
13        Create a scantable from a saved one or make a reference
14        Parameters:
[181]15            filename:    the name of an asap table on disk
16                         or
17                         the name of a rpfits/sdfits/ms file
18                         (integrations within scans are auto averaged
19                         and the whole file is read)
20                         or
21                         [advanced] a reference to an existing
[102]22                         scantable
23        """
[226]24        self._vb = rcParams['verbose']
[113]25        self._p = None
[181]26        from os import stat as st
27        import stat
28        if isinstance(filename,sdtable):
29            sdtable.__init__(self, filename)           
30        else:
[226]31            try:
32                mode = st(filename)[stat.ST_MODE]
33            except OSError:
34                print "File not found"
35                return
[181]36            if stat.S_ISDIR(mode):
37                # crude check if asap table
38                if stat.S_ISREG(st(filename+'/table.info')[stat.ST_MODE]):
39                    sdtable.__init__(self, filename)
40                else:
41                    print 'The given file is not a valid asap table'
[226]42                    return
43            else:
44                autoav = rcParams['scantable.autoaverage']
45
[181]46                from asap._asap import sdreader
47                r = sdreader(filename)
48                print 'Importing data...'
49                r.read([-1])
50                tbl = r.getdata()
[226]51                if autoav:
52                    from asap._asap import average
53                    tmp = tuple([tbl])
54                    print 'Auto averaging integrations...'
55                    tbl2 = average(tmp,(),True,'none')
56                    sdtable.__init__(self,tbl2)
57                    del r,tbl
58                else:
59                    sdtable.__init__(self,tbl)
[102]60
[256]61    def save(self, name=None, format=None, overwrite=False):
[116]62        """
63        Store the scantable on disk. This can be a asap file or SDFITS/MS2.
64        Parameters:
[196]65            name:        the name of the outputfile. For format="FITS" this
66                         is the root file name (and can be empty).
[116]67            format:      an optional file format. Default is ASAP.
[194]68                         Allowed are - 'ASAP' (save as ASAP Table),
69                                       'SDFITS' (save as SDFITS file)
70                                       'FITS' (saves each row as a FITS Image)
[200]71                                       'ASCII' (saves as ascii text file)
[226]72                                       'MS2' (saves as an aips++
73                                              MeasurementSet V2)
[256]74            overwrite:   if the file should be overwritten if it exists.
75                         The default False is to return with warning
76                         without writing the output
[116]77        Example:
78            scan.save('myscan.asap')
79            scan.save('myscan.sdfits','SDFITS')
80        """
[226]81        if format is None: format = rcParams['scantable.save']
[256]82        suffix = '.'+format.lower()
83        if name is None or name =="":
84            name = 'scantable'+suffix
85        from os import path
86        if path.isfile(name) or path.isdir(name):
87            if not overwrite:
88                print "File %s already exists." % name
89                return
[116]90        if format == 'ASAP':
91            self._save(name)
92        else:
93            from asap._asap import sdwriter as _sw
[194]94            w = _sw(format)
95            w.write(self, name)
[116]96        return
97
[102]98    def copy(self):
99        """
100        Return a copy of this scantable.
101        Parameters:
[113]102            none
[102]103        Example:
104            copiedscan = scan.copy()
105        """
[113]106        sd = scantable(sdtable._copy(self))
107        return sd
108
[102]109    def get_scan(self, scanid=None):
110        """
111        Return a specific scan (by scanno) or collection of scans (by
112        source name) in a new scantable.
113        Parameters:
114            scanid:    a scanno or a source name
115        Example:
[113]116            scan.get_scan('323p459')
[102]117            # gets all scans containing the source '323p459'
118        """
119        if scanid is None:
120            print "Please specify a scan no or name to retrieve from the scantable"
121        try:
122            if type(scanid) is str:
[113]123                s = sdtable._getsource(self,scanid)
[102]124                return scantable(s)
125            elif type(scanid) is int:
[113]126                s = sdtable._getscan(self,scanid)
[102]127                return scantable(s)
128        except RuntimeError:
129            print "Couldn't find any match."
130
131    def __str__(self):
[256]132        return sdtable._summary(self)
[102]133
134    def summary(self,filename=None):
135        """
136        Print a summary of the contents of this scantable.
137        Parameters:
138            filename:    the name of a file to write the putput to
139                         Default - no file output
140        """
[256]141        info = sdtable._summary(self)
[102]142        if filename is not None:
[256]143            if filename is "":
144                filename = 'scantable_summary.txt'
[102]145            data = open(filename, 'w')
146            data.write(info)
147            data.close()
148        print info
149
[256]150    def set_cursor(self, thebeam=0,theif=0,thepol=0):
[102]151        """
152        Set the spectrum for individual operations.
153        Parameters:
154            thebeam,theif,thepol:    a number
155        Example:
[256]156            scan.set_cursor(0,0,1)
[135]157            pol1sig = scan.stats(all=False) # returns std dev for beam=0
[181]158                                            # if=0, pol=1
[102]159        """
160        self.setbeam(thebeam)
161        self.setpol(thepol)
162        self.setif(theif)
163        return
164
[256]165    def get_cursor(self):
[113]166        """
167        Return/print a the current 'cursor' into the Beam/IF/Pol cube.
168        Parameters:
169            none
170        Returns:
171            a list of values (currentBeam,currentIF,currentPol)
172        Example:
173            none
174        """
[102]175        i = self.getbeam()
176        j = self.getif()
177        k = self.getpol()
[113]178        if self._vb:
[181]179            print "--------------------------------------------------"
[256]180            print " Cursor position"
[181]181            print "--------------------------------------------------"
[226]182            out = 'Beam=%d IF=%d Pol=%d ' % (i,j,k)
[113]183            print out
[102]184        return i,j,k
185
[226]186    def stats(self, stat='stddev', mask=None, all=None):
[102]187        """
[135]188        Determine the specified statistic of the current beam/if/pol
[102]189        Takes a 'mask' as an optional parameter to specify which
190        channels should be excluded.
191        Parameters:
[135]192            stat:    'min', 'max', 'sumsq', 'sum', 'mean'
193                     'var', 'stddev', 'avdev', 'rms', 'median'
194            mask:    an optional mask specifying where the statistic
[102]195                     should be determined.
[241]196            all:     if true show all (default or .asaprc) rather
197                     that the cursor selected spectrum of Beam/IF/Pol
[102]198
199        Example:
[113]200            scan.set_unit('channel')
[102]201            msk = scan.create_mask([100,200],[500,600])
[135]202            scan.stats(stat='mean', mask=m)
[102]203        """
[226]204        if all is None: all = rcParams['scantable.allaxes']
[135]205        from asap._asap import stats as _stats
[256]206        from numarray import array,zeros,Float
[102]207        if mask == None:
208            mask = ones(self.nchan())
[256]209        axes = ['Beam','IF','Pol','Time']
210
[102]211        if all:
[256]212            n = self.nbeam()*self.nif()*self.npol()*self.nrow()
213            shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
214            arr = array(zeros(n),shape=shp,type=Float)
215
216            for i in range(self.nbeam()):
217                self.setbeam(i)
218                for j in range(self.nif()):
219                    self.setif(j)
220                    for k in range(self.npol()):
221                        self.setpol(k)
222                        arr[i,j,k,:] = _stats(self,mask,stat,-1)
223            retval = {'axes': axes, 'data': arr, 'cursor':None}
224            tm = [self._gettime(val) for val in range(self.nrow())]
[181]225            if self._vb:
[256]226                self._print_values(retval,stat,tm)
227            return retval
[102]228
229        else:
[256]230            i,j,k = (self.getbeam(),self.getif(),self.getpol())
[241]231            statval = _stats(self,mask,stat,-1)
[181]232            out = ''
233            for l in range(self.nrow()):
234                tm = self._gettime(l)
235                out += 'Time[%s]:\n' % (tm)
236                if self.nbeam() > 1: out +=  ' Beam[%d] ' % (i)
237                if self.nif() > 1: out +=  ' IF[%d] ' % (j)
238                if self.npol() > 1: out +=  ' Pol[%d] ' % (k)
239                out += '= %3.3f\n' % (statval[l])
240                out +=  "--------------------------------------------------\n"
[226]241
[181]242            if self._vb:
243                print "--------------------------------------------------"
244                print " ",stat
245                print "--------------------------------------------------"
246                print out
[256]247            retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
248            return retval
[102]249
[226]250    def stddev(self,mask=None, all=None):
[135]251        """
252        Determine the standard deviation of the current beam/if/pol
253        Takes a 'mask' as an optional parameter to specify which
254        channels should be excluded.
255        Parameters:
256            mask:    an optional mask specifying where the standard
257                     deviation should be determined.
[226]258            all:     optional flag to show all or a cursor selected
259                     spectrum of Beam/IF/Pol. Default is all or taken
260                     from .asaprc
[135]261
262        Example:
263            scan.set_unit('channel')
264            msk = scan.create_mask([100,200],[500,600])
265            scan.stddev(mask=m)
266        """
[226]267        if all is None: all = rcParams['scantable.allaxes']
[135]268        return self.stats(stat='stddev',mask=mask, all=all);
269
[226]270    def get_tsys(self, all=None):
[113]271        """
272        Return the System temperatures.
273        Parameters:
274            all:    optional parameter to get the Tsys values for all
275                    Beams/IFs/Pols (default) or just the one selected
[256]276                    with scantable.set_cursor()
[113]277                    [True or False]
278        Returns:
279            a list of Tsys values.
280        """
[226]281        if all is None: all = rcParams['scantable.allaxes']
[256]282        from numarray import array,zeros,Float
283        axes = ['Beam','IF','Pol','Time']
284
[102]285        if all:
[256]286            n = self.nbeam()*self.nif()*self.npol()*self.nrow()
287            shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
288            arr = array(zeros(n),shape=shp,type=Float)
289
290            for i in range(self.nbeam()):
291                self.setbeam(i)
292                for j in range(self.nif()):
293                    self.setif(j)
294                    for k in range(self.npol()):
295                        self.setpol(k)
296                        arr[i,j,k,:] = self._gettsys()
297            retval = {'axes': axes, 'data': arr, 'cursor':None}
298            tm = [self._gettime(val) for val in range(self.nrow())]
[181]299            if self._vb:
[256]300                self._print_values(retval,'Tsys',tm)
301            return retval
302
[102]303        else:
[256]304            i,j,k = (self.getbeam(),self.getif(),self.getpol())
305            statval = self._gettsys()
[181]306            out = ''
307            for l in range(self.nrow()):
308                tm = self._gettime(l)
309                out += 'Time[%s]:\n' % (tm)
310                if self.nbeam() > 1: out +=  ' Beam[%d] ' % (i)
311                if self.nif() > 1: out +=  ' IF[%d] ' % (j)
312                if self.npol() > 1: out +=  ' Pol[%d] ' % (k)
[256]313                out += '= %3.3f\n' % (statval[l])
314                out +=  "--------------------------------------------------\n"
315
[181]316            if self._vb:
317                print "--------------------------------------------------"
[256]318                print " TSys"
[181]319                print "--------------------------------------------------"
320                print out
[256]321            retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
322            return retval
[113]323       
324    def get_time(self):
325        """
326        Get a list of time stamps for the observations.
[181]327        Return a string for each integration in the scantable.
[113]328        Parameters:
329            none
330        Example:
331            none
332        """
333        out = []
334        for i in range(self.nrow()):
335            out.append(self._gettime(i))
336        return out
[102]337
338    def set_unit(self, unit='channel'):
339        """
340        Set the unit for all following operations on this scantable
341        Parameters:
342            unit:    optional unit, default is 'channel'
[113]343                     one of '*Hz','km/s','channel', ''
[102]344        """
[113]345
346        if unit in ['','pixel', 'channel']:
347            unit = ''
348        inf = list(self._getcoordinfo())
349        inf[0] = unit
350        self._setcoordinfo(inf)
351        if self._p: self.plot()
352
[226]353    def set_freqframe(self, frame=None):
[113]354        """
355        Set the frame type of the Spectral Axis.
356        Parameters:
357            frame:   an optional frame type, default 'LSRK'.
358        Examples:
359            scan.set_freqframe('BARY')
360        """
[226]361        if not frame: frame = rcParams['scantable.freqframe']
[113]362        valid = ['REST','TOPO','LSRD','LSRK','BARY', \
363                   'GEO','GALACTO','LGROUP','CMB']
364        if frame in valid:
365            inf = list(self._getcoordinfo())
366            inf[1] = frame
367            self._setcoordinfo(inf)
[102]368        else:
[113]369            print "Please specify a valid freq type. Valid types are:\n",valid
370           
371    def get_unit(self):
372        """
373        Get the default unit set in this scantable
374        Parameters:
375        Returns:
376            A unit string
377        """
378        inf = self._getcoordinfo()
379        unit = inf[0]
380        if unit == '': unit = 'channel'
381        return unit
[102]382
[158]383    def get_abcissa(self, rowno=0):
[102]384        """
[158]385        Get the abcissa in the current coordinate setup for the currently
[113]386        selected Beam/IF/Pol
387        Parameters:
[226]388            rowno:    an optional row number in the scantable. Default is the
389                      first row, i.e. rowno=0
[113]390        Returns:
[158]391            The abcissa values and it's format string.
[113]392        """
[256]393        abc = self._getabcissa(rowno)
394        lbl = self._getabcissalabel(rowno)
[158]395        return abc, lbl
[113]396
397    def create_mask(self, *args, **kwargs):
398        """
[102]399        Compute and return a mask based on [min,max] windows.
[189]400        The specified windows are to be INCLUDED, when the mask is
[113]401        applied.
[102]402        Parameters:
403            [min,max],[min2,max2],...
404                Pairs of start/end points specifying the regions
405                to be masked
[189]406            invert:     optional argument. If specified as True,
407                        return an inverted mask, i.e. the regions
408                        specified are EXCLUDED
[102]409        Example:
[113]410            scan.set_unit('channel')
411
412            a)
[102]413            msk = scan.set_mask([400,500],[800,900])
[189]414            # masks everything outside 400 and 500
[113]415            # and 800 and 900 in the unit 'channel'
416
417            b)
418            msk = scan.set_mask([400,500],[800,900], invert=True)
[189]419            # masks the regions between 400 and 500
[113]420            # and 800 and 900 in the unit 'channel'
421           
[102]422        """
[113]423        u = self._getcoordinfo()[0]
424        if self._vb:
425            if u == "": u = "channel"
426            print "The current mask window unit is", u
[102]427        n = self.nchan()
[256]428        data = self._getabcissa()
[189]429        msk = zeros(n)
[102]430        for  window in args:
431            if (len(window) != 2 or window[0] > window[1] ):
432                print "A window needs to be defined as [min,max]"
433                return
434            for i in range(n):
[113]435                if data[i] >= window[0] and data[i] < window[1]:
[189]436                    msk[i] = 1
[113]437        if kwargs.has_key('invert'):
438            if kwargs.get('invert'):
439                from numarray import logical_not
440                msk = logical_not(msk)
[102]441        return msk
[113]442   
443    def set_restfreqs(self, freqs, unit='Hz'):
[102]444        """
445        Set the restfrequency(s) for this scantable.
446        Parameters:
447            freqs:    one or more frequencies
448            unit:     optional 'unit', default 'Hz'
449        Example:
[113]450            scan.set_restfreqs([1000000000.0])
[102]451        """
[113]452        if type(freqs) is float or int:
453            freqs = (freqs)
454        sdtable._setrestfreqs(self,freqs, unit)
[102]455        return
[256]456    def get_restfreqs(self):
457        """
458        Get the restfrequency(s) stored in this scantable.
459        The return value(s) are always of unit 'Hz'
460        Parameters:
461            none
462        Returns:
463            a list of doubles
464        """
465        return list(self._getrestfreqs())
[102]466
467    def flag_spectrum(self, thebeam, theif, thepol):
468        """
469        This flags a selected spectrum in the scan 'for good'.
470        USE WITH CARE - not reversible.
471        Use masks for non-permanent exclusion of channels.
472        Parameters:
473            thebeam,theif,thepol:    all have to be explicitly
474                                     specified
475        Example:
476            scan.flag_spectrum(0,0,1)
477            flags the spectrum for Beam=0, IF=0, Pol=1
478        """
479        if (thebeam < self.nbeam() and  theif < self.nif() and thepol < self.npol()):
480            stable.setbeam(thebeam)
481            stable.setif(theif)
482            stable.setpol(thepol)
483            stable._flag(self)
484        else:
485            print "Please specify a valid (Beam/IF/Pol)"
486        return
[113]487
488    def plot(self, what='spectrum',col='Pol', panel=None):
489        """
490        Plot the spectra contained in the scan. Alternatively you can also
491        Plot Tsys vs Time
492        Parameters:
493            what:     a choice of 'spectrum' (default) or 'tsys'
[135]494            col:      which out of Beams/IFs/Pols should be colour stacked
[113]495            panel:    set up multiple panels, currently not working.
496        """
497        validcol = {'Beam':self.nbeam(),'IF':self.nif(),'Pol':self.npol()}
[124]498
[113]499        validyax = ['spectrum','tsys']
[189]500        from asap.asaplot import ASAPlot
[113]501        if not self._p:
502            self._p = ASAPlot()
[189]503            #print "Plotting not enabled"
504            #return
505        if self._p.is_dead:
506            del self._p
507            self._p = ASAPlot()
[113]508        npan = 1
509        x = None
510        if what == 'tsys':
511            n = self.nrow()
512            if n < 2:
513                print "Only one integration. Can't plot."
514                return
[124]515        self._p.hold()
516        self._p.clear()
[113]517        if panel == 'Time':
518            npan = self.nrow()
[124]519            self._p.set_panels(rows=npan)
[113]520        xlab,ylab,tlab = None,None,None
[226]521        self._vb = False
[256]522        sel = self.get_cursor()       
[113]523        for i in range(npan):
[226]524            if npan > 1:
525                self._p.subplot(i)
[113]526            for j in range(validcol[col]):
527                x = None
528                y = None
529                m = None
530                tlab = self._getsourcename(i)
[124]531                import re
532                tlab = re.sub('_S','',tlab)
[113]533                if col == 'Beam':
534                    self.setbeam(j)
535                elif col == 'IF':
536                    self.setif(j)
537                elif col == 'Pol':
538                    self.setpol(j)
539                if what == 'tsys':
540                    x = range(self.nrow())
541                    xlab = 'Time [pixel]'
542                    m = list(ones(len(x)))
543                    y = []
544                    ylab = r'$T_{sys}$'
545                    for k in range(len(x)):
546                        y.append(self._gettsys(k))
547                else:
[158]548                    x,xlab = self.get_abcissa(i)
[256]549                    y = self._getspectrum(i)
[113]550                    ylab = r'Flux'
[256]551                    m = self._getmask(i)
[113]552                llab = col+' '+str(j)
553                self._p.set_line(label=llab)
554                self._p.plot(x,y,m)
[124]555            self._p.set_axes('xlabel',xlab)
556            self._p.set_axes('ylabel',ylab)
557            self._p.set_axes('title',tlab)
[113]558        self._p.release()
[256]559        self.set_cursor(sel[0],sel[1],sel[2])
[226]560        self._vb = rcParams['verbose']
[113]561        return
[256]562
563        print out
564
565    def _print_values(self, dat, label='', timestamps=[]):
566        d = dat['data']
567        a = dat['axes']
568        shp = d.getshape()
569        out = ''
570        for i in range(shp[3]):
571            out += '%s [%s]:\n' % (a[3],timestamps[i])
572            t = d[:,:,:,i]
573            for j in range(shp[0]):
574                if shp[0] > 1: out +=  ' %s[%d] ' % (a[0],j)
575                for k in range(shp[1]):
576                    if shp[1] > 1: out +=  ' %s[%d] ' % (a[1],k)
577                    for l in range(shp[2]):
578                        if shp[2] > 1: out +=  ' %s[%d] ' % (a[2],l)
579                        out += '= %3.3f\n' % (t[j,k,l])
580            out += "--------------------------------------------------\n"
581        print "--------------------------------------------------"
582        print " ", label
583        print "--------------------------------------------------"
584        print out
Note: See TracBrowser for help on using the repository browser.