GitHub user rlei-odes created a discussion: Making per-series chart styling reachable
I'm new to contributing here. Using Superset with a real dataset for the first time, I ran into a wall trying to style individual series, and I think the wall is smaller than it looks. Two small PRs to offer, and one question I'd like opinions on before writing anything. ## What I'm trying to build <img width="823" height="409" alt="goal_example_chart" src="https://github.com/user-attachments/assets/046c3306-d66c-4f25-b6c1-86f5c6fd3e40" /> Grey for previous years, dark for actual, hatched for forecast, outline for plan. A common convention in business reporting, recently formalised as ISO 24896. The point is that the *fill* carries the meaning, so the chart reads without the legend and colour stays free for something else. The screenshot is from the plugin I made, see links below. My goal would be to get closer to achieving this by adding the necessary features. ## Where it stands ECharts does all of this natively, and Superset ships it. The two properties I need are `itemStyle.borderColor` + `borderWidth` for the outline, and `itemStyle.decal` for the hatching. Neither has a control, so the only way to set them is *Customize → ECharts Options (JS object literals)*, the free-text box where you can hand-write ECharts options that get merged over the ones Superset computed. What you write there is checked against an allowlist schema first, and anything not on it is dropped. - **Outline** is on that allowlist already. - **Hatching** isn't - `decal` is the only member of `itemStyle` missing from `itemStyleSchema`, which looks accidental. But neither is actually reachable, for a reason that has nothing to do with the allowlist: both are *per-series* properties, so setting one means writing a `series` key. `mergeCustomEChartOptions` replaces arrays instead of merging them: ```js // mergeCustomEChartOptions.ts // Replace arrays and primitive values directly (result as PlainObject)[key] = customValue; ``` So supplying `series` discards the series Superset just computed, data included. The replacement can't carry its own data either, since `data` isn't in `seriesSchema` (deliberately, and rightly). So that box works well for top-level objects like `xAxis` and `yAxis`, which do merge, and cannot express anything per series at all. ## Two PRs I'd like to offer Both small, additive, and useful on their own: 1. **Allow `decal` in the options schema.** One property on `itemStyleSchema`, mirroring ECharts' `DecalObject`. `borderColor` and `lineStyle.type` are already allowed and a decal is the same kind of value, so this mostly closes an inconsistency. On its own it changes nothing that renders, see the question below. 2. **Chart chrome as controls** - gridlines, axis ticks, axis labels, axis line colour and width. Currently hardcoded as `splitLine: { show: !isSmallChart }` in the transform. Useful well beyond my use case; the sparse look in the chart above isn't reachable today without hand-written JSON. ## The question Neither of those makes per-series styling work. That needs the array problem solved, and I can see two ways: **a) Merge `series` element-wise instead of replacing it.** Then `{ series: [{ itemStyle: { decal: {...} } }] }` would decorate the first series without destroying its data, and both outline and hatching become usable immediately through a control that already exists. This looks small, and ECharts itself merges by index or id in `setOption`. The obvious risk is that it changes behaviour for anyone currently relying on replacement, and series indices are positional, so it may be fragile when the series count changes. **b) A real control for per-series styling**, rather than routing it through JSON. More work, better UX, and it raises a design question I don't want to answer alone: how should a series be addressed? Matching on the rendered series name is the obvious answer and I'd argue against it. Names are composed from the metric and groupby values, so a rule silently stops matching the moment someone adds a dimension. Is either direction something Superset wants? I'm happy to do the work, but I'd rather find out now than arrive with a large PR. And if the answer is "this belongs in a plugin", that's useful to know too. ## Working code All of the above is running in a fork as a self-contained plugin: - [Diff against master](https://github.com/apache/superset/compare/master...rlei-odes:superset:business-charts) - [What's added versus merely surfaced](https://github.com/rlei-odes/superset/blob/business-charts/superset-frontend/plugins/plugin-chart-business-charts/FEATURES.md) GitHub link: https://github.com/apache/superset/discussions/43426 ---- This is an automatically sent email for [email protected]. To unsubscribe, please send an email to: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
