Skip to main content

vizly

Fully themable, low-boilerplate charting over Apache ECharts.

Ship production charts in a few lines of Python (DataFrame in, HTML or JSON out) without nested option builders. Built for speed (local assets, one ECharts load per page) and for native embeds in the stacks you already use.

  • Easy to use: set a theme, call vz.line / vz.bar / …, export with to_html() or to_option()
  • Highly performant: vendored JS by default; GL and plugins load only when a chart needs them
  • Worldwide maps by default: bundled world atlas plus usa; register extra GeoJSON packs when you need them
  • Trusted asset defaults: no Chinese CDN forced in the backend (unlike many other Python ECharts wrappers)
  • Wide chart coverage: cartesian, statistical, geo, graph, 3D, compose (page / tab / timeline), and more. See Chart inventory.
  • Native integrations: Streamlit, FastAPI, Flask, Django, HTMX, and Jupyter
import vizly as vz
vz.map(df)                 # world (default)
vz.map(df, map="usa")      # US states
vz.register_map_pack(...)  # custom GeoJSON you supply

Install

Requires Python 3.9 or later.

pip install vizly

Framework extras (install only what you use): vizly[streamlit], vizly[fastapi], vizly[flask], vizly[django].

HTMX helpers (vizly.integrations.htmx) ship in the base package. No vizly[htmx] extra.

30-second example

import pandas as pd
import vizly as vz

vz.set_theme("corporate")
df = pd.DataFrame({"date": ["2026-01-01", "2026-01-02"], "revenue": [10, 20]})
chart = vz.line(df, x="date", y="revenue", title="Revenue")
chart.to_html()       # self-contained local ECharts
chart.to_option()     # plain dict for APIs / agents

Theming

vz.set_theme("corporate")
# builtins: default, light, dark, corporate, minimal, contrast,
#           ops_grafana, ops_cloudwatch, ops_kibana  # ops-inspired (see below)
vz.set_theme({"palette": ["#0B1F33", "#2F6FED"]})  # deep-merge override
vz.register_theme("acme", {"background": "#FFFFFF", "palette": ["#111111"]})
vz.load_theme("examples/themes/atlantic.json", activate=True, register=True)
vz.export_theme("acme", "acme.json")

# Per-chart override does not mutate the session theme
vz.bar(df, x="region", y="sales", theme="dark")

Ops-inspired themes

ops_grafana, ops_cloudwatch, and ops_kibana are visual inspiration only: denser grids, muted animation, and step-friendly lines so charts feel at home next to common ops UIs. They are not affiliated with Grafana Labs, Amazon Web Services, or Elastic; no logos or proprietary design-system assets are shipped. Theme IDs use an ops_ prefix intentionally (zero trademark surface).

CDN asset URLs are allowlisted to cdn.jsdelivr.net and unpkg.com only. See src/vizly/assets/README.md for vendored file provenance.

Ops metric helpers

Agents/ops often receive Prometheus, CloudWatch, or Elasticsearch JSON. Shape it, then chart:

import vizly as vz

df = vz.from_prometheus(prom_api_json)          # timestamp, value, series
df = vz.from_cloudwatch(cw_datapoints)          # timestamp, value [, unit|series]
df = vz.from_elasticsearch(es_search_json)      # timestamp, value  (alias: from_elk)

vz.set_theme("ops_grafana")
vz.line(df, x="timestamp", y="value")           # single series
# multi-series Prometheus matrix → group or filter by `series` column

These helpers do not call live APIs. They only normalize payloads you already have.

Trust / asset policy

Mode Behavior
assets.mode = "local" (default) Inline vendored echarts.min.js (+ GL/plugins only when needed)
assets.mode = "cdn" Allowlisted hosts only
Banned by default China-primary CDN hosts (bootcdn, npmmirror, assets.pyecharts.org, …)

Maps: bundled world + usa; extra regional packs via register_map_pack.

Chart inventory

vz.list_chart_types()
vz.list_unavailable_chart_types()  # e.g. chord (upstream-unavailable)

line, bar, area, scatter, pie, donut, boxplot, heatmap, candlestick / kline, radar, funnel, gauge, sankey, treemap, map, grid, mix / combo, effect_scatter, waterfall, polar, parallel, sunburst, tree, graph, wordcloud, geo, bar3d, line3d, scatter3d, page, tab, timeline, pictorial_bar, theme_river, liquid, surface3d

Extra map packs are not chart types. Register them with vz.register_map_pack when you need them.

Integrations

Shared embed contract (vizly.integrations):

Mode Helper idea Output
Full document Streamlit / FastAPI page <!DOCTYPE html>…
Fragment Flask/Django/HTMX div.vizly-embed + scripts
Dashboard dashboard_html / vz.page / st_dashboard many charts, ECharts once
JSON APIs / SPA to_option() / to_json()

Multi-chart / dashboard (important)

Single-chart helpers can include the ECharts library so one embed works alone. For several charts on one page, load assets once. Otherwise each chart ships ~1MB of JS.

from vizly.integrations import assets_html, chart_html, dashboard_html

# Pattern A: shell page (auto GL/plugins from charts=)
head = assets_html(charts=[c1, c2])
a = chart_html(c1, fragment=True, include_assets=False)
b = chart_html(c2, fragment=True, include_assets=False)

# Pattern B: one HTML blob (assets once internally)
html = dashboard_html([c1, c2], title="Ops")
# same idea: vz.page(charts=[c1, c2]).to_html()

Django:

{% load vizly_tags %}
<head>{% vizly_assets charts=charts %}</head>
{% vizly_chart c1 %}
{% vizly_chart c2 %}
{{ c3|vizly_html }}
{# or one blob: {% vizly_dashboard charts %} #}

HTMX fragments already default include_assets=False (see examples/htmx_demo).

Streamlit

Each components.html call is a separate iframe. Prefer one iframe for many charts:

from vizly.integrations.streamlit import st_vizly, st_dashboard

st_vizly(chart, height=420)                 # one chart
st_dashboard([c1, c2], height=900)          # many charts, ECharts once
st_vizly([c1, c2], height=900)              # same as st_dashboard
# examples/streamlit_app.py

FastAPI

from vizly.integrations.fastapi import html_response, json_response, dashboard_response
# examples/fastapi_app.py  →  /  /dashboard  /option

Flask

from vizly.integrations.flask import assets_html, chart_html, dashboard_response
# examples/flask_app.py  →  /  /dashboard  /dashboard/full

Django templates

INSTALLED_APPS = [..., "vizly.integrations.django"]
{% load vizly_tags %}
{% vizly_assets charts=charts %}
{% vizly_chart chart height="420px" %}
{{ chart|vizly_html }}
{# single chart without assets tag: {{ chart|vizly_html:"assets" }} #}

See examples/django_demo/.

HTMX

from vizly.integrations.htmx import htmx_chart_fragment, htmx_or_full
# examples/htmx_demo/app.py: button hx-get swaps #chart

Jupyter

Open examples/jupyter_gallery.ipynb: charts display via _repr_html_().

Less boilerplate than raw option builders

Verbose option-builder style (illustrative): many nested calls for series, axes, tooltip, and theme (~15-25 lines).

vizly after one theme call:

vz.set_theme("corporate")
vz.bar(df, x="region", y="sales", title="Sales")  # ~1-2 lines

Escape hatches remain: chart.update(...), chart.merge_option({...}), vz.from_option(option).

Examples

Path Purpose
examples/streamlit_app.py Streamlit (single + dashboard)
examples/fastapi_app.py FastAPI HTML/JSON/dashboard
examples/flask_app.py Flask + Jinja fragment / dashboard
examples/django_demo/ Django {% vizly_chart %} + {% vizly_assets %}
examples/htmx_demo/app.py HTMX partial swap
examples/jupyter_gallery.ipynb Notebook
examples/themes/atlantic.json Custom theme
examples/band_a_gallery.py / band_bc_gallery.py Chart HTML gallery seeds

Development

For work on this repository (not needed for pip install vizly):

pip install -e ".[dev,examples]"
python -m pytest -m "not browser" -v
Level Command Role
1+2 (CI gate) pytest -m "not browser" Contracts + sample/golden HTML
3 Browser pytest -m browser Headless hero charts (Playwright)
Local visual review python scripts/validate_samples_browser.py --gallery Headed Chromium + gallery

Refresh option goldens: python scripts/update_sample_goldens.py

Full testing runbook: TESTING.md. Also CHANGELOG.md and RELEASE.md.

Known limitations

  • SPA / JSON + maps: to_option() / json_response return the ECharts option only. They do not embed GeoJSON. HTML rendering calls echarts.registerMap for you; SPA clients must register map packs themselves (or use HTML embeds).
  • page / tab JSON: to_option() returns a compose descriptor under _vizly_compose (child options). Use HTML embeds (dashboard_html / to_html) for browser layout.
  • PNG/PDF export (deferred): vizly[export] is not shipped yet. ECharts draws in JavaScript, so image export needs a JS canvas runtime (Node + node-canvas per Apache’s SSR guide, or a headless browser), not a pure-Python conversion of the option dict. Use to_html() / to_option() meanwhile.

Download files

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

Source Distribution

vizly-0.2.1.tar.gz (901.4 kB view details)

Uploaded Source

Built Distribution

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

vizly-0.2.1-py3-none-any.whl (902.1 kB view details)

Uploaded Python 3

File details

Details for the file vizly-0.2.1.tar.gz.

File metadata

  • Download URL: vizly-0.2.1.tar.gz
  • Upload date:
  • Size: 901.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for vizly-0.2.1.tar.gz
Algorithm Hash digest
SHA256 aa208dcbbbef884a6c9183e31fb9d505ffc155ef41ae4da52ef05a7a1235fc22
MD5 f25010c62eb218c2ae2f67d9b55cc5d5
BLAKE2b-256 5148e80e763441121f76735619b841d210697de532c8521dadc51f6166740a66

See more details on using hashes here.

Provenance

The following attestation bundles were made for vizly-0.2.1.tar.gz:

Publisher: release.yml on kineticquant/vizly

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

File details

Details for the file vizly-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: vizly-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 902.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for vizly-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9736c73f20e40b51ae497de114587aab47479f9ead489e59a12e39c91a755563
MD5 fe7b7d1e51762f7f8bfa8d4e250d9f5f
BLAKE2b-256 4ea2a1a221f55ef8a0f5821d5056020c06e817223aa18a00afe8ce7755c91c6b

See more details on using hashes here.

Provenance

The following attestation bundles were made for vizly-0.2.1-py3-none-any.whl:

Publisher: release.yml on kineticquant/vizly

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

Release history Release notifications | RSS feed

1.0.1

2 files

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.0

2 files

Supported by

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