Skip to content

Panel Grid

This example arranges four independent panels in a 2x2 figure grid.

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/panel_grid (build and run), or rerun ./build/examples/c/features/panel_grid
Python Available; manually maintained direct-engine example python3 -m examples.python.gallery.features.panel_grid
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

Each panel has its own border, background, and small point visual with position, color, and diameter_px arrays. The same point pattern is repeated with a different accent color in each grid cell, so compare how gutters, margins, and panel-local clipping keep the plots separated. Grid panels are useful for small multiples and side-by-side scientific comparisons.

Source

#!/usr/bin/env python3
"""Two-by-two panel grid with one point cluster per panel."""

from __future__ import annotations

import numpy as np

import datoviz as dvz

from examples.python.gallery import common as ex


def main() -> None:
    scene = dvz.dvz_scene()
    figure = dvz.dvz_figure(scene, ex.WIDTH, ex.HEIGHT, 0)

    centers = [(-0.32, 0.22), (0.34, 0.18), (-0.24, -0.28), (0.28, -0.22)]
    colors = [ex.CYAN, ex.GREEN, ex.YELLOW, ex.RED]
    for i, (col, row) in enumerate([(0, 0), (1, 0), (0, 1), (1, 1)]):
        panel = ex.panel_rect(figure, 0.05 + 0.48 * col, 0.06 + 0.45 * row, 0.42, 0.38)
        cx, cy = centers[i]
        positions = np.array(
            [[cx - 0.18, cy - 0.12, 0.0], [cx, cy + 0.18, 0.0], [cx + 0.18, cy - 0.12, 0.0]],
            dtype=np.float32,
        )
        ex.add_points(
            scene,
            panel,
            positions,
            ex.color_array(colors[i], ex.TEXT, colors[i]),
            np.array([32.0, 44.0, 32.0], dtype=np.float32),
        )

    ex.run(scene, figure, "Panel Grid")


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
 */

/* This example arranges four independent panels in a 2x2 figure grid.
 *
 * What to look for: each panel has its own border, background, and small point visual with
 * position, color, and diameter_px arrays. The same point pattern is repeated with a different
 * accent color in each grid cell, so compare how gutters, margins, and panel-local clipping keep
 * the plots separated. Grid panels are useful for small multiples and side-by-side scientific
 * comparisons.
 *
 * Scenario: features_panel_grid
 * Style: features, graphite_cyan, 1280x720 window target
 *
 * Build:  just example-c features/panel_grid
 * Run:    ./build/examples/c/features/panel_grid --live
 * Smoke:  ./build/examples/c/features/panel_grid --png
 */



/*************************************************************************************************/
/*  Includes                                                                                     */
/*************************************************************************************************/

#include <stdbool.h>
#include <stdint.h>

#include "datoviz/scene.h"
#include "example_style.h"
#include "runner/scenario_runner.h"



/*************************************************************************************************/
/*  Forward declarations                                                                         */
/*************************************************************************************************/

DvzScenarioSpec dvz_example_panel_grid_scenario(void);



/*************************************************************************************************/
/*  Constants                                                                                    */
/*************************************************************************************************/

#define WIDTH  EXAMPLE_WINDOW_WIDTH
#define HEIGHT EXAMPLE_WINDOW_HEIGHT
#define PANEL_COUNT 4u
#define POINT_COUNT 4u



/*************************************************************************************************/
/*  Helpers                                                                                      */
/*************************************************************************************************/

/**
 * Add one small point group to a grid panel.
 *
 * @param scene scene owning the visual
 * @param panel panel receiving the visual
 * @param accent main color for this panel
 * @return true when the visual was added
 */
static bool _add_panel_points(DvzScene* scene, DvzPanel* panel, DvzColor accent)
{
    const vec3 positions[POINT_COUNT] = {
        {-0.35f, -0.28f, 0.0f},
        {+0.35f, -0.28f, 0.0f},
        {+0.00f, +0.32f, 0.0f},
        {+0.00f, +0.00f, 0.0f},
    };
    DvzColor colors[POINT_COUNT] = {
        accent,
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_SECONDARY),
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_WARNING),
    };
    const float diameters[POINT_COUNT] = {26.0f, 26.0f, 34.0f, 12.0f};

    DvzVisual* point = dvz_point(scene, 0);
    if (point == NULL)
        return false;

    DvzVisualDataUpdate updates[] = {
        {.attr_name = "position", .data = positions, .item_count = POINT_COUNT},
        {.attr_name = "color", .data = colors, .item_count = POINT_COUNT},
        {.attr_name = "diameter_px", .data = diameters, .item_count = POINT_COUNT},
    };
    if (dvz_visual_set_data_many(point, updates, 3) != 0)
        return false;

    DvzPointStyleDesc style = dvz_point_style_desc();
    style.aspect = DVZ_SHAPE_ASPECT_FILLED;
    style.stroke_width_px = 0.0f;
    if (dvz_point_set_style(point, &style) != 0)
        return false;
    if (dvz_visual_set_depth_test(point, false) != 0)
        return false;

    return dvz_panel_add_visual(panel, point, NULL) == 0;
}



/*************************************************************************************************/
/*  Scenario callbacks                                                                           */
/*************************************************************************************************/

/**
 * Initialize the grid layout scenario.
 *
 * @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;

    DvzGrid* grid = dvz_figure_grid(ctx->figure, 2, 2);
    if (grid == NULL)
        return false;
    if (dvz_grid_set_margins(
            grid,
            &(DvzPanelReserve){
                .left_px = 56.0f, .right_px = 56.0f, .top_px = 56.0f, .bottom_px = 56.0f}) != DVZ_OK)
        return false;
    if (dvz_grid_set_gutter(grid, 36.0f, 36.0f) != DVZ_OK)
        return false;

    DvzPanel* panels[PANEL_COUNT] = {
        dvz_grid_panel(grid, 0, 0),
        dvz_grid_panel(grid, 0, 1),
        dvz_grid_panel(grid, 1, 0),
        dvz_grid_panel(grid, 1, 1),
    };
    DvzColor accents[PANEL_COUNT] = {
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_PRIMARY),
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_SECONDARY),
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_WARNING),
        example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ERROR),
    };

    for (uint32_t i = 0; i < PANEL_COUNT; i++)
    {
        if (panels[i] == NULL)
            return false;
        example_graphite_cyan_set_panel_background(panels[i]);

        DvzPanelBorderDesc border = dvz_panel_border_desc();
        border.color = example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_GRID);
        border.width_px = 1.5f;
        if (dvz_panel_set_border(panels[i], &border) != DVZ_OK)
            return false;

        if (!_add_panel_points(ctx->scene, panels[i], accents[i]))
            return false;
    }

    return true;
}



/**
 * Return the panel-grid scenario specification.
 *
 * @return scenario specification
 */
DvzScenarioSpec dvz_example_panel_grid_scenario(void)
{
    return (DvzScenarioSpec){
        .id = "features_panel_grid",
        .title = "Panel Grid",
        .width = WIDTH,
        .height = HEIGHT,
        .fps = 60.0,
        .requirements = DVZ_SCENARIO_REQ_POINT_VISUAL,
        .init = _scenario_init,
    };
}



/*************************************************************************************************/
/*  Functions                                                                                    */
/*************************************************************************************************/

/**
 * Run the grid layout 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_panel_grid_scenario();
    return dvz_scenario_run_native_cli(&spec, argc, argv) == 0 ? 0 : 1;
}
#endif
Example details

Data

Field Value
kind synthetic