theme_text_align_to/
theme_text_align_to.rs1use hephaestus::backend::vello::VelloRenderer;
13use hephaestus::color::{rgb, rgb8, Color};
14use hephaestus::composition::{beside, Patch};
15use hephaestus::geometry::Size;
16use hephaestus::plot::chrome::axis::{Axis, AxisPlacement};
17use hephaestus::plot::chrome::legend::Legend;
18use hephaestus::plot::theme::{AlignTo, Element, HAlign, Theme};
19use hephaestus::plot::{scale, Plot, PlotComposition, PointGeom};
20use hephaestus::scales::chrome::{AxisSide, LegendSide};
21use hephaestus::scene::SceneBuilder;
22use hephaestus::Renderer;
23
24fn main() {
25 let (w, h) = (1400u32, 500u32);
26 let dpi = 96.0;
27
28 let comp = || beside(Patch::new("a"), Patch::new("b"));
29 let xs: Vec<f64> = (0..40).map(|i| i as f64 * 0.15).collect();
30 let ys: Vec<f64> = xs.iter().map(|x| (x * 0.7).sin() * 0.4 + 0.5).collect();
31 let categories: Vec<&str> = xs
32 .iter()
33 .map(|x| match (*x as usize) % 4 {
34 0 => "A",
35 1 => "B",
36 2 => "C",
37 _ => "D",
38 })
39 .collect();
40
41 let make_plot = |patch_id: &str, title: &str| {
42 let mut plot = Plot::new(&comp(), patch_id)
43 .bind("x", "x_scale")
44 .bind("y", "y_scale")
45 .bind("stroke", "category")
46 .title(title);
47 plot.add_geom(
48 PointGeom::builder()
49 .set("x", xs.clone())
50 .set("y", ys.clone())
51 .set("size", 6.0_f64)
52 .set("fill", rgb(0.20, 0.45, 0.85))
53 .set("stroke", categories.clone())
54 .set("linewidth", 1.0_f64)
55 .build(),
56 );
57 plot.add_axis(
58 Axis::rail("x_scale", AxisPlacement::Cartesian(AxisSide::Bottom)).title("Time (s)"),
59 );
60 plot.add_axis(
61 Axis::rail("y_scale", AxisPlacement::Cartesian(AxisSide::Left))
62 .title("A wide y-axis title"),
63 );
64 plot.add_legend(
65 Legend::new("category")
66 .side(LegendSide::Right)
67 .title("Group")
68 .key(
69 hephaestus::plot::chrome::legend::LegendKeySpec::point()
70 .scaled("stroke", "category"),
71 ),
72 );
73 plot
74 };
75
76 let category_scale = scale::discrete([
77 hephaestus::scales::Value::String(std::sync::Arc::from("A")),
78 hephaestus::scales::Value::String(std::sync::Arc::from("B")),
79 hephaestus::scales::Value::String(std::sync::Arc::from("C")),
80 hephaestus::scales::Value::String(std::sync::Arc::from("D")),
81 ])
82 .range_colors([
83 hephaestus::color::rgb(0.20, 0.20, 0.20),
84 hephaestus::color::rgb(0.70, 0.20, 0.20),
85 hephaestus::color::rgb(0.20, 0.60, 0.20),
86 hephaestus::color::rgb(0.20, 0.20, 0.70),
87 ]);
88
89 let mut theme = Theme {
97 plot_text_align_to: AlignTo::Plot,
98 ..Theme::default()
99 };
100 if let Element::Set(t) = &mut theme.plot_title {
101 t.align = Some(HAlign::Start);
102 }
103 let mut view = PlotComposition::new(&comp())
104 .add_scale("x_scale", scale::continuous(0.0..=6.0))
105 .add_scale("y_scale", scale::continuous(0.0..=1.0))
106 .add_scale("category", category_scale)
107 .theme(theme);
108 view.attach_plot(make_plot(
109 "a",
110 "AlignTo::Plot — title left-edge aligns to plot interior",
111 ));
112 view.attach_plot(
114 make_plot("b", "AlignTo::Panel — title left-edge aligns to panel").theme_override(
115 hephaestus::plot::theme::ThemePart {
116 plot_text_align_to: Some(AlignTo::Panel),
117 ..hephaestus::plot::theme::ThemePart::default()
118 },
119 ),
120 );
121
122 let mut renderer = VelloRenderer::new().expect("vello renderer init");
123 let bg: Color = rgb8(245, 245, 245);
124 {
125 let scene = renderer.scene();
126 scene.clear();
127 view.render(scene, Size::new(w as f64, h as f64), dpi);
128 }
129 let mut pixels = vec![0u8; (w * h * 4) as usize];
130 renderer
131 .render_to_buffer(w, h, bg, &mut pixels)
132 .expect("render");
133 let path = std::env::current_dir()
134 .unwrap()
135 .join("examples/theme_text_align_to.png");
136 hephaestus::image::write_png(&path, w, h, &pixels).expect("write png");
137 println!("wrote {}", path.display());
138}