source: trunk/python/scantable.py @ 1145

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

added average_beam which is part of Ticket #45

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