source: trunk/python/scantable.py @ 1093

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

removed FITS output, added drop_scan function

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