Skip to content

Commit bb25570

Browse files
authored
Merge pull request #481 from jonaspleyer/master
Enable macro usage for users to define colormaps
2 parents 62783f4 + 88a1492 commit bb25570

File tree

2 files changed

+92
-30
lines changed

2 files changed

+92
-30
lines changed

plotters/blub.png

Lines changed: 3 additions & 0 deletions
Loading

plotters/src/style/colors/colormaps.rs

Lines changed: 89 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
use crate::style::{HSLColor, RGBAColor, RGBColor};
22

3-
use num_traits::{Float, FromPrimitive, ToPrimitive};
4-
53
/// Converts scalar values to colors.
64
pub trait ColorMap<ColorType: crate::prelude::Color, FloatType = f32>
75
where
8-
FloatType: Float,
6+
FloatType: num_traits::Float,
97
{
108
/// Takes a scalar value 0.0 <= h <= 1.0 and returns the corresponding color.
119
/// Typically color-scales are named according to which color-type they return.
@@ -47,6 +45,8 @@ impl<ColorType: crate::style::Color + Clone> DerivedColorMap<ColorType> {
4745
}
4846
}
4947

48+
#[macro_export]
49+
#[doc(hidden)]
5050
macro_rules! calculate_new_color_value(
5151
($relative_difference:expr, $colors:expr, $index_upper:expr, $index_lower:expr, RGBColor) => {
5252
RGBColor(
@@ -81,20 +81,34 @@ macro_rules! calculate_new_color_value(
8181
};
8282
);
8383

84-
fn calculate_relative_difference_index_lower_upper<
85-
FloatType: Float + FromPrimitive + ToPrimitive,
84+
// Helper function to calculate the lower and upper index nearest to a provided float value.
85+
//
86+
// Used to obtain colors from a colorscale given a value h between 0.0 and 1.0.
87+
// It also returns the relative difference which can then be used to calculate a linear interpolation between the two nearest colors.
88+
// ```
89+
// # use plotters::prelude::*;
90+
// let r = calculate_relative_difference_index_lower_upper(1.2, 1.0, 3.0, 4);
91+
// let (relative_difference, lower_index, upper_index) = r;
92+
//
93+
// assert_eq!(relative_difference, 0.7000000000000001);
94+
// assert_eq!(lower_index, 0);
95+
// assert_eq!(upper_index, 1);
96+
// ```
97+
#[doc(hidden)]
98+
pub fn calculate_relative_difference_index_lower_upper<
99+
FloatType: num_traits::Float + num_traits::FromPrimitive + num_traits::ToPrimitive,
86100
>(
87101
h: FloatType,
88102
min: FloatType,
89103
max: FloatType,
90-
n_colors: usize,
104+
n_steps: usize,
91105
) -> (FloatType, usize, usize) {
92106
// Ensure that we do have a value in bounds
93107
let h = num_traits::clamp(h, min, max);
94108
// Next calculate a normalized value between 0.0 and 1.0
95109
let t = (h - min) / (max - min);
96110
let approximate_index =
97-
t * (FloatType::from_usize(n_colors).unwrap() - FloatType::one()).max(FloatType::zero());
111+
t * (FloatType::from_usize(n_steps).unwrap() - FloatType::one()).max(FloatType::zero());
98112
// Calculate which index are the two most nearest of the supplied value
99113
let index_lower = approximate_index.floor().to_usize().unwrap();
100114
let index_upper = approximate_index.ceil().to_usize().unwrap();
@@ -106,7 +120,7 @@ fn calculate_relative_difference_index_lower_upper<
106120
macro_rules! implement_color_scale_for_derived_color_map{
107121
($($color_type:ident),+) => {
108122
$(
109-
impl<FloatType: Float + FromPrimitive + ToPrimitive> ColorMap<$color_type, FloatType> for DerivedColorMap<$color_type> {
123+
impl<FloatType: num_traits::Float + num_traits::FromPrimitive + num_traits::ToPrimitive> ColorMap<$color_type, FloatType> for DerivedColorMap<$color_type> {
110124
fn get_color_normalized(&self, h: FloatType, min: FloatType, max: FloatType) -> $color_type {
111125
let (
112126
relative_difference,
@@ -119,7 +133,7 @@ macro_rules! implement_color_scale_for_derived_color_map{
119133
self.colors.len()
120134
);
121135
// Interpolate the final color linearly
122-
calculate_new_color_value!(
136+
$crate::calculate_new_color_value!(
123137
relative_difference,
124138
self.colors,
125139
index_upper,
@@ -134,11 +148,30 @@ macro_rules! implement_color_scale_for_derived_color_map{
134148

135149
implement_color_scale_for_derived_color_map! {RGBAColor, RGBColor, HSLColor}
136150

151+
#[macro_export]
152+
#[doc(hidden)]
153+
// Counts the number of arguments which are separated by spaces
154+
//
155+
// This macro is used internally to determine the size of an array to hold all new colors.
156+
// ```
157+
// # use plotters::count;
158+
// let counted = count!{Plotting is fun};
159+
// assert_eq!(counted, 3);
160+
//
161+
// let counted2 = count!{0_usize was my favourite 1_f64 last century};
162+
// assert_eq!(counted2, 7);
163+
//
164+
// let new_array = ["Hello"; count!(Plotting is fun)];
165+
// assert_eq!(new_array, ["Hello"; 3]);
166+
// ```
137167
macro_rules! count {
138168
() => (0usize);
139-
($x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
169+
($x:tt $($xs:tt)* ) => (1usize + $crate::count!($($xs)*));
140170
}
141171

172+
#[macro_export]
173+
#[doc(hidden)]
174+
/// Converts a given color identifier and a sequence of colors to an array of them.
142175
macro_rules! define_colors_from_list_of_values_or_directly{
143176
($color_type:ident, $(($($color_value:expr),+)),+) => {
144177
[$($color_type($($color_value),+)),+]
@@ -148,9 +181,12 @@ macro_rules! define_colors_from_list_of_values_or_directly{
148181
};
149182
}
150183

184+
#[macro_export]
185+
#[doc(hidden)]
186+
/// Implements the [ColorMap] trait on a given color scale.
151187
macro_rules! implement_linear_interpolation_color_map {
152188
($color_scale_name:ident, $color_type:ident) => {
153-
impl<FloatType: std::fmt::Debug + Float + FromPrimitive + ToPrimitive>
189+
impl<FloatType: std::fmt::Debug + num_traits::Float + num_traits::FromPrimitive + num_traits::ToPrimitive>
154190
ColorMap<$color_type, FloatType> for $color_scale_name
155191
{
156192
fn get_color_normalized(
@@ -170,7 +206,7 @@ macro_rules! implement_linear_interpolation_color_map {
170206
Self::COLORS.len()
171207
);
172208
// Interpolate the final color linearly
173-
calculate_new_color_value!(
209+
$crate::calculate_new_color_value!(
174210
relative_difference,
175211
Self::COLORS,
176212
index_upper,
@@ -184,7 +220,7 @@ macro_rules! implement_linear_interpolation_color_map {
184220
#[doc = "Get color value from `"]
185221
#[doc = stringify!($color_scale_name)]
186222
#[doc = "` by supplying a parameter 0.0 <= h <= 1.0"]
187-
pub fn get_color<FloatType: std::fmt::Debug + Float + FromPrimitive + ToPrimitive>(
223+
pub fn get_color<FloatType: std::fmt::Debug + num_traits::Float + num_traits::FromPrimitive + num_traits::ToPrimitive>(
188224
h: FloatType,
189225
) -> $color_type {
190226
let color_scale = $color_scale_name {};
@@ -195,7 +231,7 @@ macro_rules! implement_linear_interpolation_color_map {
195231
#[doc = stringify!($color_scale_name)]
196232
#[doc = "` by supplying lower and upper bounds min, max and a parameter h where min <= h <= max"]
197233
pub fn get_color_normalized<
198-
FloatType: std::fmt::Debug + Float + FromPrimitive + ToPrimitive,
234+
FloatType: std::fmt::Debug + num_traits::Float + num_traits::FromPrimitive + num_traits::ToPrimitive,
199235
>(
200236
h: FloatType,
201237
min: FloatType,
@@ -208,34 +244,57 @@ macro_rules! implement_linear_interpolation_color_map {
208244
};
209245
}
210246

247+
#[doc(inline)]
248+
pub use crate::def_linear_colormap;
249+
211250
#[macro_export]
212-
/// Macro to create a new colormap with evenly spaced colors at compile-time.
213-
macro_rules! define_linear_interpolation_color_map{
251+
#[doc(hidden)]
252+
/// Create a new colormap with evenly spaced colors and interpolates between them automatically.
253+
///
254+
/// This macro works by taking a identifier (name) for the colormap, the type of color to specify, a
255+
/// docstring and a list of colors and constructs an empty struct on which it implements the [ColorMap] trait.
256+
///
257+
/// ```
258+
/// use plotters::prelude::*;
259+
/// def_linear_colormap! {
260+
/// BlackWhite,
261+
/// RGBColor,
262+
/// "Simple chromatic colormap from black to white.",
263+
/// ( 0, 0, 0),
264+
/// (255, 255, 255)
265+
/// }
266+
///
267+
/// assert_eq!(BlackWhite::get_color(0.0), RGBColor(0,0,0));
268+
/// ```
269+
///
270+
/// Hint: Some helper macros and functions have been deliberately hidden from end users.
271+
/// Look for them in the source code if you are interested.
272+
macro_rules! def_linear_colormap{
214273
($color_scale_name:ident, $color_type:ident, $doc:expr, $(($($color_value:expr),+)),*) => {
215274
#[doc = $doc]
216-
pub struct $color_scale_name {}
275+
pub struct $color_scale_name;
217276

218277
impl $color_scale_name {
219278
// const COLORS: [$color_type; $number_colors] = [$($color_type($($color_value),+)),+];
220-
// const COLORS: [$color_type; count!($(($($color_value:expr),+))*)] = [$($color_type($($color_value),+)),+];
221-
const COLORS: [$color_type; count!($(($($color_value:expr),+))*)] = define_colors_from_list_of_values_or_directly!{$color_type, $(($($color_value),+)),*};
279+
// const COLORS: [$color_type; $crate::count!($(($($color_value:expr),+))*)] = [$($color_type($($color_value),+)),+];
280+
const COLORS: [$color_type; $crate::count!($(($($color_value:expr),+))*)] = $crate::define_colors_from_list_of_values_or_directly!{$color_type, $(($($color_value),+)),*};
222281
}
223282

224-
implement_linear_interpolation_color_map!{$color_scale_name, $color_type}
283+
$crate::implement_linear_interpolation_color_map!{$color_scale_name, $color_type}
225284
};
226285
($color_scale_name:ident, $color_type:ident, $doc:expr, $($color_complete:tt),+) => {
227286
#[doc = $doc]
228-
pub struct $color_scale_name {}
287+
pub struct $color_scale_name;
229288

230289
impl $color_scale_name {
231-
const COLORS: [$color_type; count!($($color_complete)*)] = define_colors_from_list_of_values_or_directly!{$($color_complete),+};
290+
const COLORS: [$color_type; $crate::count!($($color_complete)*)] = $crate::define_colors_from_list_of_values_or_directly!{$($color_complete),+};
232291
}
233292

234-
implement_linear_interpolation_color_map!{$color_scale_name, $color_type}
293+
$crate::implement_linear_interpolation_color_map!{$color_scale_name, $color_type}
235294
}
236295
}
237296

238-
define_linear_interpolation_color_map! {
297+
def_linear_colormap! {
239298
ViridisRGBA,
240299
RGBAColor,
241300
"A colormap optimized for visually impaired people (RGBA format).
@@ -251,7 +310,7 @@ define_linear_interpolation_color_map! {
251310
(254, 232, 37, 1.0)
252311
}
253312

254-
define_linear_interpolation_color_map! {
313+
def_linear_colormap! {
255314
ViridisRGB,
256315
RGBColor,
257316
"A colormap optimized for visually impaired people (RGB Format).
@@ -267,23 +326,23 @@ define_linear_interpolation_color_map! {
267326
(254, 232, 37)
268327
}
269328

270-
define_linear_interpolation_color_map! {
329+
def_linear_colormap! {
271330
BlackWhite,
272331
RGBColor,
273332
"Simple chromatic colormap from black to white.",
274333
( 0, 0, 0),
275334
(255, 255, 255)
276335
}
277336

278-
define_linear_interpolation_color_map! {
337+
def_linear_colormap! {
279338
MandelbrotHSL,
280339
HSLColor,
281340
"Colormap created to replace the one used in the mandelbrot example.",
282341
(0.0, 1.0, 0.5),
283342
(1.0, 1.0, 0.5)
284343
}
285344

286-
define_linear_interpolation_color_map! {
345+
def_linear_colormap! {
287346
VulcanoHSL,
288347
HSLColor,
289348
"A vulcanic colormap that display red/orange and black colors",
@@ -292,7 +351,7 @@ define_linear_interpolation_color_map! {
292351
}
293352

294353
use super::full_palette::*;
295-
define_linear_interpolation_color_map! {
354+
def_linear_colormap! {
296355
Bone,
297356
RGBColor,
298357
"Dark colormap going from black over blue to white.",
@@ -301,7 +360,7 @@ define_linear_interpolation_color_map! {
301360
WHITE
302361
}
303362

304-
define_linear_interpolation_color_map! {
363+
def_linear_colormap! {
305364
Copper,
306365
RGBColor,
307366
"Friendly black to brown colormap.",

0 commit comments

Comments
 (0)