Bar groups and pie
The two categorical items — the ones whose data points carry a name, not just
a number. plot_bar_groups draws several labelled series clustered into groups (a
grouped or stacked bar chart); plot_pie_chart splits a whole into named slices.
Both take their per-series labels as a plain array<string>: a daslang string
array is already laid out as the const char* const[] block ImPlot wants, so the
labels pass straight through with no repacking — the same fact dasImgui’s list_box
relies on.
// 3 series x 4 groups, flat row-major (values[item*GROUPS + group])
var g_bar_labels <- ["merchant", "consumer", "industrial"]
var g_bar_values <- [10.0lf, 14.0lf, 9.0lf, 12.0lf,
8.0lf, 11.0lf, 13.0lf, 7.0lf,
6.0lf, 9.0lf, 15.0lf, 10.0lf]
...
plot(BARS, (title = "quarterly volume", size = float2(560.0f, 560.0f), flags = ImPlotFlags.None)) {
setup_axes("group", "value")
plot_bar_groups(g_bar_labels, g_bar_values, ITEMS, GROUPS)
}
plot(PIE, (title = "budget split", size = float2(-1.0f, 560.0f), flags = ImPlotFlags.Equal)) {
setup_axes("", "", ImPlotAxisFlags.NoDecorations, ImPlotAxisFlags.NoDecorations)
setup_axes_limits(0.0lf, 1.0lf, 0.0lf, 1.0lf, ImPlotCond.Always)
plot_pie_chart(g_pie_labels, g_pie_values, 0.5lf, 0.5lf, 0.45lf, "%.0f%%")
}
Source: examples/tutorial/bar_groups_and_pie.das.
1options gen2
2options _comment_hygiene = true
3
4require imgui/imgui_harness
5require imgui/imgui_containers_builtin
6require imgui/imgui_widgets_builtin
7require imgui/imgui_implot_boost_v2
8require implot
9
10// =============================================================================
11// TUTORIAL: bar_groups_and_pie — the two categorical / labelled items.
12//
13// plot_bar_groups(label_ids, values, item_count, group_count) — item_count series
14// clustered into group_count groups. `values` is a flat item_count*group_count
15// row-major matrix (values[item*group_count+group]); `label_ids` names one
16// series per row (they show up in the legend). The Stacked / Horizontal flags
17// restack / reorient the bars.
18// plot_pie_chart(label_ids, values, x, y, radius) — one slice per
19// (label, value) pair, centered at data-coords (x, y). Pie plots want square,
20// decoration-free axes spanning [0,1].
21//
22// Both take label_ids : array<string> — a daslang string array IS already a
23// const char* const[] block, so it passes straight to ImPlot.
24//
25// STANDALONE: daslang.exe modules/dasImguiImplot/examples/tutorial/bar_groups_and_pie.das
26// LIVE: daslang-live modules/dasImguiImplot/examples/tutorial/bar_groups_and_pie.das
27// =============================================================================
28
29let ITEMS = 3 // series (one label / color each)
30let GROUPS = 4 // clusters along the x-axis
31
32var g_ctx : ImPlotContext?
33var g_bar_labels : array<string>
34var g_bar_values : array<double> // ITEMS*GROUPS, row-major
35var g_pie_labels : array<string>
36var g_pie_values : array<double>
37
38[export]
39def init() {
40 harness_init("dasImguiImplot — bar_groups_and_pie", 1280, 720)
41 g_ctx = implot::CreateContext()
42
43 // One row of GROUPS values per series, laid out flat (values[item*GROUPS+group]).
44 g_bar_labels <- ["merchant", "consumer", "industrial"]
45 g_bar_values <- [10.0lf, 14.0lf, 9.0lf, 12.0lf, // merchant
46 8.0lf, 11.0lf, 13.0lf, 7.0lf, // consumer
47 6.0lf, 9.0lf, 15.0lf, 10.0lf] // industrial
48
49 // One slice per (label, value); values need not be normalized.
50 g_pie_labels <- ["rent", "food", "transit", "savings"]
51 g_pie_values <- [35.0lf, 25.0lf, 18.0lf, 22.0lf]
52}
53
54[export]
55def update() {
56 if (!harness_begin_frame()) return
57 harness_new_frame()
58
59 SetNextWindowPos(float2(20.0, 20.0), ImGuiCond.Always)
60 SetNextWindowSize(float2(1240.0, 680.0), ImGuiCond.Always)
61 window(PLOT_WIN, (text = "bar groups & pie", closable = false,
62 flags = ImGuiWindowFlags.None)) {
63 text("plot_bar_groups clusters labelled series; plot_pie_chart splits a whole.")
64 plot(BARS, (title = "quarterly volume", size = float2(560.0f, 560.0f),
65 flags = ImPlotFlags.None)) {
66 setup_axes("group", "value")
67 setup_axes_limits(-0.5lf, double(GROUPS) - 0.5lf, 0.0lf, 18.0lf, ImPlotCond.Always)
68 plot_bar_groups(g_bar_labels, g_bar_values, ITEMS, GROUPS)
69 }
70 same_line()
71 plot(PIE, (title = "budget split", size = float2(-1.0f, 560.0f),
72 flags = ImPlotFlags.Equal)) {
73 setup_axes("", "", ImPlotAxisFlags.NoDecorations, ImPlotAxisFlags.NoDecorations)
74 setup_axes_limits(0.0lf, 1.0lf, 0.0lf, 1.0lf, ImPlotCond.Always)
75 plot_pie_chart(g_pie_labels, g_pie_values, 0.5lf, 0.5lf, 0.45lf, "%.0f%%")
76 }
77 }
78
79 harness_end_frame()
80}
81
82[export]
83def shutdown() {
84 if (g_ctx != null) {
85 DestroyContext(g_ctx)
86 }
87 harness_shutdown()
88}
89
90[export]
91def main() {
92 init()
93 while (!exit_requested()) {
94 update()
95 }
96 shutdown()
97}
Walkthrough
The recording tours both charts and exercises the grouped bars’ legend with real
synthetic input: clicking a series in the legend hides it across every group at
once — the whole industrial color drops out of all four quarters — and a second
click brings it back. It self-verifies that the series’ shown flag flips both ways
and that both plots render, so a no-op toggle or a missing chart fails at teardown.
Bar groups
plot_bar_groups(label_ids, values, item_count, group_count, group_size, shift, flags)
plots item_count series across group_count clusters. values is one flat
array of item_count * group_count numbers in row-major order — series i’s
value for group g is values[i*group_count + g] — and label_ids names one
series per row (the names appear in the legend, each in its series color). The groups
sit at integer x positions 0 .. group_count-1 by default. Two flags reshape the
chart without touching the data: ImPlotBarGroupsFlags.Stacked stacks the series
within each group instead of placing them side by side, and ImPlotBarGroupsFlags.Horizontal
swaps the bars onto the y-axis.
Pie charts
plot_pie_chart(label_ids, values, x, y, radius, label_fmt, angle0, flags) draws one
slice per (label_ids, values) pair, centered at data-coordinates (x, y) with
radius in data units. A pie wants a square, decoration-free coordinate space:
set ImPlotFlags.Equal on the plot so the circle is not stretched, hide both axes with
ImPlotAxisFlags.NoDecorations, and pin the limits to [0,1] x [0,1]. label_fmt is
a printf format applied to each slice’s value ("%.0f%%" here) — pass "" to draw no
slice labels. Values need not sum to one; the Normalize flag forces a full circle when
they sum to less than one.
Coloring
Both items auto-color from the active colormap — series and slices take successive
colormap entries, exactly like the auto-colored lines in
colormaps and style. Wrap either plot in
with_colormap(...) to recolor the whole family, or call next_fill_style(col) before
a single plot_bars to override one series.
Testing the categorical items
test_bar_groups_and_pie opens both plots through the
playwright layer and asserts each rendered. The bar
plot pins its axis limits with ImPlotCond.Always, so wait_for_axis_limits converging
proves the scope ran past plot_bar_groups — i.e. the labelled-series item submitted,
exercising the array<string> → const char* const[] path end to end on the real
headless render.