【rust】《Rust深度学习[3]-数据可视化库(Plotters)》
什么是Plotters?
Plotters是一个用纯Rust开发的图形库,用于中渲染图形、图表和数据可视化。它支持静态图片渲染和实时渲染,并支持多种后端,包括:位图格式(png、bmp、gif等)、矢量图(svg)、窗口和HTML5 Canvas。
Plotters对不同后端使用统一的高级API,并允许开发者自定义坐标系。在Plotters中,任何类型的图表都被抽象为一系列绘图操作,通过这些绘图操作,开发者可以自由地操控和组合绘图内容。因此Plotters不会限制图表类型,开发者可以组合出任意内容的图表。
导入依赖库
[dependencies] plotters = "0.3.3"
折线图
use plotters::prelude::*; fn main() -> Result<(), Box<dyn std::error::Error>> { // 创建svg图片对象 let root = SVGBackend::new("plot.svg", (640, 480)).into_drawing_area(); // 图片对象的背景颜色填充 root.fill(&WHITE)?; // 创建绘图对象 let mut chart = ChartBuilder::on(&root) // 图表名称 (字体样式, 字体大小) .caption("折线图", ("sans-serif", 30)) // 图表左侧与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Left, 40) // 图表底部与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Bottom, 40) // 构建二维图像, x轴 0.0 - 10.0; y轴 0.0 - 10.0; .build_cartesian_2d(0.0..10.0, 0.0..10.0)?; // 配置网格线 chart.configure_mesh().draw()?; // 绘制折线 chart.draw_series(LineSeries::new( // vec![(0., 2.), (1., 1.), (2., 2.), (3., 3.), (4., 4.), (5., 5.), (6., 6.), (7., 7.), (8., 8.), (9., 9.)], vec![0., 1., 2., 3., 4., 5., 6., 7., 8.].iter().map(|x| (*x, *x)), // 线条颜色 &BLUE, ))?; Ok(()) }
多折线图
use plotters::prelude::*; fn main() -> Result<(), Box<dyn std::error::Error>> { // 创建svg图片对象 let root = SVGBackend::new("plot.svg", (640, 480)).into_drawing_area(); // 图片对象的背景颜色填充 root.fill(&WHITE)?; // 创建绘图对象 let mut chart = ChartBuilder::on(&root) // 图表名称 (字体样式, 字体大小) .caption("多折线图", ("sans-serif", 30)) // 图表左侧与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Left, 40) // 图表底部与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Bottom, 40) // 构建二维图像, x轴 0.0 - 10.0; y轴 0.0 - 10.0; .build_cartesian_2d(0.0..10.0, 0.0..10.0)?; // 配置网格线 chart.configure_mesh().draw()?; // 绘制多折线图 // 折线1 chart.draw_series(LineSeries::new( // x.powf(2) 求x的2次幂 (0..10).map(|x| (x as f64, (x as f64).powf(2.0))), &RED.stroke_width(5).color, // 标签 ))?.label("y=x^2") .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED)); // 折线2 chart.draw_series(LineSeries::new( (0..10).map(|x| (x as f64, (x as f64).powf(2.0) + 2.0)), &BLUE.stroke_width(5).color, // 标签 ))?.label("y=x^2+2") .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE)); // 配置标签样式 chart.configure_series_labels() .background_style(&WHITE.mix(0.8)) .border_style(&BLACK) .draw()?; Ok(()) }
散点图
use plotters::prelude::*; fn main() -> Result<(), Box<dyn std::error::Error>> { // 创建svg图片对象 let root = SVGBackend::new("plot.svg", (640, 480)).into_drawing_area(); // 图片对象的背景颜色填充 root.fill(&WHITE)?; // 创建绘图对象 let mut chart = ChartBuilder::on(&root) // 图表名称 (字体样式, 字体大小) .caption("散点图", ("sans-serif", 30)) // 图表左侧与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Left, 40) // 图表底部与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Bottom, 40) // 构建二维图像, x轴 0.0 - 10.0; y轴 0.0 - 10.0; .build_cartesian_2d(0.0..10.0, 0.0..10.0)?; // 配置网格线 chart.configure_mesh().draw()?; // 散点位置 let data = [ (1., 2.), (2., 3.), (3., 4.), (4., 5.), (5., 6.), ]; // 绘制散点 chart.draw_series( data.iter() .map(|(x, y)| { Circle::new((*x, *y), 5, BLUE.filled()) }) .collect::<Vec<_>>(), )?; Ok(()) }
多标记散点图
use plotters::prelude::*; const DATA1: [(i32, i32); 30] = [ (-3, 1), (-2, 3), (4, 2), (3, 0), (6, -5), (3, 11), (6, 0), (2, 14), (3, 9), (14, 7), (8, 11), (10, 16), (7, 15), (13, 8), (17, 14), (13, 17), (19, 11), (18, 8), (15, 8), (23, 23), (15, 20), (22, 23), (22, 21), (21, 30), (19, 28), (22, 23), (30, 23), (26, 35), (33, 19), (26, 19) ]; const DATA2: [(i32, i32); 30] = [ (1, 22), (0, 22), (1, 20), (2, 24), (4, 26), (6, 24), (5, 27), (6, 27), (7, 27), (8, 30), (10, 30), (10, 33), (12, 34), (13, 31), (15, 35), (14, 33), (17, 36), (16, 35), (17, 39), (19, 38), (21, 38), (22, 39), (23, 43), (24, 44), (24, 46), (26, 47), (27, 48), (26, 49), (28, 47), (28, 50) ]; fn main() -> Result<(), Box<dyn std::error::Error>> { // 创建svg图片对象 let root = SVGBackend::new("plot.svg", (640, 480)).into_drawing_area(); // 图片对象的背景颜色填充 root.fill(&WHITE)?; // 创建绘图对象 let mut chart = ChartBuilder::on(&root) // 图表名称 (字体样式, 字体大小) .caption("散点图", ("sans-serif", 30)) // 图表左侧与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Left, 40) // 图表底部与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Bottom, 40) // 构建二维图像, x轴 0.0 - 10.0; y轴 0.0 - 10.0; .build_cartesian_2d(-10..50, -10..50)?; // 配置网格线 chart.configure_mesh().draw()?; // 设置三角形标记散点 chart.draw_series( DATA1.iter().map( |point| TriangleMarker::new(*point, 5, &BLUE) ), )?.label("三角") .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE)); // 设置圆圈标记散点 chart.draw_series( DATA2.iter().map( |point| Circle::new(*point, 5, &RED) ), )?.label("圆圈") .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED)); // 配置标签样式 chart.configure_series_labels() .background_style(&WHITE.mix(0.8)) .border_style(&BLACK) .draw()?; Ok(()) }
面积图
use plotters::prelude::*; fn main() -> Result<(), Box<dyn std::error::Error>> { // 创建svg图片对象 let root = SVGBackend::new("plot.svg", (640, 480)).into_drawing_area(); // 图片对象的背景颜色填充 root.fill(&WHITE)?; // 创建绘图对象 let mut chart = ChartBuilder::on(&root) // 图表名称 (字体样式, 字体大小) .caption("面积图", ("sans-serif", 30)) // 图表左侧与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Left, 40) // 图表底部与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Bottom, 40) // 构建二维图像, x轴 0.0 - 10.0; y轴 0.0 - 10.0; .build_cartesian_2d(0..10, 0..50)?; // 配置网格线 chart.configure_mesh().draw()?; let data = [25, 37, 15, 32, 45, 33, 32, 10, 29, 0, 21]; let temp = (0..).zip(data.iter().map(|x| *x)); println!("{:?}", temp); chart.draw_series( // 绘制面积图 AreaSeries::new( // { a: 0.., b: Map { iter: Iter([25, 37, 15, 32, 45, 33, 32, 10, 29, 0, 21]) } } // 0.. 顺序x轴 (0..).zip(data.iter().map(|x| *x)), // 基线 0, // 透明度 &RED.mix(0.2) ).border_style(&RED) // 最亮边线的样式 )?; Ok(()) }
柱状图
use plotters::prelude::*; fn main() -> Result<(), Box<dyn std::error::Error>> { // 创建svg图片对象 let root = SVGBackend::new("plot.svg", (640, 480)).into_drawing_area(); // 图片对象的背景颜色填充 root.fill(&WHITE)?; // 创建绘图对象 let mut chart = ChartBuilder::on(&root) // 图表名称 (字体样式, 字体大小) .caption("柱状图", ("sans-serif", 30)) // 图表左侧与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Left, 40) // 图表底部与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Bottom, 40) // 构建二维图像, x轴 0.0 - 10.0; y轴 0.0 - 10.0; // 重点!!!! 这里的传值必须为SegmentedCoord类型 .build_cartesian_2d((0..10).into_segmented(), 0..50)?; // 配置网格线 chart.configure_mesh().draw()?; // 数值 let data = [25, 37, 15, 32, 45, 33, 32, 10, 0, 21, 5]; chart.draw_series( (0..).zip(data.iter()).map( |(x, y)| { // 创建x轴底部分段对象 let x0 = SegmentValue::Exact(x); // 创建x轴顶部分段对象 let x1 = SegmentValue::Exact(x + 1); let mut bar = Rectangle::new([(x0, 0), (x1, *y)], RED.filled()); // 柱左右间距 bar.set_margin(0, 0, 5, 5); bar } ))?; Ok(()) }
水平柱状图
use plotters::prelude::*; fn main() -> Result<(), Box<dyn std::error::Error>> { // 创建svg图片对象 let root = SVGBackend::new("plot.svg", (640, 480)).into_drawing_area(); // 图片对象的背景颜色填充 root.fill(&WHITE)?; // 创建绘图对象 let mut chart = ChartBuilder::on(&root) // 图表名称 (字体样式, 字体大小) .caption("水平柱状图", ("sans-serif", 30)) // 图表左侧与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Left, 40) // 图表底部与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Bottom, 40) // 构建二维图像, x轴 0.0 - 10.0; y轴 0.0 - 10.0; // 重点!!!! 这里的传值必须为SegmentedCoord类型 .build_cartesian_2d(0..50, (0..10).into_segmented())?; // 配置网格线 chart.configure_mesh().draw()?; // 数值 let data = [25, 37, 15, 32, 45, 33, 32, 10, 0, 21, 5]; // y轴 let index = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; chart.draw_series( // 循环x轴数据 // 压缩y轴生成结构 data.iter().zip(index.iter()).map( |(x, y)| { // 创建y轴左部分段对象 let y0 = SegmentValue::Exact(*y); // 创建y轴右部分段对象 let y1 = SegmentValue::Exact(*y + 1); let mut bar = Rectangle::new([(0, y0), (*x, y1)], GREEN.filled()); // 设置上下柱间距 bar.set_margin(5, 5, 0, 0); bar } ))?; Ok(()) }
真假柱状图
use plotters::prelude::*; fn main() -> Result<(), Box<dyn std::error::Error>> { // 创建svg图片对象 let root = SVGBackend::new("plot.svg", (640, 480)).into_drawing_area(); // 图片对象的背景颜色填充 root.fill(&WHITE)?; // 创建绘图对象 let mut chart = ChartBuilder::on(&root) // 图表名称 (字体样式, 字体大小) .caption("真假柱状图", ("sans-serif", 30)) // 图表左侧与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Left, 40) // 图表底部与图片边缘的间距 .set_label_area_size(LabelAreaPosition::Bottom, 40) // 构建二维图像, x轴 0.0 - 10.0; y轴 0.0 - 10.0; // 重点!!!! 这里的传值必须为SegmentedCoord类型 .build_cartesian_2d([true, false].into_segmented(), 0..50)?; // 配置网格线 chart.configure_mesh().draw()?; // 数值 let prim:Vec<_> = (2..50).map(is_prime).collect(); chart.draw_series( Histogram::vertical(&chart) .margin(100) .data(prim.iter().map(|x| (x, 1))) )?; Ok(()) } fn is_prime(n: i32) -> bool { for i in 2..n { if n % i == 0 { return false; } } true }
箱式图
use chrono::{Duration, NaiveDate}; use plotters::prelude::*; fn main() -> Result<(), Box<dyn std::error::Error>> { // 获取股票数据 let data = get_data(); // 创建绘图区域,大小为 1024x768 let root = BitMapBackend::new("stock.png", (1024, 768)).into_drawing_area(); // 填充白色背景 root.fill(&WHITE)?; // 计算数据的起始和结束日期 let (to_date, from_date) = ( parse_time(data[0].0) + Duration::days(1), parse_time(data[29].0) - Duration::days(1), ); // 创建图表构建器 let mut chart = ChartBuilder::on(&root) .x_label_area_size(40) .y_label_area_size(40) .caption("MSFT Stock Price", ("sans-serif", 50.0).into_font()) .build_cartesian_2d(from_date..to_date, 110f32..135f32)?; // 配置网格样式 chart.configure_mesh().light_line_style(WHITE).draw()?; // 绘制蜡烛图 chart.draw_series( data.iter().map(|x| { CandleStick::new(parse_time(x.0), x.1, x.2, x.3, x.4, GREEN.filled(), RED, 15) }), )?; // 保存图表到文件 root.present().expect("无法将结果写入文件,请确保当前目录下存在该目录"); Ok(()) } // 解析日期字符串为 NaiveDate 类型 fn parse_time(t: &str) -> NaiveDate { NaiveDate::parse_from_str(&format!("{} 0:0", t), "%Y-%m-%d %H:%M").unwrap() } // 获取股票数据 fn get_data() -> Vec<(&'static str, f32, f32, f32, f32)> { vec![ ("2019-04-25", 130.06, 131.37, 128.83, 129.15), ("2019-04-24", 125.79, 125.85, 124.52, 125.01), ("2019-04-23", 124.1, 125.58, 123.83, 125.44), ("2019-04-22", 122.62, 124.0000, 122.57, 123.76), ("2019-04-18", 122.19, 123.52, 121.3018, 123.37), ("2019-04-17", 121.24, 121.85, 120.54, 121.77), ("2019-04-16", 121.64, 121.65, 120.1, 120.77), ("2019-04-15", 120.94, 121.58, 120.57, 121.05), ("2019-04-12", 120.64, 120.98, 120.37, 120.95), ("2019-04-11", 120.54, 120.85, 119.92, 120.33), ("2019-04-10", 119.76, 120.35, 119.54, 120.19), ("2019-04-09", 118.63, 119.54, 118.58, 119.28), ("2019-04-08", 119.81, 120.02, 118.64, 119.93), ("2019-04-05", 119.39, 120.23, 119.37, 119.89), ("2019-04-04", 120.1, 120.23, 118.38, 119.36), ("2019-04-03", 119.86, 120.43, 119.15, 119.97), ("2019-04-02", 119.06, 119.48, 118.52, 119.19), ("2019-04-01", 118.95, 119.1085, 118.1, 119.02), ("2019-03-29", 118.07, 118.32, 116.96, 117.94), ("2019-03-28", 117.44, 117.58, 116.13, 116.93), ("2019-03-27", 117.875, 118.21, 115.5215, 116.77), ("2019-03-26", 118.62, 118.705, 116.85, 117.91), ("2019-03-25", 116.56, 118.01, 116.3224, 117.66), ("2019-03-22", 119.5, 119.59, 117.04, 117.05), ("2019-03-21", 117.135, 120.82, 117.09, 120.22), ("2019-03-20", 117.39, 118.75, 116.71, 117.52), ("2019-03-19", 118.09, 118.44, 116.99, 117.65), ("2019-03-18", 116.17, 117.61, 116.05, 117.57), ("2019-03-15", 115.34, 117.25, 114.59, 115.91), ("2019-03-14", 114.54, 115.2, 114.33, 114.59), ] }
其他可视化图-参考地址:https://plotters-rs.github.io/book/basic/draw_3d_plots.html
https://github.com/plotters-rs/plotters/tree/master?tab=readme-ov-file
部分内容来源:https://jarod.blog.csdn.net/article/details/128126174
本文作者:芋白🥕
本文链接:https://www.cnblogs.com/-CO-/p/18152675
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
( 1 ) --> Rust
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步