source: trunk/python/scantable.py @ 1099

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

moved average_channel into average_time as an addition weight

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