source: trunk/python/scantable.py @ 1115

Last change on this file since 1115 was 1115, checked in by mar637, 18 years ago

added patch from Tak, so the constructor works with ms directories.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.1 KB
Line 
1from asap._asap import Scantable
2from asap import rcParams
3from asap import print_log, asaplog
4from asap import selector
5from numarray import ones,zeros
6import sys
7
8class scantable(Scantable):
9    """
10        The ASAP container for scans
11    """
12
13    def __init__(self, filename, average=None, unit=None):
14        """
15        Create a scantable from a saved one or make a reference
16        Parameters:
17            filename:    the name of an asap table on disk
18                         or
19                         the name of a rpfits/sdfits/ms file
20                         (integrations within scans are auto averaged
21                         and the whole file is read)
22                         or
23                         [advanced] a reference to an existing
24                         scantable
25            average:     average all integrations withinb a scan on read.
26                         The default (True) is taken from .asaprc.
27            unit:         brightness unit; must be consistent with K or Jy.
28                         Over-rides the default selected by the reader
29                         (input rpfits/sdfits/ms) or replaces the value
30                         in existing scantables
31        """
32        if average is None:
33            average = rcParams['scantable.autoaverage']
34        varlist = vars()
35        from asap._asap import stmath
36        self._math = stmath()
37        if isinstance(filename, Scantable):
38            Scantable.__init__(self, filename)
39        else:
40            if isinstance(filename,str):
41                import os.path
42                filename = os.path.expandvars(filename)
43                filename = os.path.expanduser(filename)
44                if not os.path.exists(filename):
45                    s = "File '%s' not found." % (filename)
46                    if rcParams['verbose']:
47                        asaplog.push(s)
48                        print asaplog.pop().strip()
49                        return
50                    raise IOError(s)
51                if os.path.isdir(filename) \
52                   and not os.path.exists(filename+'/table.f1'):
53                    # crude check if asap table
54                    if os.path.exists(filename+'/table.info'):
55                        Scantable.__init__(self, filename, rcParams['scantable.storage']=='disk')
56                        if unit is not None:
57                            self.set_fluxunit(unit)
58                        self.set_freqframe(rcParams['scantable.freqframe'])
59                    else:
60                        msg = "The given file '%s'is not a valid asap table." % (filename)
61                        if rcParams['verbose']:
62                            print msg
63                            return
64                        else:
65                            raise IOError(msg)
66                else:
67                    self._fill([filename],unit, average)
68            elif (isinstance(filename,list) or isinstance(filename,tuple)) \
69                  and isinstance(filename[-1], str):
70                self._fill(filename, unit, average)
71        print_log()
72
73    def save(self, name=None, format=None, overwrite=False):
74        """
75        Store the scantable on disk. This can be an asap (aips++) Table, SDFITS,
76        Image FITS or MS2 format.
77        Parameters:
78            name:        the name of the outputfile. For format "ASCII"
79                         this is the root file name (data in 'name'.txt
80                         and header in 'name'_header.txt)
81            format:      an optional file format. Default is ASAP.
82                         Allowed are - 'ASAP' (save as ASAP [aips++] Table),
83                                       'SDFITS' (save as SDFITS file)
84                                       'ASCII' (saves as ascii text file)
85                                       'MS2' (saves as an aips++
86                                              MeasurementSet V2)
87            overwrite:   If the file should be overwritten if it exists.
88                         The default False is to return with warning
89                         without writing the output. USE WITH CARE.
90        Example:
91            scan.save('myscan.asap')
92            scan.save('myscan.sdfits','SDFITS')
93        """
94        from os import path
95        if format is None: format = rcParams['scantable.save']
96        suffix = '.'+format.lower()
97        if name is None or name =="":
98            name = 'scantable'+suffix
99            from asap import asaplog
100            msg = "No filename given. Using default name %s..." % name
101            asaplog.push(msg)
102        name = path.expandvars(name)
103        if path.isfile(name) or path.isdir(name):
104            if not overwrite:
105                msg = "File %s exists." % name
106                if rcParams['verbose']:
107                    print msg
108                    return
109                else:
110                    raise IOError(msg)
111        format2 = format.upper()
112        if format2 == 'ASAP':
113            self._save(name)
114        else:
115            from asap._asap import stwriter as stw
116            w = stw(format2)
117            w.write(self, name)
118        print_log()
119        return
120
121    def copy(self):
122        """
123        Return a copy of this scantable.
124        Parameters:
125            none
126        Example:
127            copiedscan = scan.copy()
128        """
129        sd = scantable(Scantable._copy(self))
130        return sd
131
132    def drop_scan(self, scanid=None):
133        """
134        Return a new scantable where the specified scan number(s) has(have)
135        been dropped.
136        Parameters:
137            scanid:    a (list of) scan number(s)
138        """
139        from asap import _is_sequence_or_number as _is_valid
140        from asap import _to_list
141        from asap import unique
142        if not _is_valid(scanid):
143            if rcParams['verbose']:
144                print "Please specify a scanno to drop from the scantable"
145                return
146            else:
147                raise RuntimeError("No scan given")
148        try:
149            scanid = _to_list(scanid)
150            allscans = unique([ self.getscan(i) for i in range(self.nrow())])
151            for sid in scanid: allscans.remove(sid)
152            if len(allscans) == 0: raise ValueError("Can't remove all scans")
153        except ValueError:
154            if rcParams['verbose']:
155                print "Couldn't find any match."
156                return
157            else: raise
158        try:
159            bsel = self.get_selection()
160            sel = selector()
161            sel.set_scans(allscans)
162            self.set_selection(bsel+sel)
163            scopy = self._copy()
164            self.set_selection(bsel)
165            return scantable(scopy)
166        except RuntimeError:
167            if rcParams['verbose']: print "Couldn't find any match."
168            else: raise
169
170
171    def get_scan(self, scanid=None):
172        """
173        Return a specific scan (by scanno) or collection of scans (by
174        source name) in a new scantable.
175        Parameters:
176            scanid:    a (list of) scanno or a source name, unix-style
177                       patterns are accepted for source name matching, e.g.
178                       '*_R' gets all 'ref scans
179        Example:
180            # get all scans containing the source '323p459'
181            newscan = scan.get_scan('323p459')
182            # get all 'off' scans
183            refscans = scan.get_scan('*_R')
184            # get a susbset of scans by scanno (as listed in scan.summary())
185            newscan = scan.get_scan([0,2,7,10])
186        """
187        if scanid is None:
188            if rcParams['verbose']:
189                print "Please specify a scan no or name to retrieve from the scantable"
190                return
191            else:
192                raise RuntimeError("No scan given")
193
194        try:
195            bsel = self.get_selection()
196            sel = selector()
197            if type(scanid) is str:
198                sel.set_name(scanid)
199                self.set_selection(bsel+sel)
200                scopy = self._copy()
201                self.set_selection(bsel)
202                return scantable(scopy)
203            elif type(scanid) is int:
204                sel.set_scans([scanid])
205                self.set_selection(bsel+sel)
206                scopy = self._copy()
207                self.set_selection(bsel)
208                return scantable(scopy)
209            elif type(scanid) is list:
210                sel.set_scans(scanid)
211                self.set_selection(sel)
212                scopy = self._copy()
213                self.set_selection(bsel)
214                return scantable(scopy)
215            else:
216                msg = "Illegal scanid type, use 'int' or 'list' if ints."
217                if rcParams['verbose']:
218                    print msg
219                else:
220                    raise TypeError(msg)
221        except RuntimeError:
222            if rcParams['verbose']: print "Couldn't find any match."
223            else: raise
224
225    def __str__(self):
226        return Scantable._summary(self,True)
227
228    def summary(self, filename=None):
229        """
230        Print a summary of the contents of this scantable.
231        Parameters:
232            filename:    the name of a file to write the putput to
233                         Default - no file output
234            verbose:     print extra info such as the frequency table
235                         The default (False) is taken from .asaprc
236        """
237        info = Scantable._summary(self, True)
238        #if verbose is None: verbose = rcParams['scantable.verbosesummary']
239        if filename is not None:
240            if filename is "":
241                filename = 'scantable_summary.txt'
242            from os.path import expandvars, isdir
243            filename = expandvars(filename)
244            if not isdir(filename):
245                data = open(filename, 'w')
246                data.write(info)
247                data.close()
248            else:
249                msg = "Illegal file name '%s'." % (filename)
250                if rcParams['verbose']:
251                    print msg
252                else:
253                    raise IOError(msg)
254        if rcParams['verbose']:
255            try:
256                from IPython.genutils import page as pager
257            except ImportError:
258                from pydoc import pager
259            pager(info)
260        else:
261            return info
262
263
264    def get_selection(self):
265        """
266        Get the selection object currently set on this scantable.
267        Parameters:
268            none
269        Example:
270            sel = scan.get_selection()
271            sel.set_ifs(0)              # select IF 0
272            scan.set_selection(sel)     # apply modified selection
273        """
274        return selector(self._getselection())
275
276    def set_selection(self, selection=selector()):
277        """
278        Select a subset of the data. All following operations on this scantable
279        are only applied to thi selection.
280        Parameters:
281            selection:    a selector object (default unset the selection)
282        Examples:
283            sel = selector()         # create a selection object
284            self.set_scans([0,3])    # select SCANNO 0 and 3
285            scan.set_selection(sel)  # set the selection
286            scan.summary()           # will only print summary of scanno 0 an 3
287            scan.set_selection()     # unset the selection
288        """
289        self._setselection(selection)
290
291    def set_cursor(self, beam=0, IF=0, pol=0):
292        print "DEPRECATED - use set_selection"
293
294    def get_cursor(self):
295        print "DEPRECATED - use get_selection"
296
297    def stats(self, stat='stddev', mask=None):
298        """
299        Determine the specified statistic of the current beam/if/pol
300        Takes a 'mask' as an optional parameter to specify which
301        channels should be excluded.
302        Parameters:
303            stat:    'min', 'max', 'sumsq', 'sum', 'mean'
304                     'var', 'stddev', 'avdev', 'rms', 'median'
305            mask:    an optional mask specifying where the statistic
306                     should be determined.
307        Example:
308            scan.set_unit('channel')
309            msk = scan.create_mask([100,200],[500,600])
310            scan.stats(stat='mean', mask=m)
311        """
312        from numarray import array,zeros,Float
313        if mask == None:
314            mask = []
315        axes = ['Beam','IF','Pol','Time']
316        if not self._check_ifs():
317             raise ValueError("Cannot apply mask as the IFs have different number of channels"
318                              "Please use setselection() to select individual IFs")
319
320        statvals = self._math._stats(self, mask, stat)
321        out = ''
322        axes = []
323        for i in range(self.nrow()):
324            axis = []
325            axis.append(self.getscan(i))
326            axis.append(self.getbeam(i))
327            axis.append(self.getif(i))
328            axis.append(self.getpol(i))
329            axis.append(self.getcycle(i))
330            axes.append(axis)
331            tm = self._gettime(i)
332            src = self._getsourcename(i)
333            out += 'Scan[%d] (%s) ' % (axis[0], src)
334            out += 'Time[%s]:\n' % (tm)
335            if self.nbeam(-1) > 1: out +=  ' Beam[%d] ' % (axis[1])
336            if self.nif(-1) > 1: out +=  ' IF[%d] ' % (axis[2])
337            if self.npol(-1) > 1: out +=  ' Pol[%d] ' % (axis[3])
338            out += '= %3.3f\n' % (statvals[i])
339            out +=  "--------------------------------------------------\n"
340
341        if rcParams['verbose']:
342            print "--------------------------------------------------"
343            print " ",stat
344            print "--------------------------------------------------"
345            print out
346        retval = { 'axesnames': ['scanno','beamno','ifno','polno','cycleno'],
347                   'axes' : axes,
348                   'data': statvals}
349        return retval
350
351    def stddev(self,mask=None):
352        """
353        Determine the standard deviation of the current beam/if/pol
354        Takes a 'mask' as an optional parameter to specify which
355        channels should be excluded.
356        Parameters:
357            mask:    an optional mask specifying where the standard
358                     deviation should be determined.
359
360        Example:
361            scan.set_unit('channel')
362            msk = scan.create_mask([100,200],[500,600])
363            scan.stddev(mask=m)
364        """
365        return self.stats(stat='stddev',mask=mask);
366
367
368    def column_names(self):
369        """
370        Return a  list of column names, which can be used for selection.
371        """
372        return list(Scantable.column_names(self))
373
374    def get_tsys(self):
375        """
376        Return the System temperatures.
377        Parameters:
378
379        Returns:
380            a list of Tsys values for the current selection
381        """
382
383        return self._row_callback(self._gettsys, "Tsys")
384
385    def _row_callback(self, callback, label):
386        axes = []
387        axesnames = ['scanno','beamno','ifno','polno','cycleno']
388        out = ""
389        outvec =[]
390        for i in range(self.nrow()):
391            axis = []
392            axis.append(self.getscan(i))
393            axis.append(self.getbeam(i))
394            axis.append(self.getif(i))
395            axis.append(self.getpol(i))
396            axis.append(self.getcycle(i))
397            axes.append(axis)
398            tm = self._gettime(i)
399            src = self._getsourcename(i)
400            out += 'Scan[%d] (%s) ' % (axis[0], src)
401            out += 'Time[%s]:\n' % (tm)
402            if self.nbeam(-1) > 1: out +=  ' Beam[%d] ' % (axis[1])
403            if self.nif(-1) > 1: out +=  ' IF[%d] ' % (axis[2])
404            if self.npol(-1) > 1: out +=  ' Pol[%d] ' % (axis[3])
405            outvec.append(callback(i))
406            out += '= %3.3f\n' % (outvec[i])
407            out +=  "--------------------------------------------------\n"
408        if rcParams['verbose']:
409            print "--------------------------------------------------"
410            print " %s" % (label)
411            print "--------------------------------------------------"
412            print out
413        retval = {'axesnames': axesnames, 'axes': axes, 'data': outvec}
414        return retval
415
416    def _get_column(self, callback, row=-1):
417        """
418        """
419        if row == -1:
420            return [callback(i) for i in range(self.nrow())]
421        else:
422            if  0 <= row < self.nrow():
423                return callback(row)
424
425
426    def get_time(self, row=-1):
427        """
428        Get a list of time stamps for the observations.
429        Return a string for each integration in the scantable.
430        Parameters:
431            row:    row no of integration. Default -1 return all rows
432        Example:
433            none
434        """
435        return self._get_column(self._gettime, row)
436
437    def get_sourcename(self, row=-1):
438        """
439        Get a list source names for the observations.
440        Return a string for each integration in the scantable.
441        Parameters:
442            row:    row no of integration. Default -1 return all rows
443        Example:
444            none
445        """
446        return self._get_column(self._getsourcename, row)
447
448    def get_elevation(self, row=-1):
449        """
450        Get a list of elevations for the observations.
451        Return a float for each integration in the scantable.
452        Parameters:
453            row:    row no of integration. Default -1 return all rows
454        Example:
455            none
456        """
457        return self._get_column(self._getelevation, row)
458
459    def get_azimuth(self, row=-1):
460        """
461        Get a list of azimuths for the observations.
462        Return a float for each integration in the scantable.
463        Parameters:
464            row:    row no of integration. Default -1 return all rows
465        Example:
466            none
467        """
468        return self._get_column(self._getazimuth, row)
469
470    def get_parangle(self, row=-1):
471        """
472        Get a list of parallactic angles for the observations.
473        Return a float for each integration in the scantable.
474        Parameters:
475            row:    row no of integration. Default -1 return all rows
476        Example:
477            none
478        """
479        return self._get_column(self._getparangle, row)
480
481    def get_direction(self, row=-1):
482        """
483        Get a list of Positions on the sky (direction) for the observations.
484        Return a float for each integration in the scantable.
485        Parameters:
486            row:    row no of integration. Default -1 return all rows
487        Example:
488            none
489        """
490        return self._get_column(self._getdirection, row)
491
492    def set_unit(self, unit='channel'):
493        """
494        Set the unit for all following operations on this scantable
495        Parameters:
496            unit:    optional unit, default is 'channel'
497                     one of '*Hz','km/s','channel', ''
498        """
499        varlist = vars()
500        if unit in ['','pixel', 'channel']:
501            unit = ''
502        inf = list(self._getcoordinfo())
503        inf[0] = unit
504        self._setcoordinfo(inf)
505        self._add_history("set_unit",varlist)
506
507    def set_instrument(self, instr):
508        """
509        Set the instrument for subsequent processing
510        Parameters:
511            instr:    Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
512                      'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
513        """
514        self._setInstrument(instr)
515        self._add_history("set_instument",vars())
516        print_log()
517
518    def set_doppler(self, doppler='RADIO'):
519        """
520        Set the doppler for all following operations on this scantable.
521        Parameters:
522            doppler:    One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
523        """
524        varlist = vars()
525        inf = list(self._getcoordinfo())
526        inf[2] = doppler
527        self._setcoordinfo(inf)
528        self._add_history("set_doppler",vars())
529        print_log()
530
531    def set_freqframe(self, frame=None):
532        """
533        Set the frame type of the Spectral Axis.
534        Parameters:
535            frame:   an optional frame type, default 'LSRK'. Valid frames are:
536                     'REST','TOPO','LSRD','LSRK','BARY',
537                     'GEO','GALACTO','LGROUP','CMB'
538        Examples:
539            scan.set_freqframe('BARY')
540        """
541        if frame is None: frame = rcParams['scantable.freqframe']
542        varlist = vars()
543        valid = ['REST','TOPO','LSRD','LSRK','BARY', \
544                   'GEO','GALACTO','LGROUP','CMB']
545
546        if frame in valid:
547            inf = list(self._getcoordinfo())
548            inf[1] = frame
549            self._setcoordinfo(inf)
550            self._add_history("set_freqframe",varlist)
551        else:
552            msg  = "Please specify a valid freq type. Valid types are:\n",valid
553            if rcParams['verbose']:
554                print msg
555            else:
556                raise TypeError(msg)
557        print_log()
558
559    def set_dirframe(self, frame=""):
560        """
561        Set the frame type of the Direction on the sky.
562        Parameters:
563            frame:   an optional frame type, default ''. Valid frames are:
564                     'J2000', 'B1950', 'GALACTIC'
565        Examples:
566            scan.set_dirframe('GALACTIC')
567        """
568        varlist = vars()
569        try:
570            Scantable.set_dirframe(self, frame)
571        except RuntimeError,msg:
572            if rcParams['verbose']:
573                print msg
574            else:
575                raise
576        self._add_history("set_dirframe",varlist)
577
578    def get_unit(self):
579        """
580        Get the default unit set in this scantable
581        Parameters:
582        Returns:
583            A unit string
584        """
585        inf = self._getcoordinfo()
586        unit = inf[0]
587        if unit == '': unit = 'channel'
588        return unit
589
590    def get_abcissa(self, rowno=0):
591        """
592        Get the abcissa in the current coordinate setup for the currently
593        selected Beam/IF/Pol
594        Parameters:
595            rowno:    an optional row number in the scantable. Default is the
596                      first row, i.e. rowno=0
597        Returns:
598            The abcissa values and it's format string (as a dictionary)
599        """
600        abc = self._getabcissa(rowno)
601        lbl = self._getabcissalabel(rowno)
602        print_log()
603        return abc, lbl
604
605    def flag(self, mask=[]):
606        """
607        Flag the selected data using an optional channel mask.
608        Parameters:
609            mask:   an optional channel mask, created with create_mask. Default
610                    (no mask) is all channels.
611        """
612        varlist = vars()
613        try:
614            self._flag(mask)
615        except RuntimeError,msg:
616            if rcParams['verbose']:
617                print msg
618                return
619            else: raise
620        self._add_history("flag", varlist)
621
622
623    def create_mask(self, *args, **kwargs):
624        """
625        Compute and return a mask based on [min,max] windows.
626        The specified windows are to be INCLUDED, when the mask is
627        applied.
628        Parameters:
629            [min,max],[min2,max2],...
630                Pairs of start/end points (inclusive)specifying the regions
631                to be masked
632            invert:     optional argument. If specified as True,
633                        return an inverted mask, i.e. the regions
634                        specified are EXCLUDED
635            row:        create the mask using the specified row for
636                        unit conversions, default is row=0
637                        only necessary if frequency varies over rows.
638        Example:
639            scan.set_unit('channel')
640            a)
641            msk = scan.create_mask([400,500],[800,900])
642            # masks everything outside 400 and 500
643            # and 800 and 900 in the unit 'channel'
644
645            b)
646            msk = scan.create_mask([400,500],[800,900], invert=True)
647            # masks the regions between 400 and 500
648            # and 800 and 900 in the unit 'channel'
649            c)
650            mask only channel 400
651            msk =  scan.create_mask([400,400])
652        """
653        row = 0
654        if kwargs.has_key("row"):
655            row = kwargs.get("row")
656        data = self._getabcissa(row)
657        u = self._getcoordinfo()[0]
658        if rcParams['verbose']:
659            if u == "": u = "channel"
660            from asap import asaplog
661            msg = "The current mask window unit is %s" % u
662            if not self._check_ifs():
663                msg += "\nThis mask is only valid for IF=%d" % (self.getif(i))
664            asaplog.push(msg)
665        n = self.nchan()
666        msk = zeros(n)
667        # test if args is a 'list' or a 'normal *args - UGLY!!!
668
669        ws = (isinstance(args[-1][-1],int) or isinstance(args[-1][-1],float)) and args or args[0]
670        for window in ws:
671            if (len(window) != 2 or window[0] > window[1] ):
672                raise TypeError("A window needs to be defined as [min,max]")
673            for i in range(n):
674                if data[i] >= window[0] and data[i] <= window[1]:
675                    msk[i] = 1
676        if kwargs.has_key('invert'):
677            if kwargs.get('invert'):
678                from numarray import logical_not
679                msk = logical_not(msk)
680        print_log()
681        return msk
682
683    def get_restfreqs(self):
684        """
685        Get the restfrequency(s) stored in this scantable.
686        The return value(s) are always of unit 'Hz'
687        Parameters:
688            none
689        Returns:
690            a list of doubles
691        """
692        return list(self._getrestfreqs())
693
694
695    def set_restfreqs(self, freqs=None, unit='Hz'):
696        """
697        Set or replace the restfrequency specified and
698        If the 'freqs' argument holds a scalar,
699        then that rest frequency will be applied to all the selected
700        data.  If the 'freqs' argument holds
701        a vector, then it MUST be of equal or smaller length than
702        the number of IFs (and the available restfrequencies will be
703        replaced by this vector).  In this case, *all* data have
704        the restfrequency set per IF according
705        to the corresponding value you give in the 'freqs' vector.
706        E.g. 'freqs=[1e9,2e9]'  would mean IF 0 gets restfreq 1e9 and
707        IF 1 gets restfreq 2e9.
708        You can also specify the frequencies via known line names
709        from the built-in Lovas table.
710        Parameters:
711            freqs:   list of rest frequency values or string idenitfiers
712            unit:    unit for rest frequency (default 'Hz')
713
714        Example:
715            # set the given restfrequency for the whole table
716            scan.set_restfreqs(freqs=1.4e9)
717            # If thee number of IFs in the data is >= 2 the IF0 gets the first
718            # value IF1 the second...
719            scan.set_restfreqs(freqs=[1.4e9,1.67e9])
720            #set the given restfrequency for the whole table (by name)
721            scan.set_restfreqs(freqs="OH1667")
722
723        Note:
724            To do more sophisticate Restfrequency setting, e.g. on a
725            source and IF basis, use scantable.set_selection() before using
726            this function.
727            # provide your scantable is call scan
728            selection = selector()
729            selection.set_name("ORION*")
730            selection.set_ifs([1])
731            scan.set_selection(selection)
732            scan.set_restfreqs(freqs=86.6e9)
733
734        """
735        varlist = vars()
736
737        t = type(freqs)
738        if isinstance(freqs, int) or isinstance(freqs,float):
739           self._setrestfreqs(freqs, unit)
740        elif isinstance(freqs, list) or isinstance(freqs,tuple):
741            if isinstance(freqs[-1], int) or isinstance(freqs[-1],float):
742                sel = selector()
743                savesel = self._getselection()
744                for i in xrange(len(freqs)):
745                    sel.set_ifs([i])
746                    self._setselection(sel)
747                    self._setrestfreqs(freqs[i], unit)
748                self._setselection(savesel)
749            elif isinstance(freqs[-1], str):
750                # not yet implemented
751                pass
752        else:
753            return
754        self._add_history("set_restfreqs", varlist)
755
756
757
758    def history(self):
759        hist = list(self._gethistory())
760        out = "-"*80
761        for h in hist:
762            if h.startswith("---"):
763                out += "\n"+h
764            else:
765                items = h.split("##")
766                date = items[0]
767                func = items[1]
768                items = items[2:]
769                out += "\n"+date+"\n"
770                out += "Function: %s\n  Parameters:" % (func)
771                for i in items:
772                    s = i.split("=")
773                    out += "\n   %s = %s" % (s[0],s[1])
774                out += "\n"+"-"*80
775        try:
776            from IPython.genutils import page as pager
777        except ImportError:
778            from pydoc import pager
779        pager(out)
780        return
781
782    #
783    # Maths business
784    #
785
786    def average_time(self, mask=None, scanav=False, weight='tint', align=False):
787        """
788        Return the (time) weighted average of a scan.
789        Note:
790            in channels only - align if necessary
791        Parameters:
792            one scan or comma separated  scans
793            mask:     an optional mask (only used for 'var' and 'tsys'
794                      weighting)
795            scanav:   True averages each scan separately
796                      False (default) averages all scans together,
797            weight:   Weighting scheme.
798                      'none'     (mean no weight)
799                      'var'      (1/var(spec) weighted)
800                      'tsys'     (1/Tsys**2 weighted)
801                      'tint'     (integration time weighted)
802                      'tintsys'  (Tint/Tsys**2)
803                      'median'   ( median averaging)
804                      The default is 'tint'
805            align:    align the spectra in velocity before averaging. It takes
806                      the time of the first spectrum as reference time.
807        Example:
808            # time average the scantable without using a mask
809            newscan = scan.average_time()
810        """
811        varlist = vars()
812        if weight is None: weight = 'TINT'
813        if mask is None: mask = ()
814        if scanav: scanav = "SCAN"
815        else: scanav = "NONE"
816        scan = (self,)
817        try:
818          if align:
819              scan = (self.freq_align(insitu=False),)
820          s = None
821          if weight.upper() == 'MEDIAN':
822              s = scantable(self._math._averagechannel(scan[0], 'MEDIAN', scanav))
823          else:
824              s = scantable(self._math._average(scan, mask, weight.upper(),
825                        scanav))
826        except RuntimeError,msg:
827            if rcParams['verbose']:
828                print msg
829                return
830            else: raise
831        s._add_history("average_time", varlist)
832        print_log()
833        return s
834
835    def convert_flux(self, jyperk=None, eta=None, d=None, insitu=None):
836        """
837        Return a scan where all spectra are converted to either
838        Jansky or Kelvin depending upon the flux units of the scan table.
839        By default the function tries to look the values up internally.
840        If it can't find them (or if you want to over-ride), you must
841        specify EITHER jyperk OR eta (and D which it will try to look up
842        also if you don't set it). jyperk takes precedence if you set both.
843        Parameters:
844            jyperk:      the Jy / K conversion factor
845            eta:         the aperture efficiency
846            d:           the geomtric diameter (metres)
847            insitu:      if False a new scantable is returned.
848                         Otherwise, the scaling is done in-situ
849                         The default is taken from .asaprc (False)
850            allaxes:         if True apply to all spectra. Otherwise
851                         apply only to the selected (beam/pol/if)spectra only
852                         The default is taken from .asaprc (True if none)
853        """
854        if insitu is None: insitu = rcParams['insitu']
855        self._math._setinsitu(insitu)
856        varlist = vars()
857        if jyperk is None: jyperk = -1.0
858        if d is None: d = -1.0
859        if eta is None: eta = -1.0
860        s = scantable(self._math._convertflux(self, d, eta, jyperk))
861        s._add_history("convert_flux", varlist)
862        print_log()
863        if insitu: self._assign(s)
864        else: return s
865
866    def gain_el(self, poly=None, filename="", method="linear", insitu=None):
867        """
868        Return a scan after applying a gain-elevation correction.
869        The correction can be made via either a polynomial or a
870        table-based interpolation (and extrapolation if necessary).
871        You specify polynomial coefficients, an ascii table or neither.
872        If you specify neither, then a polynomial correction will be made
873        with built in coefficients known for certain telescopes (an error
874        will occur if the instrument is not known).
875        The data and Tsys are *divided* by the scaling factors.
876        Parameters:
877            poly:        Polynomial coefficients (default None) to compute a
878                         gain-elevation correction as a function of
879                         elevation (in degrees).
880            filename:    The name of an ascii file holding correction factors.
881                         The first row of the ascii file must give the column
882                         names and these MUST include columns
883                         "ELEVATION" (degrees) and "FACTOR" (multiply data
884                         by this) somewhere.
885                         The second row must give the data type of the
886                         column. Use 'R' for Real and 'I' for Integer.
887                         An example file would be
888                         (actual factors are arbitrary) :
889
890                         TIME ELEVATION FACTOR
891                         R R R
892                         0.1 0 0.8
893                         0.2 20 0.85
894                         0.3 40 0.9
895                         0.4 60 0.85
896                         0.5 80 0.8
897                         0.6 90 0.75
898            method:      Interpolation method when correcting from a table.
899                         Values are  "nearest", "linear" (default), "cubic"
900                         and "spline"
901            insitu:      if False a new scantable is returned.
902                         Otherwise, the scaling is done in-situ
903                         The default is taken from .asaprc (False)
904        """
905
906        if insitu is None: insitu = rcParams['insitu']
907        self._math._setinsitu(insitu)
908        varlist = vars()
909        if poly is None:
910           poly = ()
911        from os.path import expandvars
912        filename = expandvars(filename)
913        s = scantable(self._math._gainel(self, poly, filename, method))
914        s._add_history("gain_el", varlist)
915        print_log()
916        if insitu: self._assign(s)
917        else: return s
918
919    def freq_align(self, reftime=None, method='cubic', insitu=None):
920        """
921        Return a scan where all rows have been aligned in frequency/velocity.
922        The alignment frequency frame (e.g. LSRK) is that set by function
923        set_freqframe.
924        Parameters:
925            reftime:     reference time to align at. By default, the time of
926                         the first row of data is used.
927            method:      Interpolation method for regridding the spectra.
928                         Choose from "nearest", "linear", "cubic" (default)
929                         and "spline"
930            insitu:      if False a new scantable is returned.
931                         Otherwise, the scaling is done in-situ
932                         The default is taken from .asaprc (False)
933        """
934        if insitu is None: insitu = rcParams["insitu"]
935        self._math._setinsitu(insitu)
936        varlist = vars()
937        if reftime is None: reftime = ""
938        s = scantable(self._math._freq_align(self, reftime, method))
939        s._add_history("freq_align", varlist)
940        print_log()
941        if insitu: self._assign(s)
942        else: return s
943
944    def opacity(self, tau, insitu=None):
945        """
946        Apply an opacity correction. The data
947        and Tsys are multiplied by the correction factor.
948        Parameters:
949            tau:         Opacity from which the correction factor is
950                         exp(tau*ZD)
951                         where ZD is the zenith-distance
952            insitu:      if False a new scantable is returned.
953                         Otherwise, the scaling is done in-situ
954                         The default is taken from .asaprc (False)
955        """
956        if insitu is None: insitu = rcParams['insitu']
957        self._math._setinsitu(insitu)
958        varlist = vars()
959        s = scantable(self._math._opacity(self, tau))
960        s._add_history("opacity", varlist)
961        print_log()
962        if insitu: self._assign(s)
963        else: return s
964
965    def bin(self, width=5, insitu=None):
966        """
967        Return a scan where all spectra have been binned up.
968            width:       The bin width (default=5) in pixels
969            insitu:      if False a new scantable is returned.
970                         Otherwise, the scaling is done in-situ
971                         The default is taken from .asaprc (False)
972        """
973        if insitu is None: insitu = rcParams['insitu']
974        self._math._setinsitu(insitu)
975        varlist = vars()
976        s = scantable(self._math._bin(self, width))
977        s._add_history("bin",varlist)
978        print_log()
979        if insitu: self._assign(s)
980        else: return s
981
982
983    def resample(self, width=5, method='cubic', insitu=None):
984        """
985        Return a scan where all spectra have been binned up
986            width:       The bin width (default=5) in pixels
987            method:      Interpolation method when correcting from a table.
988                         Values are  "nearest", "linear", "cubic" (default)
989                         and "spline"
990            insitu:      if False a new scantable is returned.
991                         Otherwise, the scaling is done in-situ
992                         The default is taken from .asaprc (False)
993        """
994        if insitu is None: insitu = rcParams['insitu']
995        self._math._setinsitu(insitu)
996        varlist = vars()
997        s = scantable(self._math._resample(self, method, width))
998        s._add_history("resample",varlist)
999        print_log()
1000        if insitu: self._assign(s)
1001        else: return s
1002
1003
1004    def average_pol(self, mask=None, weight='none'):
1005        """
1006        Average the Polarisations together.
1007        Parameters:
1008            mask:        An optional mask defining the region, where the
1009                         averaging will be applied. The output will have all
1010                         specified points masked.
1011            weight:      Weighting scheme. 'none' (default), 'var' (1/var(spec)
1012                         weighted), or 'tsys' (1/Tsys**2 weighted)
1013        """
1014        varlist = vars()
1015        if mask is None:
1016            mask = ()
1017        s = scantable(self._math._averagepol(self, mask, weight.upper()))
1018        s._add_history("average_pol",varlist)
1019        print_log()
1020        return s
1021
1022    def convert_pol(self, poltype=None):
1023        """
1024        Convert the data to a different polarisation type.
1025        Parameters:
1026            poltype:    The new polarisation type. Valid types are:
1027                        "linear", "stokes" and "circular"
1028        """
1029        varlist = vars()
1030        try:
1031            s = scantable(self._math._convertpol(self, poltype))
1032        except RuntimeError,msg:
1033            if rcParams['verbose']:
1034              print msg
1035              return
1036            else:
1037                raise
1038        s._add_history("convert_pol",varlist)
1039        print_log()
1040        return s
1041
1042    def smooth(self, kernel="hanning", width=5.0, insitu=None):
1043        """
1044        Smooth the spectrum by the specified kernel (conserving flux).
1045        Parameters:
1046            scan:       The input scan
1047            kernel:     The type of smoothing kernel. Select from
1048                        'hanning' (default), 'gaussian' and 'boxcar'.
1049                        The first three characters are sufficient.
1050            width:      The width of the kernel in pixels. For hanning this is
1051                        ignored otherwise it defauls to 5 pixels.
1052                        For 'gaussian' it is the Full Width Half
1053                        Maximum. For 'boxcar' it is the full width.
1054            insitu:     if False a new scantable is returned.
1055                        Otherwise, the scaling is done in-situ
1056                        The default is taken from .asaprc (False)
1057        Example:
1058             none
1059        """
1060        if insitu is None: insitu = rcParams['insitu']
1061        self._math._setinsitu(insitu)
1062        varlist = vars()
1063        s = scantable(self._math._smooth(self,kernel.lower(),width))
1064        s._add_history("smooth", varlist)
1065        print_log()
1066        if insitu: self._assign(s)
1067        else: return s
1068
1069
1070    def poly_baseline(self, mask=None, order=0, plot=False, insitu=None):
1071        """
1072        Return a scan which has been baselined (all rows) by a polynomial.
1073        Parameters:
1074            scan:       a scantable
1075            mask:       an optional mask
1076            order:      the order of the polynomial (default is 0)
1077            plot:       plot the fit and the residual. In this each
1078                        indivual fit has to be approved, by typing 'y'
1079                        or 'n'
1080            insitu:     if False a new scantable is returned.
1081                        Otherwise, the scaling is done in-situ
1082                        The default is taken from .asaprc (False)
1083        Example:
1084            # return a scan baselined by a third order polynomial,
1085            # not using a mask
1086            bscan = scan.poly_baseline(order=3)
1087        """
1088        if insitu is None: insitu = rcParams['insitu']
1089        varlist = vars()
1090        if mask is None:
1091            from numarray import ones
1092            mask = list(ones(self.nchan(-1)))
1093        from asap.asapfitter import fitter
1094        f = fitter()
1095        f.set_scan(self, mask)
1096        f.set_function(poly=order)
1097        s = f.auto_fit(insitu, plot=plot)
1098        s._add_history("poly_baseline", varlist)
1099        print_log()
1100        if insitu: self._assign(s)
1101        else: return s
1102
1103    def auto_poly_baseline(self, mask=[], edge=(0,0), order=0,
1104                           threshold=3, plot=False, insitu=None):
1105        """
1106        Return a scan which has been baselined (all rows) by a polynomial.
1107        Spectral lines are detected first using linefinder and masked out
1108        to avoid them affecting the baseline solution.
1109
1110        Parameters:
1111            mask:       an optional mask retreived from scantable
1112            edge:       an optional number of channel to drop at
1113                        the edge of spectrum. If only one value is
1114                        specified, the same number will be dropped from
1115                        both sides of the spectrum. Default is to keep
1116                        all channels. Nested tuples represent individual
1117                        edge selection for different IFs (a number of spectral
1118                        channels can be different)
1119            order:      the order of the polynomial (default is 0)
1120            threshold:  the threshold used by line finder. It is better to
1121                        keep it large as only strong lines affect the
1122                        baseline solution.
1123            plot:       plot the fit and the residual. In this each
1124                        indivual fit has to be approved, by typing 'y'
1125                        or 'n'
1126            insitu:     if False a new scantable is returned.
1127                        Otherwise, the scaling is done in-situ
1128                        The default is taken from .asaprc (False)
1129
1130        Example:
1131            scan2=scan.auto_poly_baseline(order=7)
1132        """
1133        if insitu is None: insitu = rcParams['insitu']
1134        varlist = vars()
1135        from asap.asapfitter import fitter
1136        from asap.asaplinefind import linefinder
1137        from asap import _is_sequence_or_number as _is_valid
1138
1139        # check whether edge is set up for each IF individually
1140        individualEdge = False;
1141        if len(edge)>1:
1142           if isinstance(edge[0],list) or isinstance(edge[0],tuple):
1143               individualEdge = True;
1144
1145        if not _is_valid(edge, int) and not individualEdge:
1146            raise ValueError, "Parameter 'edge' has to be an integer or a \
1147            pair of integers specified as a tuple. Nested tuples are allowed \
1148            to make individual selection for different IFs."
1149
1150        curedge = (0,0)
1151        if individualEdge:
1152           for edge_par in edge:
1153               if not _is_valid(edge,int):
1154                  raise ValueError, "Each element of the 'edge' tuple has \
1155                  to be a pair of integers or an integer."
1156        else:
1157           curedge = edge;
1158
1159        # setup fitter
1160        f = fitter()
1161        f.set_function(poly=order)
1162
1163        # setup line finder
1164        fl=linefinder()
1165        fl.set_options(threshold=threshold)
1166
1167        if not insitu:
1168            workscan=self.copy()
1169        else:
1170            workscan=self
1171
1172        fl.set_scan(workscan)
1173
1174        rows=range(workscan.nrow())
1175        from asap import asaplog
1176        asaplog.push("Processing:")
1177        for r in rows:
1178            msg = " Scan[%d] Beam[%d] IF[%d] Pol[%d] Cycle[%d]" %        (workscan.getscan(r),workscan.getbeam(r),workscan.getif(r),workscan.getpol(r), workscan.getcycle(r))
1179            asaplog.push(msg, False)
1180
1181            # figure out edge parameter
1182            if individualEdge:
1183               if len(edge)>=workscan.getif(r):
1184                  raise RuntimeError, "Number of edge elements appear to be less than the number of IFs"
1185                  curedge = edge[workscan.getif(r)]
1186
1187            # setup line finder
1188            fl.find_lines(r,mask,curedge)
1189            f.set_scan(workscan, fl.get_mask())
1190            f.x = workscan._getabcissa(r)
1191            f.y = workscan._getspectrum(r)
1192            f.data = None
1193            f.fit()
1194            x = f.get_parameters()
1195            if plot:
1196                f.plot(residual=True)
1197                x = raw_input("Accept fit ( [y]/n ): ")
1198                if x.upper() == 'N':
1199                    continue
1200            workscan._setspectrum(f.fitter.getresidual(), r)
1201        if plot:
1202            f._p.unmap()
1203            f._p = None
1204        workscan._add_history("auto_poly_baseline", varlist)
1205        if insitu:
1206            self._assign(workscan)
1207        else:
1208            return workscan
1209
1210    def rotate_linpolphase(self, angle):
1211        """
1212        Rotate the phase of the complex polarization O=Q+iU correlation.
1213        This is always done in situ in the raw data.  So if you call this
1214        function more than once then each call rotates the phase further.
1215        Parameters:
1216            angle:   The angle (degrees) to rotate (add) by.
1217        Examples:
1218            scan.rotate_linpolphase(2.3)
1219        """
1220        varlist = vars()
1221        self._math._rotate_linpolphase(self, angle)
1222        self._add_history("rotate_linpolphase", varlist)
1223        print_log()
1224        return
1225
1226
1227    def rotate_xyphase(self, angle):
1228        """
1229        Rotate the phase of the XY correlation.  This is always done in situ
1230        in the data.  So if you call this function more than once
1231        then each call rotates the phase further.
1232        Parameters:
1233            angle:   The angle (degrees) to rotate (add) by.
1234        Examples:
1235            scan.rotate_xyphase(2.3)
1236        """
1237        varlist = vars()
1238        self._math._rotate_xyphase(self, angle)
1239        self._add_history("rotate_xyphase", varlist)
1240        print_log()
1241        return
1242
1243    def swap_linears(self):
1244        """
1245        Swap the linear polarisations XX and YY
1246        """
1247        varlist = vars()
1248        self._math._swap_linears(self)
1249        self._add_history("swap_linears", varlist)
1250        print_log()
1251        return
1252
1253    def invert_phase(self):
1254        """
1255        Invert the phase of the complex polarisation
1256        """
1257        varlist = vars()
1258        self._math._invert_phase(self)
1259        self._add_history("invert_phase", varlist)
1260        print_log()
1261        return
1262
1263    def add(self, offset, insitu=None):
1264        """
1265        Return a scan where all spectra have the offset added
1266        Parameters:
1267            offset:      the offset
1268            insitu:      if False a new scantable is returned.
1269                         Otherwise, the scaling is done in-situ
1270                         The default is taken from .asaprc (False)
1271        """
1272        if insitu is None: insitu = rcParams['insitu']
1273        self._math._setinsitu(insitu)
1274        varlist = vars()
1275        s = scantable(self._math._unaryop(self, offset, "ADD", False))
1276        s._add_history("add",varlist)
1277        print_log()
1278        if insitu:
1279            self._assign(s)
1280        else:
1281            return s
1282
1283    def scale(self, factor, tsys=True, insitu=None,):
1284        """
1285        Return a scan where all spectra are scaled by the give 'factor'
1286        Parameters:
1287            factor:      the scaling factor
1288            insitu:      if False a new scantable is returned.
1289                         Otherwise, the scaling is done in-situ
1290                         The default is taken from .asaprc (False)
1291            tsys:        if True (default) then apply the operation to Tsys
1292                         as well as the data
1293        """
1294        if insitu is None: insitu = rcParams['insitu']
1295        self._math._setinsitu(insitu)
1296        varlist = vars()
1297        s = scantable(self._math._unaryop(self, factor, "MUL", tsys))
1298        s._add_history("scale",varlist)
1299        print_log()
1300        if insitu:
1301            self._assign(s)
1302        else:
1303            return s
1304
1305    def auto_quotient(self, mode='time', preserve=True):
1306        """
1307        This function allows to build quotients automatically.
1308        It assumes the observation to have the same numer of
1309        "ons" and "offs"
1310        It will support "closest off in time" in the future
1311        Parameters:
1312            mode:           the on/off detection mode; 'suffix' (default)
1313                            'suffix' identifies 'off' scans by the
1314                            trailing '_R' (Mopra/Parkes) or
1315                            '_e'/'_w' (Tid)
1316            preserve:       you can preserve (default) the continuum or
1317                            remove it.  The equations used are
1318                            preserve: Output = Toff * (on/off) - Toff
1319                            remove:   Output = Toff * (on/off) - Ton
1320        """
1321        modes = ["time"]
1322        if not mode in modes:
1323            msg = "please provide valid mode. Valid modes are %s" % (modes)
1324            raise ValueError(msg)
1325        varlist = vars()
1326        s = scantable(self._math._auto_quotient(self, mode, preserve))
1327        s._add_history("auto_quotient",varlist)
1328        print_log()
1329        return s
1330
1331
1332
1333
1334    def freq_switch(self, insitu=None):
1335        """
1336        Apply frequency switching to the data.
1337        Parameters:
1338            insitu:      if False a new scantable is returned.
1339                         Otherwise, the swictching is done in-situ
1340                         The default is taken from .asaprc (False)
1341        Example:
1342            none
1343        """
1344        if insitu is None: insitu = rcParams['insitu']
1345        self._math._setinsitu(insitu)
1346        varlist = vars()
1347        s = scantable(self._math._freqswitch(self))
1348        s._add_history("freq_switch",varlist)
1349        print_log()
1350        if insitu: self._assign(s)
1351        else: return s
1352
1353    def recalc_azel(self):
1354        """
1355        Recalculate the azimuth and elevation for each position.
1356        Parameters:
1357            none
1358        Example:
1359        """
1360        varlist = vars()
1361        self._recalcazel()
1362        self._add_history("recalc_azel", varlist)
1363        print_log()
1364        return
1365
1366    def __add__(self, other):
1367        varlist = vars()
1368        s = None
1369        if isinstance(other, scantable):
1370            print "scantable + scantable NYI"
1371            return
1372        elif isinstance(other, float):
1373            s = scantable(self._math._unaryop(self, other, "ADD", False))
1374        else:
1375            raise TypeError("Other input is not a scantable or float value")
1376        s._add_history("operator +", varlist)
1377        print_log()
1378        return s
1379
1380    def __sub__(self, other):
1381        """
1382        implicit on all axes and on Tsys
1383        """
1384        varlist = vars()
1385        s = None
1386        if isinstance(other, scantable):
1387            print "scantable - scantable NYI"
1388            return
1389        elif isinstance(other, float):
1390            s = scantable(self._math._unaryop(self, other, "SUB", False))
1391        else:
1392            raise TypeError("Other input is not a scantable or float value")
1393        s._add_history("operator -", varlist)
1394        print_log()
1395        return s
1396
1397    def __mul__(self, other):
1398        """
1399        implicit on all axes and on Tsys
1400        """
1401        varlist = vars()
1402        s = None
1403        if isinstance(other, scantable):
1404            print "scantable * scantable NYI"
1405            return
1406        elif isinstance(other, float):
1407            s = scantable(self._math._unaryop(self, other, "MUL", False))
1408        else:
1409            raise TypeError("Other input is not a scantable or float value")
1410        s._add_history("operator *", varlist)
1411        print_log()
1412        return s
1413
1414
1415    def __div__(self, other):
1416        """
1417        implicit on all axes and on Tsys
1418        """
1419        varlist = vars()
1420        s = None
1421        if isinstance(other, scantable):
1422            print "scantable / scantable NYI"
1423            return
1424        elif isinstance(other, float):
1425            if other == 0.0:
1426                raise ZeroDivisionError("Dividing by zero is not recommended")
1427            s = scantable(self._math._unaryop(self, other, "DIV", False))
1428        else:
1429            raise TypeError("Other input is not a scantable or float value")
1430        s._add_history("operator /", varlist)
1431        print_log()
1432        return s
1433
1434    def get_fit(self, row=0):
1435        """
1436        Print or return the stored fits for a row in the scantable
1437        Parameters:
1438            row:    the row which the fit has been applied to.
1439        """
1440        if row > self.nrow():
1441            return
1442        from asap.asapfit import asapfit
1443        fit = asapfit(self._getfit(row))
1444        if rcParams['verbose']:
1445            print fit
1446            return
1447        else:
1448            return fit.as_dict()
1449
1450    def _add_history(self, funcname, parameters):
1451        # create date
1452        sep = "##"
1453        from datetime import datetime
1454        dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
1455        hist = dstr+sep
1456        hist += funcname+sep#cdate+sep
1457        if parameters.has_key('self'): del parameters['self']
1458        for k,v in parameters.iteritems():
1459            if type(v) is dict:
1460                for k2,v2 in v.iteritems():
1461                    hist += k2
1462                    hist += "="
1463                    if isinstance(v2,scantable):
1464                        hist += 'scantable'
1465                    elif k2 == 'mask':
1466                        if isinstance(v2,list) or isinstance(v2,tuple):
1467                            hist += str(self._zip_mask(v2))
1468                        else:
1469                            hist += str(v2)
1470                    else:
1471                        hist += str(v2)
1472            else:
1473                hist += k
1474                hist += "="
1475                if isinstance(v,scantable):
1476                    hist += 'scantable'
1477                elif k == 'mask':
1478                    if isinstance(v,list) or isinstance(v,tuple):
1479                        hist += str(self._zip_mask(v))
1480                    else:
1481                        hist += str(v)
1482                else:
1483                    hist += str(v)
1484            hist += sep
1485        hist = hist[:-2] # remove trailing '##'
1486        self._addhistory(hist)
1487
1488
1489    def _zip_mask(self, mask):
1490        mask = list(mask)
1491        i = 0
1492        segments = []
1493        while mask[i:].count(1):
1494            i += mask[i:].index(1)
1495            if mask[i:].count(0):
1496                j = i + mask[i:].index(0)
1497            else:
1498                j = len(mask)
1499            segments.append([i,j])
1500            i = j
1501        return segments
1502
1503    def _get_ordinate_label(self):
1504        fu = "("+self.get_fluxunit()+")"
1505        import re
1506        lbl = "Intensity"
1507        if re.match(".K.",fu):
1508            lbl = "Brightness Temperature "+ fu
1509        elif re.match(".Jy.",fu):
1510            lbl = "Flux density "+ fu
1511        return lbl
1512
1513    def _check_ifs(self):
1514        nchans = [self.nchan(i) for i in range(self.nif(-1))]
1515        nchans = filter(lambda t: t > 0, nchans)
1516        return (sum(nchans)/len(nchans) == nchans[0])
1517
1518    def _fill(self, names, unit, average):
1519        import os
1520        varlist = vars()
1521        from asap._asap import stfiller
1522        first = True
1523        fullnames = []
1524        for name in names:
1525            name = os.path.expandvars(name)
1526            name = os.path.expanduser(name)
1527            if not os.path.exists(name):
1528                msg = "File '%s' does not exists" % (name)
1529                if rcParams['verbose']:
1530                    asaplog.push(msg)
1531                    print asaplog.pop().strip()
1532                    return
1533                raise IOError(msg)
1534            fullnames.append(name)
1535        if average:
1536            asaplog.push('Auto averaging integrations')
1537        stype = int(rcParams['scantable.storage'].lower() == 'disk')
1538        for name in fullnames:
1539            tbl = Scantable(stype)
1540            r = stfiller(tbl)
1541            msg = "Importing %s..." % (name)
1542            asaplog.push(msg,False)
1543            print_log()
1544            r._open(name,-1,-1)
1545            r._read()
1546            #tbl = r._getdata()
1547            if average:
1548                tbl = self._math._average((tbl,),(),'NONE','SCAN')
1549                #tbl = tbl2
1550            if not first:
1551                tbl = self._math._merge([self, tbl])
1552                #tbl = tbl2
1553            Scantable.__init__(self, tbl)
1554            r._close()
1555            del r,tbl
1556            first = False
1557        if unit is not None:
1558            self.set_fluxunit(unit)
1559        self.set_freqframe(rcParams['scantable.freqframe'])
1560        #self._add_history("scantable", varlist)
1561
Note: See TracBrowser for help on using the repository browser.