Skip to content

View Size Policies

This example demonstrates how requested view size policies resolve to real view sizes.

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/view_size_policies (build and run), or rerun ./build/examples/c/features/view_size_policies
Python Available; direct-engine adaptation python3 -m examples.python.gallery.features.view_size_policies
Browser Native only demonstrates native window, framebuffer, and physical-size policies

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

Pass --policy pixel, host, reference, or physical to choose framebuffer pixels, host logical pixels, reference-DPI canvas pixels, or physical millimeters. The example prints the resolved canvas, host-logical, framebuffer, scale, and physical sizes, then renders a small point visual with position, color, and diameter_px arrays. This is useful when figures need reproducible screenshot dimensions across HiDPI monitors and different host toolkits.

Source

#!/usr/bin/env python3
"""Requested view size policies resolved into concrete view sizes."""

from __future__ import annotations

import argparse
import ctypes

import numpy as np

import datoviz as dvz

from examples.python.gallery import common as ex


POINT_COUNT = 5
DEFAULT_VIEW_KIND = dvz.DVZ_VIEW_WINDOW


def _policy_name(policy: int) -> str:
    labels = {
        dvz.DVZ_VIEW_SIZE_FRAMEBUFFER_PX: "pixel_exact",
        dvz.DVZ_VIEW_SIZE_HOST_LOGICAL_PX: "host_logical_px",
        dvz.DVZ_VIEW_SIZE_REFERENCE_PX: "reference_px",
        dvz.DVZ_VIEW_SIZE_PHYSICAL_MM: "physical_mm",
    }
    return labels.get(policy, "unknown")


def _size_desc(policy: str):
    if policy in {"pixel", "pixel_exact"}:
        return dvz.dvz_view_size_desc_framebuffer_px(ex.WIDTH, ex.HEIGHT)
    if policy in {"host", "host_logical", "host_logical_px"}:
        return dvz.dvz_view_size_desc_host_logical_px(ex.WIDTH, ex.HEIGHT)
    if policy in {"physical", "physical_mm"}:
        return dvz.dvz_view_size_desc_physical_mm(338.7, 190.5, 96.0)
    return dvz.dvz_view_size_desc_reference_px(float(ex.WIDTH), float(ex.HEIGHT), 96.0)


def _add_points(scene, panel) -> None:
    positions = np.array(
        [
            [-0.70, -0.35, 0.0],
            [-0.35, +0.26, 0.0],
            [+0.00, +0.00, 0.0],
            [+0.35, -0.24, 0.0],
            [+0.70, +0.36, 0.0],
        ],
        dtype=np.float32,
    )
    colors = ex.color_array(ex.WHITE, ex.CYAN, ex.YELLOW, ex.RED, ex.BLUE)
    diameters = np.array([26.0, 34.0, 46.0, 58.0, 70.0], dtype=np.float32)

    point = dvz.dvz_point(scene, 0)
    if not point:
        raise RuntimeError("dvz_point() failed")
    if dvz.dvz_visual_set_data_many(
        point,
        {
            "position": positions,
            "color": colors,
            "diameter_px": diameters,
        },
    ) != 0:
        raise RuntimeError("dvz_visual_set_data_many(point) failed")
    ex.set_filled_point_style(point)
    ex.add_visual(panel, point)


def _print_resolved(resolved) -> None:
    print(f"policy: {_policy_name(resolved.requested_policy)}")
    print(f"canvas_px: {resolved.canvas_width_px:.1f}x{resolved.canvas_height_px:.1f}")
    print(f"host_logical_px: {resolved.host_logical_width}x{resolved.host_logical_height}")
    print(f"framebuffer_px: {resolved.framebuffer_width}x{resolved.framebuffer_height}")
    print(
        "framebuffer_per_canvas_px: "
        f"{resolved.framebuffer_per_canvas_px_x:.3f}x{resolved.framebuffer_per_canvas_px_y:.3f}"
    )
    if resolved.target_width_mm > 0.0 and resolved.target_height_mm > 0.0:
        print(f"target_physical_mm: {resolved.target_width_mm:.1f}x{resolved.target_height_mm:.1f}")


def _build_scene(size, kind=DEFAULT_VIEW_KIND):
    initial = dvz.dvz_view_size_resolve(ctypes.byref(size), kind)
    width = int(initial.host_logical_width or ex.WIDTH)
    height = int(initial.host_logical_height or ex.HEIGHT)

    scene = dvz.dvz_scene()
    if not scene:
        raise RuntimeError("dvz_scene() failed")
    figure = dvz.dvz_figure(scene, width, height, 0)
    if not figure:
        dvz.dvz_scene_destroy(scene)
        raise RuntimeError("dvz_figure() failed")
    panel = dvz.dvz_panel_full(figure)
    if not panel:
        dvz.dvz_scene_destroy(scene)
        raise RuntimeError("dvz_panel_full() failed")
    dvz.dvz_panel_set_background_color(panel, ex.BG)
    _add_points(scene, panel)
    return scene, figure, panel


def _view_desc(kind, size):
    desc = dvz.dvz_view_desc(kind)
    desc.size_policy = size.policy
    desc.size_width = size.width
    desc.size_height = size.height
    desc.size_reference_dpi = size.reference_dpi
    desc.size_requested_device_scale = size.requested_device_scale
    desc.size_monitor_dpi_x_override = size.monitor_dpi_x_override
    desc.size_monitor_dpi_y_override = size.monitor_dpi_y_override
    desc.size_strict_framebuffer_size = size.strict_framebuffer_size
    desc.title = b"View Size Policies"
    return desc


def _run_view(policy: str = "reference", *, kind=DEFAULT_VIEW_KIND) -> tuple:
    size = _size_desc(policy)
    scene, figure, panel = _build_scene(size, kind)
    app = dvz.dvz_app(scene)
    if not app:
        dvz.dvz_scene_destroy(scene)
        raise RuntimeError("dvz_app() failed")
    try:
        desc = _view_desc(kind, size)
        view = dvz.dvz_view(app, figure, ctypes.byref(desc))
        if not view:
            raise RuntimeError("dvz_view() failed")
        if not dvz.dvz_view_panzoom(view, panel, None):
            raise RuntimeError("dvz_view_panzoom() failed")
        return scene, app, view, dvz.dvz_view_resolved_size(view)
    except Exception:
        dvz.dvz_app_destroy(app)
        dvz.dvz_scene_destroy(scene)
        raise


def _run_smoke(policy: str = "pixel"):
    scene, app, view, resolved = _run_view(policy, kind=dvz.DVZ_VIEW_OFFSCREEN)
    try:
        status = dvz.dvz_view_render_once(view)
        if status != dvz.DVZ_CANVAS_FRAME_READY:
            raise RuntimeError("dvz_view_render_once() failed")
        ex.capture_smoke(view)
        if resolved.framebuffer_width <= 0 or resolved.framebuffer_height <= 0:
            raise RuntimeError("resolved framebuffer size is empty")
        return resolved
    finally:
        dvz.dvz_app_destroy(app)
        dvz.dvz_scene_destroy(scene)


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--policy",
        choices=(
            "pixel",
            "pixel_exact",
            "host",
            "host_logical",
            "host_logical_px",
            "reference",
            "physical",
            "physical_mm",
        ),
        default="reference",
    )
    parser.add_argument("--frames", type=int, default=0)
    parser.add_argument("--smoke", action="store_true")
    args = parser.parse_args()

    if args.smoke or ex.SMOKE_MODE:
        resolved = _run_smoke(args.policy)
        _print_resolved(resolved)
        return

    scene, app, view, resolved = _run_view(args.policy, kind=dvz.DVZ_VIEW_WINDOW)
    try:
        _print_resolved(resolved)
        if args.frames > 0 and not ex.SMOKE_MODE:
            dvz.dvz_app_run(app, args.frames)
        else:
            ex.run_app(app, view)
    finally:
        dvz.dvz_app_destroy(app)
        dvz.dvz_scene_destroy(scene)


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 demonstrates how requested view size policies resolve to real view sizes.
 *
 * What to look for: pass --policy pixel, host, reference, or physical to choose framebuffer pixels,
 * host logical pixels, reference-DPI canvas pixels, or physical millimeters. The example prints
 * the resolved canvas, host-logical, framebuffer, scale, and physical sizes, then renders a small
 * point visual with position, color, and diameter_px arrays. This is useful when figures need
 * reproducible screenshot dimensions across HiDPI monitors and different host toolkits.
 *
 * Scenario: features_view_size_policies
 * Style: features, graphite_cyan
 *
 * Build:  just example-c features/view_size_policies
 * Run:    ./build/examples/c/features/view_size_policies --policy reference
 * Smoke:  ./build/examples/c/features/view_size_policies --policy pixel --frames 1
 */



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

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

#include "datoviz/app.h"
#include "datoviz/scene.h"
#include "example_common.h"
#include "example_style.h"



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

#define WIDTH  EXAMPLE_WINDOW_WIDTH
#define HEIGHT EXAMPLE_WINDOW_HEIGHT
#define POINT_COUNT 5u



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

static const char* _policy_name(DvzViewSizePolicy policy)
{
    switch (policy)
    {
    case DVZ_VIEW_SIZE_FRAMEBUFFER_PX:
        return "pixel_exact";
    case DVZ_VIEW_SIZE_HOST_LOGICAL_PX:
        return "host_logical_px";
    case DVZ_VIEW_SIZE_REFERENCE_PX:
        return "reference_px";
    case DVZ_VIEW_SIZE_PHYSICAL_MM:
        return "physical_mm";
    default:
        return "unknown";
    }
}



static DvzViewSizeDesc _parse_size_policy(int argc, char** argv)
{
    const char* policy = "reference";
    (void)example_arg_value(argc, argv, "--policy", &policy);

    if (strcmp(policy, "pixel") == 0 || strcmp(policy, "pixel_exact") == 0)
        return dvz_view_size_desc_framebuffer_px(WIDTH, HEIGHT);
    if (strcmp(policy, "host") == 0 || strcmp(policy, "host_logical") == 0 ||
        strcmp(policy, "host_logical_px") == 0)
        return dvz_view_size_desc_host_logical_px(WIDTH, HEIGHT);
    if (strcmp(policy, "physical") == 0 || strcmp(policy, "physical_mm") == 0)
        return dvz_view_size_desc_physical_mm(338.7, 190.5, 96.0);
    return dvz_view_size_desc_reference_px((double)WIDTH, (double)HEIGHT, 96.0);
}



static bool _parse_frame_count(int argc, char** argv, uint32_t* out)
{
    if (out == NULL)
        return false;

    const char* value = NULL;
    if (example_arg_value(argc, argv, "--frames", &value))
        return example_parse_u32(value, out);

    *out = example_frame_count_any(argc, argv);
    return true;
}



static bool _add_points(DvzScene* scene, DvzPanel* panel)
{
    vec3 positions[POINT_COUNT] = {
        {-0.70f, -0.35f, 0.0f},
        {-0.35f, +0.26f, 0.0f},
        {+0.00f, +0.00f, 0.0f},
        {+0.35f, -0.24f, 0.0f},
        {+0.70f, +0.36f, 0.0f},
    };
    DvzColor colors[POINT_COUNT] = {
        {245, 245, 245, 255},
        {47, 197, 205, 255},
        {250, 219, 82, 255},
        {223, 84, 116, 255},
        {110, 137, 241, 255},
    };
    float diameters[POINT_COUNT] = {26.0f, 34.0f, 46.0f, 58.0f, 70.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, DVZ_ARRAY_COUNT(updates)) != 0)
        return false;
    DvzPointStyleDesc style = dvz_point_style_desc();
    style.stroke_width_px = 0.0f;
    if (dvz_point_set_style(point, &style) != 0)
        return false;
    return dvz_panel_add_visual(panel, point, NULL) == 0;
}



static void _print_resolved(const DvzResolvedViewSize* resolved)
{
    dvz_fprintf(stdout, "policy: %s\n", _policy_name(resolved->requested_policy));
    dvz_fprintf(
        stdout, "canvas_px: %.1fx%.1f\n", resolved->canvas_width_px, resolved->canvas_height_px);
    dvz_fprintf(
        stdout,
        "host_logical_px: %ux%u\n", resolved->host_logical_width,
        resolved->host_logical_height);
    dvz_fprintf(
        stdout,
        "framebuffer_px: %ux%u\n", resolved->framebuffer_width,
        resolved->framebuffer_height);
    dvz_fprintf(
        stdout,
        "framebuffer_per_canvas_px: %.3fx%.3f\n", resolved->framebuffer_per_canvas_px_x,
        resolved->framebuffer_per_canvas_px_y);
    if (resolved->target_width_mm > 0.0 && resolved->target_height_mm > 0.0)
        dvz_fprintf(
            stdout,
            "target_physical_mm: %.1fx%.1f\n", resolved->target_width_mm,
            resolved->target_height_mm);
}



/*************************************************************************************************/
/*  Main                                                                                         */
/*************************************************************************************************/

int main(int argc, char** argv)
{
    int ret = 1;
    DvzScene* scene = NULL;
    DvzApp* app = NULL;
    uint32_t frame_count = 0;

    EXAMPLE_CHECK(_parse_frame_count(argc, argv, &frame_count), "invalid --frames value");

    scene = dvz_scene();
    EXAMPLE_CHECK(scene != NULL, "dvz_scene() failed");

    DvzViewSizeDesc size = _parse_size_policy(argc, argv);
    DvzResolvedViewSize initial = dvz_view_size_resolve(&size, DVZ_VIEW_WINDOW);

    DvzFigure* figure = dvz_figure(
        scene, initial.host_logical_width, initial.host_logical_height, 0);
    DvzPanel* panel = figure != NULL ? dvz_panel_full(figure) : NULL;
    EXAMPLE_CHECK(figure != NULL && panel != NULL, "failed to create figure/panel");
    example_graphite_cyan_set_panel_background(panel);
    EXAMPLE_CHECK(_add_points(scene, panel), "failed to add points");

    app = dvz_app(scene);
    EXAMPLE_CHECK(app != NULL, "dvz_app() failed (no GPU or display?)");

    DvzViewDesc desc = dvz_view_desc(DVZ_VIEW_WINDOW);
    desc.size_policy = size.policy;
    desc.size_width = size.width;
    desc.size_height = size.height;
    desc.size_reference_dpi = size.reference_dpi;
    desc.size_requested_device_scale = size.requested_device_scale;
    desc.size_monitor_dpi_x_override = size.monitor_dpi_x_override;
    desc.size_monitor_dpi_y_override = size.monitor_dpi_y_override;
    desc.size_strict_framebuffer_size = size.strict_framebuffer_size;
    desc.title = "View Size Policies";
    DvzView* view = dvz_view(app, figure, &desc);
    EXAMPLE_CHECK(view != NULL, "dvz_view() failed");
    EXAMPLE_CHECK(dvz_view_panzoom(view, panel, NULL) != NULL, "dvz_view_panzoom() failed");

    DvzResolvedViewSize resolved = dvz_view_resolved_size(view);
    _print_resolved(&resolved);

    dvz_app_run(app, frame_count);
    ret = 0;

cleanup:
    if (app != NULL)
        dvz_app_destroy(app);
    if (scene != NULL)
        dvz_scene_destroy(scene);
    return ret;
}
Example details
  • ID: features_view_size_policies
  • Category: feature
  • Lane: features
  • Status: supported
  • Source: examples/c/features/view_size_policies.c
  • Approved adaptation starter: yes
  • Python source: examples/python/gallery/features/view_size_policies.py
  • Python adaptation: Available; direct-engine adaptation
  • Browser support: Native only
  • Browser note: demonstrates native window, framebuffer, and physical-size policies
  • Browser capability tags: native-view, view-size-policy
  • Validation: smoke+interaction

Tags

view-size, framebuffer, window

Data

Field Value
kind synthetic