10000 Merge pull request #4174 from jaimefrio/contiguous_regions · matplotlib/matplotlib@f4f872b · GitHub
[go: up one dir, main page]

Skip to content

Commit f4f872b

Browse files
committed
Merge pull request #4174 from jaimefrio/contiguous_regions
ENH: speed-up mlab.contiguous_regions using numpy
2 parents 13a8f31 + 8197e2b commit f4f872b

File tree

2 files changed

+41
-14
lines changed

2 files changed

+41
-14
lines changed

lib/matplotlib/mlab.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3874,23 +3874,26 @@ def contiguous_regions(mask):
38743874
"""
38753875
return a list of (ind0, ind1) such that mask[ind0:ind1].all() is
38763876
True and we cover all such regions
3877-
3878-
TODO: this is a pure python implementation which probably has a much
3879-
faster numpy impl
38803877
"""
3878+
mask = np.asarray(mask, dtype=bool)
3879+
3880+
if not mask.size:
3881+
return []
3882+
3883+
# Find the indices of region changes, and correct offset
3884+
idx, = np.nonzero(mask[:-1] != mask[1:])
3885+
idx += 1
3886+
3887+
# List operations are faster for moderately sized arrays
3888+
idx = idx.tolist()
38813889

3882-
in_region = None
3883-
boundaries = []
3884-
for i, val in enumerate(mask):
3885-
if in_region is None and val:
3886-
in_region = i
3887-
elif in_region is not None and not val:
3888-
boundaries.append((in_region, i))
3889-
in_region = None
3890+
# Add first and/or last index if needed
3891+
if mask[0]:
3892+
idx = [0] + idx
3893+
if mask[-1]:
3894+
idx.append(len(mask))
38903895

3891-
if in_region is not None:
3892-
boundaries.append((in_region, i+1))
3893-
return boundaries
3896+
return list(zip(idx[::2], idx[1::2]))
38943897

38953898

38963899
def cross_from_below(x, threshold):

lib/matplotlib/tests/test_mlab.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2963,6 +2963,30 @@ def test_evaluate_equal_dim_and_num_lt(self):
29632963

29642964

29652965
#*****************************************************************
2966+
2967+
def test_contiguous_regions():
2968+
a, b, c = 3, 4, 5
2969+
# Starts and ends with True
2970+
mask = [True]*a + [False]*b + [True]*c
2971+
expected = [(0, a), (a+b, a+b+c)]
2972+
assert_equal(mlab.contiguous_regions(mask), expected)
2973+
d, e = 6, 7
2974+
# Starts with True ends with False
2975+
mask = mask + [False]*e
2976+
assert_equal(mlab.contiguous_regions(mask), expected)
2977+
# Starts with False ends with True
2978+
mask = [False]*d + mask[:-e]
2979+
expected = [(d, d+a), (d+a+b, d+a+b+c)]
2980+
assert_equal(mlab.contiguous_regions(mask), expected)
2981+
# Starts and ends with False
2982+
mask = mask + [False]*e
2983+
assert_equal(mlab.contiguous_regions(mask), expected)
2984+
# No True in mask
2985+
assert_equal(mlab.contiguous_regions([False]*5), [])
2986+
# Empty mask
2987+
assert_equal(mlab.contiguous_regions([]), [])
2988+
2989+
29662990
#*****************************************************************
29672991

29682992
if __name__ == '__main__':

0 commit comments

Comments
 (0)
0