#!/cvmfs/neugrid.egi.eu/software/x86_64/c-pack-d788610/linuxbrew/Cellar/python/2.7.11/bin/python # emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- # vi: set ft=python sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the NiBabel package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """ Output a summary table for neuroimaging files (resolution, dimensionality, etc.) """ from __future__ import division, print_function, absolute_import __author__ = 'Yaroslav Halchenko' __copyright__ = 'Copyright (c) 2011-2012 Yaroslav Halchenko ' \ 'and NiBabel contributors' __license__ = 'MIT' import re import sys from math import ceil from optparse import OptionParser, Option from io import StringIO import numpy as np import nibabel as nib from nibabel.py3k import asunicode # global verbosity switch verbose_level = 0 def verbose(l, msg): """Print `s` if `l` is less than the `verbose_level` """ # TODO: consider using nibabel's logger if l <= int(verbose_level): print("%s%s" % (' ' * l, msg)) def error(msg, exit_code): print >> sys.stderr, msg sys.exit(exit_code) def table2string(table, out=None): """Given list of lists figure out their common widths and print to out Parameters ---------- table : list of lists of strings What is aimed to be printed out : None or stream Where to print. If None -- will print and return string Returns ------- string if out was None """ print2string = out is None if print2string: out = StringIO() # equalize number of elements in each row Nelements_max = len(table) \ and max(len(x) for x in table) for i, table_ in enumerate(table): table[i] += [''] * (Nelements_max - len(table_)) # figure out lengths within each column atable = np.asarray(table) # eat whole entry while computing width for @w (for wide) markup_strip = re.compile('^@([lrc]|w.*)') col_width = [ max( [len(markup_strip.sub('', x)) for x in column] ) for column in atable.T ] string = "" for i, table_ in enumerate(table): string_ = "" for j, item in enumerate(table_): item = str(item) if item.startswith('@'): align = item[1] item = item[2:] if not align in ['l', 'r', 'c', 'w']: raise ValueError('Unknown alignment %s. Known are l,r,c' % align) else: align = 'c' NspacesL = max(ceil((col_width[j] - len(item))/2.0), 0) NspacesR = max(col_width[j] - NspacesL - len(item), 0) if align in ['w', 'c']: pass elif align == 'l': NspacesL, NspacesR = 0, NspacesL + NspacesR elif align == 'r': NspacesL, NspacesR = NspacesL + NspacesR, 0 else: raise RuntimeError('Should not get here with align=%s' % align) string_ += "%%%ds%%s%%%ds " \ % (NspacesL, NspacesR) % ('', item, '') string += string_.rstrip() + '\n' out.write(asunicode(string)) if print2string: value = out.getvalue() out.close() return value def ap(l, format, sep=', '): """Little helper to enforce consistency""" if l == '-': return l ls = [format % x for x in l] return sep.join(ls) def safe_get(obj, name): """ """ try: f = getattr(obj, 'get_' + name) return f() except Exception as e: verbose(2, "get_%s() failed -- %s" % (name, e)) return '-' def get_opt_parser(): # use module docstring for help output p = OptionParser( usage="%s [OPTIONS] [FILE ...]\n\n" % sys.argv[0] + __doc__, version="%prog " + nib.__version__) p.add_options([ Option("-v", "--verbose", action="count", dest="verbose", default=0, help="Make more noise. Could be specified multiple times"), Option("-s", "--stats", action="store_true", dest='stats', default=False, help="Output basic data statistics"), Option("-z", "--zeros", action="store_true", dest='stats_zeros', default=False, help="Include zeros into output basic data statistics (--stats)"), ]) return p def proc_file(f, opts): verbose(1, "Loading %s" % f) row = ["@l%s" % f] try: vol = nib.load(f) h = vol.header except Exception as e: row += ['failed'] verbose(2, "Failed to gather information -- %s" % str(e)) return row row += [ str(safe_get(h, 'data_dtype')), '@l[%s]' %ap(safe_get(h, 'data_shape'), '%3g'), '@l%s' % ap(safe_get(h, 'zooms'), '%.2f', 'x') ] # Slope if (hasattr(h, 'has_data_slope') and (h.has_data_slope or h.has_data_intercept)) \ and not h.get_slope_inter() in [(1.0, 0.0), (None, None)]: row += ['@l*%.3g+%.3g' % h.get_slope_inter()] else: row += [ '' ] if (hasattr(h, 'extensions') and len(h.extensions)): row += ['@l#exts: %d' % len(h.extensions)] else: row += [ '' ] try: if (hasattr(h, 'get_qform') and hasattr(h, 'get_sform') and (h.get_qform() != h.get_sform()).any()): row += ['sform'] else: row += [''] except Exception as e: verbose(2, "Failed to obtain qform or sform -- %s" % str(e)) if isinstance(h, nib.AnalyzeHeader): row += [''] else: row += ['error'] if opts.stats: # We are doomed to load data try: d = vol.get_data() if not opts.stats_zeros: d = d[np.nonzero(d)] # just # of elements row += ["[%d] " % np.prod(d.shape)] # stats row += [len(d) and '%.2g:%.2g' % (np.min(d), np.max(d)) or '-'] except Exception as e: verbose(2, "Failed to obtain stats -- %s" % str(e)) row += ['error'] return row def main(): """Show must go on""" parser = get_opt_parser() (opts, files) = parser.parse_args() global verbose_level verbose_level = opts.verbose if verbose_level < 3: # suppress nibabel format-compliance warnings nib.imageglobals.logger.level = 50 rows = [proc_file(f, opts) for f in files] print(table2string(rows)) if __name__ == '__main__': main()