use hephaestus::backend::vello::VelloRenderer;
use hephaestus::color::{rgb, rgb8, Color};
use hephaestus::composition::{beside, Patch};
use hephaestus::geometry::Size;
use hephaestus::plot::chrome::axis::{Axis, AxisPlacement};
use hephaestus::plot::chrome::legend::Legend;
use hephaestus::plot::theme::{AlignTo, Element, HAlign, Theme};
use hephaestus::plot::{scale, Plot, PlotComposition, PointGeom};
use hephaestus::scales::chrome::{AxisSide, LegendSide};
use hephaestus::scene::SceneBuilder;
use hephaestus::Renderer;
fn main() {
let (w, h) = (1400u32, 500u32);
let dpi = 96.0;
let comp = || beside(Patch::new("a"), Patch::new("b"));
let xs: Vec<f64> = (0..40).map(|i| i as f64 * 0.15).collect();
let ys: Vec<f64> = xs.iter().map(|x| (x * 0.7).sin() * 0.4 + 0.5).collect();
let categories: Vec<&str> = xs
.iter()
.map(|x| match (*x as usize) % 4 {
0 => "A",
1 => "B",
2 => "C",
_ => "D",
})
.collect();
let make_plot = |patch_id: &str, title: &str| {
let mut plot = Plot::new(&comp(), patch_id)
.bind("x", "x_scale")
.bind("y", "y_scale")
.bind("stroke", "category")
.title(title);
plot.add_geom(
PointGeom::builder()
.set("x", xs.clone())
.set("y", ys.clone())
.set("size", 6.0_f64)
.set("fill", rgb(0.20, 0.45, 0.85))
.set("stroke", categories.clone())
.set("linewidth", 1.0_f64)
.build(),
);
plot.add_axis(
Axis::rail("x_scale", AxisPlacement::Cartesian(AxisSide::Bottom)).title("Time (s)"),
);
plot.add_axis(
Axis::rail("y_scale", AxisPlacement::Cartesian(AxisSide::Left))
.title("A wide y-axis title"),
);
plot.add_legend(
Legend::new("category")
.side(LegendSide::Right)
.title("Group")
.key(
hephaestus::plot::chrome::legend::LegendKeySpec::point()
.scaled("stroke", "category"),
),
);
plot
};
let category_scale = scale::discrete([
hephaestus::scales::Value::String(std::sync::Arc::from("A")),
hephaestus::scales::Value::String(std::sync::Arc::from("B")),
hephaestus::scales::Value::String(std::sync::Arc::from("C")),
hephaestus::scales::Value::String(std::sync::Arc::from("D")),
])
.range_colors([
hephaestus::color::rgb(0.20, 0.20, 0.20),
hephaestus::color::rgb(0.70, 0.20, 0.20),
hephaestus::color::rgb(0.20, 0.60, 0.20),
hephaestus::color::rgb(0.20, 0.20, 0.70),
]);
let mut theme = Theme {
plot_text_align_to: AlignTo::Plot,
..Theme::default()
};
if let Element::Set(t) = &mut theme.plot_title {
t.align = Some(HAlign::Start);
}
let mut view = PlotComposition::new(&comp())
.add_scale("x_scale", scale::continuous(0.0..=6.0))
.add_scale("y_scale", scale::continuous(0.0..=1.0))
.add_scale("category", category_scale)
.theme(theme);
view.attach_plot(make_plot(
"a",
"AlignTo::Plot — title left-edge aligns to plot interior",
));
view.attach_plot(
make_plot("b", "AlignTo::Panel — title left-edge aligns to panel").theme_override(
hephaestus::plot::theme::ThemePart {
plot_text_align_to: Some(AlignTo::Panel),
..hephaestus::plot::theme::ThemePart::default()
},
),
);
let mut renderer = VelloRenderer::new().expect("vello renderer init");
let bg: Color = rgb8(245, 245, 245);
{
let scene = renderer.scene();
scene.clear();
view.render(scene, Size::new(w as f64, h as f64), dpi);
}
let mut pixels = vec![0u8; (w * h * 4) as usize];
renderer
.render_to_buffer(w, h, bg, &mut pixels)
.expect("render");
let path = std::env::current_dir()
.unwrap()
.join("examples/theme_text_align_to.png");
hephaestus::png::write_png(&path, w, h, &pixels).expect("write png");
println!("wrote {}", path.display());
}