Charting
This is the same document you'll find inside Spredin under Help.
Spredin charts are powered by Apache ECharts. A chart is a floating card bound to a cell range: edit the cells and the chart updates live. You can build and fully customise charts from the UI, from Python, or from an LLM/agent — all three drive the same options, and the raw ECharts option is always reachable as an escape hatch.
Create a chart#
- UI: select a range → Insert → Chart from selection (or ⌘K → "Chart"). The first column is the category axis; each remaining column is a series; a non-numeric first row is treated as headers (category + series names).
- Python / agent:
sheet.chart("A1:E5", "bar", "Revenue").
Chart types#
bar · stackedBar · horizontalBar · line · area · stackedArea · pie ·
rose · scatter · radar · funnel · polarBar · treemap · sunburst ·
heatmap · boxplot · candlestick
The first seven appear as quick-switch icons on the chart card; all are selectable in the ⚙ panel's Type dropdown. Notes on the extra types:
horizontalBar — bars run left→right (value on X, categories on Y).
rose — Nightingale pie (slice radius ∝ value); sums each row like pie.
radar — one axis per row (category), one polygon per value column (series).
funnel — one stage per row, summed across value columns (like pie).
polarBar — bars wrapped around a polar axis (angle = category).
treemap — one tile per row, sized by the row's total.
sunburst — two rings: each row is an inner wedge, its value columns the outer ring.
heatmap — a matrix: X = rows, Y = value columns, colour = value.
boxplot — one box per value column (min / Q1 / median / Q3 / max of that column).
candlestick (OHLC) — needs 4 value columns per row in open, close, low, high order.
Pie — one slice per row (category), valued by the sum of all value columns in that row, so it uses the whole selected region (not just the first column).
Scatter — the first value column is the shared X axis; each remaining column is a separate, colour-coded Y series named from the header row. Two columns → one series; more → a multi-series scatter that uses the full 2-D region.
Swap rows ↔ columns — the ⚙ panel's Swap rows / columns (or
transpose=Truein Python) transposes the data, so categories become series and vice-versa. Use it to pie-by-column instead of by-row, or to re-group a scatter's series.
Detailed editing (the ⚙ panel — Excel-style)#
Click ⚙ Edit chart… on a chart card for:
| Option | What it does |
|---|---|
| Type | Switch chart type |
| Data range | Re-bind to a different A1 range |
| X / Y axis title | Axis names |
| Y min / max | Fix the value-axis bounds (blank = auto) |
| Legend | Hidden / Top / Bottom / Left / Right |
| Gridlines | Toggle value-axis gridlines |
| Smooth lines | Curved vs. straight line/area |
| Data labels + format | Show values on points/bars/slices; format is an ECharts template ({c} value, {b} name, {d}% percent) |
| Log scale (Y) | Logarithmic value axis |
| Dual axis (combo) | Plot the last series on a secondary Y (e.g. bars + a %-margin line) |
| Series colours | Comma-separated hex overrides |
| Advanced (ECharts JSON) | A raw ECharts option fragment deep-merged over the generated chart — the full library |
Other niceties: drag the title bar to move, drag the corner to resize, double-click the title to rename, ⤓ exports a PNG.
Python / agent API#
# Simple
sheet.chart("A1:E5", "line", "Sales by quarter")
# Excel-style options (snake_case keywords)
sheet.chart("A1:E5", "bar", "Revenue",
x_title="Quarter", y_title="USD",
y_min=0, legend_pos="top", labels=True, label_fmt="{c}",
gridlines=False, colors=["#4f6bed", "#e5604d"])
# Combo (bars + a line on a second axis)
sheet.chart("A1:C13", "bar", "Revenue vs margin", dual_axis=True)
Full ECharts power — the echarts= escape hatch#
Anything the structured options don't cover, pass as a raw ECharts option
fragment; it is deep-merged over the generated option (objects merge,
arrays/scalars replace). This unlocks the whole library — markLine, markArea,
dataZoom, visualMap, custom tooltip formatters, multiple grids, etc.
sheet.chart("A1:E5", "line", "With an average line", echarts={
"tooltip": {"trigger": "axis"},
"series": [{"markLine": {"data": [{"type": "average", "name": "Avg"}]}}],
"dataZoom": [{"type": "inside"}],
})
Keyword options map to chart fields (
x_title→xTitle,y_min→yMin,log_y→logY,dual_axis→dualAxis,legend_pos→legendPos,label_fmt→labelFmt).echarts=takes any ECharts JSON.
Notes & limits#
- Charts are per-sheet and persist in the
.sprdworkbook (chartssection), including all of the above options and anyechartsfragment. - The card recomputes live on cell edits and on theme changes (series + chrome
colours follow the active theme unless you override
colors). - A fragment in
echarts=always wins (it's merged last), so it can override any generated setting.