From 9006c1dab34b424104d9a2aba47891a5e7457e8d Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Fri, 20 Jul 2012 17:38:06 -0500 Subject: [PATCH 1/3] Sort files from a global pattern alphanumerically Users usually expect an alphanumeric sort, not lexicographic sort, on their filenames. This is now the behaviour of ImageCollection. --- skimage/io/collection.py | 35 +++++++++++++++++++++++++++-- skimage/io/tests/test_collection.py | 16 +++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/skimage/io/collection.py b/skimage/io/collection.py index e698b52b..c754c8ad 100644 --- a/skimage/io/collection.py +++ b/skimage/io/collection.py @@ -5,11 +5,42 @@ from __future__ import with_statement __all__ = ['MultiImage', 'ImageCollection', 'imread'] from glob import glob +import re import numpy as np from ._io import imread +def _tryint(s): + try: + return int(s) + except ValueError: + return s + +def alphanumeric_key(s): + """Convert string to list of strings and ints that gives intuitive sorting. + + Parameters + ---------- + s: string + + Returns + ------- + k: a list of strings and ints + + Examples + -------- + >>> alphanumeric_key('z23a') + ['z', 23, 'a'] + >>> filenames = ['f9.10.png', 'f9.9.png', 'f10.10.png', 'f10.9.png'] + >>> sorted(filenames) + ['f10.10.png', 'f10.9.png', 'f9.10.png', 'f9.9.png'] + >>> sorted(filenames, key=alphanumeric_key) + ['f9.9.png', 'f9.10.png', 'f10.9.png', 'f10.10.png'] + """ + k = [_tryint(c) for c in re.split('([0-9]+)', s)] + return k + class MultiImage(object): """A class containing a single multi-frame image. @@ -213,7 +244,7 @@ class ImageCollection(object): (128, 128, 3) >>> ic = io.ImageCollection('/tmp/work/*.png:/tmp/other/*.jpg') - + """ def __init__(self, load_pattern, conserve_memory=True, load_func=None): """Load and manage a collection of images.""" @@ -222,7 +253,7 @@ class ImageCollection(object): self._files = [] for pattern in load_pattern: self._files.extend(glob(pattern)) - self._files.sort() + self._files = sorted(self._files, key=alphanumeric_key) else: self._files = load_pattern diff --git a/skimage/io/tests/test_collection.py b/skimage/io/tests/test_collection.py index 0d420ae7..969d3e56 100644 --- a/skimage/io/tests/test_collection.py +++ b/skimage/io/tests/test_collection.py @@ -7,6 +7,7 @@ from numpy.testing.decorators import skipif from skimage import data_dir from skimage.io import ImageCollection, MultiImage +from skimage.io.collection import alphanumeric_key try: @@ -19,6 +20,21 @@ else: if sys.version_info[0] > 2: basestring = str +class TestAlphanumericKey(): + def setUp(self): + self.test_string = 'z23a' + self.test_str_result = ['z', 23, 'a'] + self.filenames = ['f9.10.png', 'f9.9.png', 'f10.10.png', 'f10.9.png'] + self.sorted_filenames = \ + ['f9.9.png', 'f9.10.png', 'f10.9.png', 'f10.10.png'] + + def test_string_split(self): + assert_equal(alphanumeric_key(self.test_string), self.test_str_result) + + def test_string_sort(self): + sorted_filenames = sorted(self.filenames, key=alphanumeric_key) + assert_equal(sorted_filenames, self.sorted_filenames) + class TestImageCollection(): pattern = [os.path.join(data_dir, pic) for pic in ['camera.png', From 699b5d92697d3c6bb0ef17882d0c9714fb6d7dee Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Fri, 20 Jul 2012 17:50:04 -0500 Subject: [PATCH 2/3] Add test coverage for alphabetic sort alphanumeric_key should sort filenames correctly when they differ in text, not just numbers. --- skimage/io/tests/test_collection.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/skimage/io/tests/test_collection.py b/skimage/io/tests/test_collection.py index 969d3e56..c8ba154a 100644 --- a/skimage/io/tests/test_collection.py +++ b/skimage/io/tests/test_collection.py @@ -24,9 +24,11 @@ class TestAlphanumericKey(): def setUp(self): self.test_string = 'z23a' self.test_str_result = ['z', 23, 'a'] - self.filenames = ['f9.10.png', 'f9.9.png', 'f10.10.png', 'f10.9.png'] + self.filenames = ['f9.10.png', 'f9.9.png', 'f10.10.png', 'f10.9.png', + 'e9.png', 'e10.png', 'em.png'] self.sorted_filenames = \ - ['f9.9.png', 'f9.10.png', 'f10.9.png', 'f10.10.png'] + ['e9.png', 'e10.png', 'em.png', 'f9.9.png', 'f9.10.png', + 'f10.9.png', 'f10.10.png'] def test_string_split(self): assert_equal(alphanumeric_key(self.test_string), self.test_str_result) From 9cbf2ef3694522547cb8c5e0cb1b2393b54c6691 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Sat, 21 Jul 2012 00:51:55 -0500 Subject: [PATCH 3/3] Simplify alphanumeric_key logic Thanks to Tony Yu for the suggestion. --- skimage/io/collection.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/skimage/io/collection.py b/skimage/io/collection.py index c754c8ad..35e4e877 100644 --- a/skimage/io/collection.py +++ b/skimage/io/collection.py @@ -11,12 +11,6 @@ import numpy as np from ._io import imread -def _tryint(s): - try: - return int(s) - except ValueError: - return s - def alphanumeric_key(s): """Convert string to list of strings and ints that gives intuitive sorting. @@ -34,11 +28,11 @@ def alphanumeric_key(s): ['z', 23, 'a'] >>> filenames = ['f9.10.png', 'f9.9.png', 'f10.10.png', 'f10.9.png'] >>> sorted(filenames) - ['f10.10.png', 'f10.9.png', 'f9.10.png', 'f9.9.png'] + ['f10.10.png', 'f10.9.png', 'f9.10.png', 'f9.9.png', 'e10.png'] >>> sorted(filenames, key=alphanumeric_key) - ['f9.9.png', 'f9.10.png', 'f10.9.png', 'f10.10.png'] + ['e10.png', 'f9.9.png', 'f9.10.png', 'f10.9.png', 'f10.10.png'] """ - k = [_tryint(c) for c in re.split('([0-9]+)', s)] + k = [int(c) if c.isdigit() else c for c in re.split('([0-9]+)', s)] return k class MultiImage(object):