design-a-chart

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Design a Chart From a User Goal

基于用户目标设计图表

Use this scenario loop: trigger → inspect → decide → build → verify. Do not begin with a chart type, even when the request names one.
遵循以下场景循环:trigger → inspect → decide → build → verify。即使请求中指定了图表类型,也不要从选择图表类型开始。

Setup

准备步骤

Turn the request into this brief before writing chart code:
ts
interface ChartBrief {
  question: string
  decision: string
  observation: string
  metric: { value: string; unit: string; denominator?: string }
  comparison:
    'time' | 'category' | 'distribution' | 'relationship' | 'composition'
  evidence: readonly string[]
}

export const brief: ChartBrief = {
  question:
    'Which acquisition channel improved conversion without losing volume?',
  decision: 'Choose where to increase next-month spend',
  observation: 'one row per channel and month',
  metric: { value: 'conversionRate', unit: '%', denominator: 'sessions' },
  comparison: 'time',
  evidence: ['conversion rate', 'sessions', 'month', 'channel'],
}
If the question, observation, unit, denominator, or decision is unknown, inspect the data and surrounding product before choosing marks.
在编写图表代码之前,先将用户请求转化为如下概要:
ts
interface ChartBrief {
  question: string
  decision: string
  observation: string
  metric: { value: string; unit: string; denominator?: string }
  comparison:
    'time' | 'category' | 'distribution' | 'relationship' | 'composition'
  evidence: readonly string[]
}

export const brief: ChartBrief = {
  question:
    'Which acquisition channel improved conversion without losing volume?',
  decision: 'Choose where to increase next-month spend',
  observation: 'one row per channel and month',
  metric: { value: 'conversionRate', unit: '%', denominator: 'sessions' },
  comparison: 'time',
  evidence: ['conversion rate', 'sessions', 'month', 'channel'],
}
如果问题、观测数据、单位、分母或决策信息不明确,在选择标记(marks)之前先检查数据及相关产品信息。

Core Patterns

核心模式

Match the form to the reader's comparison

让图表形式匹配读者的对比需求

  • Change over ordered time → line; discrete periods → bars.
  • Named-category magnitude → sorted horizontal bars or dots.
  • Distribution → histogram, ECDF, box, violin, or faceted histograms.
  • Relationship → scatterplot; add size only for a meaningful third quantity.
  • Composition → stack for totals, normalized stack for proportions, mosaic for two categorical dimensions.
  • Flow, hierarchy, network, or spatial questions → use their first-party layouts only when topology is the question.
Read the visual-task matrix for the full routing table.
  • 有序时间维度的变化 → line图;离散时间段 → bars图。
  • 分类维度的数值大小 → 排序后的水平bars图或dots图。
  • 数据分布 → histogram、ECDF、box、violin图或分面histogram。
  • 变量关系 → scatterplot;仅当存在有意义的第三个量化指标时才添加尺寸维度。
  • 数据构成 → 堆叠图展示总计,归一化堆叠图展示占比,马赛克图展示两个分类维度的构成。
  • 流向、层级、网络或空间类问题 → 仅当拓扑结构是核心问题时,才使用对应的原生布局。
查看可视化任务矩阵获取完整的选型对照表。

Separate observed, target, and projected values

区分观测值、目标值和预测值

ts
import { areaY, defineChart, lineY, ruleY } from '@tanstack/charts'
import { scaleLinear } from '@tanstack/charts/scales/linear'
import { scalePoint } from '@tanstack/charts/scales/point'

const rows = [
  { month: 'Jan', actual: 82, forecast: null, low: null, high: null },
  { month: 'Feb', actual: 91, forecast: null, low: null, high: null },
  { month: 'Mar', actual: null, forecast: 96, low: 88, high: 106 },
  { month: 'Apr', actual: null, forecast: 103, low: 90, high: 119 },
]

export const chart = defineChart({
  marks: [
    areaY(rows, { x: 'month', y1: 'low', y2: 'high', fillOpacity: 0.15 }),
    lineY(rows, { x: 'month', y: 'actual', strokeWidth: 2.5 }),
    lineY(rows, { x: 'month', y: 'forecast', strokeDasharray: '5 4' }),
    ruleY([100], { strokeDasharray: '2 3' }),
  ],
  x: { scale: scalePoint },
  y: { scale: scaleLinear, axis: { label: 'Indexed revenue' } },
})
Use different channels for status and uncertainty. A continuous unqualified line implies equal epistemic status.
ts
import { areaY, defineChart, lineY, ruleY } from '@tanstack/charts'
import { scaleLinear } from '@tanstack/charts/scales/linear'
import { scalePoint } from '@tanstack/charts/scales/point'

const rows = [
  { month: 'Jan', actual: 82, forecast: null, low: null, high: null },
  { month: 'Feb', actual: 91, forecast: null, low: null, high: null },
  { month: 'Mar', actual: null, forecast: 96, low: 88, high: 106 },
  { month: 'Apr', actual: null, forecast: 103, low: 90, high: 119 },
]

export const chart = defineChart({
  marks: [
    areaY(rows, { x: 'month', y1: 'low', y2: 'high', fillOpacity: 0.15 }),
    lineY(rows, { x: 'month', y: 'actual', strokeWidth: 2.5 }),
    lineY(rows, { x: 'month', y: 'forecast', strokeDasharray: '5 4' }),
    ruleY([100], { strokeDasharray: '2 3' }),
  ],
  x: { scale: scalePoint },
  y: { scale: scaleLinear, axis: { label: 'Indexed revenue' } },
})
使用不同的视觉渠道区分数据状态和不确定性。一条连续无修饰的线条意味着所有数据的认知状态相同。

Define proof before polish

在优化视觉效果前先验证准确性

For every chart, verify:
  • the visual answers the stated question;
  • axes, legend, title, or adjacent copy identify units and comparison;
  • ordering, aggregation, missing-value policy, and baseline are deliberate;
  • exact-value tasks have a table or textual equivalent;
  • the smallest supported container preserves the important comparison;
  • pointer, keyboard, updates, and empty states tell the same story.
对于每个图表,需验证:
  • 可视化内容能够回答提出的问题;
  • 坐标轴、图例、标题或相邻文本明确标注了单位和对比维度;
  • 排序、聚合、缺失值处理规则和基线设置是经过审慎考虑的;
  • 需要精确数值的场景配有对应的表格或文本说明;
  • 在最小支持的容器尺寸下仍能保留核心的对比信息;
  • 指针交互、键盘交互、数据更新和空状态都传递一致的信息。

Common Mistakes

常见错误

CRITICAL Starting with the requested chart type

严重错误:从用户要求的图表类型开始

Wrong: implement “make this a pie chart” before identifying the comparison.
Correct: restate the decision and recommend the form that makes that comparison perceptually direct. If the user retains a weaker form, state its analytical limitation and preserve the underlying semantics.
A familiar chart can answer a different question than the user needs.
Source:
docs/guides/choosing-a-chart.md
错误做法:在明确对比需求之前就直接实现“制作饼图”的请求。
正确做法:重新梳理用户的决策需求,推荐能让对比感知更直接的图表形式。如果用户坚持使用效果较差的形式,需说明其分析局限性并保留底层语义。
熟悉的图表可能无法满足用户真正的需求。
来源:
docs/guides/choosing-a-chart.md

HIGH Showing a rate without its denominator

高风险错误:仅展示比率而不显示分母

Wrong: show conversion rate alone.
Correct: keep sessions or eligible population in the prepared row and expose it beside the rate or in the tooltip.
Normalized values can reverse interpretation when volume changes.
Source:
API-FRICTION.md
F-217;
docs/reference/transforms.md
错误做法:仅展示转化率。
正确做法:在预处理数据中保留会话数或合格用户群体,并将其显示在比率旁边或工具提示中。
当数据量变化时,归一化后的数值可能会逆转解读结果。
来源:
API-FRICTION.md
F-217;
docs/reference/transforms.md

CRITICAL Rendering projections as observed history

严重错误:将预测数据当作历史观测数据渲染

Wrong: connect actuals and forecasts with one undifferentiated line.
Correct: encode the forecast boundary, projected segment, and uncertainty explicitly.
Continuous treatment implies equal certainty.
Source:
docs/examples/lines-and-areas.md
;
docs/reference/marks/difference.md
错误做法:用一条无差别的线条连接实际数据和预测数据。
正确做法:明确标记预测边界、预测段和不确定性范围。
连续展示会让用户认为所有数据的确定性相同。
来源:
docs/examples/lines-and-areas.md
;
docs/reference/marks/difference.md

HIGH Choosing area or angle for precise ranking

高风险错误:使用面积或角度进行精确排名

Wrong: rank close values with wedges, bubbles, or interior stack layers.
Correct: use aligned position or length when exact ordering is the reader's task.
Area and angle emphasize shape or part-to-whole relationships, not precise rank.
Source:
docs/guides/choosing-a-chart.md
;
docs/examples/bars-and-rankings.md
错误做法:用扇形、气泡或堆叠图内层来对相近数值进行排名。
正确做法:当读者需要精确排序时,使用对齐的位置或长度维度。
面积和角度更适合强调形状或整体与部分的关系,而非精确排名。
来源:
docs/guides/choosing-a-chart.md
;
docs/examples/bars-and-rankings.md

HIGH Tension: analytical honesty versus visual simplicity

高风险矛盾:分析准确性与视觉简洁性的冲突

Simplifying aggregation can hide denominators, lineage, uncertainty, or missing-value policy. Preserve the evidence needed to interpret the result before reducing visual detail.
See also:
prepare-chart-data/SKILL.md
§ Common Mistakes
简化聚合操作可能会隐藏分母、数据来源、不确定性或缺失值处理规则。在减少视觉细节之前,需保留解读结果所需的证据。
另请参阅:
prepare-chart-data/SKILL.md
§ 常见错误

References

参考资料

  • Analytical task and visual-form matrix
See also:
prepare-chart-data/SKILL.md
and
compose-marks-and-views/SKILL.md
— the analytical task determines both the transform and mark composition.
  • 分析任务与可视化形式矩阵
另请参阅:
prepare-chart-data/SKILL.md
compose-marks-and-views/SKILL.md
—— 分析任务决定了数据转换和标记组合方式。