1use hephaestus::backend::vello::VelloRenderer;
9use hephaestus::color::{rgb, rgb8, Color};
10use hephaestus::composition::{Composition, Patch, Span};
11use hephaestus::geometry::Size;
12use hephaestus::plot::chrome::axis::{Axis, AxisPlacement};
13use hephaestus::plot::chrome::legend::{Legend, LegendKeySpec};
14use hephaestus::plot::theme::{Element, LegendTheme, Length, RectElement, Theme, ThemeColor};
15use hephaestus::plot::{scale, Plot, PlotComposition, PointGeom};
16use hephaestus::scales::chrome::{AxisSide, LegendSide};
17use hephaestus::scales::value::Value;
18use hephaestus::scene::SceneBuilder;
19use hephaestus::Renderer;
20
21fn comp() -> Composition {
22 Composition::empty(1, 1).place(1, 1, Span::cell(), Patch::new("panel"))
23}
24
25fn main() {
26 let (w, h) = (900u32, 600u32);
27 let dpi = 96.0;
28
29 let n = 24;
30 let xs: Vec<f64> = (0..n).map(|i| i as f64 * 0.4).collect();
31 let ys: Vec<f64> = (0..n)
32 .map(|i| ((i as f64) * 0.5).sin() * 0.4 + 0.5)
33 .collect();
34 let cats: [&'static str; 4] = ["A", "B", "C", "D"];
35 let fill_col: Vec<&'static str> = (0..n).map(|i| cats[i % 4]).collect();
36
37 let mut plot = Plot::new(&comp(), "panel")
38 .bind("x", "x")
39 .bind("y", "y")
40 .bind("fill", "category_color")
41 .title("Two legends, one opts into the \"hero\" theme variant");
42 plot.add_geom(
43 PointGeom::builder()
44 .set("x", xs)
45 .set("y", ys)
46 .set("fill", fill_col.clone())
47 .set("size", 6.0_f64)
48 .build(),
49 );
50 plot.add_axis(Axis::rail("x", AxisPlacement::Cartesian(AxisSide::Bottom)));
51 plot.add_axis(Axis::rail("y", AxisPlacement::Cartesian(AxisSide::Left)));
52
53 plot.add_legend(
55 Legend::new("category_color")
56 .side(LegendSide::Right)
57 .title("Category (hero)")
58 .theme_variant("hero")
59 .key(
60 LegendKeySpec::point()
61 .scaled("fill", "category_color")
62 .fixed("stroke", Value::Color(rgb(0.0, 0.0, 0.0)))
63 .fixed("size", 6.0_f64),
64 ),
65 );
66 plot.add_legend(
68 Legend::new("category_size")
69 .side(LegendSide::Bottom)
70 .title("Category (default)")
71 .key(
72 LegendKeySpec::point()
73 .scaled("fill", "category_color")
74 .fixed("size", 6.0_f64),
75 ),
76 );
77
78 let hero = LegendTheme {
81 background: Element::Set(RectElement {
82 fill: Some(ThemeColor::mix(ThemeColor::Paper, ThemeColor::Accent, 0.18)),
83 color: Some(ThemeColor::Accent),
84 linewidth_pt: Some(Length::Abs(1.0)),
85 ..RectElement::default()
86 }),
87 ..LegendTheme::default()
88 };
89
90 let theme = Theme::default().with_legend_variant("hero", hero);
91
92 let mut view = PlotComposition::new(&comp())
93 .add_scale("x", scale::continuous(0.0..=12.0))
94 .add_scale("y", scale::continuous(0.0..=1.0))
95 .add_scale(
96 "category_color",
97 scale::discrete(cats.iter().map(|s| Value::String((*s).into()))).range_colors([
98 rgb8(220, 100, 80),
99 rgb8(80, 160, 100),
100 rgb8(80, 130, 200),
101 rgb8(180, 100, 200),
102 ]),
103 )
104 .add_scale(
105 "category_size",
106 scale::discrete(cats.iter().map(|s| Value::String((*s).into())))
107 .range_numbers([4.0, 6.0, 8.0, 10.0]),
108 )
109 .theme(theme);
110 view.attach_plot(plot);
111
112 let mut renderer = VelloRenderer::new().expect("vello renderer init");
113 let bg: Color = rgb8(252, 252, 252);
114 {
115 let scene = renderer.scene();
116 scene.clear();
117 view.render(scene, Size::new(w as f64, h as f64), dpi);
118 }
119 let mut pixels = vec![0u8; (w * h * 4) as usize];
120 renderer
121 .render_to_buffer(w, h, bg, &mut pixels)
122 .expect("render");
123 let path = std::env::current_dir()
124 .unwrap()
125 .join("examples/theme_legend_variants.png");
126 hephaestus::image::write_png(&path, w, h, &pixels).expect("write png");
127 println!("wrote {}", path.display());
128}