Skip to content

Commit 5d1b19a

Browse files
committed
ENH: limit number of unique counts to be processed by 1000 and add --all-counts to override
1 parent ebc54da commit 5d1b19a

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

bin/nib-ls

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ import numpy as np
1919
import nibabel as nib
2020

2121
from math import ceil
22+
from collections import defaultdict
2223
from optparse import OptionParser, Option
2324
from io import StringIO
2425
from nibabel.py3k import asunicode
26+
from nibabel.externals.six.moves import xrange
2527

2628
__author__ = 'Yaroslav Halchenko'
2729
__copyright__ = 'Copyright (c) 2011-2016 Yaroslav Halchenko ' \
@@ -31,7 +33,13 @@ __license__ = 'MIT'
3133

3234
# global verbosity switch
3335
verbose_level = 0
36+
MAX_UNIQUE = 1000 # maximal number of unique values to report for --counts
3437

38+
def _err(msg=None):
39+
"""To return a string to signal "error" in output table"""
40+
if msg is None:
41+
msg = 'error'
42+
return '!' + msg
3543

3644
def verbose(l, msg):
3745
"""Print `s` if `l` is less than the `verbose_level`
@@ -159,6 +167,10 @@ def get_opt_parser():
159167
help="Output counts - number of entries for each numeric value "
160168
"(useful for int ROI maps)"),
161169

170+
Option("--all-counts",
171+
action="store_true", dest='all_counts', default=False,
172+
help="Output all counts, even if number of unique values > %d" % MAX_UNIQUE),
173+
162174
Option("-z", "--zeros",
163175
action="store_true", dest='stats_zeros', default=False,
164176
help="Include zeros into output basic data statistics (--stats, --counts)"),
@@ -210,7 +222,7 @@ def proc_file(f, opts):
210222
try:
211223
row += [str(h[f])]
212224
except (KeyError, ValueError):
213-
row += ['error']
225+
row += [_err()]
214226

215227
try:
216228
if (hasattr(h, 'get_qform') and hasattr(h, 'get_sform') and
@@ -223,26 +235,34 @@ def proc_file(f, opts):
223235
if isinstance(h, nib.AnalyzeHeader):
224236
row += ['']
225237
else:
226-
row += ['error']
238+
row += [_err()]
227239

228240
if opts.stats or opts.counts:
229241
# We are doomed to load data
230242
try:
231243
d = vol.get_data()
232244
if not opts.stats_zeros:
233245
d = d[np.nonzero(d)]
246+
else:
247+
# at least flatten it -- functionality below doesn't
248+
# depend on the original shape, so let's use a flat view
249+
d = d.reshape(-1)
234250
if opts.stats:
235251
# just # of elements
236252
row += ["@l[%d]" % np.prod(d.shape)]
237253
# stats
238254
row += [len(d) and '@l[%.2g, %.2g]' % (np.min(d), np.max(d)) or '-']
239255
if opts.counts:
240256
items, inv = np.unique(d, return_inverse=True)
241-
freq = np.bincount(inv)
242-
row += ["@l" + " ".join("%g:%d" % (i, f) for i, f in zip(items, freq))]
257+
if len(items) > 1000 and not opts.all_counts:
258+
counts = _err("%d uniques. Use --all-counts" % len(items))
259+
else:
260+
freq = np.bincount(inv)
261+
counts = " ".join("%g:%d" % (i, f) for i, f in zip(items, freq))
262+
row += ["@l" + counts]
243263
except IOError as e:
244264
verbose(2, "Failed to obtain stats/counts -- %s" % str(e))
245-
row += ['error']
265+
row += [_err()]
246266
return row
247267

248268

nibabel/tests/test_scripts.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,14 @@ def test_nib_ls():
6969
yield check_nib_ls_example4d
7070
yield check_nib_ls_example4d, \
7171
['-H', 'dim,bitpix'], " \[ 4 128 96 24 2 1 1 1\] 16"
72-
yield check_nib_ls_example4d, ['-c'], "", " 2:3 3:2 4:1 5:1.*"
72+
yield check_nib_ls_example4d, ['-c'], "", " !1030 uniques. Use --all-counts"
73+
yield check_nib_ls_example4d, ['-c', '--all-counts'], "", " 2:3 3:2 4:1 5:1.*"
7374
# both stats and counts
7475
yield check_nib_ls_example4d, \
75-
['-c', '-s'], "", " \[229725\] \[2, 1.2e\+03\] 2:3 3:2 4:1 5:1.*"
76+
['-c', '-s', '--all-counts'], "", " \[229725\] \[2, 1.2e\+03\] 2:3 3:2 4:1 5:1.*"
7677
# and must not error out if we allow for zeros
7778
yield check_nib_ls_example4d, \
78-
['-c', '-s', '-z'], "", " \[589824\] \[0, 1.2e\+03\] 0:360099 2:3 3:2 4:1 5:1.*"
79+
['-c', '-s', '-z', '--all-counts'], "", " \[589824\] \[0, 1.2e\+03\] 0:360099 2:3 3:2 4:1 5:1.*"
7980

8081

8182
@script_test
@@ -120,7 +121,7 @@ def test_nib_ls_multiple():
120121
'[128, 96, 24, 2] 2.00x2.00x2.20x2000.00 #exts: 2 sform [229725] [2, 1.2e+03]',
121122
'[ 32, 20, 12, 2] 2.00x2.00x2.20x2000.00 #exts: 2 sform [15360] [46, 7.6e+02]',
122123
'[ 18, 28, 29] 9.00x8.00x7.00 [14616] [0.12, 93]',
123-
'[ 91, 109, 91] 2.00x2.00x2.00 error'
124+
'[ 91, 109, 91] 2.00x2.00x2.00 !error'
124125
]
125126
)
126127

0 commit comments

Comments
 (0)