Plot 如何绘制x轴上有日期,y轴上有时间的序列?
我想绘制点,其中x坐标是日期,y坐标是时间(就像Chrono的Plot 如何绘制x轴上有日期,y轴上有时间的序列?,plot,rust,Plot,Rust,我想绘制点,其中x坐标是日期,y坐标是时间(就像Chrono的NaiveTime) 我认为这将是最简单的使用板条箱。 不幸的是,默认情况下,它不支持y轴上的时间,如下所示。然而,该文件指出 理论上,绘图仪支持任何数据类型。唯一的要求是实现轴映射特性 听起来不错 因此,我采用了他们的例子,并得出以下结论 use chrono::{Date, Duration, ParseError, DateTime, Utc, NaiveTime}; use chrono::offset::{Local, Ti
NaiveTime
)
我认为这将是最简单的使用板条箱。
不幸的是,默认情况下,它不支持y轴上的时间,如下所示。然而,该文件指出
理论上,绘图仪支持任何数据类型。唯一的要求是实现轴映射特性
听起来不错
因此,我采用了他们的例子,并得出以下结论
use chrono::{Date, Duration, ParseError, DateTime, Utc, NaiveTime};
use chrono::offset::{Local, TimeZone};
use plotters::prelude::*;
fn parse_datetime(t: &str) -> Date<Local> {
Local
.datetime_from_str(&format!("{} 0:0", t), "%Y-%m-%d %H:%M")
.unwrap()
.date()
}
/// Workaround attempt: use a mock Date in order to get a DateTime instead of a NaiveTime
fn parse_time_as_datetime(t: &str) -> Result<DateTime<Local>, ParseError> {
return match Local.datetime_from_str(&format!("2020-01-01 {}", t), "%Y-%m-%d %H:%M.%S") {
Ok(date) => Ok(date),
Err(e) => { println!("{}", e); Err(e) },
};
}
fn parse_time(t: &str) -> Result<NaiveTime, ParseError> {
return match Local.datetime_from_str(t, "%M:%S%.f") {
Ok(date) => Ok(date.time()),
Err(e) => { println!("{}", e); Err(e) },
};
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = get_data();
let root = BitMapBackend::new("stock-example.png", (1024, 768)).into_drawing_area();
root.fill(&WHITE)?;
let (from_date, to_date) = (
parse_datetime(&data[0].0) + Duration::days(1),
parse_datetime(&data[4].0) - Duration::days(1),
);
let y_min = parse_time("9:30.0").unwrap();
let y_max = parse_time("13:00.0").unwrap();
// Workaround attempt: use DateTime instead of NaiveTime
// let y_min = Local.datetime_from_str("2020-01-01 0:0", "%Y-%m-%d %H:%M").unwrap().date();
// let y_max = Local.datetime_from_str("2020-01-02 0:1", "%Y-%m-%d %H:%M").unwrap().date();
let mut chart = ChartBuilder::on(&root)
.x_label_area_size(40)
.y_label_area_size(40)
.caption("Time", ("sans-serif", 30.0).into_font())
.build_cartesian_2d(from_date..to_date, y_min..y_max)?;
chart.configure_mesh().light_line_style(&WHITE).draw()?;
chart.draw_series(
data.iter()
.map(|x| Circle::new((parse_datetime(x.0), parse_time(x.1).unwrap()), 5, BLUE.filled())),
)?;
Ok(())
}
fn get_data() -> Vec<(&'static str, &'static str, f32, f32, f32)> {
return vec![
("2019-04-18", "10:11.5", 16.0, 121.3018, 123.3700),
("2019-04-22", "10:52.2", 15.0, 122.5700, 123.7600),
("2019-04-23", "12:23.5", 14.0, 123.8300, 125.4400),
("2019-04-24", "10:15.0", 13.0, 124.5200, 125.0100),
("2019-04-25", "10:43.9", 12.0, 128.8300, 129.1500),
];
}
因此,我们更改为将结构字段公开:pub-struct-RangedDateTime(pub-DT,pub-DT)代码>。
它失败了
52 | .build_cartesian_2d(from_date..to_date, RangedDateTime(y_min, y_max))?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `RangedDateTime { 0: val, 1: val }`
52 | .build_cartesian_2d(from_date..to_date, RangedDateTime(y_min, y_max))?;
| ^^^^^^^^^^^^^^ the trait `ranged1d::types::datetime::TimeValue` is not implemented for `NaiveTime`
但是,我们无法为NaiveTime
实现TimeValue
,因为这是当前的定义:
pub trait TimeValue: Eq {
type DateType: Datelike + PartialOrd;
// ...
}
而且NaiveTime
不是DateLike
。
我不知道如何从这里开始,我考虑了以下选项:
- 将
TimeLike
添加到TimeValue
关联类型的限制中
- 从关联的
TimeValue
类型中删除DateLike
- 添加一个单独的trait
DateTimeValue
,它可以将TimeLike
作为其DateType
在这种情况下,从Chrono更容易使用,因为绘图仪也实现了RangedDuration
,只是有点隐藏
注意:您可以使用自定义轴标签格式化程序,因此如果需要,您仍然可以将其格式化为一天中的时间
固定示例:
#![feature(allocator_api)]
use chrono::{Date, Duration, ParseError, NaiveTime};
use chrono::offset::{Local, TimeZone};
use plotters::prelude::*;
fn parse_datetime(t: &str) -> Date<Local> {
Local
.datetime_from_str(&format!("{} 0:0", t), "%Y-%m-%d %H:%M")
.unwrap()
.date()
}
fn parse_time(t: &str) -> Result<Duration, ParseError> {
return match Local.datetime_from_str(&format!("2020-01-01 0:{}", t), "%Y-%m-%d %H:%M:%S%.f") {
Ok(date) => Ok(date.time().signed_duration_since(NaiveTime::from_hms(0, 0, 0))),
Err(e) => { println!("{}", e); Err(e) },
};
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = get_data();
let root = BitMapBackend::new("stock-example.png", (1024, 768)).into_drawing_area();
root.fill(&WHITE)?;
let (from_date, to_date) = (
parse_datetime(&data[0].0) - Duration::days(1),
parse_datetime(&data[data.len() - 1].0) + Duration::days(1),
);
let y_min = parse_time("9:30.0").unwrap();
let y_max = parse_time("13:00.0").unwrap();
let mut chart = ChartBuilder::on(&root)
.x_label_area_size(40)
.y_label_area_size(50)
.caption("Time", ("sans-serif", 30.0).into_font())
.build_cartesian_2d(from_date..to_date, y_min..y_max)?;
chart.configure_mesh()
.light_line_style(&WHITE)
.y_label_formatter(&|y| format!("{:02}:{:02}", y.num_minutes(), y.num_seconds() % 60))
.x_label_formatter(&|x| x.naive_local().to_string())
.draw()?;
chart.draw_series(
data.iter()
.map(|x| Circle::new((parse_datetime(x.0), parse_time(x.1).unwrap()), 5, BLUE.filled())),
)?;
Ok(())
}
fn get_data() -> Vec<(&'static str, &'static str, f32, f32, f32)> {
return vec![
("2019-04-18", "10:11.5", 16.0, 121.3018, 123.3700),
("2019-04-22", "10:52.2", 15.0, 122.5700, 123.7600),
("2019-04-23", "12:23.5", 14.0, 123.8300, 125.4400),
("2019-04-24", "10:15.0", 13.0, 124.5200, 125.0100),
("2019-04-25", "10:43.9", 12.0, 128.8300, 129.1500),
];
}
#![功能(分配器api)]
使用chrono::{Date,Duration,ParseError,NaiveTime};
使用chrono::offset::{Local,TimeZone};
使用绘图仪::前奏::*;
fn parse_datetime(t:&str)->Date{
地方的
.datetime_来自_str(&format!(“{}0:0”,t),%Y-%m-%d%H:%m”)
.unwrap()
.日期(
}
fn解析时间(t:&str)->结果{
从_str(&format!(&2020-01-01 0:{},t),%Y-%m-%d%H:%m:%S%.f)返回匹配的Local.datetime_{
Ok(date)=>Ok(date.time().signed_duration_since(NaiveTime::from_hms(0,0,0))),
Err(e)=>{println!(“{}”,e);Err(e)},
};
}
fn main()->结果{
让数据=获取_数据();
将root=BitMapBackend::new(“stock-example.png”(1024768))放入绘图区域();
根。填充(&白色)?;
出租(从日期到日期)=(
parse_datetime(&数据[0].0)-Duration::days(1),
parse_datetime(&data[data.len()-1].0)+Duration::days(1),
);
让y_min=parse_time(“9:30.0”).unwrap();
让y_max=parse_time(“13:00.0”).unwrap();
让mut chart=ChartBuilder::on(&root)
.x_标签_面积_尺寸(40)
.y\标签\面积\尺寸(50)
.caption(“Time”(“sans serif”,30.0)。转换为_font()
.构建笛卡尔2d(从日期到日期,y最小值y最大值)?;
图表.配置网格()
.light\u line\u样式(&白色)
.y_label_格式化程序(&|y|format!(“{:02}:{:02}”,y.num_minutes(),y.num_seconds()%60))
.x|u label_格式化程序(&|x|x.naive_local().to_string())
.draw()?;
chart.draw_系列(
数据.国际热核实验堆()
.map(| x | Circle::new((解析_datetime(x.0)、解析_time(x.1).unwrap()),5,BLUE.filled()),
)?;
好(())
}
fn获取_数据()->Vec{
返回vec[
("2019-04-18", "10:11.5", 16.0, 121.3018, 123.3700),
("2019-04-22", "10:52.2", 15.0, 122.5700, 123.7600),
("2019-04-23", "12:23.5", 14.0, 123.8300, 125.4400),
("2019-04-24", "10:15.0", 13.0, 124.5200, 125.0100),
("2019-04-25", "10:43.9", 12.0, 128.8300, 129.1500),
];
}
#![feature(allocator_api)]
use chrono::{Date, Duration, ParseError, NaiveTime};
use chrono::offset::{Local, TimeZone};
use plotters::prelude::*;
fn parse_datetime(t: &str) -> Date<Local> {
Local
.datetime_from_str(&format!("{} 0:0", t), "%Y-%m-%d %H:%M")
.unwrap()
.date()
}
fn parse_time(t: &str) -> Result<Duration, ParseError> {
return match Local.datetime_from_str(&format!("2020-01-01 0:{}", t), "%Y-%m-%d %H:%M:%S%.f") {
Ok(date) => Ok(date.time().signed_duration_since(NaiveTime::from_hms(0, 0, 0))),
Err(e) => { println!("{}", e); Err(e) },
};
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = get_data();
let root = BitMapBackend::new("stock-example.png", (1024, 768)).into_drawing_area();
root.fill(&WHITE)?;
let (from_date, to_date) = (
parse_datetime(&data[0].0) - Duration::days(1),
parse_datetime(&data[data.len() - 1].0) + Duration::days(1),
);
let y_min = parse_time("9:30.0").unwrap();
let y_max = parse_time("13:00.0").unwrap();
let mut chart = ChartBuilder::on(&root)
.x_label_area_size(40)
.y_label_area_size(50)
.caption("Time", ("sans-serif", 30.0).into_font())
.build_cartesian_2d(from_date..to_date, y_min..y_max)?;
chart.configure_mesh()
.light_line_style(&WHITE)
.y_label_formatter(&|y| format!("{:02}:{:02}", y.num_minutes(), y.num_seconds() % 60))
.x_label_formatter(&|x| x.naive_local().to_string())
.draw()?;
chart.draw_series(
data.iter()
.map(|x| Circle::new((parse_datetime(x.0), parse_time(x.1).unwrap()), 5, BLUE.filled())),
)?;
Ok(())
}
fn get_data() -> Vec<(&'static str, &'static str, f32, f32, f32)> {
return vec![
("2019-04-18", "10:11.5", 16.0, 121.3018, 123.3700),
("2019-04-22", "10:52.2", 15.0, 122.5700, 123.7600),
("2019-04-23", "12:23.5", 14.0, 123.8300, 125.4400),
("2019-04-24", "10:15.0", 13.0, 124.5200, 125.0100),
("2019-04-25", "10:43.9", 12.0, 128.8300, 129.1500),
];
}