1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
//! # plotters-layout
//!
//! Layout utility library for [plotters](::plotters) crate.
//!
//! ## Creating a chart whose plotting area has specified size
//!
//! ```
//! use plotters::prelude::*;
//! use plotters_layout::ChartLayout;
//! use plotters::backend::{RGBPixel, PixelFormat};
//!
//! let mut layout = ChartLayout::new();
//! layout.caption("Graph Title", ("sans-serif", 40))?
//! .margin(4)
//! .x_label_area_size(40)
//! .y_label_area_size(40);
//! let (w, h): (u32, u32) = layout.desired_image_size((200, 160));
//! let mut buf = vec![0u8; (w * h) as usize * RGBPixel::PIXEL_SIZE];
//! let graph = BitMapBackend::with_buffer(&mut buf, (w, h));
//! let root_area = graph.into_drawing_area();
//! let builder = layout.bind(&root_area)?;
//! let chart = builder.build_cartesian_2d(0f64..20f64, 0f64..16f64)?;
//! assert_eq!(chart.plotting_area().dim_in_pixel(), (200, 160));
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ## Adjusting aspect ratio
//!
//! ```
//! use plotters::prelude::*;
//! use plotters_layout::{centering_ranges, ChartLayout};
//!
//! let min_range = (-200f64..200f64, -100f64..100f64);
//!
//! let mut buf = String::new();
//! let graph = SVGBackend::with_string(&mut buf, (1280, 720));
//! let root_area = graph.into_drawing_area();
//!
//! let mut builder = ChartLayout::new()
//! .caption("Graph Title", ("sans-serif", 40))?
//! .margin(4)
//! .x_label_area_size(40)
//! .y_label_area_size(40)
//! .bind(&root_area)?;
//!
//! let (width, height) = builder.estimate_plot_area_size();
//! let (x_range, y_range) = centering_ranges(&min_range, &(width as f64, height as f64));
//!
//! // (x_range, y_range) and (width, height) has same aspect ratio
//! let inner_ratio = (x_range.end - x_range.start) / (y_range.end - y_range.start);
//! let outer_ratio = width as f64 / height as f64;
//! assert!((inner_ratio - outer_ratio).abs() < 1e-8);
//!
//! let chart = builder.build_cartesian_2d(x_range, y_range)?;
//! assert_eq!(chart.plotting_area().dim_in_pixel(), (width, height));
//!
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
mod chart;
use std::ops::{Add, Div, Mul, Range, Sub};
pub use crate::chart::*;
pub fn centering_ranges<T, S>(
minimum: &(Range<T>, Range<T>),
destination: &(S, S),
) -> (Range<T>, Range<T>)
where
T: Copy + PartialOrd + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>,
S: Copy + Into<T>,
{
let sx = minimum.0.end - minimum.0.start;
let sy = minimum.1.end - minimum.1.start;
let dx = destination.0.into();
let dy = destination.1.into();
let half = dx / (dx + dx); // == 0.5
if sx * dy < sy * dx {
// sx -> sy * dx / dy
let radius = sy * dx / dy * half;
let center = (minimum.0.start + minimum.0.end) * half;
let s0 = (center - radius)..(radius + center);
(s0, minimum.1.clone())
} else {
// sy -> sx * dy / dx
let radius = sx * dy / dx * half;
let center = (minimum.1.end + minimum.1.start) * half;
let s1 = (center - radius)..(radius + center);
(minimum.0.clone(), s1)
}
}