charts

star 9

Generate SVG/PNG charts (bar, line, pie, scatter, radar, heatmap, funnel, gauge, sankey, etc.) from ECharts JSON configs

Michaelliv By Michaelliv schedule Updated 2/25/2026

name: charts description: Generate SVG/PNG charts (bar, line, pie, scatter, radar, heatmap, funnel, gauge, sankey, etc.) from ECharts JSON configs

Charts CLI

Generate charts from the command line using ECharts. No browser needed.

Setup (one-time in container)

npm install -g charts-cli

Usage

List available chart types

charts schema --list

Get schema for a chart type

charts schema bar
charts schema pie
charts schema xAxis

Render a chart

# Pipe JSON config
echo '<json>' | charts render -o /workspace/scratch/chart.png

# From file
charts render --config option.json -o /workspace/scratch/chart.png

Options

Option Description
-o, --output <file> Output path (.svg or .png)
-W, --width <n> Width in pixels (default: 800)
-H, --height <n> Height in pixels (default: 400)
--theme <name> dark, vintage, or path to JSON
--format <type> svg or png (auto-detected from extension)

Supported chart types

bar, line, pie, scatter, radar, funnel, gauge, treemap, boxplot, heatmap, candlestick, sankey

Visual Style Rules

Always apply these defaults to every chart config for clean, modern output.

Global defaults

  • backgroundColor: "#ffffff" — mandatory; without it PNGs are transparent and unreadable on dark viewers
  • Title: left: "center", top: 14, fontSize: 16, fontWeight: "bold", color: "#111827"
  • Grid: { left: 60, right: 32, top: 60, bottom: 48 } — increase top to ~80 when using both title and legend
  • Color palette (use in order): #4f46e5, #0d9488, #d97706, #dc2626, #7c3aed, #0891b2
  • Area fill RGBA (0.10 opacity): rgba(79,70,229,0.10), rgba(13,148,136,0.10), rgba(217,119,6,0.10), rgba(220,38,38,0.10), rgba(124,58,237,0.10), rgba(8,145,178,0.10)

Axis styling (for charts that use xAxis/yAxis)

  • xAxis (category): axisTick.show: false, axisLine color #d1d5db, axisLabel color #4b5563 fontSize 13
  • yAxis (value): axisLine.show: false, axisTick.show: false, axisLabel color #9ca3af fontSize 12, splitLine dashed #e5e7eb

Bar

  • barWidth: "50%", rounded top corners borderRadius: [5,5,0,0]
  • Value labels on top: label.show: true, position: "top", color #1f2937, fontSize 13, fontWeight bold

Line

  • smooth: true for modern curves; omit for angular data
  • symbol: "circle", symbolSize: 7, lineStyle width 3
  • White-bordered data points: itemStyle.borderColor: "#ffffff", borderWidth: 2
  • Single series: area fill at ~0.15 opacity; boundaryGap: false on xAxis
  • Multi-series: no area fill (overlaps too much), explicit color per series, add legend at top: 42
  • No value labels — they clutter curves

Pie / donut

  • No grid, xAxis, yAxis. Use center: ["50%","55%"], render with -W 800 -H 500
  • White borders between segments: borderColor: "#ffffff", borderWidth: 2, borderRadius: 4
  • Labels: formatter: "{b} {d}%", color #374151, fontSize 13; labelLine color #d1d5db, length 16/20
  • emphasis.itemStyle.shadowBlur: 0 — flat look, no hover shadow
  • Set color array on the series directly (no axis to carry it)
  • Donut: radius: ["40%","65%"], bump borderWidth: 3, borderRadius: 6
  • Donut center label: title as array; second element with left/top: "center", large fontSize, subtext for descriptor
  • Legend layout (many slices): orient: "vertical", right: 24, top: "middle", hide labels, shift center to ["38%","55%"]

Scatter

  • Both axes type: "value" (not category)
  • symbolSize: 8, itemStyle.opacity: 0.7 to handle overlap
  • Use xAxis.name / yAxis.name to label axes

Radar

  • Uses radar component (not xAxis/yAxis) with indicator array: [{name, max}, ...]
  • shape: "polygon", center: ["50%","55%"], radius: "60%"
  • areaStyle.opacity: 0.3 for overlapping multi-series comparison
  • Render with -W 800 -H 500

Funnel

  • No axes. sort: "descending", gap: 2, width: "70%", height: "75%"
  • White borders: borderColor: "#ffffff", borderWidth: 3
  • Labels inside: position: "inside", white text, formatter: "{b}: {c}"
  • Assign color per data item via itemStyle.color
  • Render with -W 800 -H 500

Gauge

  • No axes. Modern arc style: progress.show: true, pointer.show: false
  • Track: axisLine.lineStyle.width: 24, color [[1, "#e5e7eb"]]; progress width matches
  • Hide ticks, splitLines, axisLabels for clean look
  • Center value: detail.formatter: "{value}%", fontSize 48, fontWeight bold, color #111827
  • Subtitle via title.offsetCenter: [0, "50%"], fontSize 14, color #6b7280
  • Multi-range: axisLine.lineStyle.color: [[0.3, "#22c55e"], [0.7, "#d97706"], [1, "#dc2626"]]
  • Render with -W 800 -H 500

Heatmap

  • Both axes type: "category". Data as [x, y, value] triples (indices into axis arrays)
  • Requires visualMap: type: "continuous", inRange.color array of 3–5 colors for gradient (e.g. ["#e0f2fe","#7dd3fc","#0ea5e9","#0369a1","#1e3a8a"])
  • Cell labels: label.show: true, fontSize 11, fontWeight bold
  • White borders: borderColor: "#ffffff", borderWidth: 2
  • Increase grid.right: 120 to make room for visualMap legend

Sankey

  • No axes. Position with left/right/top/bottom on the series
  • Data: data array (nodes with name + itemStyle.color) and links array (source, target, value)
  • lineStyle.opacity: 0.25 — semi-transparent flows prevent clutter
  • nodeWidth: 20, nodeGap: 14
  • Labels: position: "right", color #374151, fontSize 13
  • Render with -W 800 -H 500

Treemap

  • No axes. Position with width/height/left/top on the series. roam: false, breadcrumb.show: false
  • Hierarchical data: [{name, itemStyle.color, children: [{name, value}, ...]}, ...]
  • White borders: borderWidth: 3, gapWidth: 3
  • Use levels array for depth-specific styling — wider gaps at top level, smaller borders for leaves
  • Labels: white text over colored backgrounds, formatter: "{b}"
  • Assign color per top-level category; children inherit
  • Render with -W 800 -H 500

Boxplot

  • Standard category xAxis (group names) + value yAxis
  • Data: [min, Q1, median, Q3, max] per group
  • boxWidth: ["40%","70%"], fill color #4f46e5
  • Dark borders: borderColor: "#111827", borderWidth: 1.5

Candlestick

  • Standard category xAxis (dates) + value yAxis
  • Data: [open, close, low, high] per candle
  • Green up / red down: color: "#10b981", color0: "#ef4444", darker borders #059669 / #dc2626
  • yAxis.scale: true — essential; without it axis starts at 0 and candles become slivers

Reference example

Shows how the global defaults, axis styling, and bar series rules compose into a complete config:

{
  "backgroundColor": "#ffffff",
  "title": {
    "text": "Monthly Revenue (k$)",
    "textStyle": { "fontSize": 16, "fontWeight": "bold", "color": "#111827" },
    "left": "center",
    "top": 14
  },
  "grid": { "left": 60, "right": 32, "top": 60, "bottom": 48 },
  "xAxis": {
    "type": "category",
    "data": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
    "axisTick": { "show": false },
    "axisLine": { "lineStyle": { "color": "#d1d5db" } },
    "axisLabel": { "color": "#4b5563", "fontSize": 13 }
  },
  "yAxis": {
    "type": "value",
    "axisLine": { "show": false },
    "axisTick": { "show": false },
    "axisLabel": { "color": "#9ca3af", "fontSize": 12 },
    "splitLine": { "lineStyle": { "type": "dashed", "color": "#e5e7eb" } }
  },
  "series": [{
    "type": "bar",
    "data": [10, 20, 35, 28, 42, 38],
    "barWidth": "50%",
    "itemStyle": { "borderRadius": [5, 5, 0, 0], "color": "#4f46e5" },
    "label": { "show": true, "position": "top", "color": "#1f2937", "fontSize": 13, "fontWeight": "bold" }
  }]
}

Workflow

  1. Use charts schema <type> to check the config format
  2. Build the ECharts JSON option, applying the visual style rules above
  3. Pipe it to charts render -o /workspace/scratch/chart.png
  4. Use the attach tool to send the image to Slack
Install via CLI
npx skills add https://github.com/Michaelliv/charts-cli --skill charts
Repository Details
star Stars 9
call_split Forks 1
navigation Branch main
article Path SKILL.md
More from Creator