Building Check Overlays#

The built-in @plot_data_view methods (see Display & Report Methods) render fixed overlays — dimensions, balloons, the grid reference, and so on. When you write your own 2D check you usually need a different overlay: a green/red verdict on the entities that passed or failed, an explanatory label, an arrow to the thing at fault. Re-assembling those from raw plot_data rectangles, texts and line segments every time is tedious and error-prone.

drawing_tools.helpers.visualization.overlays.verdict is the reusable vocabulary for exactly that. It is the toolkit the Demo Scenarios are built on, and it is importable from the installed package so external tools can reuse it too.

Core idea: Viz and anchors#

Every helper returns a Viz — a list of plot_data primitives that also carries the bounding_rectangle of what it draws. Two consequences:

  • It concatenates like a list, so you accumulate overlays with += and hand the result straight to set_extra_plot_primitives.

  • It is itself an anchor. Every helper accepts, wherever it needs a location, either raw coordinates or an anchor — a drawing entity (anything with a .bounding_rectangle), a bare BoundingRectangle, or a Viz returned by a previous call. Overlays therefore chain naturally.

from pathlib import Path
import plot_data as pld
from volmdlr.core import BoundingRectangle
from dessia_drawing.core import Drawing
from drawing_tools.config.default_language_configs import DEFAULT_FRENCH_CONFIG, DEFAULT_ENGLISH_CONFIG
from drawing_tools.featured_drawing import FeaturedDrawing

_DATA_DIR = Path("data/json")
drawing = Drawing.from_json(str(_DATA_DIR / "2902060102_--A_DEF01_LH SUPPORT ACCUMULATOR ASSEMBLY.json"))
featured_drawing = FeaturedDrawing(drawing, language_configs=[DEFAULT_FRENCH_CONFIG, DEFAULT_ENGLISH_CONFIG])
featured_sheet = featured_drawing.sheets[1]
balloon = featured_sheet.balloons[0]

def view_by_name(name):
    """Return the sheet view with that name."""
    return next(view for view in featured_sheet.views if view.name == name)

def title_bounding_rectangle(view):
    """Union bounding rectangle of a view title's text pieces (a valid anchor)."""
    pieces = [piece for line in view.title.text_lines for piece in line.texts]
    return BoundingRectangle(
        xmin=min(p.bounding_rectangle.xmin for p in pieces),
        xmax=max(p.bounding_rectangle.xmax for p in pieces),
        ymin=min(p.bounding_rectangle.ymin for p in pieces),
        ymax=max(p.bounding_rectangle.ymax for p in pieces),
    )

verdict_overlay — the OK/NOK verdict#

verdict_overlay(anchor, *, ok, ...) is the workhorse. It draws, all colored by the ok verdict (green when True, red when False):

  • a box around the anchor,

  • an optional label beside it (a single string, or several lines),

  • a ✓ / ✗ glyph at a configurable corner.

from drawing_tools.helpers.visualization.overlays.verdict import verdict_overlay

frame = balloon.symbol.frame.bounding_rectangle

passed = verdict_overlay(frame, ok=True)                 # green box + ✓
failed = verdict_overlay(frame, ok=False, label=["BOM", "A3"])  # red box + stacked label + ✗

Appearance is grouped into small config dataclasses — VerdictBoxConfig (box offsets, opacity, stroke), VerdictLabelConfig (label side, gap, typography, inter-line spacing) and VerdictGlyphConfig (glyph corner, size, and whether it anchors on the box or on the label):

from drawing_tools.helpers.visualization.overlays.verdict import (
    VerdictBoxConfig,
    VerdictGlyphConfig,
    VerdictLabelConfig,
)

overlay = verdict_overlay(
    frame,
    ok=False,
    label="wrong zone",
    box_config=VerdictBoxConfig(opacity=0.12, line_width=1.8),
    label_config=VerdictLabelConfig(side="below", gap=2.0),
    glyph_config=VerdictGlyphConfig(corner="bottom-center", on="label"),
)

Accumulate one overlay per checked entity into set_extra_plot_primitives and you have an annotated check visualization. Here every balloon gets its glyph below the box (corner="bottom-center" instead of the default middle-right), the first balloon is flagged failing with a label, and — to show that a verdict wraps any bounding rectangle — the COUPE A2-A2 view title is checked too:

from drawing_tools.helpers.visualization.overlays.verdict import VerdictGlyphConfig

glyph_below = VerdictGlyphConfig(corner="bottom-center")

extras = []
for index, balloon in enumerate(featured_sheet.balloons):
    frame = balloon.symbol.frame.bounding_rectangle
    passed = index != 0  # flag the first balloon as failing, for illustration
    extras += verdict_overlay(
        frame, ok=passed, label=None if passed else "wrong zone", glyph_config=glyph_below
    )

title = title_bounding_rectangle(view_by_name("COUPE A2-A2"))
extras += verdict_overlay(title, ok=True, label="view title", glyph_config=glyph_below)
featured_sheet.set_extra_plot_primitives(extras)
featured_sheet.plot_data("balloons_check.html")   # or .plot() to open a browser

Source: 2902060102_–A_DEF01_LH SUPPORT ACCUMULATOR ASSEMBLY.json, Sheet 1 — balloons checked (first one failing) plus the COUPE A2-A2 title

callout — point at a target from a distance#

When the label cannot sit on the entity (a tiny title-block cell, a token buried in the cartouche), callout(target, label, *, color, ...) places the label block away from the target and draws an arrow from the block to the target’s edge. Unlike verdict_overlay the color is free — callouts are often informational (orange, blue) rather than strictly pass/fail — and an optional status adds a glyph on the label.

Here a two-line note is placed in a clear area above a balloon (the near anchor) and an arrow points down to the balloon; status="WARN" adds a ⚠ glyph:

from drawing_tools.helpers.visualization.overlays.verdict import callout, ORANGE, VerdictLabelConfig

balloon_box = featured_sheet.balloons[0].symbol.frame.bounding_rectangle
label_spot = BoundingRectangle(  # a clear band ~25-40 mm above the balloon
    xmin=balloon_box.xmin,
    xmax=balloon_box.xmax,
    ymin=balloon_box.ymax + 25,
    ymax=balloon_box.ymax + 40,
)
extras = callout(
    balloon_box,
    ["check this balloon", "against the BOM"],
    color=ORANGE,
    status="WARN",
    near=label_spot,
    label_config=VerdictLabelConfig(side="above", line_gap=10.0),  # space the two lines out
)
featured_sheet.set_extra_plot_primitives(list(extras))
featured_sheet.plot_data("balloon_callout.html")   # or .plot() to open a browser

Source: 2902060102_–A_DEF01_LH SUPPORT ACCUMULATOR ASSEMBLY.json, Sheet 1 — a WARN callout above a balloon

The safety_class demo (Safety class — drawing vs BOM) is another worked example: its entire overlay is a single callout pointing from an explanatory label down to the safety-class token in the title block.

Low-level helpers#

The three composites above cover most checks, but the primitives they are built from are public too, for overlays that do not fit the mould. Each takes raw coordinates or an anchor and returns a Viz:

  • rectangle — a colored rectangle from coordinates or around an anchor, with per-side outward offsets.

  • text — a text primitive, optionally anchored beside another element (near= / side=) and optionally framed.

  • arrow — a straight arrow (shaft + head) between two points or two anchors.

  • status_symbol — a ✓ / ✗ / ⚠ glyph at a corner of an anchor.

  • stacked_texts — several text lines placed as one block beside an anchor.

  • highlight / highlight_text — a symmetric-padding highlight around an entity, or hugging a text’s estimated footprint.

  • estimate_text_bbox / closest_edge_point — the geometry helpers used to place labels and anchor arrow endpoints.

A semantic palette (GREEN, RED, ORANGE, BLUE, PURPLE, YELLOW_FILL) and the glyph constants (CHECK_MARK, CROSS_MARK, WARN_MARK) round out the module.

Tip

For end-to-end examples that combine these overlays with real checks against a BOM or the drawing itself, see the Demo Scenarios.