diff --git a/docs/source/api.rst b/docs/source/api.rst index b9b0016f..5a51903c 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -10,7 +10,9 @@ Parallel Utilities Plot Utilities ============== -.. automodule:: skued.plot_utils +.. autofunction:: skued.plot_utils.spectrum_colors + +.. autofunction:: skued.plot_utils.rgb_sweep Array Utilities =============== diff --git a/skued/plot_utils.py b/skued/plot_utils.py index 5e64eda2..8289aad6 100644 --- a/skued/plot_utils.py +++ b/skued/plot_utils.py @@ -6,7 +6,7 @@ from collections import Iterable from colorsys import hsv_to_rgb -def linspace(start, stop, num): +def _linspace(start, stop, num): """ Generate linear space @@ -23,12 +23,29 @@ def linspace(start, stop, num): ------ val : float """ - step = (stop - start)/num + # Since we always include the endpoint, + # step does not count the last yield + step = (stop - start)/(num - 1) val = start - for _ in range(num): + for _ in range(num - 1): yield val val += step + yield stop + +def _hex_to_rgb(value): + """ Return an RGB tuple (float 0 to 1) from an hexadecimal + string representation. """ + value = value.lstrip('#') + char_per_color = len(value) // 3 + + red = int(value[0:char_per_color], base = 16) + green = int(value[char_per_color:2*char_per_color], base = 16) + blue = int(value[2*char_per_color::], base = 16) + + # We want color values between 0.0 and 1.0 + max_bits = 16**char_per_color - 1 + return (red/max_bits, green/max_bits, blue/max_bits) def spectrum_colors(num_colors): """ @@ -70,21 +87,29 @@ def rgb_sweep(num_colors, source, dest): ---------- num_colors : int Number of colors to generate. - source : 3-tuple of floats + source : 3-tuple of floats or str Source color in RGB space. Values should be between 0.0 and 1.0. - dest : 3-tuple of floats - Destination color in RGB space. Values should be between 0.0 and 1.0. + if `source` is a string, it is assumed to be in hexadecimal representation. + dest : 3-tuple of floats or str + Destination color in RGB space. RGB tuple Values should be between 0.0 and 1.0. + If `dest` is a string, it is assumed to be in hexadecimal representation. Yields ------ color : (R,G,B) tuple. R, G, B values in a tuple, from 0.0 to 1.0. """ + if isinstance(source, str): + source = _hex_to_rgb(source) + + if isinstance(dest, str): + dest = _hex_to_rgb(dest) + red_src, grn_src, blu_src = source red_dst, grn_dst, blu_dst = dest - reds = linspace(red_src, red_dst, num = num_colors) - greens = linspace(grn_src, grn_dst, num = num_colors) - blues = linspace(blu_src, blu_dst, num = num_colors) + reds = _linspace(red_src, red_dst, num = num_colors) + greens = _linspace(grn_src, grn_dst, num = num_colors) + blues = _linspace(blu_src, blu_dst, num = num_colors) yield from zip(reds, greens, blues) \ No newline at end of file diff --git a/skued/tests/test_plot_utils.py b/skued/tests/test_plot_utils.py index 1a6c972c..5ec18aab 100644 --- a/skued/tests/test_plot_utils.py +++ b/skued/tests/test_plot_utils.py @@ -35,6 +35,13 @@ def test_source_equal_to_dest(self): """ Test that rgb_sweep still works if source is equal to destination.""" colors = rgb_sweep(10, source = (1,0,0), dest = (1,0,0)) self.assertEqual(len(list(colors)), 10) + + def test_hex_colors(self): + """ Test that rgb_sweep works on hexadecimal strings """ + colors = list(rgb_sweep(10, source = '#ffffff', dest = '#000000')) + + self.assertSequenceEqual(colors[0], (1.0, 1.0, 1.0)) + self.assertSequenceEqual(colors[-1], (0.0, 0.0, 0.0)) if __name__ == '__main__': unittest.main() \ No newline at end of file