Bars And Bands¶
This example shows bars and an uncertainty band in one 2D panel.
Preview¶
Run And Adapt¶
Commands below assume a Datoviz source checkout and start at the repository root. Use your configured build environment; Python routes additionally require local bindings.
| Route | Availability | Command or action |
|---|---|---|
| C | Canonical native source | just example-c features/bars_bands (build and run), or rerun ./build/examples/c/features/bars_bands |
| Python | Available; direct-engine adaptation | python3 -m examples.python.gallery.features.bars_bands |
| Browser | Live WebGPU route | Open live example |
This example is approved as a starting point for user code and coding agents. Keep the object lifetimes and data shapes intact while adapting the data and styling.
What To Look For¶
The bar helper uses start, end, and value arrays so each bar has an explicit interval on the x axis. The band helper uses x, lower, upper, and center arrays to draw an envelope plus a central trend line. Compare the discrete bars with the continuous band and its bounds; the combination is useful for showing sampled measurements together with a model, confidence interval, or expected range.
Source¶
#!/usr/bin/env python3
"""Bars with explicit intervals and a continuous uncertainty band."""
from __future__ import annotations
import ctypes
import numpy as np
import datoviz as dvz
from examples.python.gallery import common as ex
BAR_COUNT = 9
BAND_COUNT = 96
def _configure_panel(panel) -> None:
if dvz.dvz_panel_set_domain(panel, dvz.DVZ_DIM_X, -0.5, 8.5) != 0:
raise RuntimeError("dvz_panel_set_domain(X) failed")
if dvz.dvz_panel_set_domain(panel, dvz.DVZ_DIM_Y, -0.35, 2.25) != 0:
raise RuntimeError("dvz_panel_set_domain(Y) failed")
x_axis = dvz.dvz_panel_axis(panel, dvz.DVZ_DIM_X)
y_axis = dvz.dvz_panel_axis(panel, dvz.DVZ_DIM_Y)
if not x_axis or not y_axis:
raise RuntimeError("dvz_panel_axis() failed")
if dvz.dvz_axis_set_grid(x_axis, False) != 0:
raise RuntimeError("dvz_axis_set_grid(X) failed")
if dvz.dvz_axis_set_grid(y_axis, False) != 0:
raise RuntimeError("dvz_axis_set_grid(Y) failed")
if dvz.dvz_axis_set_label(x_axis, b"sample") != 0:
raise RuntimeError("dvz_axis_set_label(X) failed")
if dvz.dvz_axis_set_label(y_axis, b"value") != 0:
raise RuntimeError("dvz_axis_set_label(Y) failed")
def _add_bars(panel) -> None:
samples = np.arange(BAR_COUNT, dtype=np.float64)
starts = samples - 0.42
ends = samples + 0.42
values = 0.42 + 0.12 * samples + 0.32 * np.sin(0.70 * samples)
desc = dvz.dvz_bars_desc()
desc.fill_color = dvz.DvzColor(76, 201, 240, 150)
desc.outline_color = dvz.DvzColor(76, 201, 240, 95)
desc.outline_width_px = 1.0
desc.gap_fraction = 0.12
bars = dvz.dvz_bars(panel, ctypes.byref(desc))
if not bars:
raise RuntimeError("dvz_bars() failed")
if dvz.dvz_bars_set_intervals(bars, starts, ends, values) != 0:
raise RuntimeError("dvz_bars_set_intervals() failed")
def _add_band(panel) -> None:
t = np.linspace(0.0, 1.0, BAND_COUNT, dtype=np.float64)
x = 8.0 * t
center = 0.74 + 0.48 * t + 0.22 * np.sin(2.0 * np.pi * (1.35 * t + 0.08))
half_width = 0.18 + 0.07 * np.cos(2.0 * np.pi * t)
lower = center - half_width
upper = center + half_width
desc = dvz.dvz_band_desc()
desc.fill_color = dvz.DvzColor(128, 255, 219, 58)
desc.line_color = dvz.DvzColor(128, 255, 219, 255)
desc.line_width_px = 5.0
desc.show_bounds = True
desc.bound_color = dvz.DvzColor(128, 255, 219, 150)
desc.bound_width_px = 1.5
band = dvz.dvz_band(panel, ctypes.byref(desc))
if not band:
raise RuntimeError("dvz_band() failed")
if dvz.dvz_band_set_bounds(band, x, lower, upper) != 0:
raise RuntimeError("dvz_band_set_bounds() failed")
if dvz.dvz_band_set_center(band, x, center) != 0:
raise RuntimeError("dvz_band_set_center() failed")
def main() -> None:
scene, figure, panel = ex.scene_panel()
_configure_panel(panel)
_add_bars(panel)
_add_band(panel)
ex.run(scene, figure, "Bars And Bands")
if __name__ == "__main__":
main()
/*
* Copyright (c) 2021 Cyrille Rossant and contributors. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project root for details.
* SPDX-License-Identifier: MIT
*/
/* bars_bands - This example shows bars and an uncertainty band in one 2D panel.
*
* Scenario: features_bars_bands
* Style: features, graphite_cyan, 1280x720 window target
*
* Build: just example-c features/bars_bands
* Run: ./build/examples/c/features/bars_bands --live
* Smoke: ./build/examples/c/features/bars_bands --png
*
* What to look for: the bar helper uses start, end, and value arrays so each bar has an explicit
* interval on the x axis. The band helper uses x, lower, upper, and center arrays to draw an
* envelope plus a central trend line. Compare the discrete bars with the continuous band and its
* bounds; the combination is useful for showing sampled measurements together with a model,
* confidence interval, or expected range.
*/
/*************************************************************************************************/
/* Includes */
/*************************************************************************************************/
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include "_assertions.h"
#include "datoviz/scene.h"
#include "example_style.h"
#include "runner/scenario_runner.h"
/*************************************************************************************************/
/* Forward declarations */
/*************************************************************************************************/
DvzScenarioSpec dvz_example_bars_bands_scenario(void);
/*************************************************************************************************/
/* Constants */
/*************************************************************************************************/
#define WIDTH EXAMPLE_WINDOW_WIDTH
#define HEIGHT EXAMPLE_WINDOW_HEIGHT
#define BAR_COUNT 9u
#define BAND_COUNT 96u
static const double TAU = 6.2831853071795864769;
/*************************************************************************************************/
/* Helpers */
/*************************************************************************************************/
/**
* Configure a compact 2D plotting panel.
*
* @param panel target panel
* @return true when axes and domains are configured
*/
static bool _configure_panel(DvzPanel* panel)
{
ANN(panel);
example_graphite_cyan_set_panel_background(panel);
if (dvz_panel_set_domain(panel, DVZ_DIM_X, -0.5, 8.5) != 0)
return false;
if (dvz_panel_set_domain(panel, DVZ_DIM_Y, -0.35, 2.25) != 0)
return false;
DvzAxis* x_axis = dvz_panel_axis(panel, DVZ_DIM_X);
DvzAxis* y_axis = dvz_panel_axis(panel, DVZ_DIM_Y);
if (x_axis == NULL || y_axis == NULL)
return false;
if (!example_graphite_cyan_apply_axis_style(x_axis, false, NULL))
return false;
if (!example_graphite_cyan_apply_axis_style(y_axis, true, NULL))
return false;
if (dvz_axis_set_grid(x_axis, false) != DVZ_OK || dvz_axis_set_grid(y_axis, false) != DVZ_OK)
return false;
return dvz_axis_set_label(x_axis, "sample") == DVZ_OK &&
dvz_axis_set_label(y_axis, "value") == DVZ_OK;
}
/**
* Add explicit-interval bars.
*
* @param panel target panel
* @return true when the bars were added
*/
static bool _add_bars(DvzPanel* panel)
{
ANN(panel);
double starts[BAR_COUNT] = {0};
double ends[BAR_COUNT] = {0};
double values[BAR_COUNT] = {0};
for (uint32_t i = 0; i < BAR_COUNT; i++)
{
starts[i] = (double)i - 0.42;
ends[i] = (double)i + 0.42;
values[i] = 0.42 + 0.12 * (double)i + 0.32 * sin(0.70 * (double)i);
}
DvzBarsDesc desc = dvz_bars_desc();
desc.fill_color = dvz_color_rgba(76, 201, 240, 150);
desc.outline_color = dvz_color_rgba(76, 201, 240, 95);
desc.outline_width_px = 1.0f;
desc.gap_fraction = 0.12f;
DvzBars* bars = dvz_bars(panel, &desc);
return bars != NULL && dvz_bars_set_intervals(bars, starts, ends, values, BAR_COUNT) == 0;
}
/**
* Add a continuous band with lower/upper bounds and a center line.
*
* @param panel target panel
* @return true when the band was added
*/
static bool _add_band(DvzPanel* panel)
{
ANN(panel);
double x[BAND_COUNT] = {0};
double lower[BAND_COUNT] = {0};
double upper[BAND_COUNT] = {0};
double center[BAND_COUNT] = {0};
for (uint32_t i = 0; i < BAND_COUNT; i++)
{
const double t = (double)i / (double)(BAND_COUNT - 1u);
x[i] = 8.0 * t;
center[i] = 0.74 + 0.48 * t + 0.22 * sin(TAU * (1.35 * t + 0.08));
const double half_width = 0.18 + 0.07 * cos(TAU * t);
lower[i] = center[i] - half_width;
upper[i] = center[i] + half_width;
}
DvzBandDesc desc = dvz_band_desc();
desc.fill_color = dvz_color_rgba(128, 255, 219, 58);
desc.line_color = dvz_color_rgba(128, 255, 219, 255);
desc.line_width_px = 5.0f;
desc.show_bounds = true;
desc.bound_color = dvz_color_rgba(128, 255, 219, 150);
desc.bound_width_px = 1.5f;
DvzBand* band = dvz_band(panel, &desc);
return band != NULL && dvz_band_set_bounds(band, x, lower, upper, BAND_COUNT) == 0 &&
dvz_band_set_center(band, x, center, BAND_COUNT) == 0;
}
/*************************************************************************************************/
/* Scenario callbacks */
/*************************************************************************************************/
/**
* Initialize the bars/bands feature example.
*
* @param ctx scenario context
* @param out_user scenario state output
* @return true on success
*/
static bool _scenario_init(DvzScenarioContext* ctx, void** out_user)
{
if (ctx == NULL)
return false;
if (out_user != NULL)
*out_user = NULL;
ctx->figure = dvz_figure(ctx->scene, ctx->width, ctx->height, 0);
if (ctx->figure == NULL)
return false;
DvzPanel* panel = dvz_panel_full(ctx->figure);
if (panel == NULL)
return false;
if (!_configure_panel(panel) || !_add_bars(panel) || !_add_band(panel))
return false;
return dvz_scenario_panzoom(ctx, panel, NULL, DVZ_DIM_MASK_XY) != NULL;
}
/**
* Return the bars/bands scenario specification.
*
* @return scenario specification
*/
DvzScenarioSpec dvz_example_bars_bands_scenario(void)
{
return (DvzScenarioSpec){
.id = "features_bars_bands",
.title = "Bars And Bands",
.width = WIDTH,
.height = HEIGHT,
.fps = 60.0,
.requirements = DVZ_SCENARIO_REQ_CONTROLLER | DVZ_SCENARIO_REQ_PANZOOM,
.init = _scenario_init,
};
}
/*************************************************************************************************/
/* Functions */
/*************************************************************************************************/
/**
* Run the bars/bands feature example through the native scenario runner.
*
* @param argc command-line argument count
* @param argv command-line argument vector
* @return process exit code
*/
#ifndef DVZ_EXAMPLE_NO_MAIN
int main(int argc, char** argv)
{
DvzScenarioSpec spec = dvz_example_bars_bands_scenario();
return dvz_scenario_run_native_cli(&spec, argc, argv) == 0 ? 0 : 1;
}
#endif
Example details
- ID:
features_bars_bands - Category:
feature - Lane:
features - Status:
supported - Source:
examples/c/features/bars_bands.c - Approved adaptation starter:
yes - Python source:
examples/python/gallery/features/bars_bands.py - Python adaptation: Available; direct-engine adaptation
- Browser support: Live in browser
- WebGPU live route:
examples/webgpu/live.html?id=features_bars_bands - Browser capability tags:
primitive,segment,axes,panzoom - Validation:
smoke+screenshot
Data
| Field | Value |
|---|---|
kind |
synthetic |
