rich_text_chrome/
rich_text_chrome.rs1use hephaestus::backend::vello::VelloRenderer;
15use hephaestus::color::{rgb8, Color};
16use hephaestus::composition::{Composition, Patch, Span};
17use hephaestus::geometry::Size;
18use hephaestus::plot::chrome::axis::{Axis, AxisPlacement};
19use hephaestus::plot::chrome::legend::{Legend, LegendKeySpec};
20use hephaestus::plot::theme::Theme;
21use hephaestus::plot::{scale, Plot, PlotComposition, PointGeom};
22use hephaestus::scales::value::Value;
23use std::sync::Arc;
24
25use hephaestus::scales::chrome::AxisSide;
26use hephaestus::scene::SceneBuilder;
27use hephaestus::Renderer;
28
29fn markdown_chrome_theme() -> Theme {
33 let mut theme = Theme::default();
34 theme.text.markdown = Some(true);
35 theme
36}
37
38fn main() {
39 let (w, h) = (900u32, 560u32);
40 let dpi = 96.0;
41 let bg: Color = rgb8(250, 250, 253);
42
43 let comp = || Composition::empty(1, 1).place(1, 1, Span::cell(), Patch::new("p"));
44
45 let n = 60;
46 let xs: Vec<f64> = (0..n).map(|i| i as f64 / (n - 1) as f64 * 10.0).collect();
47 let ys: Vec<f64> = xs
48 .iter()
49 .map(|x| 2.5 + 1.2 * (x * 0.7).sin() + 0.4 * (x * 2.1).cos())
50 .collect();
51
52 let bands: [&'static str; 3] = ["*low*", "**mid**", "{.red high}"];
55 let groups: Vec<&'static str> = ys
56 .iter()
57 .map(|y| match *y {
58 v if v < 2.0 => bands[0],
59 v if v < 3.0 => bands[1],
60 _ => bands[2],
61 })
62 .collect();
63
64 let mut plot = Plot::new(&comp(), "p")
65 .bind("x", "x")
66 .bind("y", "y")
67 .bind("fill", "band")
68 .title("Trend of **{#c14b4b price}** across the day")
69 .subtitle("Metric: *closing_bid* — sampled hourly")
70 .caption("n = **60**, source: {.gray internal}");
71 plot.add_geom(
72 PointGeom::builder()
73 .set("x", xs)
74 .set("y", ys)
75 .set("fill", groups)
76 .set("size", 8.0_f64)
77 .build(),
78 );
79 plot.add_legend(
80 Legend::new("band")
81 .title("**band** of the *close*")
82 .key(LegendKeySpec::point().scaled("fill", "band")),
83 );
84 plot.add_axis(
85 Axis::rail("x", AxisPlacement::Cartesian(AxisSide::Bottom))
86 .title("hour of day, {.gray *UTC*}"),
87 );
88 plot.add_axis(
89 Axis::rail("y", AxisPlacement::Cartesian(AxisSide::Left)).title("**price** (USD)"),
90 );
91
92 let mut view = PlotComposition::new(&comp())
93 .theme(markdown_chrome_theme())
94 .add_scale("x", scale::continuous(0.0..=10.0))
95 .add_scale("y", scale::continuous(0.0..=5.0))
96 .add_scale(
97 "band",
98 scale::discrete(bands.iter().map(|b| Value::String(Arc::from(*b)))).range_colors([
99 rgb8(88, 106, 195),
100 rgb8(214, 146, 60),
101 rgb8(193, 75, 75),
102 ]),
103 )
104 .with_plot(plot);
105
106 let mut renderer = VelloRenderer::new().expect("vello renderer init");
107 {
108 let scene = renderer.scene();
109 scene.clear();
110 view.render(scene, Size::new(w as f64, h as f64), dpi);
111 }
112 let mut pixels = vec![0u8; (w * h * 4) as usize];
113 renderer
114 .render_to_buffer(w, h, bg, &mut pixels)
115 .expect("render");
116 let path = std::env::current_dir()
117 .unwrap()
118 .join("examples/rich_text_chrome.png");
119 hephaestus::image::write_png(&path, w, h, &pixels).expect("write png");
120 println!("wrote {}", path.display());
121}