Multi axes

Two y axes with independent ranges on one plot. Temperature (0..30) and pressure (~1000 hPa) would be unreadable sharing a single axis, so pressure gets its own right-hand y axis. Three calls do it: setup_axis enables the second axis, setup_axis_limits ranges it, and set_axis routes the next items onto it.

plot(CHART, (title = "weather", size = float2(-1.0f, 600.0f), flags = ImPlotFlags.None)) {
    setup_axes("hour", "temp (C)")
    setup_axis(ImAxis.Y2, "pressure (hPa)", ImPlotAxisFlags.AuxDefault)   // enable Y2
    setup_axis_limits(ImAxis.Y1, 0.0lf, 30.0lf)
    setup_axis_limits(ImAxis.Y2, 950.0lf, 1050.0lf)
    plot_line("temp", g_temp)        // default Y1
    set_axis(ImAxis.Y2)              // route what follows to Y2
    plot_line("pressure", g_press)
}

Source: examples/tutorial/multi_axes.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
 8require math
 9
10// =============================================================================
11// TUTORIAL: multi_axes — two y axes with different scales on one plot.
12//
13//   setup_axis(ImAxis.Y2, label, ImPlotAxisFlags.AuxDefault)  — enable a 2nd y axis.
14//   setup_axis_limits(ImAxis.Y2, ...)                         — range it independently.
15//   set_axis(ImAxis.Y2)                                       — route the NEXT items to it.
16//
17// Temperature (0..30) lives on the left Y1; pressure (~1000 hPa) on the right Y2 —
18// wildly different ranges that would be unreadable sharing one axis.
19//
20// STANDALONE: daslang.exe modules/dasImguiImplot/examples/tutorial/multi_axes.das
21// LIVE:       daslang-live modules/dasImguiImplot/examples/tutorial/multi_axes.das
22// =============================================================================
23
24let N = 100
25
26var g_ctx : ImPlotContext?
27var g_temp : array<double>      // small range, Y1
28var g_press : array<double>     // large range, Y2
29
30[export]
31def init() {
32    harness_init("dasImguiImplot — multi_axes", 1100, 720)
33    g_ctx = implot::CreateContext()
34    g_temp  <- [for (i in range(N)); 17.0lf + 6.0lf * double(sin(float(i) * 0.10f))]
35    g_press <- [for (i in range(N)); 1000.0lf + 30.0lf * double(cos(float(i) * 0.07f))]
36}
37
38[export]
39def update() {
40    if (!harness_begin_frame()) return
41    harness_new_frame()
42
43    SetNextWindowPos(float2(20.0, 20.0), ImGuiCond.Always)
44    SetNextWindowSize(float2(1060.0, 680.0), ImGuiCond.Always)
45    window(PLOT_WIN, (text = "multi axes", closable = false,
46                      flags = ImGuiWindowFlags.None)) {
47        text("Temperature on Y1 (left), pressure on Y2 (right). set_axis routes an item to Y2.")
48        plot(CHART, (title = "weather", size = float2(-1.0f, 600.0f),
49                     flags = ImPlotFlags.None)) {
50            setup_axes("hour", "temp (C)")
51            setup_axis(ImAxis.Y2, "pressure (hPa)", ImPlotAxisFlags.AuxDefault)
52            setup_axis_limits(ImAxis.X1, 0.0lf, double(N))
53            setup_axis_limits(ImAxis.Y1, 0.0lf, 30.0lf)
54            setup_axis_limits(ImAxis.Y2, 950.0lf, 1050.0lf)
55            // Temperature on the default Y1.
56            next_line_style(float4(1.00f, 0.55f, 0.20f, 1.00f), 2.0f)
57            plot_line("temp", g_temp)
58            // Route the next item to Y2, then plot pressure against it.
59            set_axis(ImAxis.Y2)
60            next_line_style(float4(0.35f, 0.75f, 1.00f, 1.00f), 2.0f)
61            plot_line("pressure", g_press)
62        }
63    }
64
65    harness_end_frame()
66}
67
68[export]
69def shutdown() {
70    if (g_ctx != null) {
71        DestroyContext(g_ctx)
72    }
73    harness_shutdown()
74}
75
76[export]
77def main() {
78    init()
79    while (!exit_requested()) {
80        update()
81    }
82    shutdown()
83}

Walkthrough

Enabling a second axis

setup_axis(ImAxis.Y2, label, ImPlotAxisFlags.AuxDefault) turns on the second y axis with a sensible default style (auto-fit, opposite side). ImPlot supports up to three of each — Y1 / Y2 / Y3 and likewise for x. Each is ranged independently with setup_axis_limits(axis, …).

Routing items to an axis

Items go on whichever axis pair is current; Y1 is the default. set_axis(axis) switches the current y axis so every item after it draws against that axis — here, plot_line("pressure", …) lands on Y2. The two-axis form set_axes(x_axis, y_axis) switches both at once. Because the snapshot captures GetPlotLimits(X1, Y1), the test_multi_axes regression asserts Y1 stays [0,30] — confirming pressure’s [950,1050] lives on a genuinely separate axis.

Panning one axis

Each axis can be panned on its own: left-drag on an axis’ tick-label gutter — the strip just outside the data area — and only that axis moves. In the walkthrough, dragging the left gutter pans temperature while pressure holds, then dragging the right gutter pans pressure while temperature holds. This is the multi-axis payoff over a plain plot-body drag, which pans every axis at once. The recording drives both drags with real synthetic input and asserts the dragged axis’ range moved while the other stayed put, so a no-op — or a drag that bled across to the other axis — fails it.