Skip to main content

Pure-Python charting library with pluggable backends (SVG core, optional Pillow raster) and base64/data-URI output for HTML email.

Project description

ChartHandler (Python)

Pure-Python charting with pluggable backends and base64 / data-URI output — designed so charts drop straight into HTML emails and into any web framework (Django, Flask, and ASGI apps under uvicorn).

from charthandler import Chart

# A PNG <img> tag you can paste into an HTML email — no external request.
html = Chart.pie({"Chrome": 63, "Firefox": 19, "Safari": 18}).title("Browser share").to_email_img()

Why this design

  • The SVG backend is pure Python with zero dependencies — installs instantly anywhere (slim Docker, Alpine, serverless) and works identically under Django, Flask, FastAPI/uvicorn, etc. (a chart is just str/bytes, so it's framework-agnostic).
  • Raster (PNG/JPEG/GIF/WebP) is an optional extra via Pillow — needed because SVG doesn't render in some email clients (Outlook desktop). Install only if you need it.

Features

  • Chart types: pie, donut, bar, stacked bar, line, area, scatter, and combo (mixed bars + line/area with an independently-scaled secondary axis).
  • Outputs: raw bytes, file, base64, data: URI, ready-to-embed <img> tag.
  • Fully type-hinted (py.typed), tested, mypy-strict + ruff clean.

Install

pip install pythoncharthandler            # SVG only — zero dependencies
pip install "pythoncharthandler[raster]"  # + PNG/JPEG/GIF/WebP via Pillow

Quickstart

from charthandler import Chart, Axis, Series, LegendPosition

# Pie -> SVG string (no dependencies)
Chart.pie({"Chrome": 63, "Firefox": 19, "Safari": 18}).title("Share").to_svg()

# Bar -> PNG bytes (needs the [raster] extra)
Chart.bar([12, 19, 7, 22, 15]).categories(["Jan", "Feb", "Mar", "Apr", "May"]).to_png()

# Multi-series line, saved (format inferred from the extension)
Chart.line([Series.from_values("2024", [10, 14, 9, 18])]) \
    .add_series(Series.from_values("2025", [13, 11, 17, 21])) \
    .categories(["Q1", "Q2", "Q3", "Q4"]).save("signups.svg")

# Stacked bar
Chart.stacked_bar([
    Series.from_values("Direct", [12, 19, 15]),
    Series.from_values("Organic", [20, 24, 28]),
]).categories(["Jan", "Feb", "Mar"]).to_png()

# Scatter from (x, y) pairs
Chart.scatter([(1, 5), (2, 9), (4, 3)]).add_points("B", [(1, 2), (3, 6)]).to_svg()

# Combo: grouped bars + a line on an independently-scaled right axis
Chart.combo() \
    .add_bar("Revenue", [120, 190, 70, 220]) \
    .add_line("Conversion %", [3.2, 4.1, 2.8, 5.0], axis=Axis.RIGHT) \
    .title("Revenue vs conversion").categories(["Q1", "Q2", "Q3", "Q4"]) \
    .to_email_img()

Output methods

Method Returns Notes
to_svg() str SVG markup
to_png() / to_jpeg() bytes needs the [raster] extra
to_data_uri(fmt=Format.PNG) str data:<mime>;base64,…
to_html_img(fmt=Format.PNG, **attrs) str <img src="data:…" …>
to_email_img(**attrs) str PNG <img>use this for email
save(path) None format inferred from the extension
render(fmt) RenderedChart for full control

Using it in web frameworks

FastAPI / uvicorn:

from fastapi import Response
from charthandler import Chart

@app.get("/chart.png")
def chart() -> Response:
    png = Chart.bar({"Mon": 8, "Tue": 12, "Wed": 5}).title("This week").to_png()
    return Response(content=png, media_type="image/png")

Flask:

@app.get("/chart.png")
def chart():
    return Chart.bar([8, 12, 5]).to_png(), 200, {"Content-Type": "image/png"}

Django:

from django.http import HttpResponse

def chart(request):
    return HttpResponse(Chart.pie({"A": 60, "B": 40}).to_png(), content_type="image/png")

For inline charts in a template/email, pass chart.to_data_uri() and use <img src="{{ chart_uri }}">.

Charts in HTML email

Email clients can't fetch external images offline, and several (Outlook desktop, some Gmail setups) won't render inline SVG. The reliable approach is a base64 PNG embedded directly in the markup (to_email_img() does exactly this — it needs the [raster] extra):

img = Chart.bar({"Mon": 8, "Tue": 12, "Wed": 5}).title("This week").to_email_img(alt="Activity")
html = f"<h1>Your report</h1>{img}"
# -> <img src="data:image/png;base64,iVBORw0KGgo..." alt="Activity" />

Run the demo (Docker)

A FastAPI gallery is bundled. With Docker it serves on http://localhost:2200/:

docker compose up -d --build
# http://localhost:2200/                 — gallery (every type, inline PNG)
# http://localhost:2200/charts/combo.png — single chart as PNG
# http://localhost:2200/charts/pie.svg   — single chart as SVG

Without Docker:

pip install "pythoncharthandler[raster,demo]"
uvicorn examples.fastapi_app:app --reload   # http://127.0.0.1:8000/

Development

python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest        # tests
mypy          # strict type-check
ruff check .  # lint

A FastAPI demo lives in examples/fastapi_app.py (run with uvicorn examples.fastapi_app:app --reload).

License

MIT — see LICENSE.

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

pythoncharthandler-0.1.0.tar.gz (25.3 kB view details)

Uploaded Source

Built Distribution

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

pythoncharthandler-0.1.0-py3-none-any.whl (23.2 kB view details)

Uploaded Python 3

File details

Details for the file pythoncharthandler-0.1.0.tar.gz.

File metadata

  • Download URL: pythoncharthandler-0.1.0.tar.gz
  • Upload date:
  • Size: 25.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pythoncharthandler-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e6d09e06574e90614908bf4ab0bb4fd6c7924b34bc29b2a24cf919eefc27e2dd
MD5 a8e6db48ebfd0b53536adbf8d7bf9cb0
BLAKE2b-256 2b0ea3016814f00148d8c28246d278f874e4c41f5dddf29d60c030803320b736

See more details on using hashes here.

Provenance

The following attestation bundles were made for pythoncharthandler-0.1.0.tar.gz:

Publisher: publish.yml on hbagheri/PythonChartHandler

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pythoncharthandler-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pythoncharthandler-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d06a8d2e65b4a6d7292de140c2cb8154798ac0453f0ad8dd34c5f87b068ba1be
MD5 ca8151b3a1584b1411bc428cc0735da7
BLAKE2b-256 9d1c050d2ac1a848fa7c7bcf648f51b6f26af41a5961c5ea26366a98c2f432f8

See more details on using hashes here.

Provenance

The following attestation bundles were made for pythoncharthandler-0.1.0-py3-none-any.whl:

Publisher: publish.yml on hbagheri/PythonChartHandler

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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