Skip to content

Astrojigs/echartsy

Repository files navigation

Apache ECharts

echartsy

Interactive charts in Python — the matplotlib workflow, the ECharts experience.

PyPI version Python versions License Stars Issues

Build publication-quality interactive charts with a familiar
fig = figure()fig.bar()fig.show() workflow.
Works everywhere: Jupyter · Streamlit · standalone scripts


Why echartsy?

Familiar API If you know plt.figure() / plt.show(), you already know 90% of the API. No JSON, no JavaScript.
Interactive by default Every chart ships with tooltips, legend toggling, zoom, and an export toolbox. Zero config needed.
Three render engines Write once, render in Jupyter notebooks, Streamlit apps, or standalone browser windows.
19 chart types From bar charts and waterfall charts to sankey diagrams, sunbursts, gauges, and network graphs.
Composable & animated Layer pies on bar charts, build dual-axis dashboards, use multi-grid subplots, or animate across time with TimelineFigure.
Dark mode Adaptive dark/light theming out of the box, including automatic Streamlit theme detection.

Installation

pip install echartsy

Optional extras:

pip install echartsy[jupyter]     # Jupyter Notebook / JupyterLab
pip install echartsy[streamlit]   # Streamlit apps
pip install echartsy[scipy]       # KDE density plots
pip install echartsy[all]         # Everything

Requirements: Python 3.9+ · pandas ≥ 1.5 · numpy ≥ 1.23


Quick Start

import pandas as pd
import echartsy as ec

ec.config(engine="jupyter")          # or "python" / "streamlit"

df = pd.DataFrame({
    "Fruit": ["Apples", "Bananas", "Cherries", "Dates", "Elderberries"],
    "Sales": [120, 95, 78, 42, 63],
})

fig = ec.figure()
fig.bar(df, x="Fruit", y="Sales", gradient=True, labels=True)
fig.title("Fruit Sales")
fig.show()

Three lines from DataFrame to interactive chart.

Quick Start — Bar Chart


Chart Types

echartsy v0.7.1 supports 19 chart types covering cartesian, standalone, hierarchical, relational, and statistical visualizations.

Cartesian Charts

Method Description Key options
fig.plot() Line chart smooth, area, hue, line_style, area_style, end_label, blur, select, animation, tooltip
fig.bar() Vertical bar hue, stack, gradient, item_style, label_style, blur, select, animation, tooltip
fig.barh() Horizontal bar Same as bar(), horizontal orientation
fig.scatter() Scatter plot color, size, item_style, symbol_rotate, blur, select, animation, tooltip
fig.hist() Histogram bins, item_style, label_style, animation, tooltip
fig.boxplot() Box plot item_style, label_style, labels, color, blur, select, animation, tooltip
fig.kde() KDE density line_style, area_style, labels, connect_nulls, color, animation, tooltip
fig.waterfall() Waterfall chart total, connector, label_style, item_style, animation, tooltip
fig.candlestick() Candlestick / OHLC border_width, opacity, label_style, labels, animation, tooltip
fig.heatmap() Matrix heatmap label_style, item_style, animation, tooltip

Standalone & Hierarchical Charts

Method Description Key options
fig.pie() Pie / donut inner_radius, link_legend, min_angle, clockwise, item_style, blur, select, tooltip
fig.radar() Radar / spider shape, split_number, line_style, color, tooltip
fig.funnel() Funnel orient, funnel_align, min_size, max_size, item_style, tooltip
fig.gauge() Gauge / meter detail_formatter, progress, item_style, tooltip
fig.treemap() Treemap drill_down_icon, node_click, breadcrumb, item_style, tooltip
fig.sunburst() Sunburst node_click, label_rotate, item_style, tooltip

Relational & Calendar Charts

Method Description Key options
fig.sankey() Sankey diagram node_align, draggable, item_style, label_style, tooltip
fig.graph() Network graph repulsion, gravity, edge_label, item_style, line_style, tooltip
fig.calendar_heatmap() Calendar heatmap split_line_show, day_label_show, item_style, emphasis, tooltip

Gallery

Cartesian Charts

Bar + Pie Overlay

Bar + Pie Overlay

fig = ec.figure(height="500px")
fig.bar(df, x="Dept", y="Budget",
        gradient=True, labels=True)
fig.pie(df, names="Dept", values="Budget")  # auto-overlay
fig.show()

Smooth Line

Line Chart

fig = ec.figure()
fig.plot(df, x="Month", y="Sales",
         smooth=True, area=True)
fig.show()

Scatter Plot

Scatter Plot

fig = ec.figure()
fig.scatter(df, x="Height", y="Weight",
            color="Gender", size="Age")
fig.show()

Grouped Bar

Grouped Bar

fig = ec.figure()
fig.bar(df, x="Quarter", y="Revenue",
        hue="Region")
fig.show()

Stacked Bar

Stacked Bar

fig = ec.figure()
fig.bar(df, x="Month", y="Revenue",
        hue="Product", stack=True)
fig.show()

Histogram

Histogram

fig = ec.figure()
fig.hist(df, column="Score", bins=20)
fig.show()

Dual Axis: Bar + Line

Dual Axis

fig = ec.figure()
fig.bar(df, x="Month", y="Revenue")
fig.plot(df, x="Month", y="Growth",
         smooth=True, axis=1)
fig.ylabel("Revenue ($K)")
fig.ylabel_right("Growth %")
fig.show()

Boxplot

Boxplot

fig = ec.figure()
fig.boxplot(df, x="Department", y="Salary")
fig.show()

Standalone Charts

Donut / Pie

Donut Chart

fig = ec.figure()
fig.pie(df, names="Browser", values="Share",
        inner_radius="40%")
fig.show()

Radar

Radar Chart

fig = ec.figure()
fig.radar(indicators, data,
          series_names=["Warrior","Mage"])
fig.show()

Heatmap

Heatmap

fig = ec.figure()
fig.heatmap(df, x="Day", y="Hour",
            value="Count")
fig.show()

Funnel

Funnel

fig = ec.figure()
fig.funnel(df, names="Stage", values="Count")
fig.show()

Treemap

Treemap

fig = ec.figure()
fig.treemap(df,
    path=["Category","SubCat"],
    value="Sales")
fig.show()

Sankey Diagram

Sankey Diagram

fig = ec.figure()
fig.sankey(df,
    levels=["Source","Channel","Outcome"],
    value="Users")
fig.show()

Composite & Dashboard Charts

Bar + Pie (Dark)

Composite Dark

Triple Composite

Triple Composite

KPI Dashboard

KPI Dashboard

Stacked + Trend + Pie

Full Dashboard

Every chart is fully interactive -- hover for tooltips, click legend items to toggle series, use the toolbox to export. Open the HTML demos in assets/ for the live experience, or run python generate_demos.py yourself.


Rendering Engines

Write your chart once; ec.config() controls where it renders.

Engine Use case Install
"python" Standalone scripts -- opens the default browser No extra deps
"jupyter" Jupyter Notebook / JupyterLab inline widgets pip install echartsy[jupyter]
"streamlit" Streamlit applications pip install echartsy[streamlit]
ec.config(engine="jupyter")          # or "python" / "streamlit"

Advanced Features

Multi-Grid Subplots

Create vertically stacked chart panels sharing independent axes:

fig = ec.figure(rows=2, height="700px", row_heights=["60%", "40%"])
fig.bar(df, x="Month", y="Revenue", grid=0)
fig.plot(df, x="Month", y="Growth", grid=1, smooth=True)
fig.show()

Timeline Animations

Animate any chart across a time dimension with TimelineFigure:

fig = ec.TimelineFigure(height="500px", interval=1.5)
fig.bar(df, x="Country", y="GDP", time_col="Year", labels=True)
fig.title("GDP by Country")
fig.show()

Timeline Animation

Feature API
Playback control TimelineFigure(interval=2.0, autoplay=True, loop=True)
Adjust after creation fig.playback(interval=1.0, rewind=True)
Fixed axis ranges fig.xlim(), fig.ylim() -- consistent scales across frames
Smart frame sorting Parses years, quarters (Q1 2024), months, ISO dates, fiscal years
Supported series bar(), plot(), scatter(), pie(), hist()
Diagnose format ec.detect_time_format(df["Year"])

Annotations

Add reference lines, points, and shaded regions to any series:

fig.plot(df, x="Month", y="Sales", smooth=True)
fig.mark_line(y=500, label="Target", color="red", line_dash="dashed")
fig.mark_point(type="max")
fig.mark_area(y_range=[200, 400], color="#ccc", opacity=0.15)
fig.show()

Visual Map

Attach a colour-mapping control for continuous or piecewise data ranges:

fig.heatmap(df, x="Day", y="Hour", value="Count")
fig.visual_map(min_val=0, max_val=100,
               colors=["#313695", "#ffffbf", "#a50026"],
               calculable=True)
fig.show()

Log Scale

Switch any y-axis to logarithmic scale:

fig.yscale("log")          # shorthand
fig.ylim(scale="log")      # equivalent

Emphasis (Hover Highlighting)

Control what happens when users hover over chart elements using typed Python dataclasses:

from echartsy import Emphasis, ItemStyle

fig.bar(df, x="Month", y="Revenue", hue="Region",
        emphasis=Emphasis(
            focus="series",
            item_style=ItemStyle(shadow_blur=10),
        ))

Every chart method accepts an optional emphasis parameter with a chart-specific type:

Chart method Emphasis class
bar(), waterfall(), hist(), boxplot(), heatmap(), candlestick() Emphasis
plot(), kde() LineEmphasis
scatter() ScatterEmphasis
pie() PieEmphasis
radar() RadarEmphasis
sankey() SankeyEmphasis
funnel() FunnelEmphasis
treemap() TreemapEmphasis
graph() GraphEmphasis

Per-Series Style Control

Beyond emphasis, every chart method now accepts typed dataclass parameters for fine-grained visual control:

from echartsy import ItemStyle, LabelStyle, Blur, Select, AnimationConfig, TooltipStyle

fig.bar(df, x="Month", y="Revenue",
        item_style=ItemStyle(border_type="dashed", opacity=0.9),
        label_style=LabelStyle(show=True, rotate=45, font_family="monospace"),
        blur=Blur(item_style=ItemStyle(opacity=0.2)),
        select=Select(item_style=ItemStyle(border_width=3)),
        selected_mode="multiple",
        animation=AnimationConfig(animation_duration=1500, animation_easing="elasticOut"),
        tooltip=TooltipStyle(formatter="{b}: {c}"))

Three-tier control: scalar params (e.g. color="red") → dataclass overrides → **series_kw raw dict.

Adaptive Dark Mode

Charts automatically respond to the user's OS or browser prefers-color-scheme setting:

ec.config(engine="jupyter", adaptive="auto")     # auto-detect (default)
ec.config(engine="jupyter", adaptive="dark")     # force dark
ec.config(engine="streamlit")                    # auto-adapts to Streamlit theme

Style Presets and Palettes

Apply a pre-built visual theme or set custom colour palettes:

fig = ec.figure(style=ec.StylePreset.CLINICAL)
fig = ec.figure(style=ec.StylePreset.DASHBOARD_DARK)
fig = ec.figure(style=ec.StylePreset.KPI_REPORT)
fig = ec.figure(style=ec.StylePreset.MINIMAL)

fig.palette(["#667eea", "#764ba2", "#f093fb", "#f5576c", "#4facfe"])
fig.palette(ec.PALETTE_RUSTY)

Build custom presets for full control over fonts, grid lines, tooltip style, and more:

my_style = ec.StylePreset(
    palette=("#264653", "#2a9d8f", "#e9c46a", "#f4a261", "#e76f51"),
    bg="#fefae0",
    font_family="Georgia",
    title_font_size=20,
)
fig = ec.figure(style=my_style)

Configuration Reference

Every Figure and TimelineFigure supports these configuration methods:

# Titles
fig.title("Main Title", subtitle="Sub-title")

# Axes
fig.xlabel("X Label", rotate=30)
fig.ylabel("Y Label")
fig.ylabel_right("Secondary Y")
fig.xlim(0, 100)
fig.ylim(0, 500)
fig.yscale("log")

# Layout
fig.legend(orient="vertical", left="right", top=40)
fig.margins(left=100, right=120, top=40)
fig.grid(show=True)

# Interactivity
fig.datazoom(start=0, end=80)
fig.toolbox(download=True, zoom=True)
fig.tooltip(trigger="axis", pointer="cross")
fig.axis_pointer(type="shadow", snap=True)
fig.visual_map(min_val=0, max_val=100)

# Export
fig.save(name="my_chart", fmt="png", dpi=3)
fig.to_html("my_chart.html")
option = fig.to_option()       # raw ECharts option dict

# Palette
fig.palette(["#5470C6", "#91CC75", "#FAC858"])

API at a Glance

ec.config(engine, adaptive="auto")

Set the global rendering engine ("python", "jupyter", "streamlit") and theme adaptation mode ("auto", "light", "dark").

ec.figure(**kwargs) / ec.Figure(**kwargs)

Create a chart canvas.

Parameter Default Description
height "400px" CSS height of the chart container
width None CSS width (defaults to full container)
renderer "svg" "canvas" or "svg"
style StylePreset.CLINICAL A StylePreset instance
rows 1 Number of vertical grid panels (subplots)
row_heights None List of CSS heights per grid panel

ec.TimelineFigure(**kwargs) / ec.timeline_figure(**kwargs)

Same as Figure but adds timeline animation. Extra parameters:

Parameter Default Description
interval 2.0 Seconds between animation frames
autoplay True Start playing automatically
loop True Loop back to the first frame

Sub-style Dataclasses

Class Key fields
ec.ItemStyle color, border_color, border_width, border_radius, border_type, shadow_blur, shadow_color, shadow_offset_x, shadow_offset_y, opacity, decal
ec.LabelStyle show, position, formatter, font_size, font_weight, font_family, color, rotate, offset, align
ec.LineStyle color, width, type, shadow_blur, shadow_color, shadow_offset_x, shadow_offset_y, opacity, cap, join
ec.AreaStyle color, opacity, origin, shadow_blur, shadow_color
ec.LabelLineStyle show, length, length2
ec.EndLabelStyle show, formatter, font_size, font_weight, color
ec.Blur item_style, label, line_style, area_style
ec.Select disabled, item_style, label, line_style, area_style
ec.TooltipStyle show, formatter, value_formatter, background_color, border_color, border_width, text_color, text_size
ec.AnimationConfig animation, animation_duration, animation_easing, animation_delay

Changelog (Recent)

v0.7.4

  • Added: 6 new color palettes: PALETTE_OCEAN, PALETTE_SUNSET, PALETTE_EARTH, PALETTE_PASTEL, PALETTE_NEON, PALETTE_MONOCHROME
  • Added: 5 new style presets: StylePreset.OCEAN, SUNSET, EARTH, PASTEL, NEON
  • Renamed: PALETTE_CLINICALPALETTE_DEFAULT, StylePreset.CLINICALStylePreset.DEFAULT (old names still work)

v0.7.3

  • Added: AxesGrid / AxesRow containers — enables Shift-Tab docstring popups and tab-completion in Jupyter
  • Added: fig.margins(top, bottom, left, right) on SubplotFigure for outer grid margins
  • Added: Dual y-axis support in subplot cells (ax.plot(..., axis=1))
  • Added: Non-cartesian chart positioning in subplots (funnel, radar, gauge, treemap, sankey)
  • Added: Input validation — subplots(0, 2) now raises ValueError
  • Fixed: Per-cell ax.palette() now correctly colors individual pie slices
  • Fixed: Heatmap axes remain visible in subplot cells
  • Fixed: datazoom and visualMap axis binding uses correct indices per cell

v0.7.2

  • Fixed: Per-cell legend isolation — toggling a legend in one subplot cell no longer hides identically-named series in other cells
  • Fixed: Per-cell .title() now centers within its own cell instead of the entire container
  • Fixed: Per-cell .margins() propagation — ax.margins(top=...) etc. now correctly adjust the cell's grid area
  • Fixed: Per-cell .tooltip() propagation into the merged subplot option
  • Fixed: Pie charts in subplots now use the global palette for per-slice colors instead of a single series color
  • Added: Per-cell toolbox(), datazoom(), visual_map(), palette(), grid(), xlim()/ylim(), xticks()/yticks() propagation in subplots
  • Removed: cell_legend parameter from subplots() — use ax.legend() on individual cells instead

v0.7.1

  • Breaking: Replaced MatrixFigure with matplotlib-style ec.subplots(nrows, ncols) — each cell is a full Figure
  • Added: ec.subplots() factory returning (fig, ax) with numpy-array shape matching matplotlib (scalar / 1-D / 2-D)
  • Added: SubplotFigure container with .suptitle(), .palette(), .legend() global chrome
  • Added: Per-cell ax.legend() for independent legend control per subplot cell
  • Added: Full Figure method propagation in subplots: margins(), tooltip(), save()/toolbox(), datazoom(), visual_map(), per-cell palette()
  • Removed: MatrixFigure, auto-populate methods (group_row/group_col), pairplot()
  • Fixed: build_pie_series() type hint corrected (Optional[Any]Optional[ItemStyle])
  • Fixed: build_pie_series() now guards against empty data after NaN drop

v0.7.0

  • Added: build_scatter_series() and build_pie_series() shared builder functions in _chart_methods.py

v0.6.5

  • Added: label_style and upper_label_style on treemap() — full LabelStyle control for treemap labels (font, color, position, overflow)
  • Added: sort, square_ratio, children_visible_min, visual_min, visual_max, zoom_to_node_ratio, color_mapping_by, and levels parameters on treemap()
  • Added: vertical_align, padding, overflow, ellipsis fields on LabelStyle

v0.6.4

  • Added: upper_label and upper_label_height parameters on treemap() — enables parent category labels as header bars on treemap nodes (mirrors ECharts upperLabel feature)

v0.6.3

  • Extended: TimelineFigure API parity — added 34 missing parameters across plot(), bar(), pie(), title(), legend(), tooltip(), xlim(), ylim()
  • Added: Documentation for gauge, sunburst, graph, and calendar_heatmap chart types
  • Fixed: 10 undocumented parameters added to existing Documentation.md tables

v0.6.2

  • Added: Auto-overlay for pie() on cartesian figures — calling fig.bar(); fig.pie() now works without specifying center or radius (defaults to top-right mini pie at ["82%", "25%"]).
  • Added: link_legend parameter on pie() — controls whether overlay pie shares colors with existing series (True), uses distinct colors (False), or auto-detects based on name overlap (None, default).
  • Fixed: Overlay pies now automatically get per-series trigger: "item" tooltips so hovering works correctly (the global "axis" trigger doesn't fire for pie series).
  • Fixed: Multi-grid (subplot) figures with overlay pies now correctly inject per-series tooltips.

v0.6.1

  • Fixed: Waterfall connector=True rendered blank charts — markLine data used invalid nested format instead of [start, end] pairs.
  • Fixed: bar_width parameter mapped to barMaxWidth instead of barWidth in ECharts options.
  • Fixed: scatter() mutated the global x-axis type to "value", breaking any previously added category-based series (bar/line).
  • Fixed: Horizontal bar charts (barh()) discarded all y-axis customizations (labels, fonts, colors) during option building.
  • Fixed: heatmap() overwrote axis config entirely, discarding StylePreset axis formatting.
  • Fixed: tooltip() replaced the entire axisPointer sub-config instead of merging, losing prior axis_pointer() settings.
  • Fixed: sankey() and graph() used direct assignment for item_style/line_style, overwriting prior config instead of merging.
  • Fixed: datazoom and extra configs were not deep-copied in to_option(), causing mutable reference leaks.
  • Fixed: radar(), funnel(), and standalone pie() legend deduplication — duplicate or overwritten legend entries no longer occur.
  • Fixed: candlestick() now warns when duplicate date rows are found (only the last row per date is used).
  • Fixed: boxplot(orient="h") now warns that horizontal orientation is not yet supported instead of silently ignoring it.
  • Fixed: _sort_categories 60% parse threshold could silently drop non-date categories — now requires all unique categories to parse as dates before sorting chronologically.
  • Fixed: LineEmphasis.end_label was typed as LabelStyle instead of EndLabelStyle, allowing invalid fields.
  • Fixed: StylePreset preset constants (CLINICAL, DASHBOARD_DARK, etc.) were dataclass fields instead of ClassVar, polluting constructor, repr, and fields().
  • Fixed: Python/Jupyter HTML renderers did not escape </ sequences in JSON, allowing potential </script> injection (XSS).
  • Fixed: HTML template placeholder substitution order could corrupt user data containing __CHART_ID__ or similar strings.
  • Fixed: Malformed file:// URL on Windows in the Python standalone renderer.
  • Added: animation parameter to pie() (was missing while all other chart methods had it).

v0.6.0

  • Added: Full parameter expansion across all 19 chart methods and 6 config methods — typed ItemStyle, LabelStyle, LineStyle, AreaStyle, EndLabelStyle, Blur, Select, TooltipStyle, and AnimationConfig dataclass parameters on every series method.
  • Added: Per-series tooltip, blur, select, selected_mode, and animation support for bar, line, scatter, pie, histogram, boxplot, KDE, candlestick, heatmap, waterfall, radar, sankey, treemap, funnel, gauge, sunburst, graph, and calendar heatmap.
  • Added: Extended config methods — title() (+8 params), legend() (+11 params), tooltip() (+9 params), toolbox() (+5 params), datazoom() (+6 params), visual_map() (+6 params).
  • Added: Timeline parity — TimelineFigure.plot(), .bar(), .scatter(), .pie(), .hist() now accept all new style parameters.
  • Added: 5 new dataclasses: EndLabelStyle, Blur, Select, TooltipStyle, AnimationConfig.
  • Extended: ItemStyle (+border_type, decal), LabelStyle (+font_family, rotate, offset, align), LineStyle (+shadow_color, shadow_offset_x/y, cap, join), AreaStyle (+origin, shadow_blur, shadow_color).
  • Added: Three-tier control model: scalar params → dataclass overrides → **series_kw raw dict.

v0.5.3

  • Added: fig.waterfall() -- finance/accounting waterfall charts with cumulative positive/negative deltas, optional total bar, connector lines, and value labels.

v0.5.1

See Releases for full details.

v0.4.8

  • Changed: Default renderer switched from "canvas" to "svg" -- fixes the broken toolbox download button under canvas/iframe sandbox restrictions.

v0.4.7

  • Added: fig.candlestick() -- native OHLC candlestick charts with dual-axis support and full composability.

v0.4.6

  • Added: Emphasis support for boxplot(), heatmap(), and funnel().

v0.4.5

  • Fixed: Charts vanishing across st.tabs() in Streamlit 1.48+.

Support the Project

If echartsy saves you time or you enjoy using it, consider buying me a coffee. It helps keep the project maintained and growing.

Buy Me A Coffee


Contributing

Contributions, bug reports, and feature requests are welcome. Please open an issue or submit a pull request on GitHub.

License

MIT — Jigar, 2026

About

A matplotlib-style fluent builder API for Apache ECharts in Python

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors