Skip to content

Commit b8f5dc8

Browse files
committed
also add struct for dynamic creation of colormaps
1 parent bd0ac39 commit b8f5dc8

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

plotters/src/style/colors/colormaps.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,96 @@ where
1414
}
1515

1616

17+
/// This struct is used to dynamically construct colormaps by giving it a slice of colors.
18+
/// It can then be used when being intantiated, but not with associated functions.
19+
/// ```
20+
/// use plotters::prelude::{BLACK,BLUE,WHITE,DerivedColorMap,ColorMap};
21+
///
22+
/// let derived_colormap = DerivedColorMap::new(
23+
/// &[BLACK,
24+
/// BLUE,
25+
/// WHITE]
26+
/// );
27+
///
28+
/// assert_eq!(derived_colormap.get_color(0.0), BLACK);
29+
/// assert_eq!(derived_colormap.get_color(0.5), BLUE);
30+
/// assert_eq!(derived_colormap.get_color(1.0), WHITE);
31+
/// ```
32+
pub struct DerivedColorMap<ColorType> {
33+
colors: Vec<ColorType>,
34+
}
35+
36+
37+
impl<ColorType: crate::style::Color + Clone> DerivedColorMap<ColorType> {
38+
pub fn new(colors: &[ColorType]) -> Self {
39+
DerivedColorMap { colors: colors.iter().map(|color| color.clone()).collect::<Vec<_>>() }
40+
}
41+
}
42+
43+
44+
macro_rules! calculate_new_color_value(
45+
($relative_difference:expr, $colors:expr, $index_upper:expr, $index_lower:expr, RGBColor) => {
46+
RGBColor(
47+
// These equations are a very complicated way of writing a simple linear extrapolation with lots of casting between numerical values
48+
// In principle every cast should be safe which is why we choose to unwrap
49+
// (1.0 - r) * color_value_1 + r * color_value_2
50+
((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].0).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].0).unwrap()).round().to_u8().unwrap(),
51+
((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].1).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].1).unwrap()).round().to_u8().unwrap(),
52+
((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].2).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].2).unwrap()).round().to_u8().unwrap()
53+
)
54+
};
55+
($relative_difference:expr, $colors:expr, $index_upper:expr, $index_lower:expr, RGBAColor) => {
56+
RGBAColor(
57+
// These equations are a very complicated way of writing a simple linear extrapolation with lots of casting between numerical values
58+
// In principle every cast should be safe which is why we choose to unwrap
59+
// (1.0 - r) * color_value_1 + r * color_value_2
60+
((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].0).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].0).unwrap()).round().to_u8().unwrap(),
61+
((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].1).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].1).unwrap()).round().to_u8().unwrap(),
62+
((FloatType::one() - $relative_difference) * FloatType::from_u8($colors[$index_upper].2).unwrap() + $relative_difference * FloatType::from_u8($colors[$index_lower].2).unwrap()).round().to_u8().unwrap(),
63+
((FloatType::one() - $relative_difference) * FloatType::from_f64($colors[$index_upper].3).unwrap() + $relative_difference * FloatType::from_f64($colors[$index_lower].3).unwrap()).to_f64().unwrap()
64+
)
65+
};
66+
($relative_difference:expr, $colors:expr, $index_upper:expr, $index_lower:expr, HSLColor) => {
67+
HSLColor(
68+
// These equations are a very complicated way of writing a simple linear extrapolation with lots of casting between numerical values
69+
// In principle every cast should be safe which is why we choose to unwrap
70+
// (1.0 - r) * color_value_1 + r * color_value_2
71+
((FloatType::one() - $relative_difference) * FloatType::from_f64($colors[$index_upper].0).unwrap() + $relative_difference * FloatType::from_f64($colors[$index_lower].0).unwrap()).to_f64().unwrap(),
72+
((FloatType::one() - $relative_difference) * FloatType::from_f64($colors[$index_upper].1).unwrap() + $relative_difference * FloatType::from_f64($colors[$index_lower].1).unwrap()).to_f64().unwrap(),
73+
((FloatType::one() - $relative_difference) * FloatType::from_f64($colors[$index_upper].2).unwrap() + $relative_difference * FloatType::from_f64($colors[$index_lower].2).unwrap()).to_f64().unwrap(),
74+
)
75+
};
76+
);
77+
78+
79+
macro_rules! implement_color_scale_for_derived_ColorMap{
80+
($($color_type:tt),+) => {
81+
$(
82+
impl<FloatType: Float + FromPrimitive + ToPrimitive> ColorMap<$color_type, FloatType> for DerivedColorMap<$color_type> {
83+
fn get_color_normalized(&self, h: FloatType, min: FloatType, max: FloatType) -> $color_type {
84+
// Ensure that we do have a value in bounds
85+
let h = h.max(min).min(max);
86+
// Make sure that we really have a minimal value which is smaller than the maximal value
87+
assert_eq!(min<max, true);
88+
// Next calculate a normalized value between 0.0 and 1.0
89+
let t = (h - min)/(max-min);
90+
let approximate_index = t * (FloatType::from_usize(self.colors.len()).unwrap() - FloatType::one()).max(FloatType::zero());
91+
// Calculate which index are the two most nearest of the supplied value
92+
let index_lower = approximate_index.floor().to_usize().unwrap();
93+
let index_upper = approximate_index.ceil().to_usize().unwrap();
94+
// Calculate the relative difference, ie. is the actual value more towards the color of index_upper or index_lower?
95+
let relative_difference = approximate_index.ceil() - approximate_index;
96+
// Interpolate the final color linearly
97+
calculate_new_color_value!(relative_difference, self.colors, index_upper, index_lower, $color_type)
98+
}
99+
}
100+
)+
101+
}
102+
}
103+
104+
implement_color_scale_for_derived_ColorMap!{RGBAColor, RGBColor, HSLColor}
105+
106+
17107
macro_rules! count {
18108
() => (0usize);
19109
($x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));

0 commit comments

Comments
 (0)