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
2
3require imgui/imgui_harness
4require imgui/imgui_containers_builtin
5require imgui/imgui_widgets_builtin
6require imgui/imgui_implot_boost_v2
7require implot
8
9// =============================================================================
10// TUTORIAL: bar_groups_and_pie — the two categorical / labelled items.
11//
12// plot_bar_groups(label_ids, values, item_count, group_count) — item_count series
13// clustered into group_count groups. `values` is a flat item_count*group_count
14// row-major matrix (values[item*group_count+group]); `label_ids` names one
15// series per row (they show up in the legend). The Stacked / Horizontal flags
16// restack / reorient the bars.
17// plot_pie_chart(label_ids, values, x, y, radius) — one slice per
18// (label, value) pair, centered at data-coords (x, y). Pie plots want square,
19// decoration-free axes spanning [0,1].
20//
21// Both take label_ids : array<string> — a daslang string array IS already a
22// const char* const[] block, so it passes straight to ImPlot.
23//
24// STANDALONE: daslang.exe modules/dasImguiImplot/examples/tutorial/bar_groups_and_pie.das
25// LIVE: daslang-live modules/dasImguiImplot/examples/tutorial/bar_groups_and_pie.das
26// =============================================================================
27
28let ITEMS = 3 // series (one label / color each)
29let GROUPS = 4 // clusters along the x-axis
30
31var g_ctx : ImPlotContext?
32var g_bar_labels : array<string>
33var g_bar_values : array<double> // ITEMS*GROUPS, row-major
34var g_pie_labels : array<string>
35var g_pie_values : array<double>
36
37[export]
38def init() {
39 harness_init("dasImguiImplot — bar_groups_and_pie", 1280, 720)
40 g_ctx = implot::CreateContext()
41
42 // One row of GROUPS values per series, laid out flat (values[item*GROUPS+group]).
43 g_bar_labels <- ["merchant", "consumer", "industrial"]
44 g_bar_values <- [10.0lf, 14.0lf, 9.0lf, 12.0lf, // merchant
45 8.0lf, 11.0lf, 13.0lf, 7.0lf, // consumer
46 6.0lf, 9.0lf, 15.0lf, 10.0lf] // industrial
47
48 // One slice per (label, value); values need not be normalized.
49 g_pie_labels <- ["rent", "food", "transit", "savings"]
50 g_pie_values <- [35.0lf, 25.0lf, 18.0lf, 22.0lf]
51}
52
53[export]
54def update() {
55 if (!harness_begin_frame()) return
56 harness_new_frame()
57
58 SetNextWindowPos(float2(20.0, 20.0), ImGuiCond.Always)
59 SetNextWindowSize(float2(1240.0, 680.0), ImGuiCond.Always)
60 window(PLOT_WIN, (text = "bar groups & pie", closable = false,
61 flags = ImGuiWindowFlags.None)) {
62 text("plot_bar_groups clusters labelled series; plot_pie_chart splits a whole.")
63 plot(BARS, (title = "quarterly volume", size = float2(560.0f, 560.0f),
64 flags = ImPlotFlags.None)) {
65 setup_axes("group", "value")
66 setup_axes_limits(-0.5lf, double(GROUPS) - 0.5lf, 0.0lf, 18.0lf, ImPlotCond.Always)
67 plot_bar_groups(g_bar_labels, g_bar_values, ITEMS, GROUPS)
68 }
69 same_line()
70 plot(PIE, (title = "budget split", size = float2(-1.0f, 560.0f),
71 flags = ImPlotFlags.Equal)) {
72 setup_axes("", "", ImPlotAxisFlags.NoDecorations, ImPlotAxisFlags.NoDecorations)
73 setup_axes_limits(0.0lf, 1.0lf, 0.0lf, 1.0lf, ImPlotCond.Always)
74 plot_pie_chart(g_pie_labels, g_pie_values, 0.5lf, 0.5lf, 0.45lf, "%.0f%%")
75 }
76 }
77
78 harness_end_frame()
79}
80
81[export]
82def shutdown() {
83 if (g_ctx != null) {
84 DestroyContext(g_ctx)
85 }
86 harness_shutdown()
87}
88
89[export]
90def main() {
91 init()
92 while (!exit_requested()) {
93 update()
94 }
95 shutdown()
96}
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.