From 0868168b22b3ac3d3bf2571efa2e98b22010b9cd Mon Sep 17 00:00:00 2001 From: Nathan Hughes Date: Thu, 1 Aug 2024 01:21:46 +0000 Subject: [PATCH] add 150 class map and divergent map --- include/spark_dsg/colormaps.h | 22 +++++++++++++++-- src/colormaps.cpp | 46 +++++++++++++++++++++++++++++++++++ tests/utest_color.cpp | 18 ++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/include/spark_dsg/colormaps.h b/include/spark_dsg/colormaps.h index 06d8499..f7f71ec 100644 --- a/include/spark_dsg/colormaps.h +++ b/include/spark_dsg/colormaps.h @@ -42,9 +42,9 @@ namespace spark_dsg::colormaps { /** * @brief Generate a gray-scale color. - * @param value The value of the gray [0,1, where 0 is black and 1 is white]. + * @param value The value of the gray [0,1], where 0 is black and 1 is white. */ -Color gray(float value = 0.5f); +Color gray(float value); /** * @brief Generate a color based on a quality value. @@ -92,6 +92,18 @@ Color ironbow(float value); */ Color rainbow(float value); +/** + * @brief Generate a color from a general divergent colormap + * @param value A value in [0, 1]. 0 results in one color, 1 in the other, and 0.5 in a + * neutral color + */ +Color divergent(float value, + float hue_low = 0.66, + float hue_high = 0.0, + float saturation = 0.9, + float luminance = 0.9, + bool dark = true); + /** * @brief Generate a sequence of never repeating colors in the rainbow spectrum. * @param id The id of the color in the sequence. @@ -107,4 +119,10 @@ Color rainbowId(size_t id, size_t ids_per_revolution = 16); */ Color colorbrewer(size_t id); +/** + * @brief Pick a color from a custom palette from distinctipy with 150 colors + * @param id The id to pick from the sequence + */ +Color distrinct_150(size_t id); + } // namespace spark_dsg::colormaps diff --git a/src/colormaps.cpp b/src/colormaps.cpp index 7640a0a..e98a8aa 100644 --- a/src/colormaps.cpp +++ b/src/colormaps.cpp @@ -56,6 +56,39 @@ static const std::vector colorbrewer_palette{ {177, 89, 40}, }; +static const std::vector custom_150_palette{ + {0, 102, 51}, {0, 255, 0}, {4, 74, 246}, {191, 191, 181}, {72, 90, 13}, + {204, 0, 102}, {196, 26, 252}, {254, 217, 251}, {127, 255, 255}, {133, 87, 54}, + {130, 26, 50}, {10, 5, 65}, {3, 75, 135}, {18, 124, 89}, {21, 182, 126}, + {90, 171, 130}, {189, 217, 119}, {188, 63, 11}, {86, 82, 249}, {196, 221, 253}, + {187, 78, 62}, {188, 49, 167}, {182, 161, 248}, {112, 201, 196}, {11, 41, 99}, + {211, 102, 1}, {4, 227, 101}, {147, 201, 250}, {255, 0, 0}, {224, 33, 3}, + {254, 74, 17}, {255, 127, 0}, {176, 188, 66}, {247, 29, 54}, {74, 117, 80}, + {71, 56, 199}, {250, 107, 216}, {4, 204, 229}, {25, 208, 53}, {52, 249, 65}, + {70, 220, 121}, {68, 86, 156}, {7, 150, 36}, {255, 127, 127}, {64, 46, 6}, + {139, 167, 123}, {18, 165, 78}, {157, 166, 28}, {9, 163, 248}, {191, 67, 218}, + {135, 243, 61}, {81, 119, 190}, {0, 126, 204}, {228, 73, 252}, {227, 108, 163}, + {127, 255, 127}, {50, 211, 203}, {3, 190, 177}, {127, 255, 0}, {11, 59, 10}, + {108, 38, 143}, {243, 33, 254}, {182, 106, 251}, {120, 251, 191}, {145, 115, 208}, + {48, 129, 250}, {43, 78, 65}, {73, 0, 197}, {0, 249, 143}, {80, 160, 69}, + {200, 252, 62}, {127, 39, 198}, {139, 79, 186}, {155, 225, 169}, {239, 148, 63}, + {30, 183, 5}, {137, 90, 3}, {49, 35, 155}, {242, 186, 113}, {127, 0, 0}, + {191, 148, 1}, {134, 147, 65}, {175, 254, 104}, {84, 183, 23}, {12, 87, 183}, + {1, 20, 178}, {185, 224, 0}, {255, 255, 127}, {44, 252, 176}, {62, 186, 252}, + {3, 253, 46}, {41, 208, 156}, {138, 94, 126}, {32, 31, 231}, {192, 120, 193}, + {231, 66, 87}, {105, 0, 153}, {251, 216, 190}, {228, 45, 198}, {0, 0, 255}, + {67, 234, 247}, {156, 4, 152}, {253, 219, 57}, {183, 148, 126}, {246, 154, 179}, + {127, 127, 255}, {0, 255, 255}, {225, 189, 224}, {47, 253, 125}, {47, 0, 127}, + {92, 207, 58}, {173, 253, 235}, {251, 78, 170}, {164, 41, 91}, {0, 127, 0}, + {65, 43, 54}, {196, 100, 129}, {143, 157, 184}, {234, 190, 2}, {0, 234, 191}, + {191, 254, 179}, {149, 1, 215}, {67, 231, 11}, {131, 195, 0}, {188, 121, 62}, + {70, 143, 13}, {106, 168, 230}, {231, 106, 88}, {255, 255, 0}, {121, 54, 15}, + {127, 255, 0}, {248, 157, 252}, {63, 7, 14}, {146, 63, 249}, {185, 8, 32}, + {247, 0, 223}, {234, 252, 199}, {91, 29, 248}, {122, 0, 89}, {41, 99, 220}, + {28, 132, 140}, {127, 209, 111}, {110, 54, 79}, {63, 68, 107}, {214, 0, 171}, + {71, 9, 82}, {224, 187, 57}, {253, 20, 130}, {127, 127, 0}, {113, 132, 132}, +}; + Color gray(float value) { const auto char_value = fromUnitRange(std::clamp(value, 0.0f, 1.0f)); return Color(char_value, char_value, char_value); @@ -114,6 +147,19 @@ Color rainbow(float value) { return Color::fromHLS(std::clamp(value, 0.0f, 1.0f), 0.5f, 1.0f); } +Color divergent(float value, + float hue_low, + float hue_high, + float saturation, + float luminance, + bool dark) { + value = std::clamp(value, 0.0f, 1.0f); + const float alpha = value > 0.5f ? 2.0f * (value - 0.5f) : 2.0f * (0.5f - value); + return Color::fromHLS(value > 0.5f ? hue_high : hue_low, + dark ? alpha * luminance : (alpha * luminance) + 1.0f - alpha, + alpha * saturation); +} + Color rainbowId(size_t id, size_t ids_per_revolution) { return rainbow(exponentialOffsetId(id, ids_per_revolution)); } diff --git a/tests/utest_color.cpp b/tests/utest_color.cpp index 62e5510..6a6d649 100644 --- a/tests/utest_color.cpp +++ b/tests/utest_color.cpp @@ -168,4 +168,22 @@ TEST(Color, RainbowID) { EXPECT_EQ(colormaps::rainbowId(33, 16), Color(255, 120, 0)); } +TEST(Color, Divergent) { + const auto dark_cmap = [](float value) { + return colormaps::divergent(value, 0.0f, 2.0f / 3.0f, 1.0f, 0.5f, true); + }; + + EXPECT_EQ(dark_cmap(0.0f), Color::red()); + EXPECT_EQ(dark_cmap(0.5f), Color::black()); + EXPECT_EQ(dark_cmap(1.0f), Color::blue()); + + const auto light_cmap = [](float value) { + return colormaps::divergent(value, 0.0f, 2.0f / 3.0f, 1.0f, 0.5f, false); + }; + + EXPECT_EQ(light_cmap(0.0f), Color::red()); + EXPECT_EQ(light_cmap(0.5f), Color::white()); + EXPECT_EQ(light_cmap(1.0f), Color::blue()); +} + } // namespace spark_dsg