Skip to main content

A Python CLI tool that generates beautiful dashboard images from JSON data using PIL/Pillow

Project description

quadre

A Python tool that generates beautiful, serializable dashboard images from JSON using Pillow. Dashboard images are easy to share across slack, emails or any communication software that manage.

Use image to make your dashboards accessible by everyone.

For complete docs, see docs/index.md.

Quickstart

Render an example dashboard to PNG using uv (no install required):

uv run -m quadre.cli examples/declarative_featured.json out/featured.png

Validate a JSON document (schema + friendly warnings):

quadre validate examples/declarative_featured.json

Using the installed CLI instead of uv:

quadre render examples/declarative_featured.json out.png
quadre validate examples/declarative_featured.json

Python API

Install and render from Python without touching disk or with custom outputs:

from quadre import render, build_image, to_bytes

# 1) Simple: write a file (default plugin)
render(doc, path="out.png")

# 2) Multiple outputs: file + anything else
render(doc, outputs=[
  {"plugin": "file", "path": "out.webp", "format": "WEBP"},
  # Example: if you installed a third-party plugin registered as "s3"
  {"plugin": "s3", "bucket": "my-bucket", "key": "dashboards/out.png"},
])

# 3) In-memory usage
img = build_image(doc)          # PIL.Image
data = to_bytes(doc, "PNG")     # bytes

Typed Builder (optional)

Prefer composer code in Python? Use the typed builder to generate the same declarative JSON and keep a single rendering path:

from quadre.flex import Text, KPI, Row, Title, dref, make_doc

doc = make_doc(
    Title("Awesome dashboard"),
    Row().gap(12).add(
        Text("Headline").font("heading").no_grow(),
        KPI(title=dref("$.perf.title"), value=dref("$.perf.value")),
        KPI(title="Orders", value="12,345"),
    ),
    data={
        "perf": {"title": "Revenue", "value": "4,567k€"}
    },
    canvas={"height": "auto"},
)

# Render (uses the same validator + adapter + flex engine)
from quadre import render
render(doc.to_dict(), path="out.png")

Notes:

  • .grow(r) on children inside a Row maps to properties.width_ratio (use .no_grow() to keep intrinsic width).
  • For Column children, use .fill_remaining() to stretch or .height(px) to suggest a fixed basis.
  • You can mix builder-generated nodes with hand-written JSON in the same document if needed.

To add your own output destination, expose a function and register it:

from quadre import register_output_plugin

def my_sink(image, ctx, cfg):
    # image: PIL.Image.Image
    # ctx: OutputContext(path, format, doc, size)
    # cfg: dict from your outputs spec
    ...

register_output_plugin("my_sink", my_sink)

Features

  • Generate professional-looking dashboards from JSON data
  • Customizable KPIs, tables, and metrics
  • Support for percentage changes with visual indicators
  • Clean, modern design with rounded cards and proper typography
  • Cross-platform font support

Installation

  • Python: 3.12+
  • Recommended: uv for fast, isolated runs

From PyPI (CLI + library):

pip install quadre

Usage (uv)

Basic Usage

uv run -m quadre.cli render -h

This generates dashboard.png from your JSON data.

Specify Output File

uv run -m quadre.cli render examples/declarative_featured.json out.png

Command Line Options

  • -i, --input: Input JSON file containing dashboard data (required)
  • -o, --output: Output PNG file (default: dashboard.png)
  • -h, --help: Show help message

Examples

# Generate dashboard with default output name
uv run -m quadre.cli render -h

# Generate dashboard with custom output name
quadre render -h

# Using long form arguments
quadre render examples/declarative_featured.json out.png

See examples/flex_e2e.json for a complete working example.

Legacy KPI Layouts (Optional)

Older presets (horizontal, priority, grids, pyramid, featured, responsive, custom) remain available via the legacy or declarative paths. Flex is the default for new dashboards.

Testing Layouts

# Flex demos
uv run examples/flex_demo.py
uv run examples/flex_e2e.py

# Render your JSON with the default (Flex) path
uv run -m quadre.cli render your_data.json output.png

Images are written to out/.

Flex Layout (Default)

The renderer now uses a flexbox-like engine under src/quadre/flex as the only path. It provides:

  • Flex containers with direction (row/column), gap, align_items, padding
  • Per-child grow, shrink, and basis properties to distribute space
  • Main-axis justify_content: start | center | end | space-between | space-around | space-evenly
  • Optional container background rendering with rounded corners
  • Simple TextWidget and FixedBox examples

Auto-height is enabled by default: the image height grows to fit content (bounded). To force a fixed page height, set "canvas": { "height": "fixed" } or "canvas": { "height": 1280 }.

High-quality rendering via supersampling is available (optional). Enable with:

"canvas": {
  "height": "auto",
  "scale": 2.0,           // render at 2x
  "downscale": true       // downscale to base size with Lanczos
}

Run the demo:

python examples/flex_demo.py

This generates out/flex_demo.png. The main CLI also uses Flex for the default path.

End-to-End Example

A JSON-driven example is also included:

python examples/flex_e2e.py               # uses examples/flex_e2e.json
python examples/flex_e2e.py data.json out/flex_e2e.png

This renders a header, a KPI row, and a simple platform list using the Flex engine.

Declarative JSON

See docs/declarative-layout.md for the JSON model, components, and examples.

Theme System

quadre supports a Pydantic‑validated theme that defines the color palette, font sizes, and per‑widget defaults (e.g., FlexContainer gaps/padding and TableWidget styles). A theme is loaded for every render, then the layout can still override any property via properties.

  • Default theme file: src/quadre/theme/theme.json
  • Env override: set quadre_THEME=/path/to/theme.json
  • CLI override: quadre render --theme dark data.json out.png or --theme /path/to/theme.json
  • Keys are case‑insensitive, but the bundled themes use lowercase (e.g., colors.foreground, fonts.h1).

Example theme (partial):

{
  "colors": {
    "background": "#ffffff",
    "foreground": "#0f172a",
    "border": "#d1d5db",
    "muted": "#f1f5f9"
  },
  "fonts": { "h1": 42, "number": 40, "body": 24 },
  "widgets": {
    "TextWidget": { "fill": "foreground", "font": "body" },
    "TableWidget": {
      "min_row_height": 28,
      "style": {
        "background_color": "card_background",
        "header_background": "muted",
        "text_color": "foreground"
      }
    }
  }
}

Example CLI usage:

# Use bundled dark theme
quadre render --theme dark examples/declarative_featured.json out_dark.png

# Use a custom theme file
quadre render --theme /configs/my_theme.json examples/declarative_featured.json out.png

Notes:

  • The layout can override any property per widget via properties. For tables, you can pass properties.style to override theme table styles locally.
  • A top‑level theme object in the document can still adjust colors/fonts quickly, but per‑widget defaults come from the validated theme file.

Font Configuration

quadre automatically detects system fonts but you can customize font usage for better consistency across platforms.

Automatic Font Detection

The system automatically finds suitable fonts based on your platform:

  • macOS: Helvetica, Arial, San Francisco
  • Windows: Arial, Calibri, Segoe UI, Verdana
  • Linux: DejaVu Sans, Liberation Sans, Ubuntu

Custom Font Configuration

Set a custom font using the quadre_FONT_PATH environment variable:

# macOS
export quadre_FONT_PATH="/System/Library/Fonts/Helvetica.ttc"

# Windows  
set quadre_FONT_PATH=C:/Windows/Fonts/arial.ttf

# Linux
export quadre_FONT_PATH="/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"

Add to your shell configuration file (~/.zshrc, ~/.bashrc) to make it permanent.

Font Installation

macOS (Recommended)

# Run the automated installer
./scripts/install_fonts_macos.sh

# Or install manually with Homebrew
brew tap homebrew/cask-fonts
brew install --cask font-dejavu-sans

Linux

# Ubuntu/Debian
sudo apt install fonts-dejavu fonts-liberation

# CentOS/RHEL/Fedora
sudo dnf install dejavu-sans-fonts liberation-sans-fonts

# Arch Linux
sudo pacman -S ttf-dejavu ttf-liberation

Windows

  1. Download fonts from DejaVu Fonts
  2. Right-click .ttf files and select "Install"

Font Diagnostics

Test font availability and configuration:

# Run font diagnostic tool
uv run utils/font_diagnostic.py

# This will show:
# - Available system fonts
# - Current quadre font configuration
# - Installation recommendations
# - Generate a font test image

Troubleshooting

Fonts appear incorrect or distorted:

  • Ensure the font file exists at the specified path
  • Try a different font from your system
  • Check file permissions

"Font not found" errors:

  • Install recommended fonts for your platform
  • Set quadre_FONT_PATH to a valid font file
  • Use the diagnostic tool to find available fonts

Docker font issues:

  • Fonts are pre-installed in the Docker image
  • Custom fonts can be mounted as volumes
  • Use the quadre_FONT_PATH environment variable in containers

Output

Default canvas: 1920×1280 PNG with:

  • Header (title + date note)
  • KPI row (evenly distributed)
  • Platform table (auto columns, zebra rows)

Customization

Customize via src/quadre/components/config.py and Flex widgets in src/quadre/flex. The Flex renderer composes existing components (KPI cards, tables) with a simpler layout model.

Font Support

The tool automatically detects and uses system fonts:

  • Docker/Linux: DejaVu Sans fonts (installed in container)
  • Local: DejaVu Sans or Liberation Sans fonts
  • Fallback: PIL default font

Docker Details

The Docker setup uses:

  • Base Image: ghcr.io/astral-sh/uv:python3.13-bookworm-slim
  • Package Manager: UV for fast dependency resolution
  • Fonts: DejaVu fonts pre-installed for consistent rendering
  • Architecture: Multi-platform support (linux/amd64, linux/arm64)

Error Handling

The CLI provides clear error messages for:

  • Missing input files
  • Invalid JSON format
  • File permission issues
  • Image generation errors

License

MIT License - feel free to use and modify as needed.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quadre-0.1.1.tar.gz (46.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quadre-0.1.1-py3-none-any.whl (59.5 kB view details)

Uploaded Python 3

File details

Details for the file quadre-0.1.1.tar.gz.

File metadata

  • Download URL: quadre-0.1.1.tar.gz
  • Upload date:
  • Size: 46.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.7

File hashes

Hashes for quadre-0.1.1.tar.gz
Algorithm Hash digest
SHA256 f35489cda2d467a75740cde970ab9147ee2d2e526d716c9d3845b6fe5dae3b8d
MD5 09d71820cc4cc5b687918b5e0dbc08e7
BLAKE2b-256 e4559c14986f1074c01743d83b7c23173924a94fbe22706da466e8c05bf0173a

See more details on using hashes here.

File details

Details for the file quadre-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: quadre-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 59.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.7

File hashes

Hashes for quadre-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3eda32fd30af02e6a77e8d7929c32dae21e374e436115da6b0510a288eed7e64
MD5 fe257145dda8850e5699d46d50c96732
BLAKE2b-256 4ed13c0c60680b5dda65b5c721880b47333470204ebc4dfcbb19686b48f228de

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page