source: trunk/python/scantable.py@ 490

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