plot: Apply linear scale based on the direction of given range (#1219)
## Breaking Change - Apply linear scale based on the direction of given range. ```diff - ScaleLinear::new(vec![1., 2., 3.], vec![0., 100.]) + ScaleLinear::new(vec![1., 2., 3.], vec![100., 0.]) ``` Currently, you can draw the linear scale from minimum to maximum or from maximum to minimum; it depends on the direction of the range.
This commit is contained in:
parent
5e302866ce
commit
78dccd4d79
4 changed files with 57 additions and 19 deletions
|
|
@ -107,7 +107,7 @@ where
|
||||||
.flat_map(|v| self.y.iter().map(|y_fn| y_fn(v)))
|
.flat_map(|v| self.y.iter().map(|y_fn| y_fn(v)))
|
||||||
.chain(Some(Y::zero()))
|
.chain(Some(Y::zero()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let y = ScaleLinear::new(domain, vec![10., height]);
|
let y = ScaleLinear::new(domain, vec![height, 10.]);
|
||||||
|
|
||||||
// Draw X axis
|
// Draw X axis
|
||||||
let data_len = self.data.len();
|
let data_len = self.data.len();
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ where
|
||||||
.map(|v| y_fn(v))
|
.map(|v| y_fn(v))
|
||||||
.chain(Some(Y::zero()))
|
.chain(Some(Y::zero()))
|
||||||
.collect(),
|
.collect(),
|
||||||
vec![10., height],
|
vec![height, 10.],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Draw X axis
|
// Draw X axis
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ where
|
||||||
.map(|v| y_fn(v))
|
.map(|v| y_fn(v))
|
||||||
.chain(Some(Y::zero()))
|
.chain(Some(Y::zero()))
|
||||||
.collect(),
|
.collect(),
|
||||||
vec![10., height],
|
vec![height, 10.],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Draw X axis
|
// Draw X axis
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ use super::{sealed::Sealed, Scale};
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ScaleLinear<T> {
|
pub struct ScaleLinear<T> {
|
||||||
domain_len: usize,
|
domain_len: usize,
|
||||||
domain_min: T,
|
domain_start: T,
|
||||||
domain_diff: T,
|
domain_diff: T,
|
||||||
range_min: f32,
|
range_start: f32,
|
||||||
range_diff: f32,
|
range_diff: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -19,24 +19,34 @@ where
|
||||||
T: Copy + PartialOrd + Num + ToPrimitive + Sealed,
|
T: Copy + PartialOrd + Num + ToPrimitive + Sealed,
|
||||||
{
|
{
|
||||||
pub fn new(domain: Vec<T>, range: Vec<f32>) -> Self {
|
pub fn new(domain: Vec<T>, range: Vec<f32>) -> Self {
|
||||||
let (domain_min, domain_max) = domain
|
let (domain_start, domain_end) = domain
|
||||||
.iter()
|
.iter()
|
||||||
.minmax()
|
.minmax()
|
||||||
.into_option()
|
.into_option()
|
||||||
.map_or((T::zero(), T::zero()), |(min, max)| (*min, *max));
|
.map_or((T::zero(), T::zero()), |(min, max)| (*min, *max));
|
||||||
|
|
||||||
let (range_min, range_max) = range
|
let (range_start, range_end) =
|
||||||
.iter()
|
range
|
||||||
.minmax()
|
.iter()
|
||||||
.into_option()
|
.minmax()
|
||||||
.map_or((0., 0.), |(min, max)| (*min, *max));
|
.into_option()
|
||||||
|
.map_or((0., 0.), |(min, max)| {
|
||||||
|
let min_pos = range.iter().position(|&x| x == *min).unwrap_or(0);
|
||||||
|
let max_pos = range.iter().position(|&x| x == *max).unwrap_or(0);
|
||||||
|
|
||||||
|
if min_pos <= max_pos {
|
||||||
|
(*min, *max)
|
||||||
|
} else {
|
||||||
|
(*max, *min)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
domain_len: domain.len(),
|
domain_len: domain.len(),
|
||||||
domain_min,
|
domain_start,
|
||||||
domain_diff: domain_max - domain_min,
|
domain_diff: domain_end - domain_start,
|
||||||
range_min,
|
range_start,
|
||||||
range_diff: range_max - range_min,
|
range_diff: range_end - range_start,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -50,9 +60,9 @@ where
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ratio = ((*value - self.domain_min) / self.domain_diff).to_f32()?;
|
let ratio = ((*value - self.domain_start) / self.domain_diff).to_f32()?;
|
||||||
|
|
||||||
Some((1. - ratio) * self.range_diff + self.range_min)
|
Some(ratio * self.range_diff + self.range_start)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn least_index(&self, tick: f32) -> usize {
|
fn least_index(&self, tick: f32) -> usize {
|
||||||
|
|
@ -70,15 +80,43 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_scale_linear_1() {
|
fn test_scale_linear() {
|
||||||
let scale = ScaleLinear::new(vec![1., 2., 3.], vec![0., 100.]);
|
let scale = ScaleLinear::new(vec![1., 2., 3.], vec![0., 100.]);
|
||||||
|
assert_eq!(scale.tick(&1.), Some(0.));
|
||||||
|
assert_eq!(scale.tick(&2.), Some(50.));
|
||||||
|
assert_eq!(scale.tick(&3.), Some(100.));
|
||||||
|
|
||||||
|
let scale = ScaleLinear::new(vec![1., 2., 3.], vec![100., 0.]);
|
||||||
assert_eq!(scale.tick(&1.), Some(100.));
|
assert_eq!(scale.tick(&1.), Some(100.));
|
||||||
assert_eq!(scale.tick(&2.), Some(50.));
|
assert_eq!(scale.tick(&2.), Some(50.));
|
||||||
assert_eq!(scale.tick(&3.), Some(0.));
|
assert_eq!(scale.tick(&3.), Some(0.));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_scale_linear_2() {
|
fn test_scale_linear_multiple_range() {
|
||||||
|
let scale = ScaleLinear::new(vec![1., 2., 3.], vec![0., 50., 100.]);
|
||||||
|
assert_eq!(scale.tick(&1.), Some(0.));
|
||||||
|
assert_eq!(scale.tick(&2.), Some(50.));
|
||||||
|
assert_eq!(scale.tick(&3.), Some(100.));
|
||||||
|
|
||||||
|
let scale = ScaleLinear::new(vec![1., 2., 3.], vec![100., 50., 0.]);
|
||||||
|
assert_eq!(scale.tick(&1.), Some(100.));
|
||||||
|
assert_eq!(scale.tick(&2.), Some(50.));
|
||||||
|
assert_eq!(scale.tick(&3.), Some(0.));
|
||||||
|
|
||||||
|
let scale = ScaleLinear::new(vec![1., 2., 3.], vec![100., 0., 100.]);
|
||||||
|
assert_eq!(scale.tick(&1.), Some(100.));
|
||||||
|
assert_eq!(scale.tick(&2.), Some(50.));
|
||||||
|
assert_eq!(scale.tick(&3.), Some(0.));
|
||||||
|
|
||||||
|
let scale = ScaleLinear::new(vec![1., 2., 3.], vec![0., 100., 0.]);
|
||||||
|
assert_eq!(scale.tick(&1.), Some(0.));
|
||||||
|
assert_eq!(scale.tick(&2.), Some(50.));
|
||||||
|
assert_eq!(scale.tick(&3.), Some(100.));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scale_linear_empty() {
|
||||||
let scale = ScaleLinear::new(vec![], vec![0., 100.]);
|
let scale = ScaleLinear::new(vec![], vec![0., 100.]);
|
||||||
assert_eq!(scale.tick(&1.), None);
|
assert_eq!(scale.tick(&1.), None);
|
||||||
assert_eq!(scale.tick(&2.), None);
|
assert_eq!(scale.tick(&2.), None);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue