diff --git a/CHANGELOG.md b/CHANGELOG.md index df5654e..0f20871 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- `is_valid_color` function +- `color_complement` function +- `select_color` function ### Changed - Random mode modified +- Complementary color support for `color` and `bgcolor` parameters +- `filter_color` function modified ## [0.7] - 2022-05-04 ### Added - `fill_data` function diff --git a/README.md b/README.md index 78a6ac4..24f13f7 100644 --- a/README.md +++ b/README.md @@ -175,10 +175,11 @@ Samila is a generative art generator written in Python, Samila let's you create * Supported colors are available in `VALID_COLORS` list * `color` and `bgcolor` parameters supported formats: - 1. Color name (example: `yellow`) - 2. RGB/RGBA (example: `(0.1,0.1,0.1)`, `(0.1,0.1,0.1,0.1)`) - 3. Hex (example: `#eeefff`) - 4. Random (example: `random`) + 1. Color name (example: `color="yellow"`) + 2. RGB/RGBA (example: `color=(0.1,0.1,0.1)`, `color=(0.1,0.1,0.1,0.1)`) + 3. Hex (example: `color="#eeefff"`) + 4. Random (example: `color="random"`) + 5. Complement (example: `color="complement", bgcolor="blue"`) ### Regeneration ```pycon diff --git a/examples/demo.ipynb b/examples/demo.ipynb index 9ab48e4..2dc335a 100644 --- a/examples/demo.ipynb +++ b/examples/demo.ipynb @@ -157,10 +157,11 @@ "source": [ "* `color` and `bgcolor` parameters supported formats:\n", "\n", - " 1. Color name (example: `yellow`)\n", - " 2. RGB/RGBA (example: `(0.1,0.1,0.1)`, `(0.1,0.1,0.1,0.1)`)\n", - " 3. Hex (example: `#eeefff`)\n", - " 4. Random (example: `random`)" + " 1. Color name (example: `color=\"yellow\"`)\n", + " 2. RGB/RGBA (example: `color=(0.1,0.1,0.1)`, `color=(0.1,0.1,0.1,0.1)`)\n", + " 3. Hex (example: `color=\"#eeefff\"`)\n", + " 4. Random (example: `color=\"random\"`)\n", + " 5. Complement (example: `color=\"complement\", bgcolor=\"blue\"`)" ] }, { diff --git a/samila/functions.py b/samila/functions.py index c4ef5cc..64ac7be 100644 --- a/samila/functions.py +++ b/samila/functions.py @@ -95,17 +95,70 @@ def distance_calc(s1, s2): return distances[-1] -def filter_color(color): +def is_valid_color(color): """ - Filter given color and return it. + Check that input color format is valid or not. :param color: given color - :type color: str or tuple - :return: filtered version of color + :type color: any format + :return: result as bool + """ + try: + _ = matplotlib.colors.to_hex(color) + return True + except ValueError: + return False + + +def color_complement(color): + """ + Calculate complement color. + + :param color: given color (hex format) + :type color: str + :return: complement color (hex format) as str + """ + color = color[1:] + color = int(color, 16) + comp_color = 0xFFFFFF ^ color + comp_color = "#%06X" % comp_color + return comp_color + + +def filter_color(color, bgcolor): + """ + Filter given color and bgcolor. + + :param color: given color + :type color: any format + :param bgcolor: given background color + :type bgcolor: any format + :return: filtered version of color and bgcolor + """ + color = select_color(color) + bgcolor = select_color(bgcolor) + if color == "COMPLEMENT" and bgcolor == "COMPLEMENT": + return None, None + if color == "COMPLEMENT": + bgcolor = matplotlib.colors.to_hex(bgcolor) + color = color_complement(bgcolor) + if bgcolor == "COMPLEMENT": + color = matplotlib.colors.to_hex(color) + bgcolor = color_complement(color) + return color, bgcolor + + +def select_color(color): + """ + Select color and return it. + + :param color: given color + :type color: any format + :return: color """ - if isinstance(color, tuple): - return color if isinstance(color, str): + if color.upper() == "COMPLEMENT": + return "COMPLEMENT" if color.upper() == "RANDOM": return random_hex_color_gen() if re.match(HEX_COLOR_PATTERN, color): @@ -114,6 +167,8 @@ def filter_color(color): VALID_COLORS)) min_distance = min(distance_list) return VALID_COLORS[distance_list.index(min_distance)] + if is_valid_color(color): + return color return None @@ -196,7 +251,7 @@ def plot_params_filter( raise samilaPlotError(PLOT_DATA_ERROR.format(1)) if g.data2 is None: raise samilaPlotError(PLOT_DATA_ERROR.format(2)) - color, bgcolor = map(filter_color, [color, bgcolor]) + color, bgcolor = filter_color(color, bgcolor) projection = filter_projection(projection) alpha = filter_float(alpha) linewidth = filter_float(linewidth) diff --git a/test/function_test.py b/test/function_test.py index 48ba874..1e27538 100644 --- a/test/function_test.py +++ b/test/function_test.py @@ -2,6 +2,36 @@ """ >>> import random >>> from samila.functions import * +>>> is_valid_color("blue") +True +>>> is_valid_color((0,0,0)) +True +>>> is_valid_color((0.1,0.1,0,1)) +True +>>> is_valid_color([1,1,1,1]) +True +>>> is_valid_color([1,1,1,1,1,1]) +False +>>> is_valid_color("nothing") +False +>>> is_valid_color("#FFFAAF") +True +>>> color_complement("#FFFFFF") +'#000000' +>>> color_complement("#FFAFBF") +'#005040' +>>> color_complement("#000000") +'#FFFFFF' +>>> select_color("blue") +'blue' +>>> select_color("#FFFFFA") +'#FFFFFA' +>>> select_color((0.1,0.1,0.1)) +(0.1, 0.1, 0.1) +>>> select_color(2) +>>> select_color(None) +>>> select_color("complement") +'COMPLEMENT' >>> s = list(float_range(1,1.5,0.1)) >>> s [1.0, 1.1, 1.2000000000000002, 1.3000000000000003, 1.4000000000000004] @@ -13,16 +43,16 @@ False False >>> is_same_data(s,[]) False ->>> filter_color("yellow") -'yellow' ->>> filter_color((0.2,0.3,0.4)) -(0.2, 0.3, 0.4) ->>> filter_color("#FFFFFF") -'#FFFFFF' +>>> filter_color("yellow", "blue") +('yellow', 'blue') +>>> filter_color((0.2,0.3,0.4), (0.2,0.3,0.4,1)) +((0.2, 0.3, 0.4), (0.2, 0.3, 0.4, 1)) +>>> filter_color("#FFFFFF", "#ffffe1") +('#FFFFFF', '#ffffe1') >>> random.seed(2) ->>> color1 = filter_color("random") +>>> color1, bgcolor1 = filter_color("random", "random") >>> random.seed(3) ->>> color2 = filter_color("RANDOM") +>>> color2, bgcolor2 = filter_color("RANDOM", "RANDOM") >>> color1 == color2 False >>> random.seed(2) @@ -35,8 +65,10 @@ False 7 >>> len(color2) 7 ->>> filter_color(2) ->>> filter_color(4) +>>> filter_color(2,2) +(None, None) +>>> filter_color(4,3) +(None, None) >>> filter_size(2) >>> filter_size((2, 'test')) >>> filter_size((2, 3.5)) diff --git a/test/overall_test.py b/test/overall_test.py index 1da3fc9..937c81e 100644 --- a/test/overall_test.py +++ b/test/overall_test.py @@ -73,6 +73,21 @@ True >>> g.plot(projection=Projection.POLAR, color=(.1, .2, .8)) >>> g.color (0.1, 0.2, 0.8) +>>> g.plot(projection=Projection.POLAR, color="#FFFFF1", bgcolor="complement") +>>> g.color +'#fffff1' +>>> g.bgcolor +'#00000E' +>>> g.plot(projection=Projection.POLAR, color="complement", bgcolor="#AAAAAA") +>>> g.color +'#555555' +>>> g.bgcolor +'#aaaaaa' +>>> g.plot(projection=Projection.POLAR, color="complement", bgcolor="complement") +>>> g.color +'#555555' +>>> g.bgcolor +'#aaaaaa' >>> g.plot(bgcolor=(.1, .2, .8), spot_size=0.1) >>> g.plot(size=(20, 20)) >>> g.size