diff --git a/base/src/color.rs b/base/src/color.rs index 4406902..d6f129c 100644 --- a/base/src/color.rs +++ b/base/src/color.rs @@ -1,9 +1,10 @@ use std::str::FromStr; use std::{error, fmt}; -mod named; +mod css4; +mod xkcd; -pub use named::*; +pub use css4::*; pub trait ResolveColor { fn resolve_color(&self, color: &Color) -> ColorU8; @@ -201,6 +202,10 @@ const fn hex_to_u8(hex: u8) -> u8 { } } +const fn is_hex_char(c: u8) -> bool { + matches!(c, b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F') +} + /// Parsing error for ColorU8 #[derive(Debug)] pub enum ParseError { @@ -297,8 +302,11 @@ impl FromStr for ColorU8 { let bytes = raw.as_bytes(); match bytes.len() { 4 | 5 | 7 | 9 => { - // from_html panics if first char != '#', but we checked it - Ok(ColorU8::from_html(bytes)) + if bytes[1..].iter().all(|&c| is_hex_char(c)) { + Ok(ColorU8::from_html(bytes)) + } else { + Err(ParseError::InvalidHex) + } } _ => Err(ParseError::InvalidHex), } @@ -328,7 +336,9 @@ impl FromStr for ColorU8 { } // named color else { - if let Some(col) = named::lookup_name(raw) { + if let Some(col) = css4::lookup_name(raw) { + Ok(col) + } else if let Some(col) = xkcd::lookup_name(raw) { Ok(col) } else { Err(ParseError::UnknownName) diff --git a/base/src/color/named.rs b/base/src/color/css4.rs similarity index 100% rename from base/src/color/named.rs rename to base/src/color/css4.rs diff --git a/base/src/color/xkcd.rs b/base/src/color/xkcd.rs new file mode 100644 index 0000000..b5f7a34 --- /dev/null +++ b/base/src/color/xkcd.rs @@ -0,0 +1,961 @@ +use crate::ColorU8; + +/// Colors from the xkcd color survey. +/// These are not intended to be used directly, but are available for users who want to use them. +/// https://blog.xkcd.com/2010/05/03/color-survey-results/ + +pub fn lookup_name(name: &str) -> Option { + // License: https://creativecommons.org/publicdomain/zero/1.0/ + match name { + "cloudy blue" => Some(ColorU8::from_html(b"#acc2d9")), + "dark pastel green" => Some(ColorU8::from_html(b"#56ae57")), + "dust" => Some(ColorU8::from_html(b"#b2996e")), + "electric lime" => Some(ColorU8::from_html(b"#a8ff04")), + "fresh green" => Some(ColorU8::from_html(b"#69d84f")), + "light eggplant" => Some(ColorU8::from_html(b"#894585")), + "nasty green" => Some(ColorU8::from_html(b"#70b23f")), + "really light blue" => Some(ColorU8::from_html(b"#d4ffff")), + "tea" => Some(ColorU8::from_html(b"#65ab7c")), + "warm purple" => Some(ColorU8::from_html(b"#952e8f")), + "yellowish tan" => Some(ColorU8::from_html(b"#fcfc81")), + "cement" => Some(ColorU8::from_html(b"#a5a391")), + "dark grass green" => Some(ColorU8::from_html(b"#388004")), + "dusty teal" => Some(ColorU8::from_html(b"#4c9085")), + "grey teal" => Some(ColorU8::from_html(b"#5e9b8a")), + "macaroni and cheese" => Some(ColorU8::from_html(b"#efb435")), + "pinkish tan" => Some(ColorU8::from_html(b"#d99b82")), + "spruce" => Some(ColorU8::from_html(b"#0a5f38")), + "strong blue" => Some(ColorU8::from_html(b"#0c06f7")), + "toxic green" => Some(ColorU8::from_html(b"#61de2a")), + "windows blue" => Some(ColorU8::from_html(b"#3778bf")), + "blue blue" => Some(ColorU8::from_html(b"#2242c7")), + "blue with a hint of purple" => Some(ColorU8::from_html(b"#533cc6")), + "booger" => Some(ColorU8::from_html(b"#9bb53c")), + "bright sea green" => Some(ColorU8::from_html(b"#05ffa6")), + "dark green blue" => Some(ColorU8::from_html(b"#1f6357")), + "deep turquoise" => Some(ColorU8::from_html(b"#017374")), + "green teal" => Some(ColorU8::from_html(b"#0cb577")), + "strong pink" => Some(ColorU8::from_html(b"#ff0789")), + "bland" => Some(ColorU8::from_html(b"#afa88b")), + "deep aqua" => Some(ColorU8::from_html(b"#08787f")), + "lavender pink" => Some(ColorU8::from_html(b"#dd85d7")), + "light moss green" => Some(ColorU8::from_html(b"#a6c875")), + "light seafoam green" => Some(ColorU8::from_html(b"#a7ffb5")), + "olive yellow" => Some(ColorU8::from_html(b"#c2b709")), + "pig pink" => Some(ColorU8::from_html(b"#e78ea5")), + "deep lilac" => Some(ColorU8::from_html(b"#966ebd")), + "desert" => Some(ColorU8::from_html(b"#ccad60")), + "dusty lavender" => Some(ColorU8::from_html(b"#ac86a8")), + "purpley grey" => Some(ColorU8::from_html(b"#947e94")), + "purply" => Some(ColorU8::from_html(b"#983fb2")), + "candy pink" => Some(ColorU8::from_html(b"#ff63e9")), + "light pastel green" => Some(ColorU8::from_html(b"#b2fba5")), + "boring green" => Some(ColorU8::from_html(b"#63b365")), + "kiwi green" => Some(ColorU8::from_html(b"#8ee53f")), + "light grey green" => Some(ColorU8::from_html(b"#b7e1a1")), + "orange pink" => Some(ColorU8::from_html(b"#ff6f52")), + "tea green" => Some(ColorU8::from_html(b"#bdf8a3")), + "very light brown" => Some(ColorU8::from_html(b"#d3b683")), + "egg shell" => Some(ColorU8::from_html(b"#fffcc4")), + "eggplant purple" => Some(ColorU8::from_html(b"#430541")), + "powder pink" => Some(ColorU8::from_html(b"#ffb2d0")), + "reddish grey" => Some(ColorU8::from_html(b"#997570")), + "baby shit brown" => Some(ColorU8::from_html(b"#ad900d")), + "liliac" => Some(ColorU8::from_html(b"#c48efd")), + "stormy blue" => Some(ColorU8::from_html(b"#507b9c")), + "ugly brown" => Some(ColorU8::from_html(b"#7d7103")), + "custard" => Some(ColorU8::from_html(b"#fffd78")), + "darkish pink" => Some(ColorU8::from_html(b"#da467d")), + "deep brown" => Some(ColorU8::from_html(b"#410200")), + "greenish beige" => Some(ColorU8::from_html(b"#c9d179")), + "manilla" => Some(ColorU8::from_html(b"#fffa86")), + "off blue" => Some(ColorU8::from_html(b"#5684ae")), + "battleship grey" => Some(ColorU8::from_html(b"#6b7c85")), + "browny green" => Some(ColorU8::from_html(b"#6f6c0a")), + "bruise" => Some(ColorU8::from_html(b"#7e4071")), + "kelley green" => Some(ColorU8::from_html(b"#009337")), + "sickly yellow" => Some(ColorU8::from_html(b"#d0e429")), + "sunny yellow" => Some(ColorU8::from_html(b"#fff917")), + "azul" => Some(ColorU8::from_html(b"#1d5dec")), + "darkgreen" => Some(ColorU8::from_html(b"#054907")), + "green/yellow" => Some(ColorU8::from_html(b"#b5ce08")), + "lichen" => Some(ColorU8::from_html(b"#8fb67b")), + "light light green" => Some(ColorU8::from_html(b"#c8ffb0")), + "pale gold" => Some(ColorU8::from_html(b"#fdde6c")), + "sun yellow" => Some(ColorU8::from_html(b"#ffdf22")), + "tan green" => Some(ColorU8::from_html(b"#a9be70")), + "burple" => Some(ColorU8::from_html(b"#6832e3")), + "butterscotch" => Some(ColorU8::from_html(b"#fdb147")), + "toupe" => Some(ColorU8::from_html(b"#c7ac7d")), + "dark cream" => Some(ColorU8::from_html(b"#fff39a")), + "indian red" => Some(ColorU8::from_html(b"#850e04")), + "light lavendar" => Some(ColorU8::from_html(b"#efc0fe")), + "poison green" => Some(ColorU8::from_html(b"#40fd14")), + "baby puke green" => Some(ColorU8::from_html(b"#b6c406")), + "bright yellow green" => Some(ColorU8::from_html(b"#9dff00")), + "charcoal grey" => Some(ColorU8::from_html(b"#3c4142")), + "squash" => Some(ColorU8::from_html(b"#f2ab15")), + "cinnamon" => Some(ColorU8::from_html(b"#ac4f06")), + "light pea green" => Some(ColorU8::from_html(b"#c4fe82")), + "radioactive green" => Some(ColorU8::from_html(b"#2cfa1f")), + "raw sienna" => Some(ColorU8::from_html(b"#9a6200")), + "baby purple" => Some(ColorU8::from_html(b"#ca9bf7")), + "cocoa" => Some(ColorU8::from_html(b"#875f42")), + "light royal blue" => Some(ColorU8::from_html(b"#3a2efe")), + "orangeish" => Some(ColorU8::from_html(b"#fd8d49")), + "rust brown" => Some(ColorU8::from_html(b"#8b3103")), + "sand brown" => Some(ColorU8::from_html(b"#cba560")), + "swamp" => Some(ColorU8::from_html(b"#698339")), + "tealish green" => Some(ColorU8::from_html(b"#0cdc73")), + "burnt siena" => Some(ColorU8::from_html(b"#b75203")), + "camo" => Some(ColorU8::from_html(b"#7f8f4e")), + "dusk blue" => Some(ColorU8::from_html(b"#26538d")), + "fern" => Some(ColorU8::from_html(b"#63a950")), + "old rose" => Some(ColorU8::from_html(b"#c87f89")), + "pale light green" => Some(ColorU8::from_html(b"#b1fc99")), + "peachy pink" => Some(ColorU8::from_html(b"#ff9a8a")), + "rosy pink" => Some(ColorU8::from_html(b"#f6688e")), + "light bluish green" => Some(ColorU8::from_html(b"#76fda8")), + "light bright green" => Some(ColorU8::from_html(b"#53fe5c")), + "light neon green" => Some(ColorU8::from_html(b"#4efd54")), + "light seafoam" => Some(ColorU8::from_html(b"#a0febf")), + "tiffany blue" => Some(ColorU8::from_html(b"#7bf2da")), + "washed out green" => Some(ColorU8::from_html(b"#bcf5a6")), + "browny orange" => Some(ColorU8::from_html(b"#ca6b02")), + "nice blue" => Some(ColorU8::from_html(b"#107ab0")), + "sapphire" => Some(ColorU8::from_html(b"#2138ab")), + "greyish teal" => Some(ColorU8::from_html(b"#719f91")), + "orangey yellow" => Some(ColorU8::from_html(b"#fdb915")), + "parchment" => Some(ColorU8::from_html(b"#fefcaf")), + "straw" => Some(ColorU8::from_html(b"#fcf679")), + "very dark brown" => Some(ColorU8::from_html(b"#1d0200")), + "terracota" => Some(ColorU8::from_html(b"#cb6843")), + "ugly blue" => Some(ColorU8::from_html(b"#31668a")), + "clear blue" => Some(ColorU8::from_html(b"#247afd")), + "creme" => Some(ColorU8::from_html(b"#ffffb6")), + "foam green" => Some(ColorU8::from_html(b"#90fda9")), + "grey/green" => Some(ColorU8::from_html(b"#86a17d")), + "light gold" => Some(ColorU8::from_html(b"#fddc5c")), + "seafoam blue" => Some(ColorU8::from_html(b"#78d1b6")), + "topaz" => Some(ColorU8::from_html(b"#13bbaf")), + "violet pink" => Some(ColorU8::from_html(b"#fb5ffc")), + "wintergreen" => Some(ColorU8::from_html(b"#20f986")), + "yellow tan" => Some(ColorU8::from_html(b"#ffe36e")), + "dark fuchsia" => Some(ColorU8::from_html(b"#9d0759")), + "indigo blue" => Some(ColorU8::from_html(b"#3a18b1")), + "light yellowish green" => Some(ColorU8::from_html(b"#c2ff89")), + "pale magenta" => Some(ColorU8::from_html(b"#d767ad")), + "rich purple" => Some(ColorU8::from_html(b"#720058")), + "sunflower yellow" => Some(ColorU8::from_html(b"#ffda03")), + "green/blue" => Some(ColorU8::from_html(b"#01c08d")), + "leather" => Some(ColorU8::from_html(b"#ac7434")), + "racing green" => Some(ColorU8::from_html(b"#014600")), + "vivid purple" => Some(ColorU8::from_html(b"#9900fa")), + "dark royal blue" => Some(ColorU8::from_html(b"#02066f")), + "hazel" => Some(ColorU8::from_html(b"#8e7618")), + "muted pink" => Some(ColorU8::from_html(b"#d1768f")), + "booger green" => Some(ColorU8::from_html(b"#96b403")), + "canary" => Some(ColorU8::from_html(b"#fdff63")), + "cool grey" => Some(ColorU8::from_html(b"#95a3a6")), + "dark taupe" => Some(ColorU8::from_html(b"#7f684e")), + "darkish purple" => Some(ColorU8::from_html(b"#751973")), + "true green" => Some(ColorU8::from_html(b"#089404")), + "coral pink" => Some(ColorU8::from_html(b"#ff6163")), + "dark sage" => Some(ColorU8::from_html(b"#598556")), + "dark slate blue" => Some(ColorU8::from_html(b"#214761")), + "flat blue" => Some(ColorU8::from_html(b"#3c73a8")), + "mushroom" => Some(ColorU8::from_html(b"#ba9e88")), + "rich blue" => Some(ColorU8::from_html(b"#021bf9")), + "dirty purple" => Some(ColorU8::from_html(b"#734a65")), + "greenblue" => Some(ColorU8::from_html(b"#23c48b")), + "icky green" => Some(ColorU8::from_html(b"#8fae22")), + "light khaki" => Some(ColorU8::from_html(b"#e6f2a2")), + "warm blue" => Some(ColorU8::from_html(b"#4b57db")), + "dark hot pink" => Some(ColorU8::from_html(b"#d90166")), + "deep sea blue" => Some(ColorU8::from_html(b"#015482")), + "carmine" => Some(ColorU8::from_html(b"#9d0216")), + "dark yellow green" => Some(ColorU8::from_html(b"#728f02")), + "pale peach" => Some(ColorU8::from_html(b"#ffe5ad")), + "plum purple" => Some(ColorU8::from_html(b"#4e0550")), + "golden rod" => Some(ColorU8::from_html(b"#f9bc08")), + "neon red" => Some(ColorU8::from_html(b"#ff073a")), + "old pink" => Some(ColorU8::from_html(b"#c77986")), + "very pale blue" => Some(ColorU8::from_html(b"#d6fffe")), + "blood orange" => Some(ColorU8::from_html(b"#fe4b03")), + "grapefruit" => Some(ColorU8::from_html(b"#fd5956")), + "sand yellow" => Some(ColorU8::from_html(b"#fce166")), + "clay brown" => Some(ColorU8::from_html(b"#b2713d")), + "dark blue grey" => Some(ColorU8::from_html(b"#1f3b4d")), + "flat green" => Some(ColorU8::from_html(b"#699d4c")), + "light green blue" => Some(ColorU8::from_html(b"#56fca2")), + "warm pink" => Some(ColorU8::from_html(b"#fb5581")), + "dodger blue" => Some(ColorU8::from_html(b"#3e82fc")), + "gross green" => Some(ColorU8::from_html(b"#a0bf16")), + "ice" => Some(ColorU8::from_html(b"#d6fffa")), + "metallic blue" => Some(ColorU8::from_html(b"#4f738e")), + "pale salmon" => Some(ColorU8::from_html(b"#ffb19a")), + "sap green" => Some(ColorU8::from_html(b"#5c8b15")), + "algae" => Some(ColorU8::from_html(b"#54ac68")), + "bluey grey" => Some(ColorU8::from_html(b"#89a0b0")), + "greeny grey" => Some(ColorU8::from_html(b"#7ea07a")), + "highlighter green" => Some(ColorU8::from_html(b"#1bfc06")), + "light light blue" => Some(ColorU8::from_html(b"#cafffb")), + "light mint" => Some(ColorU8::from_html(b"#b6ffbb")), + "raw umber" => Some(ColorU8::from_html(b"#a75e09")), + "vivid blue" => Some(ColorU8::from_html(b"#152eff")), + "deep lavender" => Some(ColorU8::from_html(b"#8d5eb7")), + "dull teal" => Some(ColorU8::from_html(b"#5f9e8f")), + "light greenish blue" => Some(ColorU8::from_html(b"#63f7b4")), + "mud green" => Some(ColorU8::from_html(b"#606602")), + "pinky" => Some(ColorU8::from_html(b"#fc86aa")), + "red wine" => Some(ColorU8::from_html(b"#8c0034")), + "shit green" => Some(ColorU8::from_html(b"#758000")), + "tan brown" => Some(ColorU8::from_html(b"#ab7e4c")), + "darkblue" => Some(ColorU8::from_html(b"#030764")), + "rosa" => Some(ColorU8::from_html(b"#fe86a4")), + "lipstick" => Some(ColorU8::from_html(b"#d5174e")), + "pale mauve" => Some(ColorU8::from_html(b"#fed0fc")), + "claret" => Some(ColorU8::from_html(b"#680018")), + "dandelion" => Some(ColorU8::from_html(b"#fedf08")), + "orangered" => Some(ColorU8::from_html(b"#fe420f")), + "poop green" => Some(ColorU8::from_html(b"#6f7c00")), + "ruby" => Some(ColorU8::from_html(b"#ca0147")), + "dark" => Some(ColorU8::from_html(b"#1b2431")), + "greenish turquoise" => Some(ColorU8::from_html(b"#00fbb0")), + "pastel red" => Some(ColorU8::from_html(b"#db5856")), + "piss yellow" => Some(ColorU8::from_html(b"#ddd618")), + "bright cyan" => Some(ColorU8::from_html(b"#41fdfe")), + "dark coral" => Some(ColorU8::from_html(b"#cf524e")), + "algae green" => Some(ColorU8::from_html(b"#21c36f")), + "darkish red" => Some(ColorU8::from_html(b"#a90308")), + "reddy brown" => Some(ColorU8::from_html(b"#6e1005")), + "blush pink" => Some(ColorU8::from_html(b"#fe828c")), + "camouflage green" => Some(ColorU8::from_html(b"#4b6113")), + "lawn green" => Some(ColorU8::from_html(b"#4da409")), + "putty" => Some(ColorU8::from_html(b"#beae8a")), + "vibrant blue" => Some(ColorU8::from_html(b"#0339f8")), + "dark sand" => Some(ColorU8::from_html(b"#a88f59")), + "purple/blue" => Some(ColorU8::from_html(b"#5d21d0")), + "saffron" => Some(ColorU8::from_html(b"#feb209")), + "twilight" => Some(ColorU8::from_html(b"#4e518b")), + "warm brown" => Some(ColorU8::from_html(b"#964e02")), + "bluegrey" => Some(ColorU8::from_html(b"#85a3b2")), + "bubble gum pink" => Some(ColorU8::from_html(b"#ff69af")), + "duck egg blue" => Some(ColorU8::from_html(b"#c3fbf4")), + "greenish cyan" => Some(ColorU8::from_html(b"#2afeb7")), + "petrol" => Some(ColorU8::from_html(b"#005f6a")), + "royal" => Some(ColorU8::from_html(b"#0c1793")), + "butter" => Some(ColorU8::from_html(b"#ffff81")), + "dusty orange" => Some(ColorU8::from_html(b"#f0833a")), + "off yellow" => Some(ColorU8::from_html(b"#f1f33f")), + "pale olive green" => Some(ColorU8::from_html(b"#b1d27b")), + "orangish" => Some(ColorU8::from_html(b"#fc824a")), + "leaf" => Some(ColorU8::from_html(b"#71aa34")), + "light blue grey" => Some(ColorU8::from_html(b"#b7c9e2")), + "dried blood" => Some(ColorU8::from_html(b"#4b0101")), + "lightish purple" => Some(ColorU8::from_html(b"#a552e6")), + "rusty red" => Some(ColorU8::from_html(b"#af2f0d")), + "lavender blue" => Some(ColorU8::from_html(b"#8b88f8")), + "light grass green" => Some(ColorU8::from_html(b"#9af764")), + "light mint green" => Some(ColorU8::from_html(b"#a6fbb2")), + "sunflower" => Some(ColorU8::from_html(b"#ffc512")), + "velvet" => Some(ColorU8::from_html(b"#750851")), + "brick orange" => Some(ColorU8::from_html(b"#c14a09")), + "lightish red" => Some(ColorU8::from_html(b"#fe2f4a")), + "pure blue" => Some(ColorU8::from_html(b"#0203e2")), + "twilight blue" => Some(ColorU8::from_html(b"#0a437a")), + "violet red" => Some(ColorU8::from_html(b"#a50055")), + "yellowy brown" => Some(ColorU8::from_html(b"#ae8b0c")), + "carnation" => Some(ColorU8::from_html(b"#fd798f")), + "muddy yellow" => Some(ColorU8::from_html(b"#bfac05")), + "dark seafoam green" => Some(ColorU8::from_html(b"#3eaf76")), + "deep rose" => Some(ColorU8::from_html(b"#c74767")), + "dusty red" => Some(ColorU8::from_html(b"#b9484e")), + "grey/blue" => Some(ColorU8::from_html(b"#647d8e")), + "lemon lime" => Some(ColorU8::from_html(b"#bffe28")), + "purple/pink" => Some(ColorU8::from_html(b"#d725de")), + "brown yellow" => Some(ColorU8::from_html(b"#b29705")), + "purple brown" => Some(ColorU8::from_html(b"#673a3f")), + "wisteria" => Some(ColorU8::from_html(b"#a87dc2")), + "banana yellow" => Some(ColorU8::from_html(b"#fafe4b")), + "lipstick red" => Some(ColorU8::from_html(b"#c0022f")), + "water blue" => Some(ColorU8::from_html(b"#0e87cc")), + "brown grey" => Some(ColorU8::from_html(b"#8d8468")), + "vibrant purple" => Some(ColorU8::from_html(b"#ad03de")), + "baby green" => Some(ColorU8::from_html(b"#8cff9e")), + "barf green" => Some(ColorU8::from_html(b"#94ac02")), + "eggshell blue" => Some(ColorU8::from_html(b"#c4fff7")), + "sandy yellow" => Some(ColorU8::from_html(b"#fdee73")), + "cool green" => Some(ColorU8::from_html(b"#33b864")), + "pale" => Some(ColorU8::from_html(b"#fff9d0")), + "blue/grey" => Some(ColorU8::from_html(b"#758da3")), + "hot magenta" => Some(ColorU8::from_html(b"#f504c9")), + "greyblue" => Some(ColorU8::from_html(b"#77a1b5")), + "purpley" => Some(ColorU8::from_html(b"#8756e4")), + "baby shit green" => Some(ColorU8::from_html(b"#889717")), + "brownish pink" => Some(ColorU8::from_html(b"#c27e79")), + "dark aquamarine" => Some(ColorU8::from_html(b"#017371")), + "diarrhea" => Some(ColorU8::from_html(b"#9f8303")), + "light mustard" => Some(ColorU8::from_html(b"#f7d560")), + "pale sky blue" => Some(ColorU8::from_html(b"#bdf6fe")), + "turtle green" => Some(ColorU8::from_html(b"#75b84f")), + "bright olive" => Some(ColorU8::from_html(b"#9cbb04")), + "dark grey blue" => Some(ColorU8::from_html(b"#29465b")), + "greeny brown" => Some(ColorU8::from_html(b"#696006")), + "lemon green" => Some(ColorU8::from_html(b"#adf802")), + "light periwinkle" => Some(ColorU8::from_html(b"#c1c6fc")), + "seaweed green" => Some(ColorU8::from_html(b"#35ad6b")), + "sunshine yellow" => Some(ColorU8::from_html(b"#fffd37")), + "ugly purple" => Some(ColorU8::from_html(b"#a442a0")), + "medium pink" => Some(ColorU8::from_html(b"#f36196")), + "puke brown" => Some(ColorU8::from_html(b"#947706")), + "very light pink" => Some(ColorU8::from_html(b"#fff4f2")), + "viridian" => Some(ColorU8::from_html(b"#1e9167")), + "bile" => Some(ColorU8::from_html(b"#b5c306")), + "faded yellow" => Some(ColorU8::from_html(b"#feff7f")), + "very pale green" => Some(ColorU8::from_html(b"#cffdbc")), + "vibrant green" => Some(ColorU8::from_html(b"#0add08")), + "bright lime" => Some(ColorU8::from_html(b"#87fd05")), + "spearmint" => Some(ColorU8::from_html(b"#1ef876")), + "light aquamarine" => Some(ColorU8::from_html(b"#7bfdc7")), + "light sage" => Some(ColorU8::from_html(b"#bcecac")), + "yellowgreen" => Some(ColorU8::from_html(b"#bbf90f")), + "baby poo" => Some(ColorU8::from_html(b"#ab9004")), + "dark seafoam" => Some(ColorU8::from_html(b"#1fb57a")), + "deep teal" => Some(ColorU8::from_html(b"#00555a")), + "heather" => Some(ColorU8::from_html(b"#a484ac")), + "rust orange" => Some(ColorU8::from_html(b"#c45508")), + "dirty blue" => Some(ColorU8::from_html(b"#3f829d")), + "fern green" => Some(ColorU8::from_html(b"#548d44")), + "bright lilac" => Some(ColorU8::from_html(b"#c95efb")), + "weird green" => Some(ColorU8::from_html(b"#3ae57f")), + "peacock blue" => Some(ColorU8::from_html(b"#016795")), + "avocado green" => Some(ColorU8::from_html(b"#87a922")), + "faded orange" => Some(ColorU8::from_html(b"#f0944d")), + "grape purple" => Some(ColorU8::from_html(b"#5d1451")), + "hot green" => Some(ColorU8::from_html(b"#25ff29")), + "lime yellow" => Some(ColorU8::from_html(b"#d0fe1d")), + "mango" => Some(ColorU8::from_html(b"#ffa62b")), + "shamrock" => Some(ColorU8::from_html(b"#01b44c")), + "bubblegum" => Some(ColorU8::from_html(b"#ff6cb5")), + "purplish brown" => Some(ColorU8::from_html(b"#6b4247")), + "vomit yellow" => Some(ColorU8::from_html(b"#c7c10c")), + "pale cyan" => Some(ColorU8::from_html(b"#b7fffa")), + "key lime" => Some(ColorU8::from_html(b"#aeff6e")), + "tomato red" => Some(ColorU8::from_html(b"#ec2d01")), + "lightgreen" => Some(ColorU8::from_html(b"#76ff7b")), + "merlot" => Some(ColorU8::from_html(b"#730039")), + "night blue" => Some(ColorU8::from_html(b"#040348")), + "purpleish pink" => Some(ColorU8::from_html(b"#df4ec8")), + "apple" => Some(ColorU8::from_html(b"#6ecb3c")), + "baby poop green" => Some(ColorU8::from_html(b"#8f9805")), + "green apple" => Some(ColorU8::from_html(b"#5edc1f")), + "heliotrope" => Some(ColorU8::from_html(b"#d94ff5")), + "yellow/green" => Some(ColorU8::from_html(b"#c8fd3d")), + "almost black" => Some(ColorU8::from_html(b"#070d0d")), + "cool blue" => Some(ColorU8::from_html(b"#4984b8")), + "leafy green" => Some(ColorU8::from_html(b"#51b73b")), + "mustard brown" => Some(ColorU8::from_html(b"#ac7e04")), + "dusk" => Some(ColorU8::from_html(b"#4e5481")), + "dull brown" => Some(ColorU8::from_html(b"#876e4b")), + "frog green" => Some(ColorU8::from_html(b"#58bc08")), + "vivid green" => Some(ColorU8::from_html(b"#2fef10")), + "bright light green" => Some(ColorU8::from_html(b"#2dfe54")), + "fluro green" => Some(ColorU8::from_html(b"#0aff02")), + "kiwi" => Some(ColorU8::from_html(b"#9cef43")), + "seaweed" => Some(ColorU8::from_html(b"#18d17b")), + "navy green" => Some(ColorU8::from_html(b"#35530a")), + "ultramarine blue" => Some(ColorU8::from_html(b"#1805db")), + "iris" => Some(ColorU8::from_html(b"#6258c4")), + "pastel orange" => Some(ColorU8::from_html(b"#ff964f")), + "yellowish orange" => Some(ColorU8::from_html(b"#ffab0f")), + "perrywinkle" => Some(ColorU8::from_html(b"#8f8ce7")), + "tealish" => Some(ColorU8::from_html(b"#24bca8")), + "dark plum" => Some(ColorU8::from_html(b"#3f012c")), + "pear" => Some(ColorU8::from_html(b"#cbf85f")), + "pinkish orange" => Some(ColorU8::from_html(b"#ff724c")), + "midnight purple" => Some(ColorU8::from_html(b"#280137")), + "light urple" => Some(ColorU8::from_html(b"#b36ff6")), + "dark mint" => Some(ColorU8::from_html(b"#48c072")), + "greenish tan" => Some(ColorU8::from_html(b"#bccb7a")), + "light burgundy" => Some(ColorU8::from_html(b"#a8415b")), + "turquoise blue" => Some(ColorU8::from_html(b"#06b1c4")), + "ugly pink" => Some(ColorU8::from_html(b"#cd7584")), + "sandy" => Some(ColorU8::from_html(b"#f1da7a")), + "electric pink" => Some(ColorU8::from_html(b"#ff0490")), + "muted purple" => Some(ColorU8::from_html(b"#805b87")), + "mid green" => Some(ColorU8::from_html(b"#50a747")), + "greyish" => Some(ColorU8::from_html(b"#a8a495")), + "neon yellow" => Some(ColorU8::from_html(b"#cfff04")), + "banana" => Some(ColorU8::from_html(b"#ffff7e")), + "carnation pink" => Some(ColorU8::from_html(b"#ff7fa7")), + "tomato" => Some(ColorU8::from_html(b"#ef4026")), + "sea" => Some(ColorU8::from_html(b"#3c9992")), + "muddy brown" => Some(ColorU8::from_html(b"#886806")), + "turquoise green" => Some(ColorU8::from_html(b"#04f489")), + "buff" => Some(ColorU8::from_html(b"#fef69e")), + "fawn" => Some(ColorU8::from_html(b"#cfaf7b")), + "muted blue" => Some(ColorU8::from_html(b"#3b719f")), + "pale rose" => Some(ColorU8::from_html(b"#fdc1c5")), + "dark mint green" => Some(ColorU8::from_html(b"#20c073")), + "amethyst" => Some(ColorU8::from_html(b"#9b5fc0")), + "blue/green" => Some(ColorU8::from_html(b"#0f9b8e")), + "chestnut" => Some(ColorU8::from_html(b"#742802")), + "sick green" => Some(ColorU8::from_html(b"#9db92c")), + "pea" => Some(ColorU8::from_html(b"#a4bf20")), + "rusty orange" => Some(ColorU8::from_html(b"#cd5909")), + "stone" => Some(ColorU8::from_html(b"#ada587")), + "rose red" => Some(ColorU8::from_html(b"#be013c")), + "pale aqua" => Some(ColorU8::from_html(b"#b8ffeb")), + "deep orange" => Some(ColorU8::from_html(b"#dc4d01")), + "earth" => Some(ColorU8::from_html(b"#a2653e")), + "mossy green" => Some(ColorU8::from_html(b"#638b27")), + "grassy green" => Some(ColorU8::from_html(b"#419c03")), + "pale lime green" => Some(ColorU8::from_html(b"#b1ff65")), + "light grey blue" => Some(ColorU8::from_html(b"#9dbcd4")), + "pale grey" => Some(ColorU8::from_html(b"#fdfdfe")), + "asparagus" => Some(ColorU8::from_html(b"#77ab56")), + "blueberry" => Some(ColorU8::from_html(b"#464196")), + "purple red" => Some(ColorU8::from_html(b"#990147")), + "pale lime" => Some(ColorU8::from_html(b"#befd73")), + "greenish teal" => Some(ColorU8::from_html(b"#32bf84")), + "caramel" => Some(ColorU8::from_html(b"#af6f09")), + "deep magenta" => Some(ColorU8::from_html(b"#a0025c")), + "light peach" => Some(ColorU8::from_html(b"#ffd8b1")), + "milk chocolate" => Some(ColorU8::from_html(b"#7f4e1e")), + "ocher" => Some(ColorU8::from_html(b"#bf9b0c")), + "off green" => Some(ColorU8::from_html(b"#6ba353")), + "purply pink" => Some(ColorU8::from_html(b"#f075e6")), + "lightblue" => Some(ColorU8::from_html(b"#7bc8f6")), + "dusky blue" => Some(ColorU8::from_html(b"#475f94")), + "golden" => Some(ColorU8::from_html(b"#f5bf03")), + "light beige" => Some(ColorU8::from_html(b"#fffeb6")), + "butter yellow" => Some(ColorU8::from_html(b"#fffd74")), + "dusky purple" => Some(ColorU8::from_html(b"#895b7b")), + "french blue" => Some(ColorU8::from_html(b"#436bad")), + "ugly yellow" => Some(ColorU8::from_html(b"#d0c101")), + "greeny yellow" => Some(ColorU8::from_html(b"#c6f808")), + "orangish red" => Some(ColorU8::from_html(b"#f43605")), + "shamrock green" => Some(ColorU8::from_html(b"#02c14d")), + "orangish brown" => Some(ColorU8::from_html(b"#b25f03")), + "tree green" => Some(ColorU8::from_html(b"#2a7e19")), + "deep violet" => Some(ColorU8::from_html(b"#490648")), + "gunmetal" => Some(ColorU8::from_html(b"#536267")), + "blue/purple" => Some(ColorU8::from_html(b"#5a06ef")), + "cherry" => Some(ColorU8::from_html(b"#cf0234")), + "sandy brown" => Some(ColorU8::from_html(b"#c4a661")), + "warm grey" => Some(ColorU8::from_html(b"#978a84")), + "dark indigo" => Some(ColorU8::from_html(b"#1f0954")), + "midnight" => Some(ColorU8::from_html(b"#03012d")), + "bluey green" => Some(ColorU8::from_html(b"#2bb179")), + "grey pink" => Some(ColorU8::from_html(b"#c3909b")), + "soft purple" => Some(ColorU8::from_html(b"#a66fb5")), + "blood" => Some(ColorU8::from_html(b"#770001")), + "brown red" => Some(ColorU8::from_html(b"#922b05")), + "medium grey" => Some(ColorU8::from_html(b"#7d7f7c")), + "berry" => Some(ColorU8::from_html(b"#990f4b")), + "poo" => Some(ColorU8::from_html(b"#8f7303")), + "purpley pink" => Some(ColorU8::from_html(b"#c83cb9")), + "light salmon" => Some(ColorU8::from_html(b"#fea993")), + "snot" => Some(ColorU8::from_html(b"#acbb0d")), + "easter purple" => Some(ColorU8::from_html(b"#c071fe")), + "light yellow green" => Some(ColorU8::from_html(b"#ccfd7f")), + "dark navy blue" => Some(ColorU8::from_html(b"#00022e")), + "drab" => Some(ColorU8::from_html(b"#828344")), + "light rose" => Some(ColorU8::from_html(b"#ffc5cb")), + "rouge" => Some(ColorU8::from_html(b"#ab1239")), + "purplish red" => Some(ColorU8::from_html(b"#b0054b")), + "slime green" => Some(ColorU8::from_html(b"#99cc04")), + "baby poop" => Some(ColorU8::from_html(b"#937c00")), + "irish green" => Some(ColorU8::from_html(b"#019529")), + "pink/purple" => Some(ColorU8::from_html(b"#ef1de7")), + "dark navy" => Some(ColorU8::from_html(b"#000435")), + "greeny blue" => Some(ColorU8::from_html(b"#42b395")), + "light plum" => Some(ColorU8::from_html(b"#9d5783")), + "pinkish grey" => Some(ColorU8::from_html(b"#c8aca9")), + "dirty orange" => Some(ColorU8::from_html(b"#c87606")), + "rust red" => Some(ColorU8::from_html(b"#aa2704")), + "pale lilac" => Some(ColorU8::from_html(b"#e4cbff")), + "orangey red" => Some(ColorU8::from_html(b"#fa4224")), + "primary blue" => Some(ColorU8::from_html(b"#0804f9")), + "kermit green" => Some(ColorU8::from_html(b"#5cb200")), + "brownish purple" => Some(ColorU8::from_html(b"#76424e")), + "murky green" => Some(ColorU8::from_html(b"#6c7a0e")), + "wheat" => Some(ColorU8::from_html(b"#fbdd7e")), + "very dark purple" => Some(ColorU8::from_html(b"#2a0134")), + "bottle green" => Some(ColorU8::from_html(b"#044a05")), + "watermelon" => Some(ColorU8::from_html(b"#fd4659")), + "deep sky blue" => Some(ColorU8::from_html(b"#0d75f8")), + "fire engine red" => Some(ColorU8::from_html(b"#fe0002")), + "yellow ochre" => Some(ColorU8::from_html(b"#cb9d06")), + "pumpkin orange" => Some(ColorU8::from_html(b"#fb7d07")), + "pale olive" => Some(ColorU8::from_html(b"#b9cc81")), + "light lilac" => Some(ColorU8::from_html(b"#edc8ff")), + "lightish green" => Some(ColorU8::from_html(b"#61e160")), + "carolina blue" => Some(ColorU8::from_html(b"#8ab8fe")), + "mulberry" => Some(ColorU8::from_html(b"#920a4e")), + "shocking pink" => Some(ColorU8::from_html(b"#fe02a2")), + "auburn" => Some(ColorU8::from_html(b"#9a3001")), + "bright lime green" => Some(ColorU8::from_html(b"#65fe08")), + "celadon" => Some(ColorU8::from_html(b"#befdb7")), + "pinkish brown" => Some(ColorU8::from_html(b"#b17261")), + "poo brown" => Some(ColorU8::from_html(b"#885f01")), + "bright sky blue" => Some(ColorU8::from_html(b"#02ccfe")), + "celery" => Some(ColorU8::from_html(b"#c1fd95")), + "dirt brown" => Some(ColorU8::from_html(b"#836539")), + "strawberry" => Some(ColorU8::from_html(b"#fb2943")), + "dark lime" => Some(ColorU8::from_html(b"#84b701")), + "copper" => Some(ColorU8::from_html(b"#b66325")), + "medium brown" => Some(ColorU8::from_html(b"#7f5112")), + "muted green" => Some(ColorU8::from_html(b"#5fa052")), + "robin's egg" => Some(ColorU8::from_html(b"#6dedfd")), + "bright aqua" => Some(ColorU8::from_html(b"#0bf9ea")), + "bright lavender" => Some(ColorU8::from_html(b"#c760ff")), + "ivory" => Some(ColorU8::from_html(b"#ffffcb")), + "very light purple" => Some(ColorU8::from_html(b"#f6cefc")), + "light navy" => Some(ColorU8::from_html(b"#155084")), + "pink red" => Some(ColorU8::from_html(b"#f5054f")), + "olive brown" => Some(ColorU8::from_html(b"#645403")), + "poop brown" => Some(ColorU8::from_html(b"#7a5901")), + "mustard green" => Some(ColorU8::from_html(b"#a8b504")), + "ocean green" => Some(ColorU8::from_html(b"#3d9973")), + "very dark blue" => Some(ColorU8::from_html(b"#000133")), + "dusty green" => Some(ColorU8::from_html(b"#76a973")), + "light navy blue" => Some(ColorU8::from_html(b"#2e5a88")), + "minty green" => Some(ColorU8::from_html(b"#0bf77d")), + "adobe" => Some(ColorU8::from_html(b"#bd6c48")), + "barney" => Some(ColorU8::from_html(b"#ac1db8")), + "jade green" => Some(ColorU8::from_html(b"#2baf6a")), + "bright light blue" => Some(ColorU8::from_html(b"#26f7fd")), + "light lime" => Some(ColorU8::from_html(b"#aefd6c")), + "dark khaki" => Some(ColorU8::from_html(b"#9b8f55")), + "orange yellow" => Some(ColorU8::from_html(b"#ffad01")), + "ocre" => Some(ColorU8::from_html(b"#c69c04")), + "maize" => Some(ColorU8::from_html(b"#f4d054")), + "faded pink" => Some(ColorU8::from_html(b"#de9dac")), + "british racing green" => Some(ColorU8::from_html(b"#05480d")), + "sandstone" => Some(ColorU8::from_html(b"#c9ae74")), + "mud brown" => Some(ColorU8::from_html(b"#60460f")), + "light sea green" => Some(ColorU8::from_html(b"#98f6b0")), + "robin egg blue" => Some(ColorU8::from_html(b"#8af1fe")), + "aqua marine" => Some(ColorU8::from_html(b"#2ee8bb")), + "dark sea green" => Some(ColorU8::from_html(b"#11875d")), + "soft pink" => Some(ColorU8::from_html(b"#fdb0c0")), + "orangey brown" => Some(ColorU8::from_html(b"#b16002")), + "cherry red" => Some(ColorU8::from_html(b"#f7022a")), + "burnt yellow" => Some(ColorU8::from_html(b"#d5ab09")), + "brownish grey" => Some(ColorU8::from_html(b"#86775f")), + "camel" => Some(ColorU8::from_html(b"#c69f59")), + "purplish grey" => Some(ColorU8::from_html(b"#7a687f")), + "marine" => Some(ColorU8::from_html(b"#042e60")), + "greyish pink" => Some(ColorU8::from_html(b"#c88d94")), + "pale turquoise" => Some(ColorU8::from_html(b"#a5fbd5")), + "pastel yellow" => Some(ColorU8::from_html(b"#fffe71")), + "bluey purple" => Some(ColorU8::from_html(b"#6241c7")), + "canary yellow" => Some(ColorU8::from_html(b"#fffe40")), + "faded red" => Some(ColorU8::from_html(b"#d3494e")), + "sepia" => Some(ColorU8::from_html(b"#985e2b")), + "coffee" => Some(ColorU8::from_html(b"#a6814c")), + "bright magenta" => Some(ColorU8::from_html(b"#ff08e8")), + "mocha" => Some(ColorU8::from_html(b"#9d7651")), + "ecru" => Some(ColorU8::from_html(b"#feffca")), + "purpleish" => Some(ColorU8::from_html(b"#98568d")), + "cranberry" => Some(ColorU8::from_html(b"#9e003a")), + "darkish green" => Some(ColorU8::from_html(b"#287c37")), + "brown orange" => Some(ColorU8::from_html(b"#b96902")), + "dusky rose" => Some(ColorU8::from_html(b"#ba6873")), + "melon" => Some(ColorU8::from_html(b"#ff7855")), + "sickly green" => Some(ColorU8::from_html(b"#94b21c")), + "silver" => Some(ColorU8::from_html(b"#c5c9c7")), + "purply blue" => Some(ColorU8::from_html(b"#661aee")), + "purpleish blue" => Some(ColorU8::from_html(b"#6140ef")), + "hospital green" => Some(ColorU8::from_html(b"#9be5aa")), + "shit brown" => Some(ColorU8::from_html(b"#7b5804")), + "mid blue" => Some(ColorU8::from_html(b"#276ab3")), + "amber" => Some(ColorU8::from_html(b"#feb308")), + "easter green" => Some(ColorU8::from_html(b"#8cfd7e")), + "soft blue" => Some(ColorU8::from_html(b"#6488ea")), + "cerulean blue" => Some(ColorU8::from_html(b"#056eee")), + "golden brown" => Some(ColorU8::from_html(b"#b27a01")), + "bright turquoise" => Some(ColorU8::from_html(b"#0ffef9")), + "red pink" => Some(ColorU8::from_html(b"#fa2a55")), + "red purple" => Some(ColorU8::from_html(b"#820747")), + "greyish brown" => Some(ColorU8::from_html(b"#7a6a4f")), + "vermillion" => Some(ColorU8::from_html(b"#f4320c")), + "russet" => Some(ColorU8::from_html(b"#a13905")), + "steel grey" => Some(ColorU8::from_html(b"#6f828a")), + "lighter purple" => Some(ColorU8::from_html(b"#a55af4")), + "bright violet" => Some(ColorU8::from_html(b"#ad0afd")), + "prussian blue" => Some(ColorU8::from_html(b"#004577")), + "slate green" => Some(ColorU8::from_html(b"#658d6d")), + "dirty pink" => Some(ColorU8::from_html(b"#ca7b80")), + "dark blue green" => Some(ColorU8::from_html(b"#005249")), + "pine" => Some(ColorU8::from_html(b"#2b5d34")), + "yellowy green" => Some(ColorU8::from_html(b"#bff128")), + "dark gold" => Some(ColorU8::from_html(b"#b59410")), + "bluish" => Some(ColorU8::from_html(b"#2976bb")), + "darkish blue" => Some(ColorU8::from_html(b"#014182")), + "dull red" => Some(ColorU8::from_html(b"#bb3f3f")), + "pinky red" => Some(ColorU8::from_html(b"#fc2647")), + "bronze" => Some(ColorU8::from_html(b"#a87900")), + "pale teal" => Some(ColorU8::from_html(b"#82cbb2")), + "military green" => Some(ColorU8::from_html(b"#667c3e")), + "barbie pink" => Some(ColorU8::from_html(b"#fe46a5")), + "bubblegum pink" => Some(ColorU8::from_html(b"#fe83cc")), + "pea soup green" => Some(ColorU8::from_html(b"#94a617")), + "dark mustard" => Some(ColorU8::from_html(b"#a88905")), + "shit" => Some(ColorU8::from_html(b"#7f5f00")), + "medium purple" => Some(ColorU8::from_html(b"#9e43a2")), + "very dark green" => Some(ColorU8::from_html(b"#062e03")), + "dirt" => Some(ColorU8::from_html(b"#8a6e45")), + "dusky pink" => Some(ColorU8::from_html(b"#cc7a8b")), + "red violet" => Some(ColorU8::from_html(b"#9e0168")), + "lemon yellow" => Some(ColorU8::from_html(b"#fdff38")), + "pistachio" => Some(ColorU8::from_html(b"#c0fa8b")), + "dull yellow" => Some(ColorU8::from_html(b"#eedc5b")), + "dark lime green" => Some(ColorU8::from_html(b"#7ebd01")), + "denim blue" => Some(ColorU8::from_html(b"#3b5b92")), + "teal blue" => Some(ColorU8::from_html(b"#01889f")), + "lightish blue" => Some(ColorU8::from_html(b"#3d7afd")), + "purpley blue" => Some(ColorU8::from_html(b"#5f34e7")), + "light indigo" => Some(ColorU8::from_html(b"#6d5acf")), + "swamp green" => Some(ColorU8::from_html(b"#748500")), + "brown green" => Some(ColorU8::from_html(b"#706c11")), + "dark maroon" => Some(ColorU8::from_html(b"#3c0008")), + "hot purple" => Some(ColorU8::from_html(b"#cb00f5")), + "dark forest green" => Some(ColorU8::from_html(b"#002d04")), + "faded blue" => Some(ColorU8::from_html(b"#658cbb")), + "drab green" => Some(ColorU8::from_html(b"#749551")), + "light lime green" => Some(ColorU8::from_html(b"#b9ff66")), + "snot green" => Some(ColorU8::from_html(b"#9dc100")), + "yellowish" => Some(ColorU8::from_html(b"#faee66")), + "light blue green" => Some(ColorU8::from_html(b"#7efbb3")), + "bordeaux" => Some(ColorU8::from_html(b"#7b002c")), + "light mauve" => Some(ColorU8::from_html(b"#c292a1")), + "ocean" => Some(ColorU8::from_html(b"#017b92")), + "marigold" => Some(ColorU8::from_html(b"#fcc006")), + "muddy green" => Some(ColorU8::from_html(b"#657432")), + "dull orange" => Some(ColorU8::from_html(b"#d8863b")), + "steel" => Some(ColorU8::from_html(b"#738595")), + "electric purple" => Some(ColorU8::from_html(b"#aa23ff")), + "fluorescent green" => Some(ColorU8::from_html(b"#08ff08")), + "yellowish brown" => Some(ColorU8::from_html(b"#9b7a01")), + "blush" => Some(ColorU8::from_html(b"#f29e8e")), + "soft green" => Some(ColorU8::from_html(b"#6fc276")), + "bright orange" => Some(ColorU8::from_html(b"#ff5b00")), + "lemon" => Some(ColorU8::from_html(b"#fdff52")), + "purple grey" => Some(ColorU8::from_html(b"#866f85")), + "acid green" => Some(ColorU8::from_html(b"#8ffe09")), + "pale lavender" => Some(ColorU8::from_html(b"#eecffe")), + "violet blue" => Some(ColorU8::from_html(b"#510ac9")), + "light forest green" => Some(ColorU8::from_html(b"#4f9153")), + "burnt red" => Some(ColorU8::from_html(b"#9f2305")), + "khaki green" => Some(ColorU8::from_html(b"#728639")), + "cerise" => Some(ColorU8::from_html(b"#de0c62")), + "faded purple" => Some(ColorU8::from_html(b"#916e99")), + "apricot" => Some(ColorU8::from_html(b"#ffb16d")), + "dark olive green" => Some(ColorU8::from_html(b"#3c4d03")), + "grey brown" => Some(ColorU8::from_html(b"#7f7053")), + "green grey" => Some(ColorU8::from_html(b"#77926f")), + "true blue" => Some(ColorU8::from_html(b"#010fcc")), + "pale violet" => Some(ColorU8::from_html(b"#ceaefa")), + "periwinkle blue" => Some(ColorU8::from_html(b"#8f99fb")), + "light sky blue" => Some(ColorU8::from_html(b"#c6fcff")), + "blurple" => Some(ColorU8::from_html(b"#5539cc")), + "green brown" => Some(ColorU8::from_html(b"#544e03")), + "bluegreen" => Some(ColorU8::from_html(b"#017a79")), + "bright teal" => Some(ColorU8::from_html(b"#01f9c6")), + "brownish yellow" => Some(ColorU8::from_html(b"#c9b003")), + "pea soup" => Some(ColorU8::from_html(b"#929901")), + "forest" => Some(ColorU8::from_html(b"#0b5509")), + "barney purple" => Some(ColorU8::from_html(b"#a00498")), + "ultramarine" => Some(ColorU8::from_html(b"#2000b1")), + "purplish" => Some(ColorU8::from_html(b"#94568c")), + "puke yellow" => Some(ColorU8::from_html(b"#c2be0e")), + "bluish grey" => Some(ColorU8::from_html(b"#748b97")), + "dark periwinkle" => Some(ColorU8::from_html(b"#665fd1")), + "dark lilac" => Some(ColorU8::from_html(b"#9c6da5")), + "reddish" => Some(ColorU8::from_html(b"#c44240")), + "light maroon" => Some(ColorU8::from_html(b"#a24857")), + "dusty purple" => Some(ColorU8::from_html(b"#825f87")), + "terra cotta" => Some(ColorU8::from_html(b"#c9643b")), + "avocado" => Some(ColorU8::from_html(b"#90b134")), + "marine blue" => Some(ColorU8::from_html(b"#01386a")), + "teal green" => Some(ColorU8::from_html(b"#25a36f")), + "slate grey" => Some(ColorU8::from_html(b"#59656d")), + "lighter green" => Some(ColorU8::from_html(b"#75fd63")), + "electric green" => Some(ColorU8::from_html(b"#21fc0d")), + "dusty blue" => Some(ColorU8::from_html(b"#5a86ad")), + "golden yellow" => Some(ColorU8::from_html(b"#fec615")), + "bright yellow" => Some(ColorU8::from_html(b"#fffd01")), + "light lavender" => Some(ColorU8::from_html(b"#dfc5fe")), + "umber" => Some(ColorU8::from_html(b"#b26400")), + "poop" => Some(ColorU8::from_html(b"#7f5e00")), + "dark peach" => Some(ColorU8::from_html(b"#de7e5d")), + "jungle green" => Some(ColorU8::from_html(b"#048243")), + "eggshell" => Some(ColorU8::from_html(b"#ffffd4")), + "denim" => Some(ColorU8::from_html(b"#3b638c")), + "yellow brown" => Some(ColorU8::from_html(b"#b79400")), + "dull purple" => Some(ColorU8::from_html(b"#84597e")), + "chocolate brown" => Some(ColorU8::from_html(b"#411900")), + "wine red" => Some(ColorU8::from_html(b"#7b0323")), + "neon blue" => Some(ColorU8::from_html(b"#04d9ff")), + "dirty green" => Some(ColorU8::from_html(b"#667e2c")), + "light tan" => Some(ColorU8::from_html(b"#fbeeac")), + "ice blue" => Some(ColorU8::from_html(b"#d7fffe")), + "cadet blue" => Some(ColorU8::from_html(b"#4e7496")), + "dark mauve" => Some(ColorU8::from_html(b"#874c62")), + "very light blue" => Some(ColorU8::from_html(b"#d5ffff")), + "grey purple" => Some(ColorU8::from_html(b"#826d8c")), + "pastel pink" => Some(ColorU8::from_html(b"#ffbacd")), + "very light green" => Some(ColorU8::from_html(b"#d1ffbd")), + "dark sky blue" => Some(ColorU8::from_html(b"#448ee4")), + "evergreen" => Some(ColorU8::from_html(b"#05472a")), + "dull pink" => Some(ColorU8::from_html(b"#d5869d")), + "aubergine" => Some(ColorU8::from_html(b"#3d0734")), + "mahogany" => Some(ColorU8::from_html(b"#4a0100")), + "reddish orange" => Some(ColorU8::from_html(b"#f8481c")), + "deep green" => Some(ColorU8::from_html(b"#02590f")), + "vomit green" => Some(ColorU8::from_html(b"#89a203")), + "purple pink" => Some(ColorU8::from_html(b"#e03fd8")), + "dusty pink" => Some(ColorU8::from_html(b"#d58a94")), + "faded green" => Some(ColorU8::from_html(b"#7bb274")), + "camo green" => Some(ColorU8::from_html(b"#526525")), + "pinky purple" => Some(ColorU8::from_html(b"#c94cbe")), + "pink purple" => Some(ColorU8::from_html(b"#db4bda")), + "brownish red" => Some(ColorU8::from_html(b"#9e3623")), + "dark rose" => Some(ColorU8::from_html(b"#b5485d")), + "mud" => Some(ColorU8::from_html(b"#735c12")), + "brownish" => Some(ColorU8::from_html(b"#9c6d57")), + "emerald green" => Some(ColorU8::from_html(b"#028f1e")), + "pale brown" => Some(ColorU8::from_html(b"#b1916e")), + "dull blue" => Some(ColorU8::from_html(b"#49759c")), + "burnt umber" => Some(ColorU8::from_html(b"#a0450e")), + "medium green" => Some(ColorU8::from_html(b"#39ad48")), + "clay" => Some(ColorU8::from_html(b"#b66a50")), + "light aqua" => Some(ColorU8::from_html(b"#8cffdb")), + "light olive green" => Some(ColorU8::from_html(b"#a4be5c")), + "brownish orange" => Some(ColorU8::from_html(b"#cb7723")), + "dark aqua" => Some(ColorU8::from_html(b"#05696b")), + "purplish pink" => Some(ColorU8::from_html(b"#ce5dae")), + "dark salmon" => Some(ColorU8::from_html(b"#c85a53")), + "greenish grey" => Some(ColorU8::from_html(b"#96ae8d")), + "jade" => Some(ColorU8::from_html(b"#1fa774")), + "ugly green" => Some(ColorU8::from_html(b"#7a9703")), + "dark beige" => Some(ColorU8::from_html(b"#ac9362")), + "emerald" => Some(ColorU8::from_html(b"#01a049")), + "pale red" => Some(ColorU8::from_html(b"#d9544d")), + "light magenta" => Some(ColorU8::from_html(b"#fa5ff7")), + "sky" => Some(ColorU8::from_html(b"#82cafc")), + "light cyan" => Some(ColorU8::from_html(b"#acfffc")), + "yellow orange" => Some(ColorU8::from_html(b"#fcb001")), + "reddish purple" => Some(ColorU8::from_html(b"#910951")), + "reddish pink" => Some(ColorU8::from_html(b"#fe2c54")), + "orchid" => Some(ColorU8::from_html(b"#c875c4")), + "dirty yellow" => Some(ColorU8::from_html(b"#cdc50a")), + "orange red" => Some(ColorU8::from_html(b"#fd411e")), + "deep red" => Some(ColorU8::from_html(b"#9a0200")), + "orange brown" => Some(ColorU8::from_html(b"#be6400")), + "cobalt blue" => Some(ColorU8::from_html(b"#030aa7")), + "neon pink" => Some(ColorU8::from_html(b"#fe019a")), + "rose pink" => Some(ColorU8::from_html(b"#f7879a")), + "greyish purple" => Some(ColorU8::from_html(b"#887191")), + "raspberry" => Some(ColorU8::from_html(b"#b00149")), + "aqua green" => Some(ColorU8::from_html(b"#12e193")), + "salmon pink" => Some(ColorU8::from_html(b"#fe7b7c")), + "tangerine" => Some(ColorU8::from_html(b"#ff9408")), + "brownish green" => Some(ColorU8::from_html(b"#6a6e09")), + "red brown" => Some(ColorU8::from_html(b"#8b2e16")), + "greenish brown" => Some(ColorU8::from_html(b"#696112")), + "pumpkin" => Some(ColorU8::from_html(b"#e17701")), + "pine green" => Some(ColorU8::from_html(b"#0a481e")), + "charcoal" => Some(ColorU8::from_html(b"#343837")), + "baby pink" => Some(ColorU8::from_html(b"#ffb7ce")), + "cornflower" => Some(ColorU8::from_html(b"#6a79f7")), + "blue violet" => Some(ColorU8::from_html(b"#5d06e9")), + "chocolate" => Some(ColorU8::from_html(b"#3d1c02")), + "greyish green" => Some(ColorU8::from_html(b"#82a67d")), + "scarlet" => Some(ColorU8::from_html(b"#be0119")), + "green yellow" => Some(ColorU8::from_html(b"#c9ff27")), + "dark olive" => Some(ColorU8::from_html(b"#373e02")), + "sienna" => Some(ColorU8::from_html(b"#a9561e")), + "pastel purple" => Some(ColorU8::from_html(b"#caa0ff")), + "terracotta" => Some(ColorU8::from_html(b"#ca6641")), + "aqua blue" => Some(ColorU8::from_html(b"#02d8e9")), + "sage green" => Some(ColorU8::from_html(b"#88b378")), + "blood red" => Some(ColorU8::from_html(b"#980002")), + "deep pink" => Some(ColorU8::from_html(b"#cb0162")), + "grass" => Some(ColorU8::from_html(b"#5cac2d")), + "moss" => Some(ColorU8::from_html(b"#769958")), + "pastel blue" => Some(ColorU8::from_html(b"#a2bffe")), + "bluish green" => Some(ColorU8::from_html(b"#10a674")), + "green blue" => Some(ColorU8::from_html(b"#06b48b")), + "dark tan" => Some(ColorU8::from_html(b"#af884a")), + "greenish blue" => Some(ColorU8::from_html(b"#0b8b87")), + "pale orange" => Some(ColorU8::from_html(b"#ffa756")), + "vomit" => Some(ColorU8::from_html(b"#a2a415")), + "forrest green" => Some(ColorU8::from_html(b"#154406")), + "dark lavender" => Some(ColorU8::from_html(b"#856798")), + "dark violet" => Some(ColorU8::from_html(b"#34013f")), + "purple blue" => Some(ColorU8::from_html(b"#632de9")), + "dark cyan" => Some(ColorU8::from_html(b"#0a888a")), + "olive drab" => Some(ColorU8::from_html(b"#6f7632")), + "pinkish" => Some(ColorU8::from_html(b"#d46a7e")), + "cobalt" => Some(ColorU8::from_html(b"#1e488f")), + "neon purple" => Some(ColorU8::from_html(b"#bc13fe")), + "light turquoise" => Some(ColorU8::from_html(b"#7ef4cc")), + "apple green" => Some(ColorU8::from_html(b"#76cd26")), + "dull green" => Some(ColorU8::from_html(b"#74a662")), + "wine" => Some(ColorU8::from_html(b"#80013f")), + "powder blue" => Some(ColorU8::from_html(b"#b1d1fc")), + "off white" => Some(ColorU8::from_html(b"#ffffe4")), + "electric blue" => Some(ColorU8::from_html(b"#0652ff")), + "dark turquoise" => Some(ColorU8::from_html(b"#045c5a")), + "blue purple" => Some(ColorU8::from_html(b"#5729ce")), + "azure" => Some(ColorU8::from_html(b"#069af3")), + "bright red" => Some(ColorU8::from_html(b"#ff000d")), + "pinkish red" => Some(ColorU8::from_html(b"#f10c45")), + "cornflower blue" => Some(ColorU8::from_html(b"#5170d7")), + "light olive" => Some(ColorU8::from_html(b"#acbf69")), + "grape" => Some(ColorU8::from_html(b"#6c3461")), + "greyish blue" => Some(ColorU8::from_html(b"#5e819d")), + "purplish blue" => Some(ColorU8::from_html(b"#601ef9")), + "yellowish green" => Some(ColorU8::from_html(b"#b0dd16")), + "greenish yellow" => Some(ColorU8::from_html(b"#cdfd02")), + "medium blue" => Some(ColorU8::from_html(b"#2c6fbb")), + "dusty rose" => Some(ColorU8::from_html(b"#c0737a")), + "light violet" => Some(ColorU8::from_html(b"#d6b4fc")), + "midnight blue" => Some(ColorU8::from_html(b"#020035")), + "bluish purple" => Some(ColorU8::from_html(b"#703be7")), + "red orange" => Some(ColorU8::from_html(b"#fd3c06")), + "dark magenta" => Some(ColorU8::from_html(b"#960056")), + "greenish" => Some(ColorU8::from_html(b"#40a368")), + "ocean blue" => Some(ColorU8::from_html(b"#03719c")), + "coral" => Some(ColorU8::from_html(b"#fc5a50")), + "cream" => Some(ColorU8::from_html(b"#ffffc2")), + "reddish brown" => Some(ColorU8::from_html(b"#7f2b0a")), + "burnt sienna" => Some(ColorU8::from_html(b"#b04e0f")), + "brick" => Some(ColorU8::from_html(b"#a03623")), + "sage" => Some(ColorU8::from_html(b"#87ae73")), + "grey green" => Some(ColorU8::from_html(b"#789b73")), + "white" => Some(ColorU8::from_html(b"#ffffff")), + "robin's egg blue" => Some(ColorU8::from_html(b"#98eff9")), + "moss green" => Some(ColorU8::from_html(b"#658b38")), + "steel blue" => Some(ColorU8::from_html(b"#5a7d9a")), + "eggplant" => Some(ColorU8::from_html(b"#380835")), + "light yellow" => Some(ColorU8::from_html(b"#fffe7a")), + "leaf green" => Some(ColorU8::from_html(b"#5ca904")), + "light grey" => Some(ColorU8::from_html(b"#d8dcd6")), + "puke" => Some(ColorU8::from_html(b"#a5a502")), + "pinkish purple" => Some(ColorU8::from_html(b"#d648d7")), + "sea blue" => Some(ColorU8::from_html(b"#047495")), + "pale purple" => Some(ColorU8::from_html(b"#b790d4")), + "slate blue" => Some(ColorU8::from_html(b"#5b7c99")), + "blue grey" => Some(ColorU8::from_html(b"#607c8e")), + "hunter green" => Some(ColorU8::from_html(b"#0b4008")), + "fuchsia" => Some(ColorU8::from_html(b"#ed0dd9")), + "crimson" => Some(ColorU8::from_html(b"#8c000f")), + "pale yellow" => Some(ColorU8::from_html(b"#ffff84")), + "ochre" => Some(ColorU8::from_html(b"#bf9005")), + "mustard yellow" => Some(ColorU8::from_html(b"#d2bd0a")), + "light red" => Some(ColorU8::from_html(b"#ff474c")), + "cerulean" => Some(ColorU8::from_html(b"#0485d1")), + "pale pink" => Some(ColorU8::from_html(b"#ffcfdc")), + "deep blue" => Some(ColorU8::from_html(b"#040273")), + "rust" => Some(ColorU8::from_html(b"#a83c09")), + "light teal" => Some(ColorU8::from_html(b"#90e4c1")), + "slate" => Some(ColorU8::from_html(b"#516572")), + "goldenrod" => Some(ColorU8::from_html(b"#fac205")), + "dark yellow" => Some(ColorU8::from_html(b"#d5b60a")), + "dark grey" => Some(ColorU8::from_html(b"#363737")), + "army green" => Some(ColorU8::from_html(b"#4b5d16")), + "grey blue" => Some(ColorU8::from_html(b"#6b8ba4")), + "seafoam" => Some(ColorU8::from_html(b"#80f9ad")), + "puce" => Some(ColorU8::from_html(b"#a57e52")), + "spring green" => Some(ColorU8::from_html(b"#a9f971")), + "dark orange" => Some(ColorU8::from_html(b"#c65102")), + "sand" => Some(ColorU8::from_html(b"#e2ca76")), + "pastel green" => Some(ColorU8::from_html(b"#b0ff9d")), + "mint" => Some(ColorU8::from_html(b"#9ffeb0")), + "light orange" => Some(ColorU8::from_html(b"#fdaa48")), + "bright pink" => Some(ColorU8::from_html(b"#fe01b1")), + "chartreuse" => Some(ColorU8::from_html(b"#c1f80a")), + "deep purple" => Some(ColorU8::from_html(b"#36013f")), + "dark brown" => Some(ColorU8::from_html(b"#341c02")), + "taupe" => Some(ColorU8::from_html(b"#b9a281")), + "pea green" => Some(ColorU8::from_html(b"#8eab12")), + "puke green" => Some(ColorU8::from_html(b"#9aae07")), + "kelly green" => Some(ColorU8::from_html(b"#02ab2e")), + "seafoam green" => Some(ColorU8::from_html(b"#7af9ab")), + "blue green" => Some(ColorU8::from_html(b"#137e6d")), + "khaki" => Some(ColorU8::from_html(b"#aaa662")), + "burgundy" => Some(ColorU8::from_html(b"#610023")), + "dark teal" => Some(ColorU8::from_html(b"#014d4e")), + "brick red" => Some(ColorU8::from_html(b"#8f1402")), + "royal purple" => Some(ColorU8::from_html(b"#4b006e")), + "plum" => Some(ColorU8::from_html(b"#580f41")), + "mint green" => Some(ColorU8::from_html(b"#8fff9f")), + "gold" => Some(ColorU8::from_html(b"#dbb40c")), + "baby blue" => Some(ColorU8::from_html(b"#a2cffe")), + "yellow green" => Some(ColorU8::from_html(b"#c0fb2d")), + "bright purple" => Some(ColorU8::from_html(b"#be03fd")), + "dark red" => Some(ColorU8::from_html(b"#840000")), + "pale blue" => Some(ColorU8::from_html(b"#d0fefe")), + "grass green" => Some(ColorU8::from_html(b"#3f9b0b")), + "navy" => Some(ColorU8::from_html(b"#01153e")), + "aquamarine" => Some(ColorU8::from_html(b"#04d8b2")), + "burnt orange" => Some(ColorU8::from_html(b"#c04e01")), + "neon green" => Some(ColorU8::from_html(b"#0cff0c")), + "bright blue" => Some(ColorU8::from_html(b"#0165fc")), + "rose" => Some(ColorU8::from_html(b"#cf6275")), + "light pink" => Some(ColorU8::from_html(b"#ffd1df")), + "mustard" => Some(ColorU8::from_html(b"#ceb301")), + "indigo" => Some(ColorU8::from_html(b"#380282")), + "lime" => Some(ColorU8::from_html(b"#aaff32")), + "sea green" => Some(ColorU8::from_html(b"#53fca1")), + "periwinkle" => Some(ColorU8::from_html(b"#8e82fe")), + "dark pink" => Some(ColorU8::from_html(b"#cb416b")), + "olive green" => Some(ColorU8::from_html(b"#677a04")), + "peach" => Some(ColorU8::from_html(b"#ffb07c")), + "pale green" => Some(ColorU8::from_html(b"#c7fdb5")), + "light brown" => Some(ColorU8::from_html(b"#ad8150")), + "hot pink" => Some(ColorU8::from_html(b"#ff028d")), + "black" => Some(ColorU8::from_html(b"#000000")), + "lilac" => Some(ColorU8::from_html(b"#cea2fd")), + "navy blue" => Some(ColorU8::from_html(b"#001146")), + "royal blue" => Some(ColorU8::from_html(b"#0504aa")), + "beige" => Some(ColorU8::from_html(b"#e6daa6")), + "salmon" => Some(ColorU8::from_html(b"#ff796c")), + "olive" => Some(ColorU8::from_html(b"#6e750e")), + "maroon" => Some(ColorU8::from_html(b"#650021")), + "bright green" => Some(ColorU8::from_html(b"#01ff07")), + "dark purple" => Some(ColorU8::from_html(b"#35063e")), + "mauve" => Some(ColorU8::from_html(b"#ae7181")), + "forest green" => Some(ColorU8::from_html(b"#06470c")), + "aqua" => Some(ColorU8::from_html(b"#13eac9")), + "cyan" => Some(ColorU8::from_html(b"#00ffff")), + "tan" => Some(ColorU8::from_html(b"#d1b26f")), + "dark blue" => Some(ColorU8::from_html(b"#00035b")), + "lavender" => Some(ColorU8::from_html(b"#c79fef")), + "turquoise" => Some(ColorU8::from_html(b"#06c2ac")), + "dark green" => Some(ColorU8::from_html(b"#033500")), + "violet" => Some(ColorU8::from_html(b"#9a0eea")), + "light purple" => Some(ColorU8::from_html(b"#bf77f6")), + "lime green" => Some(ColorU8::from_html(b"#89fe05")), + "grey" => Some(ColorU8::from_html(b"#929591")), + "sky blue" => Some(ColorU8::from_html(b"#75bbfd")), + "yellow" => Some(ColorU8::from_html(b"#ffff14")), + "magenta" => Some(ColorU8::from_html(b"#c20078")), + "light green" => Some(ColorU8::from_html(b"#96f97b")), + "orange" => Some(ColorU8::from_html(b"#f97306")), + "teal" => Some(ColorU8::from_html(b"#029386")), + "light blue" => Some(ColorU8::from_html(b"#95d0fc")), + "red" => Some(ColorU8::from_html(b"#e50000")), + "brown" => Some(ColorU8::from_html(b"#653700")), + "pink" => Some(ColorU8::from_html(b"#ff81c0")), + "blue" => Some(ColorU8::from_html(b"#0343df")), + "green" => Some(ColorU8::from_html(b"#15b01a")), + "purple" => Some(ColorU8::from_html(b"#7e1e9c")), + _ => None, + } +} diff --git a/examples/gauss.rs b/examples/gauss.rs index da5c76e..1d40331 100644 --- a/examples/gauss.rs +++ b/examples/gauss.rs @@ -51,7 +51,7 @@ fn main() { let dist_series = des::Series::Line( des::series::Line::new(x.into(), y.into()) .with_name("distribution") - .with_line(style::series::Stroke { + .with_stroke(style::series::Stroke { width: 4.0, ..style::Stroke::default() }), diff --git a/examples/polars_sine.rs b/examples/polars_sine.rs index 1ef5d70..9ad1a94 100644 --- a/examples/polars_sine.rs +++ b/examples/polars_sine.rs @@ -27,7 +27,7 @@ fn main() { let series = des::Series::Line( des::series::Line::new(des::data_src_ref("x"), des::data_src_ref("y")) .with_name("y=sin(x)") - .with_line(style::series::Stroke::default().with_width(4.0)), + .with_stroke(style::series::Stroke::default().with_width(4.0)), ); let plot = des::Plot::new(vec![series]) diff --git a/examples/sine.rs b/examples/sine.rs index 64a58f2..e3fefa7 100644 --- a/examples/sine.rs +++ b/examples/sine.rs @@ -7,7 +7,7 @@ mod common; fn main() { let fig = des::series::Line::new(des::data_src_ref("x"), des::data_src_ref("y")) .with_name("y=sin(x)") - .with_line(style::series::Stroke::default().with_width(4.0)) + .with_stroke(style::series::Stroke::default().with_width(4.0)) .into_plot() .with_x_axis( des::Axis::new() diff --git a/iced/examples/scope.rs b/iced/examples/scope.rs index 8886a96..63c53d0 100644 --- a/iced/examples/scope.rs +++ b/iced/examples/scope.rs @@ -134,7 +134,7 @@ fn build_figure() -> des::Figure { des::DataCol::SrcRef("y".to_string()), ) .with_name("y=sin(x)".to_string()) - .with_line(style::series::Stroke::default().with_width(2.0)), + .with_stroke(style::series::Stroke::default().with_width(2.0)), ); let plot = des::Plot::new(vec![series]) diff --git a/run_all_examples.sh b/run_all_examples.sh index 8b43e6a..5aa1dde 100755 --- a/run_all_examples.sh +++ b/run_all_examples.sh @@ -23,6 +23,7 @@ done cargo run --example text_line --package plotive-text --features noto-sans cargo run --example text_rich --package plotive-text --features noto-sans,noto-serif +cargo run --example area -- ${POS_ARGS[@]} cargo run --example bars -- ${POS_ARGS[@]} cargo run --example gauss -- ${POS_ARGS[@]} cargo run --example sine -- ${POS_ARGS[@]} diff --git a/src/des/series.rs b/src/des/series.rs index 17cfeb6..6d84273 100644 --- a/src/des/series.rs +++ b/src/des/series.rs @@ -184,6 +184,7 @@ pub struct Line { x_axis: axis::Ref, y_axis: axis::Ref, stroke: style::series::Stroke, + marker: Option, interpolation: Interpolation, } @@ -198,6 +199,7 @@ impl Line { x_axis: Default::default(), y_axis: Default::default(), stroke: style::series::Stroke::default().with_width(defaults::SERIES_LINE_WIDTH), + marker: None, interpolation: Interpolation::default(), } } @@ -225,8 +227,14 @@ impl Line { } /// Set the line style and return self for chaining - pub fn with_line(mut self, line: style::series::Stroke) -> Self { - self.stroke = line; + pub fn with_stroke(mut self, stroke: style::series::Stroke) -> Self { + self.stroke = stroke; + self + } + + /// Set the marker style and return self for chaining + pub fn with_marker(mut self, marker: style::series::Marker) -> Self { + self.marker = Some(marker); self } @@ -266,6 +274,11 @@ impl Line { &self.stroke } + /// Get the marker style, if any + pub fn marker(&self) -> Option<&style::series::Marker> { + self.marker.as_ref() + } + /// Chaining helper to build a plot from this series /// This can only be used if your plot contains a single series. /// This is equivalent to `Plot::new(vec![self.into()])` @@ -298,6 +311,13 @@ impl Line { /// /// Plots data as individual scatter points without connecting them. /// Useful for visualizing correlations, distributions, and discrete data points. +/// +/// Optional sizes data column can be used to specify the size of each marker, for bubble charts. +/// If provided, the size field of the marker is ignored and the size of each marker +/// is determined by the corresponding value in the sizes data column. +/// Just like marker size, the size data is interpreted as an area. +/// (diameter = sqrt(size data) for circle marker). +/// The sizes data column must have the same length as the x and y data columns. #[derive(Debug, Clone)] pub struct Scatter { x_data: DataCol, @@ -307,6 +327,7 @@ pub struct Scatter { x_axis: axis::Ref, y_axis: axis::Ref, marker: style::series::Marker, + sizes_data: Option, } impl Scatter { @@ -320,6 +341,7 @@ impl Scatter { x_axis: Default::default(), y_axis: Default::default(), marker: style::series::Marker::default(), + sizes_data: None, } } @@ -351,6 +373,12 @@ impl Scatter { self } + /// Set the sizes data column and return self for chaining + pub fn with_sizes(mut self, sizes_data: DataCol) -> Self { + self.sizes_data = Some(sizes_data); + self + } + /// Get the x data column pub fn x_data(&self) -> &DataCol { &self.x_data @@ -380,6 +408,11 @@ impl Scatter { pub fn marker(&self) -> &style::series::Marker { &self.marker } + + /// Get the sizes data column, if any + pub fn sizes_data(&self) -> Option<&DataCol> { + self.sizes_data.as_ref() + } } /// Definition for the `y2_data` field of the Area plot. @@ -585,7 +618,7 @@ pub struct Histogram { x_axis: axis::Ref, y_axis: axis::Ref, fill: style::series::Fill, - line: Option, + stroke: Option, bins: u32, density: bool, } @@ -600,7 +633,7 @@ impl Histogram { x_axis: Default::default(), y_axis: Default::default(), fill: style::series::Fill::default(), - line: None, + stroke: None, bins: 10, density: false, } @@ -631,9 +664,9 @@ impl Histogram { Self { fill, ..self } } - /// Set the line style for the histogram outline and return self for chaining - pub fn with_line(mut self, line: style::series::Stroke) -> Self { - self.line = Some(line); + /// Set the stroke style for the histogram outline and return self for chaining + pub fn with_outline(mut self, stroke: style::series::Stroke) -> Self { + self.stroke = Some(stroke); self } @@ -674,9 +707,9 @@ impl Histogram { &self.fill } - /// Get the line style, if any - pub fn line(&self) -> Option<&style::series::Stroke> { - self.line.as_ref() + /// Get the outline style, if any + pub fn outline(&self) -> Option<&style::series::Stroke> { + self.stroke.as_ref() } /// Get the number of bins @@ -726,7 +759,7 @@ pub struct Bars { x_axis: axis::Ref, y_axis: axis::Ref, fill: style::series::Fill, - line: Option, + stroke: Option, position: BarsPosition, } @@ -741,7 +774,7 @@ impl Bars { x_axis: Default::default(), y_axis: Default::default(), fill: style::series::Fill::default(), - line: None, + stroke: None, position: BarsPosition::default(), } } @@ -759,10 +792,10 @@ impl Bars { Self { fill, ..self } } - /// Set the line style for the bar outline and return self for chaining - pub fn with_line(self, line: style::series::Stroke) -> Self { + /// Set the stroke style for the bar outline and return self for chaining + pub fn with_outline(self, stroke: style::series::Stroke) -> Self { Self { - line: Some(line), + stroke: Some(stroke), ..self } } @@ -802,9 +835,9 @@ impl Bars { &self.fill } - /// Get the line style, if any - pub fn line(&self) -> Option<&style::series::Stroke> { - self.line.as_ref() + /// Get the outline style, if any + pub fn outline(&self) -> Option<&style::series::Stroke> { + self.stroke.as_ref() } /// Get the position configuration @@ -823,7 +856,7 @@ pub struct BarSeries { name: Option, fill: style::series::Fill, - line: Option, + stroke: Option, } impl BarSeries { @@ -834,7 +867,7 @@ impl BarSeries { name: None, fill: style::series::Fill::default(), - line: None, + stroke: None, } } @@ -851,10 +884,10 @@ impl BarSeries { Self { fill, ..self } } - /// Set the line style for the bar outline and return self for chaining - pub fn with_line(self, line: style::series::Stroke) -> Self { + /// Set the stroke style for the bar outline and return self for chaining + pub fn with_outline(self, stroke: style::series::Stroke) -> Self { Self { - line: Some(line), + stroke: Some(stroke), ..self } } @@ -874,9 +907,9 @@ impl BarSeries { &self.fill } - /// Get the line style, if any - pub fn line(&self) -> Option<&style::series::Stroke> { - self.line.as_ref() + /// Get the outline style, if any + pub fn outline(&self) -> Option<&style::series::Stroke> { + self.stroke.as_ref() } } diff --git a/src/drawing/annot.rs b/src/drawing/annot.rs index 1a21362..3f1f78b 100644 --- a/src/drawing/annot.rs +++ b/src/drawing/annot.rs @@ -298,14 +298,21 @@ impl Annot { let (x, y) = marker.position(); let x = x_axis.coord_map().map_coord_num(x); let y = y_axis.coord_map().map_coord_num(y); - let path = marker::marker_path(marker.marker()); + let marker = marker.marker(); + let path = marker::marker_path(marker.shape); + let scale = marker.size.to_visual_size(); let transform = - geom::Transform::from_translate(plot_rect.left() + x, plot_rect.bottom() - y); + geom::Transform::from_translate(plot_rect.left() + x, plot_rect.bottom() - y) + .pre_scale(scale, scale); + let rpath = render::Path { path: &path, - fill: marker.marker().fill.as_ref().map(|f| f.as_paint(style)), - stroke: marker.marker().stroke.as_ref().map(|l| l.as_stroke(style)), + fill: marker.fill.as_ref().map(|f| f.as_paint(style)), + stroke: marker + .stroke + .as_ref() + .map(|l| l.as_stroke(style).with_multiplied_width(1.0 / scale)), transform: Some(&transform), }; surface.draw_path(&rpath); diff --git a/src/drawing/legend.rs b/src/drawing/legend.rs index 43e1b87..7dd3567 100644 --- a/src/drawing/legend.rs +++ b/src/drawing/legend.rs @@ -281,14 +281,19 @@ impl LegendEntry { surface.draw_path(&line); } Shape::Marker(marker) => { - let path = crate::drawing::marker::marker_path(&marker); + let path = crate::drawing::marker::marker_path(marker.shape); + let scale = style::MarkerSize::default().to_visual_size(); let transform = - geom::Transform::from_translate(shape_rect.center_x(), shape_rect.center_y()); + geom::Transform::from_translate(shape_rect.center_x(), shape_rect.center_y()) + .pre_scale(scale, scale); let path = render::Path { path: &path, fill: marker.fill.as_ref().map(|f| f.as_paint(&rc)), - stroke: marker.stroke.as_ref().map(|s| s.as_stroke(&rc)), + stroke: marker + .stroke + .as_ref() + .map(|s| s.as_stroke(&rc).with_multiplied_width(1.0 / scale)), transform: Some(&transform), }; surface.draw_path(&path); diff --git a/src/drawing/marker.rs b/src/drawing/marker.rs index b7b7a23..74ea027 100644 --- a/src/drawing/marker.rs +++ b/src/drawing/marker.rs @@ -1,16 +1,18 @@ -use crate::{Color, geom, style}; +use crate::{geom, style}; -const SQRT2: f32 = 1.41421356237; +const SQRT2: f32 = 1.4142135623730951; +const TAN30: f32 = 0.5773502691896257; -pub fn marker_path(marker: &style::Marker) -> geom::Path { - match marker.shape { +/// Generate a path for a marker shape of size 1.0 and centered at (0, 0) +pub fn marker_path(shape: style::MarkerShape) -> geom::Path { + match shape { style::MarkerShape::Circle => { - let radius = marker.size.0 / 2.0; + let radius = 0.5; geom::PathBuilder::from_circle(0.0, 0.0, radius).expect("Should be a valid path") } style::MarkerShape::Square => { - let half_w = marker.size.0 / 2.0; - let half_h = marker.size.0 / 2.0; + let half_w = 0.5; + let half_h = 0.5; let mut builder = geom::PathBuilder::new(); builder.move_to(-half_w, -half_h); builder.line_to(half_w, -half_h); @@ -20,8 +22,8 @@ pub fn marker_path(marker: &style::Marker) -> geom::Path { builder.finish().expect("Should be a valid path") } style::MarkerShape::Diamond => { - let half_w = marker.size.0 / SQRT2; - let half_h = marker.size.0 / SQRT2; + let half_w = 1.0 / SQRT2; + let half_h = 1.0 / SQRT2; let mut builder = geom::PathBuilder::new(); builder.move_to(0.0, -half_h); builder.line_to(half_w, 0.0); @@ -31,8 +33,8 @@ pub fn marker_path(marker: &style::Marker) -> geom::Path { builder.finish().expect("Should be a valid path") } style::MarkerShape::Cross => { - let half_w = marker.size.0 / 2.0; - let half_h = marker.size.0 / 2.0; + let half_w = 0.5; + let half_h = 0.5; let mut builder = geom::PathBuilder::new(); builder.move_to(-half_w, -half_h); builder.line_to(half_w, half_h); @@ -42,8 +44,8 @@ pub fn marker_path(marker: &style::Marker) -> geom::Path { builder.finish().expect("Should be a valid path") } style::MarkerShape::Plus => { - let half_w = marker.size.0 / SQRT2; - let half_h = marker.size.0 / SQRT2; + let half_w = 1.0 / SQRT2; + let half_h = 1.0 / SQRT2; let mut builder = geom::PathBuilder::new(); builder.move_to(0.0, -half_h); builder.line_to(0.0, half_h); @@ -53,22 +55,42 @@ pub fn marker_path(marker: &style::Marker) -> geom::Path { builder.finish().expect("Should be a valid path") } style::MarkerShape::TriangleUp => { - let half_w = marker.size.0 / 2.0; - let half_h = marker.size.0 * SQRT2 / 2.0; + let height = 1.0; + let base = 2.0 * height * TAN30; let mut builder = geom::PathBuilder::new(); - builder.move_to(0.0, -half_h); - builder.line_to(half_w, half_h); - builder.line_to(-half_w, half_h); + builder.move_to(0.0, -2.0 * height / 3.0); + builder.line_to(base / 2.0, height / 3.0); + builder.line_to(-base / 2.0, height / 3.0); builder.close(); builder.finish().expect("Should be a valid path") } style::MarkerShape::TriangleDown => { - let half_w = marker.size.0 / 2.0; - let half_h = marker.size.0 * SQRT2 / 2.0; + let height = 1.0; + let base = 2.0 * height * TAN30; let mut builder = geom::PathBuilder::new(); - builder.move_to(0.0, half_h); - builder.line_to(half_w, -half_h); - builder.line_to(-half_w, -half_h); + builder.move_to(0.0, 2.0 * height / 3.0); + builder.line_to(base / 2.0, -height / 3.0); + builder.line_to(-base / 2.0, -height / 3.0); + builder.close(); + builder.finish().expect("Should be a valid path") + } + style::MarkerShape::TriangleRight => { + let height = 1.0; + let base = 2.0 * height * TAN30; + let mut builder = geom::PathBuilder::new(); + builder.move_to(2.0 * height / 3.0, 0.0); + builder.line_to(-height / 3.0, base / 2.0); + builder.line_to(-height / 3.0, -base / 2.0); + builder.close(); + builder.finish().expect("Should be a valid path") + } + style::MarkerShape::TriangleLeft => { + let height = 1.0; + let base = 2.0 * height * TAN30; + let mut builder = geom::PathBuilder::new(); + builder.move_to(-2.0 * height / 3.0, 0.0); + builder.line_to(height / 3.0, base / 2.0); + builder.line_to(height / 3.0, -base / 2.0); builder.close(); builder.finish().expect("Should be a valid path") } diff --git a/src/drawing/series.rs b/src/drawing/series.rs index 8b25f58..42ee50f 100644 --- a/src/drawing/series.rs +++ b/src/drawing/series.rs @@ -54,7 +54,7 @@ impl SeriesExt for des::series::Histogram { self.name().map(|n| legend::Entry { label: n.as_ref(), font: None, - shape: legend::ShapeRef::Rect(Some(self.fill()), self.line()), + shape: legend::ShapeRef::Rect(Some(self.fill()), self.outline()), }) } } @@ -64,7 +64,7 @@ impl SeriesExt for des::series::Bars { self.name().map(|n| legend::Entry { label: n.as_ref(), font: None, - shape: legend::ShapeRef::Rect(Some(self.fill()), self.line()), + shape: legend::ShapeRef::Rect(Some(self.fill()), self.outline()), }) } } @@ -74,7 +74,7 @@ impl SeriesExt for des::series::BarSeries { self.name().map(|n| legend::Entry { label: n.as_ref(), font: None, - shape: legend::ShapeRef::Rect(Some(self.fill()), self.line()), + shape: legend::ShapeRef::Rect(Some(self.fill()), self.outline()), }) } } @@ -585,6 +585,55 @@ fn calc_xy_line_path( } } +#[derive(Debug, Clone)] +struct MarkerData { + path: geom::Path, + points: Vec<(geom::Point, f32)>, // pos and scale + marker: style::series::Marker, +} + +impl MarkerData { + fn new(marker: style::series::Marker) -> Self { + let path = marker::marker_path(marker.shape); + Self { + path, + points: Vec::new(), + marker, + } + } + + fn clear(&mut self) { + self.points.clear(); + } + + fn draw(&self, surface: &mut S, style: &Style, index: usize) + where + S: render::Surface, + { + if self.points.is_empty() { + return; + } + + let rc = (style, index); + + for p in &self.points { + let transform = geom::Transform::from_translate(p.0.x, p.0.y).pre_scale(p.1, p.1); + + let path = render::Path { + path: &self.path, + fill: self.marker.fill.as_ref().map(|f| f.as_paint(&rc)), + stroke: self + .marker + .stroke + .as_ref() + .map(|l| l.as_stroke(&rc).with_multiplied_width(1.0 / p.1)), + transform: Some(&transform), + }; + surface.draw_path(&path); + } + } +} + #[derive(Debug, Clone)] struct Line { index: usize, @@ -594,6 +643,7 @@ struct Line { path: Option, stroke: style::series::Stroke, interpolation: des::series::Interpolation, + marker_data: Option, } impl Line { @@ -603,6 +653,7 @@ impl Line { { let cols = (des.x_data().clone(), des.y_data().clone()); let xy_bounds = calc_xy_bounds(data_source, &cols.0, &cols.1)?; + let marker_data = des.marker().cloned().map(MarkerData::new); Ok(Line { index, cols, @@ -611,6 +662,7 @@ impl Line { path: None, stroke: des.stroke().clone(), interpolation: des.interpolation(), + marker_data, }) } @@ -639,25 +691,43 @@ impl Line { let path = calc_xy_line_path(x_col, y_col, self.interpolation, rect, cm); self.path = Some(path); + + if let Some(marker_data) = self.marker_data.as_mut() { + let size = marker_data.marker.size.to_visual_size(); + let mut points = Vec::with_capacity(x_col.len()); + + for (x, y) in x_col.sample_iter().zip(y_col.sample_iter()) { + if x.is_null() || y.is_null() { + continue; + } + let (x, y) = cm.map_coord((x, y)).expect("Should be valid coordinates"); + let x = rect.left() + x; + let y = rect.bottom() - y; + points.push((geom::Point { x, y }, size)); + } + marker_data.points = points; + } } fn draw(&self, surface: &mut S, style: &Style) where S: render::Surface, { - if self.path.is_none() { - return; - } - let rc = (style, self.index); - let path = render::Path { - path: self.path.as_ref().unwrap(), - fill: None, - stroke: Some(self.stroke.as_stroke(&rc)), - transform: None, - }; - surface.draw_path(&path); + if let Some(path) = self.path.as_ref() { + let rpath = render::Path { + path, + fill: None, + stroke: Some(self.stroke.as_stroke(&rc)), + transform: None, + }; + surface.draw_path(&rpath); + } + + if let Some(marker) = self.marker_data.as_ref() { + marker.draw(surface, style, self.index); + } } } @@ -665,11 +735,10 @@ impl Line { struct Scatter { index: usize, cols: (des::DataCol, des::DataCol), + sizes_col: Option, ab: Option<(axis::Bounds, axis::Bounds)>, axes: (des::axis::Ref, des::axis::Ref), - path: geom::Path, - points: Vec, - marker: style::series::Marker, + marker_data: MarkerData, } impl Scatter { @@ -678,16 +747,16 @@ impl Scatter { D: data::Source + ?Sized, { let cols = (des.x_data().clone(), des.y_data().clone()); + let sizes_col = des.sizes_data().cloned(); let xy_bounds = calc_xy_bounds(data_source, &cols.0, &cols.1)?; - let path = marker::marker_path(des.marker()); + let marker_data = MarkerData::new(des.marker().clone()); Ok(Scatter { index, cols, + sizes_col, ab: xy_bounds, axes: (des.x_axis().clone(), des.y_axis().clone()), - path, - points: Vec::new(), - marker: des.marker().clone(), + marker_data, }) } @@ -699,8 +768,14 @@ impl Scatter { let y_col = get_column(&self.cols.1, data_source).unwrap(); debug_assert!(x_col.len() == y_col.len()); + let sizes_col = self + .sizes_col + .as_ref() + .map(|col| get_column(col, data_source).unwrap()); + debug_assert!(sizes_col.map_or(true, |sc| sc.len() == x_col.len())); + if self.ab.is_none() && x_col.is_empty() { - self.points.clear(); + self.marker_data.clear(); return; } @@ -712,39 +787,35 @@ impl Scatter { } let mut points = Vec::with_capacity(x_col.len()); + let default_vs = self.marker_data.marker.size.to_visual_size(); + + let mut sizes_iter = sizes_col.map(|sc| sc.sample_iter()); for (x, y) in x_col.sample_iter().zip(y_col.sample_iter()) { if x.is_null() || y.is_null() { continue; } + let (x, y) = cm.map_coord((x, y)).expect("Should be valid coordinates"); let x = rect.left() + x; let y = rect.bottom() - y; - points.push(geom::Point { x, y }); + let vs = sizes_iter + .as_mut() + .and_then(|iter| iter.next()) + .and_then(|v| v.as_num()) + .map(|v| style::MarkerSize::from(v as f32).to_visual_size()) + .unwrap_or(default_vs); + + points.push((geom::Point { x, y }, vs)); } - self.points = points; + self.marker_data.points = points; } fn draw(&self, surface: &mut S, style: &Style) where S: render::Surface, { - if self.points.is_empty() { - return; - } - - let rc = (style, self.index); - - for p in &self.points { - let transform = geom::Transform::from_translate(p.x, p.y); - let path = render::Path { - path: &self.path, - fill: self.marker.fill.as_ref().map(|f| f.as_paint(&rc)), - stroke: self.marker.stroke.as_ref().map(|l| l.as_stroke(&rc)), - transform: Some(&transform), - }; - surface.draw_path(&path); - } + self.marker_data.draw(surface, style, self.index); } } @@ -1018,7 +1089,7 @@ impl Histogram { bins, path: None, fill: hist.fill().clone(), - line: hist.line().cloned(), + line: hist.outline().cloned(), updated_once: false, }) } @@ -1168,7 +1239,7 @@ impl Bars { position: des.position().clone(), path: None, fill: des.fill().clone(), - line: des.line().cloned(), + line: des.outline().cloned(), }) } @@ -1492,7 +1563,7 @@ impl BarsGroup { let rpath = render::Path { path, fill: Some(series.fill().as_paint(&rc)), - stroke: series.line().map(|l| l.as_stroke(&rc)), + stroke: series.outline().map(|l| l.as_stroke(&rc)), transform: None, }; surface.draw_path(&rpath); diff --git a/src/drawing/ticks.rs b/src/drawing/ticks.rs index f07776d..5f3f6ba 100644 --- a/src/drawing/ticks.rs +++ b/src/drawing/ticks.rs @@ -75,7 +75,7 @@ pub fn locate_minor( Ok(LogLocator::new_minor(*base).ticks(nb)) } _ => Err(Error::InconsistentDesign(format!( - "Unsupported locator/scale combination: {:?}/{:?}", + "Unsupported minor locator/scale combination: {:?}/{:?}", locator, scale ))), } diff --git a/src/lib.rs b/src/lib.rs index 1524fff..419cbfd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,41 +192,7 @@ pub use text::bundled_font_db; pub use text::fontdb; #[cfg(feature = "utils")] -pub mod utils { - //! Utility functions for data generation - - #[cfg(feature = "time")] - use crate::time::DateTime; - - /// Create a linearly spaced vector of `num` elements between `start` and `end` - pub fn linspace(start: f64, end: f64, num: usize) -> Vec { - let step = (end - start) / (num as f64 - 1.0); - (0..num).map(|i| start + i as f64 * step).collect() - } - - /// Create a log-spaced vector of `num` elements between `start` and `end` - pub fn logspace(start: f64, end: f64, num: usize) -> Vec { - let log_start = start.log10(); - let log_end = end.log10(); - let step = (log_end - log_start) / (num as f64 - 1.0); - (0..num) - .map(|i| 10f64.powf(log_start + i as f64 * step)) - .collect() - } - - #[cfg(feature = "time")] - /// Create a linearly spaced time vector of `num` elements between `start` and `end` - pub fn timespace(start: DateTime, end: DateTime, num: usize) -> Vec { - let step = (end - start) / (num as f64 - 1.0); - let mut result = Vec::with_capacity(num); - let mut cur = start; - for _ in 0..num { - result.push(cur); - cur += step; - } - result - } -} +pub mod utils; /// Module containing missing configuration values /// Basically we put here all magic values that would require proper parameters diff --git a/src/render.rs b/src/render.rs index 0e99648..4b4ebeb 100644 --- a/src/render.rs +++ b/src/render.rs @@ -73,6 +73,14 @@ pub struct Stroke<'a> { pub pattern: LinePattern<'a>, } +impl Stroke<'_> { + /// Multiply the line width by the given factor, useful for keeping visual width with scaled paths. + pub fn with_multiplied_width(mut self, factor: f32) -> Self { + self.width *= factor; + self + } +} + /// Rectangle to draw #[derive(Debug, Clone)] pub struct Rect<'a> { diff --git a/src/style.rs b/src/style.rs index 90b7ca9..bc2d25b 100644 --- a/src/style.rs +++ b/src/style.rs @@ -167,8 +167,10 @@ pub enum LinePattern { Solid, /// Dashed line. The pattern is relative to the line width. Dash(Dash), - /// Dotted line. Equivalent to Dash(1.0, 1.0) + /// Dotted line. Equivalent to Dash(vec![1.0, 1.0]) Dot, + /// Dash-dot line. Equivalent to Dash(vec![5.0, 5.0, 1.0, 5.0]) + DashDot, } impl Default for LinePattern { @@ -200,6 +202,7 @@ pub struct Stroke { } const DOT_DASH: &[f32] = &[1.0, 1.0]; +const DASH_DOT_DASH: &[f32] = &[5.0, 5.0, 1.0, 5.0]; impl Stroke { /// Set the line width in figure units, returning self for chaining @@ -235,6 +238,7 @@ impl Stroke { LinePattern::Solid => render::LinePattern::Solid, LinePattern::Dash(Dash(a)) => render::LinePattern::Dash(a.as_slice()), LinePattern::Dot => render::LinePattern::Dash(DOT_DASH), + LinePattern::DashDot => render::LinePattern::Dash(DASH_DOT_DASH), }; render::Stroke { @@ -371,12 +375,24 @@ pub enum MarkerShape { TriangleUp, /// Downward pointing triangle marker TriangleDown, + /// Rightward pointing triangle marker + TriangleRight, + /// Leftward pointing triangle marker + TriangleLeft, } /// Size of a marker, used in scatter plots +/// The size is interpreted as an area, so it scales quadratically with the visual size of the marker. #[derive(Debug, Clone, Copy)] pub struct MarkerSize(pub f32); +impl MarkerSize { + /// Convert the marker size to a visual size (e.g. diameter for circle marker) + pub fn to_visual_size(&self) -> f32 { + self.0.sqrt() + } +} + impl Default for MarkerSize { fn default() -> Self { MarkerSize(defaults::MARKER_SIZE) @@ -402,17 +418,116 @@ pub struct Marker { pub stroke: Option>, } +impl Marker { + /// Create a new marker with both fill and stroke set to the same color + pub fn new_with_color(color: C) -> Self { + Marker { + size: MarkerSize::default(), + shape: MarkerShape::default(), + fill: Some(Fill::Solid { + color, + opacity: None, + }), + stroke: Some(Stroke { + color, + width: defaults::SERIES_LINE_WIDTH, + pattern: LinePattern::default(), + opacity: None, + }), + } + } + + /// Set the marker size, returning self for chaining + pub fn with_size>(self, size: S) -> Self { + Self { + size: size.into(), + ..self + } + } + + /// Set the marker shape, returning self for chaining + pub fn with_shape(self, shape: MarkerShape) -> Self { + Self { shape, ..self } + } + + /// Set the marker fill style, returning self for chaining + pub fn with_fill(self, fill: Fill) -> Self { + Self { + fill: Some(fill), + ..self + } + } + + /// Set the marker stroke style, returning self for chaining + pub fn with_stroke(self, stroke: Stroke) -> Self { + Self { + stroke: Some(stroke), + ..self + } + } + + /// Shorthand for setting both fill and stroke to the same color, returning self for chaining + pub fn with_color(self, color: C) -> Self { + let mut fill = self.fill.unwrap_or_else(|| Fill::Solid { + color, + opacity: None, + }); + match &mut fill { + Fill::Solid { color: col, .. } => *col = color, + } + + let mut stroke = self.stroke.unwrap_or_else(|| Stroke { + color, + width: defaults::SERIES_LINE_WIDTH, + opacity: None, + pattern: LinePattern::default(), + }); + stroke.color = color; + + Self { + fill: Some(fill), + stroke: Some(stroke), + ..self + } + } + + /// Shorthand for setting opacity of the fill, returning self for chaining + pub fn with_fill_opacity(self, opacity: f32) -> Self { + match self.fill { + Some(Fill::Solid { color, .. }) => self.with_fill(Fill::Solid { + color, + opacity: Some(opacity), + }), + None => self, + } + } + + /// Shorthand for setting stroke width, returning self for chaining + pub fn with_stroke_width(self, width: f32) -> Self { + let stroke = match self.stroke { + Some(Stroke { + color, + pattern, + opacity, + .. + }) => Some(Stroke { + color, + width, + pattern, + opacity, + }), + None => None, + }; + Self { stroke, ..self } + } +} + impl Default for Marker where C: Color + Default, { fn default() -> Self { - Marker { - size: MarkerSize::default(), - shape: MarkerShape::default(), - fill: Some(Fill::default()), - stroke: None, - } + Marker::new_with_color(C::default()) } } diff --git a/src/style/defaults.rs b/src/style/defaults.rs index a498130..0efd912 100644 --- a/src/style/defaults.rs +++ b/src/style/defaults.rs @@ -10,7 +10,7 @@ pub const AXIS_LABEL_FONT_SIZE: f32 = 16.0; pub const TICKS_LABEL_FONT_SIZE: f32 = 12.0; pub const SERIES_LINE_WIDTH: f32 = 1.5; -pub const MARKER_SIZE: f32 = 10.0; +pub const MARKER_SIZE: f32 = 8.5 * 8.5; pub const LEGEND_LABEL_FONT_SIZE: f32 = 13.0; pub const LEGEND_SHAPE_SPACING: f32 = 10.0; diff --git a/src/style/series.rs b/src/style/series.rs index ff6432d..20a8a0d 100644 --- a/src/style/series.rs +++ b/src/style/series.rs @@ -169,15 +169,7 @@ pub type Marker = style::Marker; impl From for Marker { fn from(color: ColorU8) -> Self { - Marker { - size: Default::default(), - shape: Default::default(), - fill: Some(Fill::Solid { - color: color.into(), - opacity: None, - }), - stroke: None, - } + Marker::new_with_color(color.into()) } } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..1711041 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,216 @@ +//! Utility traits and functions + +use std::fmt; + +use plotive_base::{ColorU8, color}; + +use crate::des::series; +use crate::style; +#[cfg(feature = "time")] +use crate::time::DateTime; + +/// Create a linearly spaced vector of `num` elements between `start` and `end` +pub fn linspace(start: f64, end: f64, num: usize) -> Vec { + let step = (end - start) / (num as f64 - 1.0); + (0..num).map(|i| start + i as f64 * step).collect() +} + +/// Create a log-spaced vector of `num` elements between `start` and `end` +pub fn logspace(start: f64, end: f64, num: usize) -> Vec { + let log_start = start.log10(); + let log_end = end.log10(); + let step = (log_end - log_start) / (num as f64 - 1.0); + (0..num) + .map(|i| 10f64.powf(log_start + i as f64 * step)) + .collect() +} + +#[cfg(feature = "time")] +/// Create a linearly spaced time vector of `num` elements between `start` and `end` +pub fn timespace(start: DateTime, end: DateTime, num: usize) -> Vec { + let step = (end - start) / (num as f64 - 1.0); + let mut result = Vec::with_capacity(num); + let mut cur = start; + for _ in 0..num { + result.push(cur); + cur += step; + } + result +} + +/// Error type for Matplotlib style parsing +#[derive(Debug)] +pub struct MplStyleError(String); + +impl From for MplStyleError { + fn from(s: String) -> Self { + MplStyleError(s) + } +} + +impl From<&str> for MplStyleError { + fn from(s: &str) -> Self { + MplStyleError(s.to_string()) + } +} + +impl fmt::Display for MplStyleError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Matplotlib style parsing error: {}", self.0) + } +} + +impl std::error::Error for MplStyleError {} + +/// Trait for applying Matplotlib styles to series +pub trait MplStyle { + /// Return a new instance of the series with the given Matplotlib style applied. + /// + /// E.g. for line series, see the format string section of + /// [matplotlib.pyplot.plot](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html) + fn with_mpl_style(self, mpl_style: &str) -> Result + where + Self: Sized; +} + +impl MplStyle for series::Line { + fn with_mpl_style(mut self, mpl_style: &str) -> Result { + if let Ok(c) = mpl_style.parse::() { + let mut s = self.stroke().clone(); + s.color = c.into(); + return Ok(self.with_stroke(s)); + } + + let style = match LineMplStyle::parse(mpl_style) { + Ok(s) => s, + Err(e) => { + return Err(MplStyleError(format!( + "Failed to parse Matplotlib style string '{}': {}", + mpl_style, e + ))); + } + }; + + if let Some(shape) = style.marker_shape { + let mut marker = self.marker().cloned().unwrap_or_default(); + marker.shape = shape; + self = self.with_marker(marker); + } + + if let Some(pattern) = style.pattern { + let mut s = self.stroke().clone(); + s.pattern = pattern; + self = self.with_stroke(s); + } + + if let Some(c) = style.color { + let mut s = self.stroke().clone(); + s.color = c; + self = self.with_stroke(s); + } + + Ok(self) + } +} + +struct LineMplStyle { + marker_shape: Option, + pattern: Option, + color: Option, +} +impl LineMplStyle { + fn parse(mpl_style: &str) -> Result { + let mut style = LineMplStyle { + marker_shape: None, + pattern: None, + color: None, + }; + + let mut chars = mpl_style.chars().enumerate().peekable(); + + while let Some((i, c)) = chars.next() { + match c { + 'o' => style.set_marker_shape(style::MarkerShape::Circle)?, + 's' => style.set_marker_shape(style::MarkerShape::Square)?, + 'D' => style.set_marker_shape(style::MarkerShape::Diamond)?, + 'x' => style.set_marker_shape(style::MarkerShape::Cross)?, + '+' => style.set_marker_shape(style::MarkerShape::Plus)?, + 'v' => style.set_marker_shape(style::MarkerShape::TriangleDown)?, + '^' => style.set_marker_shape(style::MarkerShape::TriangleUp)?, + '>' => style.set_marker_shape(style::MarkerShape::TriangleRight)?, + '<' => style.set_marker_shape(style::MarkerShape::TriangleLeft)?, + '-' => { + if let Some((_, next)) = chars.peek() { + match next { + '-' => { + chars.next(); + style.set_pattern(style::Dash::default().into())?; + } + '.' => { + chars.next(); + style.set_pattern(style::LinePattern::DashDot)?; + } + _ => style.set_pattern(style::LinePattern::Solid)?, + } + } else { + style.set_pattern(style::LinePattern::Solid)?; + } + } + ':' => style.set_pattern(style::LinePattern::Dot)?, + 'b' => style.set_color(ColorU8::from_html(b"#0000ff").into())?, + 'g' => style.set_color(ColorU8::from_html(b"#008000").into())?, + 'r' => style.set_color(ColorU8::from_html(b"#ff0000").into())?, + 'c' => style.set_color(ColorU8::from_html(b"#00bfbf").into())?, + 'm' => style.set_color(ColorU8::from_html(b"#bf00bf").into())?, + 'y' => style.set_color(ColorU8::from_html(b"#bfbf00").into())?, + 'k' => style.set_color(ColorU8::from_html(b"#000000").into())?, + 'w' => style.set_color(ColorU8::from_html(b"#ffffff").into())?, + 'C' => { + let s: usize = mpl_style[i + 1..].parse().map_err(|_| { + MplStyleError(format!( + "Invalid color index after 'C' in Matplotlib style string: '{}'", + mpl_style + )) + })?; + style.set_color(style::series::IndexColor(s).into())?; + break; + } + _ => { + return Err(MplStyleError(format!( + "Unknown Matplotlib style character '{}'", + c + ))); + } + } + } + + Ok(style) + } + + fn set_marker_shape(&mut self, shape: style::MarkerShape) -> Result<(), MplStyleError> { + if self.marker_shape.is_some() { + Err(MplStyleError("Multiple marker shapes".to_string())) + } else { + self.marker_shape = Some(shape); + Ok(()) + } + } + + fn set_pattern(&mut self, pattern: style::LinePattern) -> Result<(), MplStyleError> { + if self.pattern.is_some() { + Err(MplStyleError("Multiple line patterns".to_string())) + } else { + self.pattern = Some(pattern); + Ok(()) + } + } + + fn set_color(&mut self, color: style::series::Color) -> Result<(), MplStyleError> { + if self.color.is_some() { + Err(MplStyleError("Multiple colors".to_string())) + } else { + self.color = Some(color); + Ok(()) + } + } +} diff --git a/tests/Cargo.toml b/tests/Cargo.toml index e2475c5..06af53b 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -10,7 +10,7 @@ keywords.workspace = true publish = false [dependencies] -plotive = { workspace = true, features=["time"] } +plotive = { workspace = true, features=["time", "utils"] } plotive-pxl.workspace = true plotive-svg.workspace = true tiny-skia.workspace = true diff --git a/tests/refs/series/scatter-sizes.png b/tests/refs/series/scatter-sizes.png new file mode 100644 index 0000000..49ad4d0 Binary files /dev/null and b/tests/refs/series/scatter-sizes.png differ diff --git a/tests/refs/series/scatter-sizes.svg b/tests/refs/series/scatter-sizes.svg new file mode 100644 index 0000000..46b3187 --- /dev/null +++ b/tests/refs/series/scatter-sizes.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/dash-fat.png b/tests/refs/style/dash-fat.png new file mode 100644 index 0000000..beb450a Binary files /dev/null and b/tests/refs/style/dash-fat.png differ diff --git a/tests/refs/style/dash-fat.svg b/tests/refs/style/dash-fat.svg new file mode 100644 index 0000000..8f1459a --- /dev/null +++ b/tests/refs/style/dash-fat.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/dash.png b/tests/refs/style/dash.png new file mode 100644 index 0000000..c515845 Binary files /dev/null and b/tests/refs/style/dash.png differ diff --git a/tests/refs/style/dash.svg b/tests/refs/style/dash.svg new file mode 100644 index 0000000..3f20ff8 --- /dev/null +++ b/tests/refs/style/dash.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/dash_dot-spline.png b/tests/refs/style/dash_dot-spline.png new file mode 100644 index 0000000..92ece4f Binary files /dev/null and b/tests/refs/style/dash_dot-spline.png differ diff --git a/tests/refs/style/dash_dot-spline.svg b/tests/refs/style/dash_dot-spline.svg new file mode 100644 index 0000000..45b98d9 --- /dev/null +++ b/tests/refs/style/dash_dot-spline.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/dash_dot.png b/tests/refs/style/dash_dot.png new file mode 100644 index 0000000..42d4fb1 Binary files /dev/null and b/tests/refs/style/dash_dot.png differ diff --git a/tests/refs/style/dash_dot.svg b/tests/refs/style/dash_dot.svg new file mode 100644 index 0000000..53de079 --- /dev/null +++ b/tests/refs/style/dash_dot.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/dot.png b/tests/refs/style/dot.png new file mode 100644 index 0000000..f21abf7 Binary files /dev/null and b/tests/refs/style/dot.png differ diff --git a/tests/refs/style/dot.svg b/tests/refs/style/dot.svg new file mode 100644 index 0000000..0b7401b --- /dev/null +++ b/tests/refs/style/dot.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-circle.png b/tests/refs/style/line-markers-circle.png new file mode 100644 index 0000000..031f5f1 Binary files /dev/null and b/tests/refs/style/line-markers-circle.png differ diff --git a/tests/refs/style/line-markers-circle.svg b/tests/refs/style/line-markers-circle.svg new file mode 100644 index 0000000..87bc805 --- /dev/null +++ b/tests/refs/style/line-markers-circle.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-cross.png b/tests/refs/style/line-markers-cross.png new file mode 100644 index 0000000..6e1b3f9 Binary files /dev/null and b/tests/refs/style/line-markers-cross.png differ diff --git a/tests/refs/style/line-markers-cross.svg b/tests/refs/style/line-markers-cross.svg new file mode 100644 index 0000000..e9324d1 --- /dev/null +++ b/tests/refs/style/line-markers-cross.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-diamond.png b/tests/refs/style/line-markers-diamond.png new file mode 100644 index 0000000..4b99013 Binary files /dev/null and b/tests/refs/style/line-markers-diamond.png differ diff --git a/tests/refs/style/line-markers-diamond.svg b/tests/refs/style/line-markers-diamond.svg new file mode 100644 index 0000000..d8aee57 --- /dev/null +++ b/tests/refs/style/line-markers-diamond.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-plus.png b/tests/refs/style/line-markers-plus.png new file mode 100644 index 0000000..bc1cb24 Binary files /dev/null and b/tests/refs/style/line-markers-plus.png differ diff --git a/tests/refs/style/line-markers-plus.svg b/tests/refs/style/line-markers-plus.svg new file mode 100644 index 0000000..3d04b3a --- /dev/null +++ b/tests/refs/style/line-markers-plus.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-square.png b/tests/refs/style/line-markers-square.png new file mode 100644 index 0000000..e599cd0 Binary files /dev/null and b/tests/refs/style/line-markers-square.png differ diff --git a/tests/refs/style/line-markers-square.svg b/tests/refs/style/line-markers-square.svg new file mode 100644 index 0000000..dec4494 --- /dev/null +++ b/tests/refs/style/line-markers-square.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-tridown.png b/tests/refs/style/line-markers-tridown.png new file mode 100644 index 0000000..ba4d947 Binary files /dev/null and b/tests/refs/style/line-markers-tridown.png differ diff --git a/tests/refs/style/line-markers-tridown.svg b/tests/refs/style/line-markers-tridown.svg new file mode 100644 index 0000000..9d6a0ac --- /dev/null +++ b/tests/refs/style/line-markers-tridown.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-trileft.png b/tests/refs/style/line-markers-trileft.png new file mode 100644 index 0000000..efc7b84 Binary files /dev/null and b/tests/refs/style/line-markers-trileft.png differ diff --git a/tests/refs/style/line-markers-trileft.svg b/tests/refs/style/line-markers-trileft.svg new file mode 100644 index 0000000..f0cd8e2 --- /dev/null +++ b/tests/refs/style/line-markers-trileft.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-triright.png b/tests/refs/style/line-markers-triright.png new file mode 100644 index 0000000..6c7d79b Binary files /dev/null and b/tests/refs/style/line-markers-triright.png differ diff --git a/tests/refs/style/line-markers-triright.svg b/tests/refs/style/line-markers-triright.svg new file mode 100644 index 0000000..d3de5da --- /dev/null +++ b/tests/refs/style/line-markers-triright.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-triup-color.png b/tests/refs/style/line-markers-triup-color.png new file mode 100644 index 0000000..d6c826b Binary files /dev/null and b/tests/refs/style/line-markers-triup-color.png differ diff --git a/tests/refs/style/line-markers-triup-color.svg b/tests/refs/style/line-markers-triup-color.svg new file mode 100644 index 0000000..fe166b8 --- /dev/null +++ b/tests/refs/style/line-markers-triup-color.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/refs/style/line-markers-triup.png b/tests/refs/style/line-markers-triup.png new file mode 100644 index 0000000..a40071b Binary files /dev/null and b/tests/refs/style/line-markers-triup.png differ diff --git a/tests/refs/style/line-markers-triup.svg b/tests/refs/style/line-markers-triup.svg new file mode 100644 index 0000000..441306d --- /dev/null +++ b/tests/refs/style/line-markers-triup.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/src/tests.rs b/tests/src/tests.rs index 80e9ae7..d32e1b8 100644 --- a/tests/src/tests.rs +++ b/tests/src/tests.rs @@ -47,6 +47,7 @@ mod interp; mod legend; mod nulls; mod series; +mod style; mod subplots; #[test] diff --git a/tests/src/tests/axes.rs b/tests/src/tests/axes.rs index df51671..76d1160 100644 --- a/tests/src/tests/axes.rs +++ b/tests/src/tests/axes.rs @@ -212,7 +212,7 @@ fn axes_categories() { let y = vec![1.0, 1.4, 3.0]; let series = des::series::Bars::new(x.into(), y.into()) .with_fill(color::TRANSPARENT.into()) - .with_line(Default::default()); + .with_outline(Default::default()); let plot = des::Plot::new(vec![series.into()]) .with_x_axis(des::Axis::new().with_ticks(Default::default())); diff --git a/tests/src/tests/series.rs b/tests/src/tests/series.rs index fe89658..1031aa5 100644 --- a/tests/src/tests/series.rs +++ b/tests/src/tests/series.rs @@ -31,6 +31,30 @@ fn series_scatter_nodata() { assert_fig_eq_ref!(&fig, "series/scatter-nodata"); } +#[test] +fn series_scatter_sizes() { + let x = vec![1.0, 2.0, 3.0, 4.0, 5.0]; + let y = vec![1.0, 4.0, 9.0, 16.0, 25.0]; + let sizes = vec![300.0, 250.0, 200.0, 150.0, 100.0]; + + let color: plotive::ColorU8 = "light eggplant".parse().unwrap(); + + let plot = des::Plot::new(vec![ + des::series::Scatter::new(des::data_inline(x), des::data_inline(y)) + .with_sizes(des::data_inline(sizes)) + .with_marker( + style::series::Marker::default() + .with_color(color.into()) + .with_fill_opacity(0.6) + .with_stroke_width(2.0), + ) + .into(), + ]); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "series/scatter-sizes"); +} + #[test] fn series_area_double() { let x = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]; diff --git a/tests/src/tests/style.rs b/tests/src/tests/style.rs new file mode 100644 index 0000000..06c8169 --- /dev/null +++ b/tests/src/tests/style.rs @@ -0,0 +1,149 @@ +use plotive::utils::MplStyle; +use plotive::{ColorU8, des}; + +use super::{fig_small, line}; +use crate::{TestHarness, assert_fig_eq_ref}; + +fn line_spline() -> des::series::Line { + let x = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; + let y = vec![0.0, 2.0, 3.0, 1.0, 4.0, 4.0]; + des::series::Line::new(des::data_inline(x), des::data_inline(y)) + .with_interpolation(des::series::Interpolation::Spline) +} + +#[test] +fn style_dash_mpl() { + let series = line().with_mpl_style("--").unwrap().into(); + let plot = des::Plot::new(vec![series]); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/dash"); +} + +#[test] +fn style_dash_dot_mpl() { + let series = line().with_mpl_style("-.").unwrap().into(); + let plot = des::Plot::new(vec![series]); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/dash_dot"); +} + +#[test] +fn style_dash_dot_spline_mpl() { + let series = line_spline().with_mpl_style("-.").unwrap().into(); + let plot = des::Plot::new(vec![series]); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/dash_dot-spline"); +} + +#[test] +fn style_dot_mpl() { + let series = line().with_mpl_style(":").unwrap().into(); + let plot = des::Plot::new(vec![series]); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/dot"); +} + +#[test] +fn style_dash_scales_with_width_mpl() { + let series = line() + .with_stroke(plotive::style::series::Stroke::default().with_width(4.0)) + .with_mpl_style("--") + .unwrap() + .into(); + let plot = des::Plot::new(vec![series]); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/dash-fat"); +} + +#[test] +fn style_line_markers_circle_mpl() { + let plot = line_spline().with_mpl_style("o").unwrap().into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-circle"); +} + +#[test] +fn style_line_markers_square_mpl() { + let plot = line_spline().with_mpl_style("s").unwrap().into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-square"); +} + +#[test] +fn style_line_markers_diamond_mpl() { + let plot = line_spline().with_mpl_style("D").unwrap().into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-diamond"); +} + +#[test] +fn style_line_markers_cross_mpl() { + let plot = line_spline().with_mpl_style("x").unwrap().into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-cross"); +} + +#[test] +fn style_line_markers_plus_mpl() { + let plot = line_spline().with_mpl_style("+").unwrap().into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-plus"); +} + +#[test] +fn style_line_markers_triup_mpl() { + let plot = line_spline().with_mpl_style("^").unwrap().into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-triup"); +} + +#[test] +fn style_line_markers_tridown_mpl() { + let plot = line_spline().with_mpl_style("v").unwrap().into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-tridown"); +} + +#[test] +fn style_line_markers_trileft_mpl() { + let plot = line_spline().with_mpl_style("<").unwrap().into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-trileft"); +} + +#[test] +fn style_line_markers_triright_mpl() { + let plot = line_spline().with_mpl_style(">").unwrap().into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-triright"); +} + +#[test] +fn style_line_markers_triup_color() { + let plot = line_spline() + .with_marker( + plotive::style::series::Marker::new_with_color( + plotive::ColorU8::from_html(b"#000").into(), + ) + .with_stroke(ColorU8::from_html(b"#080").into()) + .with_shape(plotive::style::MarkerShape::TriangleUp), + ) + .into_plot(); + let fig = fig_small(plot); + + assert_fig_eq_ref!(&fig, "style/line-markers-triup-color"); +} diff --git a/text/examples/text_line.rs b/text/examples/text_line.rs index 3ba585f..6ee3a65 100644 --- a/text/examples/text_line.rs +++ b/text/examples/text_line.rs @@ -3,7 +3,8 @@ use plotive_base::geom; use plotive_text::{bundled_font_db, font, line}; fn main() { - let db = bundled_font_db(); + let mut db = bundled_font_db(); + db.load_system_fonts(); let font = font::Font::default().with_families(vec![ font::Family::Named("Noto Sans".to_string()),