source: trunk/python/scantable.py@ 488

Last change on this file since 488 was 484, checked in by mar637, 20 years ago
  • added history
  • added contructor argument for (auto) averaging
  • tidying
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.2 KB
Line 
1from asap._asap import sdtable
2from asap import rcParams
3from numarray import ones,zeros
4import sys
5
6class scantable(sdtable):
7 """
8 The ASAP container for scans
9 """
10
11 def __init__(self, filename, average=None, unit=None):
12 """
13 Create a scantable from a saved one or make a reference
14 Parameters:
15 filename: the name of an asap table on disk
16 or
17 the name of a rpfits/sdfits/ms file
18 (integrations within scans are auto averaged
19 and the whole file is read)
20 or
21 [advanced] a reference to an existing
22 scantable
23 average: average all integrations withinb a scan on read.
24 The default (True) is taken from .asaprc.
25 unit: brightness unit; must be consistent with K or Jy.
26 Over-rides the default selected by the reader
27 (input rpfits/sdfits/ms) or replaces the value
28 in existing scantables
29 """
30 varlist = vars()
31 self._vb = rcParams['verbose']
32 self._p = None
33
34 if average is None or type(average) is not bool:
35 autoav = rcParams['scantable.autoaverage']
36
37 if isinstance(filename,sdtable):
38 sdtable.__init__(self, filename)
39 if unit is not None:
40 self.set_fluxunit(unit)
41 else:
42 import os.path
43 if not os.path.exists(filename):
44 print "File '%s' not found." % (filename)
45 return
46 filename = os.path.expandvars(filename)
47 if os.path.isdir(filename):
48 # crude check if asap table
49 if os.path.exists(filename+'/table.info'):
50 sdtable.__init__(self, filename)
51 if unit is not None:
52 self.set_fluxunit(unit)
53 else:
54 print "The given file '%s'is not a valid asap table." % (filename)
55 return
56 else:
57 from asap._asap import sdreader
58 ifSel = -1
59 beamSel = -1
60 r = sdreader(filename,ifSel,beamSel)
61 print 'Importing data...'
62 r._read([-1])
63 tbl = r._getdata()
64 if unit is not None:
65 tbl.set_fluxunit(unit)
66 if autoav:
67 from asap._asap import average
68 tmp = tuple([tbl])
69 print 'Auto averaging integrations...'
70 tbl2 = average(tmp,(),True,'none')
71 sdtable.__init__(self,tbl2)
72 del r,tbl
73 else:
74 sdtable.__init__(self,tbl)
75 self._add_history("scantable", varlist)
76
77 def save(self, name=None, format=None, stokes=False, overwrite=False):
78 """
79 Store the scantable on disk. This can be an asap (aips++) Table, SDFITS,
80 Image FITS or MS2 format.
81 Parameters:
82 name: the name of the outputfile. For format="FITS" this
83 is the directory file name into which all the files will
84 be written (default is 'asap_FITS')
85 format: an optional file format. Default is ASAP.
86 Allowed are - 'ASAP' (save as ASAP [aips++] Table),
87 'SDFITS' (save as SDFITS file)
88 'FITS' (saves each row as a FITS Image)
89 'ASCII' (saves as ascii text file)
90 'MS2' (saves as an aips++
91 MeasurementSet V2)
92 stokes: Convert to Stokes parameters. Default is False.
93 overwrite: If the file should be overwritten if it exists.
94 The default False is to return with warning
95 without writing the output. USE WITH CARE.
96 Example:
97 scan.save('myscan.asap')
98 scan.save('myscan.sdfits','SDFITS')
99 """
100 from os import path
101 if format is None: format = rcParams['scantable.save']
102 suffix = '.'+format.lower()
103 if name is None or name =="":
104 name = 'scantable'+suffix
105 print "No filename given. Using default name %s..." % name
106 name = path.expandvars(name)
107 if path.isfile(name) or path.isdir(name):
108 if not overwrite:
109 print "File %s already exists." % name
110 return
111 format2 = format.upper()
112 if format2 == 'ASAP':
113 self._save(name)
114 else:
115 from asap._asap import sdwriter as _sw
116 w = _sw(format2)
117 w.write(self, name, stokes)
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(sdtable._copy(self))
129 return sd
130
131 def get_scan(self, scanid=None):
132 """
133 Return a specific scan (by scanno) or collection of scans (by
134 source name) in a new scantable.
135 Parameters:
136 scanid: a scanno or a source name
137 Example:
138 scan.get_scan('323p459')
139 # gets all scans containing the source '323p459'
140 """
141 if scanid is None:
142 print "Please specify a scan no or name to retrieve from the scantable"
143 try:
144 if type(scanid) is str:
145 s = sdtable._getsource(self,scanid)
146 return scantable(s)
147 elif type(scanid) is int:
148 s = sdtable._getscan(self,[scanid])
149 return scantable(s)
150 elif type(scanid) is list:
151 s = sdtable._getscan(self,scanid)
152 return scantable(s)
153 else:
154 print "Illegal scanid type, use 'int' or 'list' if ints."
155 except RuntimeError:
156 print "Couldn't find any match."
157
158 def __str__(self):
159 return sdtable._summary(self,True)
160
161 def summary(self,filename=None, verbose=None):
162 """
163 Print a summary of the contents of this scantable.
164 Parameters:
165 filename: the name of a file to write the putput to
166 Default - no file output
167 verbose: print extra info such as the frequency table
168 The default (False) is taken from .asaprc
169 """
170 info = sdtable._summary(self, verbose)
171 if verbose is None: verbose = rcParams['scantable.verbosesummary']
172 if filename is not None:
173 if filename is "":
174 filename = 'scantable_summary.txt'
175 from os.path import expandvars, isdir
176 filename = expandvars(filename)
177 if not isdir(filename):
178 data = open(filename, 'w')
179 data.write(info)
180 data.close()
181 else:
182 print "Illegal file name '%s'." % (filename)
183 print info
184
185 def set_cursor(self, thebeam=0,theif=0,thepol=0):
186 """
187 Set the spectrum for individual operations.
188 Parameters:
189 thebeam,theif,thepol: a number
190 Example:
191 scan.set_cursor(0,0,1)
192 pol1sig = scan.stats(all=False) # returns std dev for beam=0
193 # if=0, pol=1
194 """
195 varlist = vars()
196 self.setbeam(thebeam)
197 self.setpol(thepol)
198 self.setif(theif)
199 self._add_history("set_cursor",varlist)
200 return
201
202 def get_cursor(self):
203 """
204 Return/print a the current 'cursor' into the Beam/IF/Pol cube.
205 Parameters:
206 none
207 Returns:
208 a list of values (currentBeam,currentIF,currentPol)
209 Example:
210 none
211 """
212 i = self.getbeam()
213 j = self.getif()
214 k = self.getpol()
215 if self._vb:
216 print "--------------------------------------------------"
217 print " Cursor position"
218 print "--------------------------------------------------"
219 out = 'Beam=%d IF=%d Pol=%d ' % (i,j,k)
220 print out
221 return i,j,k
222
223 def stats(self, stat='stddev', mask=None, allaxes=None):
224 """
225 Determine the specified statistic of the current beam/if/pol
226 Takes a 'mask' as an optional parameter to specify which
227 channels should be excluded.
228 Parameters:
229 stat: 'min', 'max', 'sumsq', 'sum', 'mean'
230 'var', 'stddev', 'avdev', 'rms', 'median'
231 mask: an optional mask specifying where the statistic
232 should be determined.
233 allaxes: if True apply to all spectra. Otherwise
234 apply only to the selected (beam/pol/if)spectra only.
235 The default is taken from .asaprc (True if none)
236 Example:
237 scan.set_unit('channel')
238 msk = scan.create_mask([100,200],[500,600])
239 scan.stats(stat='mean', mask=m)
240 """
241 if allaxes is None: allaxes = rcParams['scantable.allaxes']
242 from asap._asap import stats as _stats
243 from numarray import array,zeros,Float
244 if mask == None:
245 mask = ones(self.nchan())
246 axes = ['Beam','IF','Pol','Time']
247
248 beamSel,IFSel,polSel = (self.getbeam(),self.getif(),self.getpol())
249 if allaxes:
250 n = self.nbeam()*self.nif()*self.npol()*self.nrow()
251 shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
252 arr = array(zeros(n),shape=shp,type=Float)
253
254 for i in range(self.nbeam()):
255 self.setbeam(i)
256 for j in range(self.nif()):
257 self.setif(j)
258 for k in range(self.npol()):
259 self.setpol(k)
260 arr[i,j,k,:] = _stats(self,mask,stat,-1)
261 retval = {'axes': axes, 'data': arr, 'cursor':None}
262 tm = [self._gettime(val) for val in range(self.nrow())]
263 if self._vb:
264 self._print_values(retval,stat,tm)
265 self.setbeam(beamSel)
266 self.setif(IFSel)
267 self.setpol(polSel)
268 return retval
269
270 else:
271 statval = _stats(self,mask,stat,-1)
272 out = ''
273 for l in range(self.nrow()):
274 tm = self._gettime(l)
275 out += 'Time[%s]:\n' % (tm)
276 if self.nbeam() > 1: out += ' Beam[%d] ' % (beamSel)
277 if self.nif() > 1: out += ' IF[%d] ' % (IFSel)
278 if self.npol() > 1: out += ' Pol[%d] ' % (polSel)
279 out += '= %3.3f\n' % (statval[l])
280 out += "--------------------------------------------------\n"
281
282 if self._vb:
283 print "--------------------------------------------------"
284 print " ",stat
285 print "--------------------------------------------------"
286 print out
287 retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
288 return retval
289
290 def stddev(self,mask=None, allaxes=None):
291 """
292 Determine the standard deviation of the current beam/if/pol
293 Takes a 'mask' as an optional parameter to specify which
294 channels should be excluded.
295 Parameters:
296 mask: an optional mask specifying where the standard
297 deviation should be determined.
298 allaxes: optional flag to show all or a cursor selected
299 spectrum of Beam/IF/Pol. Default is all or taken
300 from .asaprc
301
302 Example:
303 scan.set_unit('channel')
304 msk = scan.create_mask([100,200],[500,600])
305 scan.stddev(mask=m)
306 """
307 if allaxes is None: allaxes = rcParams['scantable.allaxes']
308 return self.stats(stat='stddev',mask=mask, allaxes=allaxes);
309
310 def get_tsys(self, allaxes=None):
311 """
312 Return the System temperatures.
313 Parameters:
314 allaxes: if True apply to all spectra. Otherwise
315 apply only to the selected (beam/pol/if)spectra only.
316 The default is taken from .asaprc (True if none)
317 Returns:
318 a list of Tsys values.
319 """
320 if allaxes is None: allaxes = rcParams['scantable.allaxes']
321 from numarray import array,zeros,Float
322 axes = ['Beam','IF','Pol','Time']
323
324 if allaxes:
325 n = self.nbeam()*self.nif()*self.npol()*self.nrow()
326 shp = [self.nbeam(),self.nif(),self.npol(),self.nrow()]
327 arr = array(zeros(n),shape=shp,type=Float)
328
329 for i in range(self.nbeam()):
330 self.setbeam(i)
331 for j in range(self.nif()):
332 self.setif(j)
333 for k in range(self.npol()):
334 self.setpol(k)
335 arr[i,j,k,:] = self._gettsys()
336 retval = {'axes': axes, 'data': arr, 'cursor':None}
337 tm = [self._gettime(val) for val in range(self.nrow())]
338 if self._vb:
339 self._print_values(retval,'Tsys',tm)
340 return retval
341
342 else:
343 i,j,k = (self.getbeam(),self.getif(),self.getpol())
344 statval = self._gettsys()
345 out = ''
346 for l in range(self.nrow()):
347 tm = self._gettime(l)
348 out += 'Time[%s]:\n' % (tm)
349 if self.nbeam() > 1: out += ' Beam[%d] ' % (i)
350 if self.nif() > 1: out += ' IF[%d] ' % (j)
351 if self.npol() > 1: out += ' Pol[%d] ' % (k)
352 out += '= %3.3f\n' % (statval[l])
353 out += "--------------------------------------------------\n"
354
355 if self._vb:
356 print "--------------------------------------------------"
357 print " TSys"
358 print "--------------------------------------------------"
359 print out
360 retval = {'axes': axes, 'data': array(statval), 'cursor':(i,j,k)}
361 return retval
362
363 def get_time(self, row=-1):
364 """
365 Get a list of time stamps for the observations.
366 Return a string for each integration in the scantable.
367 Parameters:
368 row: row no of integration. Default -1 return all rows
369 Example:
370 none
371 """
372 out = []
373 if row == -1:
374 for i in range(self.nrow()):
375 out.append(self._gettime(i))
376 return out
377 else:
378 if row < self.nrow():
379 return self._gettime(row)
380
381 def set_unit(self, unit='channel'):
382 """
383 Set the unit for all following operations on this scantable
384 Parameters:
385 unit: optional unit, default is 'channel'
386 one of '*Hz','km/s','channel', ''
387 """
388 varlist = vars()
389 if unit in ['','pixel', 'channel']:
390 unit = ''
391 inf = list(self._getcoordinfo())
392 inf[0] = unit
393 self._setcoordinfo(inf)
394 if self._p: self.plot()
395 self._add_history("set_unit",varlist)
396
397 def set_instrument(self, instr):
398 """
399 Set the instrument for subsequent processing
400 Parameters:
401 instr: Select from 'ATPKSMB', 'ATPKSHOH', 'ATMOPRA',
402 'DSS-43' (Tid), 'CEDUNA', and 'HOBART'
403 """
404 self._setInstrument(instr)
405 self._add_history("set_instument",vars())
406
407 def set_doppler(self, doppler='RADIO'):
408 """
409 Set the doppler for all following operations on this scantable.
410 Parameters:
411 doppler: One of 'RADIO', 'OPTICAL', 'Z', 'BETA', 'GAMMA'
412 """
413 varlist = vars()
414 inf = list(self._getcoordinfo())
415 inf[2] = doppler
416 self._setcoordinfo(inf)
417 if self._p: self.plot()
418 self._add_history("set_doppler",vars())
419
420 def set_freqframe(self, frame=None):
421 """
422 Set the frame type of the Spectral Axis.
423 Parameters:
424 frame: an optional frame type, default 'LSRK'.
425 Examples:
426 scan.set_freqframe('BARY')
427 """
428 if frame is None: frame = rcParams['scantable.freqframe']
429 varlist = vars()
430 valid = ['REST','TOPO','LSRD','LSRK','BARY', \
431 'GEO','GALACTO','LGROUP','CMB']
432 if frame in valid:
433 inf = list(self._getcoordinfo())
434 inf[1] = frame
435 self._setcoordinfo(inf)
436 self._add_history("set_freqframe",varlist)
437 else:
438 print "Please specify a valid freq type. Valid types are:\n",valid
439
440 def get_unit(self):
441 """
442 Get the default unit set in this scantable
443 Parameters:
444 Returns:
445 A unit string
446 """
447 inf = self._getcoordinfo()
448 unit = inf[0]
449 if unit == '': unit = 'channel'
450 return unit
451
452 def get_abcissa(self, rowno=0):
453 """
454 Get the abcissa in the current coordinate setup for the currently
455 selected Beam/IF/Pol
456 Parameters:
457 rowno: an optional row number in the scantable. Default is the
458 first row, i.e. rowno=0
459 Returns:
460 The abcissa values and it's format string (as a dictionary)
461 """
462 abc = self._getabcissa(rowno)
463 lbl = self._getabcissalabel(rowno)
464 return abc, lbl
465 #return {'abcissa':abc,'label':lbl}
466
467 def create_mask(self, *args, **kwargs):
468 """
469 Compute and return a mask based on [min,max] windows.
470 The specified windows are to be INCLUDED, when the mask is
471 applied.
472 Parameters:
473 [min,max],[min2,max2],...
474 Pairs of start/end points specifying the regions
475 to be masked
476 invert: optional argument. If specified as True,
477 return an inverted mask, i.e. the regions
478 specified are EXCLUDED
479 Example:
480 scan.set_unit('channel')
481
482 a)
483 msk = scan.set_mask([400,500],[800,900])
484 # masks everything outside 400 and 500
485 # and 800 and 900 in the unit 'channel'
486
487 b)
488 msk = scan.set_mask([400,500],[800,900], invert=True)
489 # masks the regions between 400 and 500
490 # and 800 and 900 in the unit 'channel'
491
492 """
493 varlist = vars()
494 u = self._getcoordinfo()[0]
495 if self._vb:
496 if u == "": u = "channel"
497 print "The current mask window unit is", u
498 n = self.nchan()
499 data = self._getabcissa()
500 msk = zeros(n)
501 for window in args:
502 if (len(window) != 2 or window[0] > window[1] ):
503 print "A window needs to be defined as [min,max]"
504 return
505 for i in range(n):
506 if data[i] >= window[0] and data[i] < window[1]:
507 msk[i] = 1
508 if kwargs.has_key('invert'):
509 if kwargs.get('invert'):
510 from numarray import logical_not
511 msk = logical_not(msk)
512 self._add_history("create_mask", varlist)
513 return msk
514
515 def get_restfreqs(self):
516 """
517 Get the restfrequency(s) stored in this scantable.
518 The return value(s) are always of unit 'Hz'
519 Parameters:
520 none
521 Returns:
522 a list of doubles
523 """
524 return list(self._getrestfreqs())
525
526 def lines(self):
527 """
528 Print the list of known spectral lines
529 """
530 sdtable._lines(self)
531
532 def set_restfreqs(self, freqs=None, unit='Hz', lines=None, source=None,
533 theif=None):
534 """
535 Select the restfrequency for the specified source and IF OR
536 replace for all IFs. If the 'freqs' argument holds a scalar,
537 then that rest frequency will be applied to the selected
538 data (and added to the list of available rest frequencies).
539 In this way, you can set a rest frequency for each
540 source and IF combination. If the 'freqs' argument holds
541 a vector, then it MUST be of length the number of IFs
542 (and the available restfrequencies will be replaced by
543 this vector). In this case, *all* data ('source' and
544 'theif' are ignored) have the restfrequency set per IF according
545 to the corresponding value you give in the 'freqs' vector.
546 E.g. 'freqs=[1e9,2e9]' would mean IF 0 gets restfreq 1e9 and
547 IF 1 gets restfreq 2e9.
548
549 You can also specify the frequencies via known line names
550 in the argument 'lines'. Use 'freqs' or 'lines'. 'freqs'
551 takes precedence. See the list of known names via function
552 scantable.lines()
553 Parameters:
554 freqs: list of rest frequencies
555 unit: unit for rest frequency (default 'Hz')
556 lines: list of known spectral lines names (alternative to freqs).
557 See possible list via scantable.lines()
558 source: Source name (blank means all)
559 theif: IF (-1 means all)
560 Example:
561 scan.set_restfreqs(freqs=1.4e9, source='NGC253', theif=2)
562 scan.set_restfreqs(freqs=[1.4e9,1.67e9])
563 """
564 varlist = vars()
565 if source is None:
566 source = ""
567 if theif is None:
568 theif = -1
569 t = type(freqs)
570 if t is int or t is float:
571 freqs = [freqs]
572 if freqs is None:
573 freqs = []
574 t = type(lines)
575 if t is str:
576 lines = [lines]
577 if lines is None:
578 lines = []
579 sdtable._setrestfreqs(self, freqs, unit, lines, source, theif)
580 self._add_history("set_restfreqs", varlist)
581
582
583
584 def flag_spectrum(self, thebeam, theif, thepol):
585 """
586 This flags a selected spectrum in the scan 'for good'.
587 USE WITH CARE - not reversible.
588 Use masks for non-permanent exclusion of channels.
589 Parameters:
590 thebeam,theif,thepol: all have to be explicitly
591 specified
592 Example:
593 scan.flag_spectrum(0,0,1)
594 flags the spectrum for Beam=0, IF=0, Pol=1
595 """
596 if (thebeam < self.nbeam() and
597 theif < self.nif() and
598 thepol < self.npol()):
599 sdtable.setbeam(self, thebeam)
600 sdtable.setif(self, theif)
601 sdtable.setpol(self, thepol)
602 sdtable._flag(self)
603 self._add_history("flag_spectrum", vars())
604 else:
605 print "Please specify a valid (Beam/IF/Pol)"
606 return
607
608 def plot(self, what='spectrum',col='Pol', panel=None):
609 """
610 Plot the spectra contained in the scan. Alternatively you can also
611 Plot Tsys vs Time
612 Parameters:
613 what: a choice of 'spectrum' (default) or 'tsys'
614 col: which out of Beams/IFs/Pols should be colour stacked
615 panel: set up multiple panels, currently not working.
616 """
617 print "Warning! Not fully functional. Use plotter.plot() instead"
618
619 validcol = {'Beam':self.nbeam(),'IF':self.nif(),'Pol':self.npol()}
620
621 validyax = ['spectrum','tsys']
622 from asap.asaplot import ASAPlot
623 if not self._p:
624 self._p = ASAPlot()
625 #print "Plotting not enabled"
626 #return
627 if self._p.is_dead:
628 del self._p
629 self._p = ASAPlot()
630 npan = 1
631 x = None
632 if what == 'tsys':
633 n = self.nrow()
634 if n < 2:
635 print "Only one integration. Can't plot."
636 return
637 self._p.hold()
638 self._p.clear()
639 if panel == 'Time':
640 npan = self.nrow()
641 self._p.set_panels(rows=npan)
642 xlab,ylab,tlab = None,None,None
643 self._vb = False
644 sel = self.get_cursor()
645 for i in range(npan):
646 if npan > 1:
647 self._p.subplot(i)
648 for j in range(validcol[col]):
649 x = None
650 y = None
651 m = None
652 tlab = self._getsourcename(i)
653 import re
654 tlab = re.sub('_S','',tlab)
655 if col == 'Beam':
656 self.setbeam(j)
657 elif col == 'IF':
658 self.setif(j)
659 elif col == 'Pol':
660 self.setpol(j)
661 if what == 'tsys':
662 x = range(self.nrow())
663 xlab = 'Time [pixel]'
664 m = list(ones(len(x)))
665 y = []
666 ylab = r'$T_{sys}$'
667 for k in range(len(x)):
668 y.append(self._gettsys(k))
669 else:
670 x,xlab = self.get_abcissa(i)
671 y = self._getspectrum(i)
672 ylab = r'Flux'
673 m = self._getmask(i)
674 llab = col+' '+str(j)
675 self._p.set_line(label=llab)
676 self._p.plot(x,y,m)
677 self._p.set_axes('xlabel',xlab)
678 self._p.set_axes('ylabel',ylab)
679 self._p.set_axes('title',tlab)
680 self._p.release()
681 self.set_cursor(sel[0],sel[1],sel[2])
682 self._vb = rcParams['verbose']
683 return
684
685 print out
686
687 def _print_values(self, dat, label='', timestamps=[]):
688 d = dat['data']
689 a = dat['axes']
690 shp = d.getshape()
691 out = ''
692 for i in range(shp[3]):
693 out += '%s [%s]:\n' % (a[3],timestamps[i])
694 t = d[:,:,:,i]
695 for j in range(shp[0]):
696 if shp[0] > 1: out += ' %s[%d] ' % (a[0],j)
697 for k in range(shp[1]):
698 if shp[1] > 1: out += ' %s[%d] ' % (a[1],k)
699 for l in range(shp[2]):
700 if shp[2] > 1: out += ' %s[%d] ' % (a[2],l)
701 out += '= %3.3f\n' % (t[j,k,l])
702 out += "-"*80
703 out += "\n"
704 print "-"*80
705 print " ", label
706 print "-"*80
707 print out
708
709 def history(self):
710 hist = list(self._gethistory())
711 print "-"*80
712 for h in hist:
713 items = h.split("##")
714 date = items[0]
715 func = items[1]
716 items = items[2:]
717 print date
718 print "Function: %s\n Parameters:" % (func)
719 for i in items:
720 s = i.split("=")
721 print " %s: %s" % (s[0],s[1])
722 print "-"*80
723 return
724
725 def _add_history(self, funcname, parameters):
726 # create date
727 sep = "##"
728 from datetime import datetime
729 dstr = datetime.now().strftime('%Y/%m/%d %H:%M:%S')
730 hist = dstr+sep
731 hist += funcname+sep#cdate+sep
732 if parameters.has_key('self'): del parameters['self']
733 for k,v in parameters.iteritems():
734 if type(v) is dict:
735 for k2,v2 in v.iteritems():
736 hist += k2
737 hist += "="
738 if isinstance(v2,scantable):
739 hist += 'scantable'
740 elif k2 == 'mask':
741 hist += str(self._zip_mask(v2))
742 else:
743 hist += str(v2)
744 else:
745 hist += k
746 hist += "="
747 if isinstance(v,scantable):
748 hist += 'scantable'
749 elif k == 'mask':
750 hist += str(self._zip_mask(v))
751 else:
752 hist += str(v)
753 hist += sep
754 hist = hist[:-2] # remove trailing '##'
755 self._addhistory(hist)
756
757
758 def _zip_mask(self, mask):
759 mask = list(mask)
760 i = 0
761 segments = []
762 while mask[i:].count(1):
763 i += mask[i:].index(1)
764 if mask[i:].count(0):
765 j = i + mask[i:].index(0)
766 else:
767 j = len(mask)
768 segments.append([i,j])
769 i = j
770 return segments
Note: See TracBrowser for help on using the repository browser.