source: trunk/python/scantable.py @ 1118

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

fixes for pylint reported violations

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