Skip to content

Render Stage

The render stage transforms compiled faces with data into visual output formats.

CompiledFace + Executor → render() → SVG | HTML | PNG | PDF | Terminal

Supported Formats

The renderer supports the following output formats:

  • SVG: Scalable vector graphics (default)
  • HTML: Interactive HTML pages with embedded charts
  • PNG: Raster image format
  • PDF: PDF documents
  • Terminal: Terminal output with ASCII/Unicode charts (prints to stdout)

Entry Points

render

The main entry point for rendering datafaces:

render

render(
    face: CompiledFace,
    executor: Executor,
    format: str = "svg",
    variables: VariableValues | None = None,
    **options: Any
) -> str | bytes

Render a compiled dataface.

Stage: RENDER (Main Entry Point)

This is the main rendering function. It walks the layout structure, renders each chart (triggering lazy query execution), and produces output in the requested format.

PARAMETER DESCRIPTION
face

Compiled dataface to render

TYPE: CompiledFace

executor

Executor for query execution

TYPE: Executor

format

Output format (svg, html, png, pdf, terminal, json)

TYPE: str DEFAULT: 'svg'

variables

Variable values for queries

TYPE: VariableValues | None DEFAULT: None

**options

Format-specific options - background: Background color - scale: Scale factor (for png) - grid: Show grid overlay (for debugging)

TYPE: Any DEFAULT: {}

RETURNS DESCRIPTION
str | bytes

Rendered output: - str for svg, html, terminal - bytes for png, pdf

RAISES DESCRIPTION
RenderError

If rendering fails

FormatError

If format is unknown

Source code in dataface/core/render/renderer.py
def render(
    face: CompiledFace,
    executor: Executor,
    format: str = "svg",
    variables: VariableValues | None = None,
    **options: Any,
) -> str | bytes:
    """Render a compiled dataface.

    Stage: RENDER (Main Entry Point)

    This is the main rendering function. It walks the layout structure,
    renders each chart (triggering lazy query execution), and produces
    output in the requested format.

    Args:
        face: Compiled dataface to render
        executor: Executor for query execution
        format: Output format (svg, html, png, pdf, terminal, json)
        variables: Variable values for queries
        **options: Format-specific options
            - background: Background color
            - scale: Scale factor (for png)
            - grid: Show grid overlay (for debugging)

    Returns:
        Rendered output:
            - str for svg, html, terminal
            - bytes for png, pdf

    Raises:
        RenderError: If rendering fails
        FormatError: If format is unknown
    """
    # Trust the normalizer - use pre-computed variable_defaults
    variable_registry = face.variable_registry or {}

    # Merge variables: start with None for all vars, then defaults, then user values
    all_variables: dict[str, Any] = dict.fromkeys(variable_registry)
    all_variables.update(face.variable_defaults)  # Pre-computed by normalizer
    # Parse JSON strings in variables (from URL parameters) and merge
    parsed_variables = parse_variable_json_strings(variables or {})
    merged_variables = {**all_variables, **parsed_variables}

    # Calculate layout with data awareness — table heights use actual row counts.
    # This executes only table chart queries (with per-chart error handling),
    # not all queries. Other queries execute lazily during render.
    face = calculate_data_aware_layout(face, executor, merged_variables)

    # Get background for format
    # Priority: 1. Override parameter, 2. Face style, 3. Config default for format
    override = options.get("background")
    if override is not None:
        background = None if override == "transparent" else override
    elif face.style and face.style.background:
        background = (
            None if face.style.background == "transparent" else face.style.background
        )
    else:
        config = get_config()
        format_config = config.rendering.get(format)
        background = format_config.background if format_config else "#ffffff"

    # JSON/text formats: skip SVG rendering entirely — walk layout tree directly
    if format == "json":
        from dataface.core.render.json_format import render_face_json

        return render_face_json(face, executor, merged_variables)

    if format == "text":
        from dataface.core.render.text_format import render_face_text

        return render_face_text(face, executor, merged_variables)

    # Render layout to SVG
    # Format determines whether variables are interactive (foreignObject) or read-only (static text)
    # PNG/PDF export requires read-only because svglib doesn't support foreignObject
    # HTML format supports foreignObject, so it should also get interactive variables
    interactive = format in ("svg", "html")

    try:
        grid_enabled = options.get("grid", False)
        svg_content = render_face_svg(
            face, executor, merged_variables, background, grid_enabled, interactive
        )
    except Exception as e:
        raise RenderError(f"Failed to render dataface: {e}") from e

    # Convert to requested format
    if format == "svg":
        return svg_content

    elif format == "html":
        # SVG-First Migration: HTML format is now a thin wrapper around SVG
        # The SVG content already contains all interactivity via foreignObject + embedded JS
        return to_html(face, svg_content, background, executor, merged_variables)

    elif format == "png":
        return to_png(svg_content, options.get("scale", 1.0))

    elif format == "pdf":
        return to_pdf(svg_content)

    elif format == "terminal":
        return _to_terminal(face, executor, merged_variables, **options)

    else:
        raise FormatError(f"Unknown format: {format}", format)

render_chart

Render a single chart:

render_chart

render_chart(
    chart: CompiledChart | ResolvedChart | Any,
    data: list[dict[str, Any]],
    format: str = "json",
    width: float | None = None,
    height: float | None = None,
    theme: str | None = None,
    structure: str | None = None,
    is_placeholder: bool = False,
) -> str

Render a chart to JSON, SVG, PNG, or PDF.

Source code in dataface/core/render/chart/vega_lite.py
def render_chart(
    chart: CompiledChart | ResolvedChart | Any,
    data: list[dict[str, Any]],
    format: str = "json",
    width: float | None = None,
    height: float | None = None,
    theme: str | None = None,
    structure: str | None = None,
    is_placeholder: bool = False,
) -> str:
    """Render a chart to JSON, SVG, PNG, or PDF."""
    resolved_chart = (
        chart if isinstance(chart, ResolvedChart) else resolve_chart(chart, data)
    )

    if format == "json":
        artifact = build_chart_json(resolved_chart, data, width=width, height=height)
        return render_chart_artifact(
            artifact,
            format,
            width=width,
            height=height,
            is_placeholder=is_placeholder,
        )

    render_data = data
    if is_placeholder and not data:
        from dataface.core.render.placeholder import generate_placeholder_data

        render_data = generate_placeholder_data(
            resolved_chart.chart_type, resolved_chart
        )

    artifact = renderer_registry.render(
        resolved_chart,
        render_data,
        width=width,
        height=height,
        theme=theme,
        structure=structure,
        is_placeholder=is_placeholder,
    )
    return render_chart_artifact(
        artifact,
        format,
        width=width,
        height=height,
        is_placeholder=is_placeholder,
    )

Layout Functions

The layout module provides functions for rendering different layout types.

Rows Layout

render_rows_layout

render_rows_layout(
    items: list[LayoutItem],
    executor: Executor,
    variables: VariableValues,
    available_width: float,
    available_height: float,
    gap: float,
    background: str | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> LayoutResult

Render items in vertical stack.

In a rows layout, items stack vertically. Heights are determined by: 1. Pre-calculated dimensions from sizing module (preferred) 2. Content-aware fallback if not pre-calculated

PARAMETER DESCRIPTION
items

Layout items to render

TYPE: list[LayoutItem]

executor

Executor for query execution

TYPE: Executor

variables

Variable values for queries

TYPE: VariableValues

available_width

Available container width

TYPE: float

available_height

Available container height

TYPE: float

gap

Gap between items

TYPE: float

background

Optional background color

TYPE: str | None DEFAULT: None

theme

Optional theme name to apply

TYPE: str | None DEFAULT: None

RETURNS DESCRIPTION
LayoutResult

LayoutResult with SVG content and dimensions

Source code in dataface/core/render/layouts.py
def render_rows_layout(
    items: list[LayoutItem],
    executor: Executor,
    variables: VariableValues,
    available_width: float,
    available_height: float,
    gap: float,
    background: str | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> LayoutResult:
    """Render items in vertical stack.

    In a rows layout, items stack vertically. Heights are determined by:
    1. Pre-calculated dimensions from sizing module (preferred)
    2. Content-aware fallback if not pre-calculated

    Args:
        items: Layout items to render
        executor: Executor for query execution
        variables: Variable values for queries
        available_width: Available container width
        available_height: Available container height
        gap: Gap between items
        background: Optional background color
        theme: Optional theme name to apply

    Returns:
        LayoutResult with SVG content and dimensions
    """
    if not items:
        return LayoutResult("", available_width, available_height)

    rendered_items: list[str] = []
    current_y = 0.0

    for item in items:
        # Trust the normalizer - sizing.py sets all item dimensions
        item_height = item.height if item.height > 0 else available_height
        item_width = item.width if item.width > 0 else available_width

        item_svg = render_layout_item(
            item, executor, variables, item_width, item_height, theme, structure
        )

        if item_svg:
            # Trust the normalizer - use pre-calculated height for positioning
            rendered_items.append(
                f'<g transform="translate(0, {current_y})">{item_svg}</g>'
            )
            current_y += item_height + gap

    total_height = max(current_y - gap, 100.0)  # Remove last gap

    bg_rect = ""
    if background:
        bg_rect = _bg_rect(available_width, total_height, background)

    content = f"{bg_rect}\n{''.join(rendered_items)}"
    return LayoutResult(content, available_width, total_height)

Columns Layout

render_cols_layout

render_cols_layout(
    items: list[LayoutItem],
    executor: Executor,
    variables: VariableValues,
    available_width: float,
    available_height: float,
    gap: float,
    background: str | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> LayoutResult

Render items in horizontal distribution.

Trusts the normalizer for all sizing. Uses pre-calculated item.x, item.width, and item.height values.

PARAMETER DESCRIPTION
items

Layout items to render (with pre-calculated dimensions from normalizer)

TYPE: list[LayoutItem]

executor

Executor for query execution

TYPE: Executor

variables

Variable values for queries

TYPE: VariableValues

available_width

Available container width

TYPE: float

available_height

Available container height (upper bound)

TYPE: float

gap

Gap between items (unused - normalizer already applied it)

TYPE: float

background

Optional background color

TYPE: str | None DEFAULT: None

theme

Optional theme name to apply

TYPE: str | None DEFAULT: None

RETURNS DESCRIPTION
LayoutResult

LayoutResult with SVG content and dimensions

Source code in dataface/core/render/layouts.py
def render_cols_layout(
    items: list[LayoutItem],
    executor: Executor,
    variables: VariableValues,
    available_width: float,
    available_height: float,
    gap: float,
    background: str | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> LayoutResult:
    """Render items in horizontal distribution.

    Trusts the normalizer for all sizing. Uses pre-calculated item.x, item.width,
    and item.height values.

    Args:
        items: Layout items to render (with pre-calculated dimensions from normalizer)
        executor: Executor for query execution
        variables: Variable values for queries
        available_width: Available container width
        available_height: Available container height (upper bound)
        gap: Gap between items (unused - normalizer already applied it)
        background: Optional background color
        theme: Optional theme name to apply

    Returns:
        LayoutResult with SVG content and dimensions
    """
    if not items:
        return LayoutResult("", available_width, available_height)

    # Render items using pre-calculated positions from normalizer
    rendered_items: list[str] = []
    max_height = 0.0

    for item in items:
        # Trust normalizer for dimensions
        item_w = item.width if item.width > 0 else available_width
        item_h = item.height if item.height > 0 else available_height
        x_pos = item.x  # Use pre-calculated x position from normalizer

        item_svg = render_layout_item(
            item, executor, variables, item_w, item_h, theme, structure
        )

        if item_svg:
            rendered_items.append(
                f'<g transform="translate({x_pos}, 0)">{item_svg}</g>'
            )
            max_height = max(max_height, item_h)

    row_height = max_height if max_height > 0 else available_height

    bg_rect = ""
    if background:
        bg_rect = _bg_rect(available_width, row_height, background)

    content = f"{bg_rect}\n{''.join(rendered_items)}"
    return LayoutResult(content, available_width, row_height)

Grid Layout

render_grid_layout

render_grid_layout(
    items: list[LayoutItem],
    executor: Executor,
    variables: VariableValues,
    available_width: float,
    available_height: float,
    columns: int,
    gap: float,
    background: str | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> LayoutResult

Render items in positioned grid.

Grid items have explicit x, y positions and width, height spans. Each item's dimensions are calculated based on the grid columns/rows.

PARAMETER DESCRIPTION
items

Layout items with grid positions (x, y, width, height)

TYPE: list[LayoutItem]

executor

Executor for query execution

TYPE: Executor

variables

Variable values for queries

TYPE: VariableValues

available_width

Available container width

TYPE: float

available_height

Available container height

TYPE: float

columns

Number of grid columns

TYPE: int

gap

Gap between grid cells

TYPE: float

background

Optional background color

TYPE: str | None DEFAULT: None

theme

Optional theme name to apply

TYPE: str | None DEFAULT: None

RETURNS DESCRIPTION
LayoutResult

LayoutResult with SVG content and dimensions

Source code in dataface/core/render/layouts.py
def render_grid_layout(
    items: list[LayoutItem],
    executor: Executor,
    variables: VariableValues,
    available_width: float,
    available_height: float,
    columns: int,
    gap: float,
    background: str | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> LayoutResult:
    """Render items in positioned grid.

    Grid items have explicit x, y positions and width, height spans.
    Each item's dimensions are calculated based on the grid columns/rows.

    Args:
        items: Layout items with grid positions (x, y, width, height)
        executor: Executor for query execution
        variables: Variable values for queries
        available_width: Available container width
        available_height: Available container height
        columns: Number of grid columns
        gap: Gap between grid cells
        background: Optional background color
        theme: Optional theme name to apply

    Returns:
        LayoutResult with SVG content and dimensions
    """
    if not items:
        return LayoutResult("", available_width, available_height)

    # Trust the normalizer - sizing.py calculates all grid positions and dimensions
    rendered_items: list[str] = []

    for item in items:
        # Use pre-calculated pixel positions and dimensions from sizing.py
        pixel_x = item.x
        pixel_y = item.y
        item_w = item.width if item.width > 0 else available_width
        item_h = item.height if item.height > 0 else available_height

        item_svg = render_layout_item(
            item, executor, variables, item_w, item_h, theme, structure
        )

        if item_svg:
            rendered_items.append(
                f'<g transform="translate({pixel_x}, {pixel_y})">{item_svg}</g>'
            )

    bg_rect = ""
    if background:
        bg_rect = _bg_rect(available_width, available_height, background)

    content = f"{bg_rect}\n{''.join(rendered_items)}"
    return LayoutResult(content, available_width, available_height)

Tabs Layout

render_tabs_layout

render_tabs_layout(
    items: list[LayoutItem],
    executor: Executor,
    variables: VariableValues,
    available_width: float,
    available_height: float,
    tab_titles: list[str] | None = None,
    tab_slugs: list[str] | None = None,
    tab_variable: str | None = None,
    active_tab: int = 0,
    tab_position: str = "top",
    background: str | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> LayoutResult

Render tabbed container (active tab only).

In a tabs layout, each tab gets the full container size minus the tab bar. Only the active tab is rendered in SVG output. The tab bar is rendered as clickable SVG links that update URL params for server re-rendering.

PARAMETER DESCRIPTION
items

Layout items (one per tab)

TYPE: list[LayoutItem]

executor

Executor for query execution

TYPE: Executor

variables

Variable values for queries

TYPE: VariableValues

available_width

Available container width

TYPE: float

available_height

Available container height

TYPE: float

tab_titles

Display titles for tabs

TYPE: list[str] | None DEFAULT: None

tab_slugs

URL-safe slugs for tabs (used in URL params)

TYPE: list[str] | None DEFAULT: None

tab_variable

Variable name for tab selection (URL param name)

TYPE: str | None DEFAULT: None

active_tab

Index of active tab (0-based)

TYPE: int DEFAULT: 0

tab_position

Position of tabs ("top" or "left")

TYPE: str DEFAULT: 'top'

background

Optional background color

TYPE: str | None DEFAULT: None

theme

Optional theme name to apply

TYPE: str | None DEFAULT: None

RETURNS DESCRIPTION
LayoutResult

LayoutResult with SVG content and dimensions

Source code in dataface/core/render/layouts.py
def render_tabs_layout(
    items: list[LayoutItem],
    executor: Executor,
    variables: VariableValues,
    available_width: float,
    available_height: float,
    tab_titles: list[str] | None = None,
    tab_slugs: list[str] | None = None,
    tab_variable: str | None = None,
    active_tab: int = 0,
    tab_position: str = "top",
    background: str | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> LayoutResult:
    """Render tabbed container (active tab only).

    In a tabs layout, each tab gets the full container size minus the tab bar.
    Only the active tab is rendered in SVG output. The tab bar is rendered as
    clickable SVG <a href> links that update URL params for server re-rendering.

    Args:
        items: Layout items (one per tab)
        executor: Executor for query execution
        variables: Variable values for queries
        available_width: Available container width
        available_height: Available container height
        tab_titles: Display titles for tabs
        tab_slugs: URL-safe slugs for tabs (used in URL params)
        tab_variable: Variable name for tab selection (URL param name)
        active_tab: Index of active tab (0-based)
        tab_position: Position of tabs ("top" or "left")
        background: Optional background color
        theme: Optional theme name to apply

    Returns:
        LayoutResult with SVG content and dimensions
    """
    if not items:
        return LayoutResult("", available_width, available_height)

    # Resolve active tab from variable value (URL param overrides default)
    if tab_variable and tab_slugs:
        var_value = variables.get(tab_variable)
        if var_value and str(var_value) in tab_slugs:
            active_tab = tab_slugs.index(str(var_value))

    # Get tab bar height from config
    from dataface.core.compile.config import get_config

    config = get_config()
    tab_bar_height = config.layout.tabs.bar_height

    # Render only active tab
    content_height = (
        available_height - tab_bar_height if tab_position == "top" else available_height
    )
    content_y = tab_bar_height if tab_position == "top" else 0.0

    active_item = items[min(active_tab, len(items) - 1)]
    item_svg = render_layout_item(
        active_item,
        executor,
        variables,
        available_width,
        content_height,
        theme,
        structure,
    )

    # Compute tab titles once - use provided titles or generate defaults
    titles = (
        tab_titles
        if tab_titles and len(tab_titles) == len(items)
        else [f"Tab {idx + 1}" for idx in range(len(items))]
    )
    slugs = tab_slugs or [f"tab_{idx}" for idx in range(len(items))]

    # Render tab bar as clickable SVG links
    tab_width = available_width / len(titles)
    tab_bar_parts: list[str] = []
    for idx, (title, slug) in enumerate(zip(titles, slugs, strict=True)):
        is_active = idx == active_tab
        x = idx * tab_width
        fill = "#e0e0e0" if is_active else "#f5f5f5"
        text_color = "#1a1a1a" if is_active else "#666666"
        weight = "600" if is_active else "400"

        tab_svg = (
            f'<rect x="{x}" y="0" width="{tab_width}" height="{tab_bar_height}" '
            f'fill="{fill}" stroke="#d0d0d0" stroke-width="1"/>'
            f'<text x="{x + tab_width / 2}" y="{tab_bar_height / 2 + 5}" '
            f'text-anchor="middle" font-size="14" fill="{text_color}" '
            f'font-weight="{weight}">{html.escape(title)}</text>'
        )

        if tab_variable and not is_active:
            href = _build_toggle_url(variables, tab_variable, slug)
            tab_bar_parts.append(f'<a href="{html.escape(href)}">{tab_svg}</a>')
        else:
            tab_bar_parts.append(tab_svg)

    tab_bar_svg = "\n".join(tab_bar_parts)

    content_svg = ""
    if item_svg:
        content_svg = f'<g transform="translate(0, {content_y})">{item_svg}</g>'

    bg_rect = ""
    if background:
        bg_rect = _bg_rect(available_width, available_height, background)

    content = f"{bg_rect}\n{tab_bar_svg}\n{content_svg}"
    return LayoutResult(content, available_width, available_height)

Vega-Lite Integration

Charts are rendered using Vega-Lite specifications.

generate_vega_lite_spec

generate_vega_lite_spec

generate_vega_lite_spec(
    chart: CompiledChart | ResolvedChart | Any,
    data: list[dict[str, Any]],
    width: float | None = None,
    height: float | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> dict[str, Any]

Generate a Vega-Lite spec for charts that render as Vega-Lite.

Source code in dataface/core/render/chart/vega_lite.py
def generate_vega_lite_spec(
    chart: CompiledChart | ResolvedChart | Any,
    data: list[dict[str, Any]],
    width: float | None = None,
    height: float | None = None,
    theme: str | None = None,
    structure: str | None = None,
) -> dict[str, Any]:
    """Generate a Vega-Lite spec for charts that render as Vega-Lite."""
    resolved_chart = (
        chart if isinstance(chart, ResolvedChart) else resolve_chart(chart, data)
    )
    if resolved_chart.chart_type == "table":
        return {"data": {"values": data}}
    if resolved_chart.chart_type == "kpi":
        # KPI participates in the SVG renderer family for full rendering,
        # but it still has a direct Vega-Lite spec representation.
        return render_standard_vega_spec(
            resolved_chart,
            data,
            width=width,
            height=height,
            theme=theme,
            structure=structure,
        )
    if resolved_chart.renderer_family == "svg":
        raise ValueError(
            f"Chart type '{resolved_chart.chart_type}' does not render to a Vega-Lite spec"
        )
    return render_standard_vega_spec(
        resolved_chart,
        data,
        width=width,
        height=height,
        theme=theme,
        structure=structure,
    )

render_chart

render_chart

render_chart(
    chart: CompiledChart | ResolvedChart | Any,
    data: list[dict[str, Any]],
    format: str = "json",
    width: float | None = None,
    height: float | None = None,
    theme: str | None = None,
    structure: str | None = None,
    is_placeholder: bool = False,
) -> str

Render a chart to JSON, SVG, PNG, or PDF.

Source code in dataface/core/render/chart/vega_lite.py
def render_chart(
    chart: CompiledChart | ResolvedChart | Any,
    data: list[dict[str, Any]],
    format: str = "json",
    width: float | None = None,
    height: float | None = None,
    theme: str | None = None,
    structure: str | None = None,
    is_placeholder: bool = False,
) -> str:
    """Render a chart to JSON, SVG, PNG, or PDF."""
    resolved_chart = (
        chart if isinstance(chart, ResolvedChart) else resolve_chart(chart, data)
    )

    if format == "json":
        artifact = build_chart_json(resolved_chart, data, width=width, height=height)
        return render_chart_artifact(
            artifact,
            format,
            width=width,
            height=height,
            is_placeholder=is_placeholder,
        )

    render_data = data
    if is_placeholder and not data:
        from dataface.core.render.placeholder import generate_placeholder_data

        render_data = generate_placeholder_data(
            resolved_chart.chart_type, resolved_chart
        )

    artifact = renderer_registry.render(
        resolved_chart,
        render_data,
        width=width,
        height=height,
        theme=theme,
        structure=structure,
        is_placeholder=is_placeholder,
    )
    return render_chart_artifact(
        artifact,
        format,
        width=width,
        height=height,
        is_placeholder=is_placeholder,
    )

HTML Output

HTML output is now a minimal wrapper around SVG output. Use format='html' to get a complete HTML document that embeds the SVG dataface with proper styling.

The SVG content includes all interactivity via embedded JavaScript and foreignObject elements for variable controls.


Errors

errors

Rendering error types.

Stage: RENDER Purpose: Define error types for rendering failures.

These errors are raised during: - General rendering failures (RenderError) - Format conversion (FormatError)

All errors inherit from RenderError → DatafaceError for easy catching.

Note: Many render errors are displayed IN the output rather than thrown, so users see helpful error messages in the rendered dataface.

RenderError

RenderError(message: str, element: str | None = None)

Bases: DatafaceError

Base error for all rendering failures.

This is the parent class for all rendering-related errors. Catch this to handle any rendering error.

ATTRIBUTE DESCRIPTION
message

Human-readable error description

element

Element that failed to render (if applicable)

Source code in dataface/core/render/errors.py
def __init__(self, message: str, element: str | None = None):
    self.message = message
    self.element = element
    super().__init__(self._format_message())

ChartDataError

ChartDataError(message: str, chart_id: str | None = None)

Bases: RenderError

Chart received data that doesn't match its requirements.

Raised when: - KPI chart receives more than 1 row - Chart references a column not present in the data - Data shape doesn't match chart type expectations

Source code in dataface/core/render/errors.py
def __init__(self, message: str, chart_id: str | None = None):
    self.chart_id = chart_id
    super().__init__(message, chart_id)

FormatError

FormatError(message: str, format: str | None = None)

Bases: RenderError

Error during format conversion.

Raised when: - Unknown format requested - SVG to PNG/PDF conversion fails - HTML template error

Example

try: ... render(face, executor, format="unknown") ... except FormatError as e: ... print(f"Format error: {e}")

Source code in dataface/core/render/errors.py
def __init__(self, message: str, format: str | None = None):
    self.format = format
    super().__init__(f"Format conversion failed: {message}", format)