You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Plotters中动态使用SegmentValue绘制Band矩形?

解决方案

以下是针对你的Plotters绘图问题的完整可运行实现,同时解决字符串类型约束与生命周期问题:

依赖配置

确保Cargo.toml包含所需依赖:

[dependencies]
plotters = "0.3"
chrono = { version = "0.4", features = ["naive", "serde"] }

完整代码实现

use chrono::NaiveDateTime;
use plotters::prelude::*;

pub struct Band {
    pub name: String,
    pub start_dt: NaiveDateTime,
    pub end_dt: NaiveDateTime,
    pub stage: String,
    pub selected: bool,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 示例演出数据
    let bands = vec![
        Band {
            name: "Storm Riders".into(),
            start_dt: NaiveDateTime::parse_from_str("2024-06-01 18:30:00", "%Y-%m-%d %H:%M:%S")?,
            end_dt: NaiveDateTime::parse_from_str("2024-06-01 20:00:00", "%Y-%m-%d %H:%M:%S")?,
            stage: "主舞台".into(),
            selected: true,
        },
        Band {
            name: "Acoustic Dream".into(),
            start_dt: NaiveDateTime::parse_from_str("2024-06-01 19:15:00", "%Y-%m-%d %H:%M:%S")?,
            end_dt: NaiveDateTime::parse_from_str("2024-06-01 20:45:00", "%Y-%m-%d %H:%M:%S")?,
            stage: "副舞台".into(),
            selected: false,
        },
        Band {
            name: "Electronic Pulse".into(),
            start_dt: NaiveDateTime::parse_from_str("2024-06-01 20:30:00", "%Y-%m-%d %H:%M:%S")?,
            end_dt: NaiveDateTime::parse_from_str("2024-06-01 22:00:00", "%Y-%m-%d %H:%M:%S")?,
            stage: "主舞台".into(),
            selected: true,
        },
    ];

    // 收集并去重舞台名称,用于构建X分类轴
    let mut stage_names: Vec<String> = bands.iter().map(|b| b.stage.clone()).collect();
    stage_names.dedup();
    let stage_count = stage_names.len();

    // 确定Y轴时间范围,转换为Unix时间戳以便数值映射
    let min_dt = bands.iter().map(|b| b.start_dt).min().unwrap();
    let max_dt = bands.iter().map(|b| b.end_dt).max().unwrap();
    let min_ts = min_dt.timestamp();
    let max_ts = max_dt.timestamp();

    // 创建绘图画布
    let root = BitMapBackend::new("band_schedule.png", (800, 600)).into_drawing_area();
    root.fill(&WHITE)?;

    // 构建笛卡尔坐标系
    let mut chart = ChartBuilder::on(&root)
        .caption("音乐节演出时间表", ("sans-serif", 20).into_font())
        .x_label_area_size(40)
        .y_label_area_size(80)
        .build_cartesian_2d(0..stage_count, min_ts..max_ts)?;

    // 配置网格与轴标签
    chart.configure_mesh()
        .x_labels(3)
        .x_label_formatter(&|idx| stage_names[*idx].clone())
        .y_labels(5)
        .y_label_formatter(&|ts| {
            NaiveDateTime::from_timestamp(*ts, 0).format("%H:%M").to_string()
        })
        .draw()?;

    // 计算X轴每个分段的宽度
    let x_unit_width = (chart.x_range().end - chart.x_range().start) as f64 / stage_count as f64;

    // 绘制每个乐队对应的演出时段矩形
    for band in &bands {
        // 找到当前舞台在分类轴中的索引
        let stage_idx = stage_names.iter().position(|s| s == &band.stage).unwrap();
        let x_start = stage_idx as f64;
        let x_end = x_start + x_unit_width;

        // 转换演出时间为Y轴坐标
        let y_start = band.start_dt.timestamp();
        let y_end = band.end_dt.timestamp();

        // 根据选中状态选择填充颜色
        let fill_color = if band.selected { BLUE.mix(0.6) } else { GREY.mix(0.6) };

        // 绘制矩形
        chart.draw_rectangle(
            (x_start, y_start)..(x_end, y_end),
            fill_color.filled(),
        )?;

        // 在矩形中心绘制乐队名称
        let text_pos = (x_start + x_unit_width / 2.0, (y_start + y_end) / 2.0);
        chart.draw_text(
            &band.name,
            ("sans-serif", 12).into_font(),
            text_pos,
            &TextStyle::from(("sans-serif", 12)).color(&BLACK).alignment(Alignment::Center),
        )?;
    }

    root.present()?;
    Ok(())
}

核心问题解决说明

  1. 字符串生命周期处理:

    • 提前收集所有舞台名称到stage_names向量并去重,确保字符串生命周期覆盖整个绘图流程。
    • 通过x_label_formatter将轴索引映射为对应舞台名称,避免临时字符串导致的生命周期不匹配。
  2. DateTime轴适配:

    • 将NaiveDateTime转换为Unix时间戳(秒),利用Plotters的LinearAxis进行数值映射。
    • 通过y_label_formatter将时间戳转换回可读的时间格式,兼顾绘图兼容性与可读性。
  3. 矩形位置计算:

    • 根据舞台在分类轴中的索引计算X轴起始/结束位置,每个分段宽度由总轴长除以舞台数量得出。
    • Y轴直接使用时间戳数值范围,保证演出时段的时长与顺序映射准确。

内容的提问来源于stack exchange,提问作者Tare

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 14:52:32