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.
The fragment is saved inside the workbook, so it travels with every copy you
send. For that reason it cannot put anything into the page: a string containing
< or >, a javascript: link, a title link, and the tooltip's CSS and DOM
options are dropped, and a custom tooltip template is drawn on the chart itself
rather than as HTML. Templates such as {b}: {c} units and rich-text styles
work as usual.
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.