summaryrefslogtreecommitdiff
path: root/silx/math/test/test_colormap.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/math/test/test_colormap.py')
-rw-r--r--silx/math/test/test_colormap.py266
1 files changed, 0 insertions, 266 deletions
diff --git a/silx/math/test/test_colormap.py b/silx/math/test/test_colormap.py
deleted file mode 100644
index 4e80710..0000000
--- a/silx/math/test/test_colormap.py
+++ /dev/null
@@ -1,266 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-"""Test for colormap mapping implementation"""
-
-from __future__ import division
-
-__authors__ = ["T. Vincent"]
-__license__ = "MIT"
-__date__ = "16/05/2018"
-
-
-import logging
-import sys
-import unittest
-
-import numpy
-
-from silx.utils.testutils import ParametricTestCase
-from silx.math import colormap
-
-
-_logger = logging.getLogger(__name__)
-
-
-class TestNormalization(ParametricTestCase):
- """Test silx.math.colormap.Normalization sub classes"""
-
- def _testCodec(self, normalization, rtol=1e-5):
- """Test apply/revert for normalizations"""
- test_data = (numpy.arange(1, 10, dtype=numpy.int32),
- numpy.linspace(1., 100., 1000, dtype=numpy.float32),
- numpy.linspace(-1., 1., 100, dtype=numpy.float32),
- 1.,
- 1)
-
- for index in range(len(test_data)):
- with self.subTest(normalization=normalization, data_index=index):
- data = test_data[index]
- normalized = normalization.apply(data, 1., 100.)
- result = normalization.revert(normalized, 1., 100.)
-
- self.assertTrue(numpy.array_equal(
- numpy.isnan(normalized), numpy.isnan(result)))
-
- if isinstance(data, numpy.ndarray):
- notNaN = numpy.logical_not(numpy.isnan(result))
- data = data[notNaN]
- result = result[notNaN]
- self.assertTrue(numpy.allclose(data, result, rtol=rtol))
-
- def testLinearNormalization(self):
- """Test for LinearNormalization"""
- normalization = colormap.LinearNormalization()
- self._testCodec(normalization)
-
- def testLogarithmicNormalization(self):
- """Test for LogarithmicNormalization"""
- normalization = colormap.LogarithmicNormalization()
- # relative tolerance is higher because of the log approximation
- self._testCodec(normalization, rtol=1e-3)
-
- # Specific extra tests
- self.assertTrue(numpy.isnan(normalization.apply(-1., 1., 100.)))
- self.assertTrue(numpy.isnan(normalization.apply(numpy.nan, 1., 100.)))
- self.assertEqual(normalization.apply(numpy.inf, 1., 100.), numpy.inf)
- self.assertEqual(normalization.apply(0, 1., 100.), - numpy.inf)
-
- def testArcsinhNormalization(self):
- """Test for ArcsinhNormalization"""
- self._testCodec(colormap.ArcsinhNormalization())
-
- def testSqrtNormalization(self):
- """Test for SqrtNormalization"""
- normalization = colormap.SqrtNormalization()
- self._testCodec(normalization)
-
- # Specific extra tests
- self.assertTrue(numpy.isnan(normalization.apply(-1., 0., 100.)))
- self.assertTrue(numpy.isnan(normalization.apply(numpy.nan, 0., 100.)))
- self.assertEqual(normalization.apply(numpy.inf, 0., 100.), numpy.inf)
- self.assertEqual(normalization.apply(0, 0., 100.), 0.)
-
-
-class TestColormap(ParametricTestCase):
- """Test silx.math.colormap.cmap"""
-
- NORMALIZATIONS = (
- 'linear',
- 'log',
- 'arcsinh',
- 'sqrt',
- colormap.LinearNormalization(),
- colormap.LogarithmicNormalization(),
- colormap.PowerNormalization(2.),
- colormap.PowerNormalization(0.5))
-
- @staticmethod
- def ref_colormap(data, colors, vmin, vmax, normalization, nan_color):
- """Reference implementation of colormap
-
- :param numpy.ndarray data: Data to convert
- :param numpy.ndarray colors: Color look-up-table
- :param float vmin: Lower bound of the colormap range
- :param float vmax: Upper bound of the colormap range
- :param str normalization: Normalization to use
- :param Union[numpy.ndarray, None] nan_color: Color to use for NaN
- """
- norm_functions = {'linear': lambda v: v,
- 'log': numpy.log10,
- 'arcsinh': numpy.arcsinh,
- 'sqrt': numpy.sqrt}
-
- if isinstance(normalization, str):
- norm_function = norm_functions[normalization]
- else:
- def norm_function(value):
- return normalization.apply(value, vmin, vmax)
-
- with numpy.errstate(divide='ignore', invalid='ignore'):
- # Ignore divide by zero and invalid value encountered in log10, sqrt
- norm_data, vmin, vmax = map(norm_function, (data, vmin, vmax))
-
- if normalization == 'arcsinh' and sys.platform == 'win32':
- # There is a difference of behavior of numpy.arcsinh
- # between Windows and other OS for results of infinite values
- # This makes Windows behaves as Linux and MacOS
- norm_data[data == numpy.inf] = numpy.inf
- norm_data[data == -numpy.inf] = -numpy.inf
-
- nb_colors = len(colors)
- scale = nb_colors / (vmax - vmin)
-
- # Substraction must be done in float to avoid overflow with uint
- indices = numpy.clip(scale * (norm_data - float(vmin)),
- 0, nb_colors - 1)
- indices[numpy.isnan(indices)] = nb_colors # Use an extra index for NaN
- indices = indices.astype('uint')
-
- # Add NaN color to array
- if nan_color is None:
- nan_color = (0,) * colors.shape[-1]
- colors = numpy.append(colors, numpy.atleast_2d(nan_color), axis=0)
-
- return colors[indices]
-
- def _test(self, data, colors, vmin, vmax, normalization, nan_color):
- """Run test of colormap against alternative implementation
-
- :param numpy.ndarray data: Data to convert
- :param numpy.ndarray colors: Color look-up-table
- :param float vmin: Lower bound of the colormap range
- :param float vmax: Upper bound of the colormap range
- :param str normalization: Normalization to use
- :param Union[numpy.ndarray, None] nan_color: Color to use for NaN
- """
- image = colormap.cmap(
- data, colors, vmin, vmax, normalization, nan_color)
-
- ref_image = self.ref_colormap(
- data, colors, vmin, vmax, normalization, nan_color)
-
- self.assertTrue(numpy.allclose(ref_image, image))
- self.assertEqual(image.dtype, colors.dtype)
- self.assertEqual(image.shape, data.shape + (colors.shape[-1],))
-
- def test(self):
- """Test all dtypes with finite data
-
- Test all supported types and endianness
- """
- colors = numpy.zeros((256, 4), dtype=numpy.uint8)
- colors[:, 0] = numpy.arange(len(colors))
- colors[:, 3] = 255
-
- # Generates (u)int and floats types
- dtypes = [e + k + i for e in '<>' for k in 'uif' for i in '1248'
- if k != 'f' or i != '1']
- dtypes.append(numpy.dtype(numpy.longdouble).name) # Add long double
-
- for normalization in self.NORMALIZATIONS:
- for dtype in dtypes:
- with self.subTest(dtype=dtype, normalization=normalization):
- _logger.info('normalization: %s, dtype: %s',
- normalization, dtype)
- data = numpy.arange(-5, 15, dtype=dtype).reshape(4, 5)
-
- self._test(data, colors, 1, 10, normalization, None)
-
- def test_not_finite(self):
- """Test float data with not finite values"""
- colors = numpy.zeros((256, 4), dtype=numpy.uint8)
- colors[:, 0] = numpy.arange(len(colors))
- colors[:, 3] = 255
-
- test_data = { # message: data
- 'no finite values': (float('inf'), float('-inf'), float('nan')),
- 'only NaN': (float('nan'), float('nan'), float('nan')),
- 'mix finite/not finite': (float('inf'), float('-inf'), 1., float('nan')),
- }
-
- for normalization in self.NORMALIZATIONS:
- for msg, data in test_data.items():
- with self.subTest(msg, normalization=normalization):
- _logger.info('normalization: %s, %s', normalization, msg)
- data = numpy.array(data, dtype=numpy.float64)
- self._test(data, colors, 1, 10, normalization, (0, 0, 0, 0))
-
- def test_errors(self):
- """Test raising exception for bad vmin, vmax, normalization parameters
- """
- colors = numpy.zeros((256, 4), dtype=numpy.uint8)
- colors[:, 0] = numpy.arange(len(colors))
- colors[:, 3] = 255
-
- data = numpy.arange(10, dtype=numpy.float64)
-
- test_params = [ # (vmin, vmax, normalization)
- (-1., 2., 'log'),
- (0., 1., 'log'),
- (1., 0., 'log'),
- (-1., 1., 'sqrt'),
- (1., -1., 'sqrt'),
- ]
-
- for vmin, vmax, normalization in test_params:
- with self.subTest(
- vmin=vmin, vmax=vmax, normalization=normalization):
- _logger.info('normalization: %s, range: [%f, %f]',
- normalization, vmin, vmax)
- with self.assertRaises(ValueError):
- self._test(data, colors, vmin, vmax, normalization, None)
-
-
-def suite():
- test_suite = unittest.TestSuite()
- test_suite.addTest(
- unittest.defaultTestLoader.loadTestsFromTestCase(TestColormap))
- test_suite.addTest(
- unittest.defaultTestLoader.loadTestsFromTestCase(TestNormalization))
- return test_suite
-
-
-if __name__ == '__main__':
- unittest.main(defaultTest='suite')