Draw 3D plots
Plotters also allows rendering 3D figures. Instead of using build_cartesian_2d
, 3D plots are build with ChartBuilder
by calling build_cartesian_3d
method. Similar to the 2D figures, Plotters also can draw basic components for 3D charts.
3D plotting environment && basic figure component
This following example demonstrate how to build a basic 3d plotting environment. Unlike 2d chart context, you need to configure configure_axes
to build the basic component.
use plotters::prelude::*;
fn main() {
let root = BitMapBackend::new("images/3d-env.png", (640, 480)).into_drawing_area();
root.fill(&WHITE).unwrap();
let mut chart = ChartBuilder::on(&root)
.margin(20)
.caption("Empty 3D Figure", ("sans-serif", 40))
.build_cartesian_3d(0.0..1.0, 0.0..1.0, 0.0..1.0)
.unwrap();
chart.configure_axes().draw().unwrap();
}
Draw a line series
In 3D plotting environment, you can draw a line series in the same way.
use plotters::prelude::*;
fn main() {
let root = BitMapBackend::new("images/3d-line.png", (640, 480)).into_drawing_area();
root.fill(&WHITE).unwrap();
let mut chart = ChartBuilder::on(&root)
.margin(20)
.caption("3D Line", ("sans-serif", 40))
.build_cartesian_3d(-1.0..1.0, -1.0..1.0, -1.0..1.0)
.unwrap();
chart.configure_axes().draw().unwrap();
chart.draw_series(LineSeries::new(
(-100..100).map(|y| y as f64 / 100.0).map(|y| ((y * 10.0).sin(), y, (y * 10.0).cos())),
&RED
)).unwrap();
}
Draw a 3D bar chart
Note: This is currently only avaiable with developement version of plotters
Next, we are going to deomonstrate Plotters' 3D elements. We use the Cubiod
3D element to build a 3D bar chart.
use plotters_master::prelude::*;
fn main() {
let root = BitMapBackend::new("images/3d-bar.png", (640, 480)).into_drawing_area();
root.fill(&WHITE).unwrap();
let mut chart = ChartBuilder::on(&root)
.margin(20)
.caption("3D Bar", ("sans-serif", 40))
.build_cartesian_3d(0i32..10, -10i32..10, 0i32..10)
.unwrap();
chart.configure_axes().draw().unwrap();
chart.draw_series(
(0i32..10i32)
.map(|x| std::iter::repeat(x).zip(0i32..10))
.flatten()
.map(|(x,z)| {
Cubiod::new([(x, 0, z), (x + 1, x - z, z + 1)], BLUE.filled(), &BLACK)
})
).unwrap();
}
3D Surface
We can draw 3d surface as well by drawing a series of polygon. Here's an example of how to draw a surface plot.
use plotters::prelude::*;
fn main() {
let root = BitMapBackend::new("images/3d-surface.png", (640, 480)).into_drawing_area();
root.fill(&WHITE).unwrap();
let mut chart = ChartBuilder::on(&root)
.margin(20)
.caption("3D Surface", ("sans-serif", 40))
.build_cartesian_3d(-3.0..3.0, -3.0..3.0, -3.0..3.0)
.unwrap();
chart.configure_axes().draw().unwrap();
let mut data = vec![];
for x in (-25..25).map(|v| v as f64 / 10.0) {
let mut row = vec![];
for z in (-25..25).map(|v| v as f64 / 10.0) {
row.push((x, (x * x + z * z).cos(), z));
}
data.push(row);
}
chart.draw_series(
(0..49)
.map(|x| std::iter::repeat(x).zip(0..49))
.flatten()
.map(|(x,z)| {
Polygon::new(vec![
data[x][z],
data[x+1][z],
data[x+1][z+1],
data[x][z+1],
], &BLUE.mix(0.3))
})
).unwrap();
}
Drawing with surface series
Note: This feature is only avaiable in development version
use plotters_master::prelude::*;
fn main() {
let root = BitMapBackend::new("images/3d-surface-series.png", (640, 480)).into_drawing_area();
root.fill(&WHITE).unwrap();
let mut chart = ChartBuilder::on(&root)
.margin(20)
.caption("3D Surface", ("sans-serif", 40))
.build_cartesian_3d(-3.0..3.0, -3.0..3.0, -3.0..3.0)
.unwrap();
chart.configure_axes().draw().unwrap();
chart.draw_series(SurfaceSeries::xoz(
(-25..25).map(|v| v as f64 / 10.0),
(-25..25).map(|v| v as f64 / 10.0),
|x:f64,z:f64|(x * x + z * z).cos()).style(&BLUE.mix(0.2))
).unwrap();
}
Customize perspective matrix
Plotters also allows user override the default prespective matrix, by doing so, you can zoom and rotate the 3d figure. The following example demostrate how.
use plotters::prelude::*;
fn main() {
let root = BitMapBackend::new("images/3d-matrix.png", (640, 480)).into_drawing_area();
root.fill(&WHITE).unwrap();
let mut chart = ChartBuilder::on(&root)
.margin(20)
.build_cartesian_3d(-1.0..1.0, -1.0..1.0, -1.0..1.0)
.unwrap();
// You need configure the projection matrix before start drawing anything
chart.with_projection(|mut pb| {
pb.pitch = 1.2;
pb.yaw = 0.5;
pb.scale = 0.7;
pb.into_matrix()
});
chart.configure_axes().draw().unwrap();
chart.draw_series(LineSeries::new(
(-100..100).map(|y| y as f64 / 100.0).map(|y| ((y * 10.0).sin(), y, (y * 10.0).cos())),
&RED
)).unwrap();
}