Skip to main content

Vizly vs PyECharts: A Thorough Comparison

· 5 min read
Rancero Dev Team
Rancero Development Team

If you ship Apache ECharts from Python and you care where your static assets come from, this post is for you.

We built vizly, a high-performance, production-ready Python visualization library over Apache ECharts. It is the culmination of a few months of consistent building. This post walks through how vizly compares to PyECharts, the most popular Python ECharts wrapper, and why we think vizly is the better default for teams shipping charts to production.

The asset problem nobody talks about

Popular alternatives like PyECharts default to China-primary CDNs for assets. That is a real problem for Western teams with security, compliance, and supply chain requirements. Every chart you render pulls JavaScript from a host you did not choose, and that host is out of your control.

Vizly delivers assets locally by default. Vendored ECharts ships inside the package and is inlined into your HTML. Optional CDN use is allowlisted only (jsDelivr and unpkg). There is no silent remote injection and no China-primary default.

Asset behaviorPyEChartsvizly
Default asset modeRemote CDNLocal, vendored
CDN hostsDefaults to China-primary hostsAllowlist only: jsDelivr, unpkg
Silent remote injectionPossibleNever
Pinned versionsNoYes (ECharts 5.5.1 and plugins)

For compliance-sensitive environments, this one difference can decide whether a charting library is usable at all.

Chart coverage

Vizly registers 40 chart types across cartesian, statistical, financial, geo, relational, hierarchical, 3D, and compose layouts. You get line, bar, area, scatter, pie, donut, boxplot, heatmap, candlestick, kline, radar, funnel, gauge, sankey, treemap, map, combo, waterfall, polar, parallel, sunburst, tree, graph, flowchart, wordcloud, geo, 3D variants, and multi-chart pages, tabs, and timelines.

PyECharts also exposes a large catalog, since both libraries sit on ECharts. The difference is not raw breadth. It is how much of that power you can reach without fighting the wrapper. PyECharts leans on a fluent options API with nested option builders. Vizly uses plain factories that infer the chart structure from your data, so flowchart, sankey, and treemap are one-liners, not 30-line option scaffolds.

Boilerplate and readability

Here is a basic bar chart in PyECharts:

from pyecharts import options as opts
from pyecharts.charts import Bar

bar = (
Bar()
.add_xaxis(["Mon", "Tue", "Wed", "Thu", "Fri"])
.add_yaxis(
"Sales",
[120, 200, 150, 80, 70],
)
.set_global_opts(
title_opts=opts.TitleOpts(title="Weekly Sales"),
xaxis_opts=opts.AxisOpts(name="Day"),
yaxis_opts=opts.AxisOpts(name="Amount"),
)
)
bar.render("bar.html")

The same chart in vizly:

import vizly as vz

vz.set_theme("corporate")
chart = vz.bar(
{"day": ["Mon", "Tue", "Wed", "Thu", "Fri"], "sales": [120, 200, 150, 80, 70]},
x="day",
y="sales",
title="Weekly Sales",
)
chart.to_html() # or .render("bar.html")

That is about 90 percent less boilerplate to ship the same chart. No opts imports, no chained builders, no global options. DataFrame in, HTML or JSON out.

Theming without a theme war

PyECharts ships a handful of themes and requires you to juggle theme registration and global config to apply them.

Vizly includes built-in themes out of the box: corporate, dark, minimal, contrast, Grafana/CloudWatch/Kibana-inspired ops themes, and editor themes like Monokai, Tokyo Night, Dracula, Nord, Solarized, and One Dark. You can also register your own, load a theme from JSON, or pass a per-chart theme= override:

vz.set_theme("ops_grafana")
vz.line(metrics, x="timestamp", y="value")

vz.bar(df, x="region", y="sales", theme="editor_tokyo_night")

Data handling

PyECharts expects you to shape data into list pairs or series lists by hand.

Vizly accepts pandas DataFrames, list[dict], columnar dicts, CSV/TSV/JSON/Excel files, and SQL directly. Loaders like from_csv, from_sql, and from_excel are in the base package, no extra install. SQL works through SQLAlchemy, so Postgres, MySQL, Oracle, SQL Server, SQLite, and anything else SQLAlchemy can reach all chart the same way:

import vizly as vz
from sqlalchemy import create_engine

table = vz.from_csv("sales.csv")
vz.bar(table, x="region", y="sales")

engine = create_engine("postgresql+psycopg://...")
vz.line(vz.from_sql("SELECT day, value FROM metrics", bind=engine), x="day", y="value")

Ops-ready from day one

Vizly normalizes observability payloads you already have. Prometheus, CloudWatch, and Elasticsearch JSON go through from_prometheus, from_cloudwatch, and from_elasticsearch (alias from_elk), then straight into a chart. No live API calls, just normalization of what you already fetched.

Native framework embeds

PyECharts renders a standalone HTML file and leaves integration to you. Vizly ships a shared embed contract with zero-boilerplate helpers for the stacks teams actually use:

  • Streamlit: st_vizly(chart) and multi-chart st_dashboard([...])
  • FastAPI: html_response, json_response, dashboard_response
  • Flask: fragment helpers for Jinja templates
  • Django: {% vizly_chart %} and {% vizly_assets %} template tags
  • HTMX: fragment swapping without reloading ECharts
  • Jupyter: native _repr_html_() rendering

Charts also support drilldowns and live updates. Click events return structured payloads (filter_by_click), and set_data / live_update_script refresh data without reloading ECharts.

AI agents emit vizly code faster

One of our favorite wins: AI agents need roughly 60 percent fewer tokens to emit charting code with vizly compared to PyECharts, and about 90 percent less boilerplate to ship the same chart. Simpler APIs mean agents produce correct code on the first pass more often, which matters for teams wiring charts through AI-assisted workflows.

Bottom line

PyECharts is a fine library and it got many people into ECharts from Python. But it was built for a different era and a different asset model. If you ship charts to production, care about supply chain hygiene, value local assets, want SQL in the base package, or need native embeds without glue code, vizly is the stronger default.

Try it now:

pip install vizly