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 toproperties.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, andbasisproperties to distribute space - Main-axis
justify_content: start | center | end | space-between | space-around | space-evenly - Optional container background rendering with rounded corners
- Simple
TextWidgetandFixedBoxexamples
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.pngor--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 passproperties.styleto override theme table styles locally. - A top‑level
themeobject 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
- Download fonts from DejaVu Fonts
- Right-click
.ttffiles 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_PATHto 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_PATHenvironment 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quadre-0.1.0.tar.gz.
File metadata
- Download URL: quadre-0.1.0.tar.gz
- Upload date:
- Size: 45.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a42cbc7d5150d52608b8fd298af5494f9b07da3e374e868b4c36467a2afd83d5
|
|
| MD5 |
fc4b869c09b80928aab31bb99a48777c
|
|
| BLAKE2b-256 |
e77d518db47943ed7783ce2a84ddea7de15d235da4f793eeabb3cd3e75a3e290
|
File details
Details for the file quadre-0.1.0-py3-none-any.whl.
File metadata
- Download URL: quadre-0.1.0-py3-none-any.whl
- Upload date:
- Size: 57.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04e21cdba1cc1ab654179b69d00bf32463af427e8e89981fdfe4b8194fe8f3c7
|
|
| MD5 |
1ba60c7c5e4700de6d57b325db0fc587
|
|
| BLAKE2b-256 |
4611a8bb9db104576998865595c7d0fefa10557c92942091d1decaa767f573ab
|