Technical Documentation: antvis/G2
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (`README.md`)
English | 简体中文
**G2: The Concise and Progressive Visualization Grammar**
G2 is named after Leland Wilkinson’s book The Grammar of Graphics and was profoundly inspired by it in the very beginning. Here are some resources you can begin with:
- Introduction - a brief overview and G2's motivations
- Examples - a large number of demos to learn from and copy-paste
- Tutorials - interactive case-driven guides of G2's core concepts
- API Reference - complete documentation for all visualization components
✨ Features
- Progressive Usage - The main objective of G2 is to help you get meaningful visualizations quickly with concise declarations and it infers the rest. But you can configure much more for complex and advanced situations.
- Declarative API - We employs a functional declarative API to specify chart options in a programmatic fashion, which contributes to better logic reuse and more flexible code organization.
- High Extensibility - To satisfy specific needs, G2 provides a convenient and consistent mechanism to extend everything you can imagine, whether a scale, a transform, a mark, etc,. You can even customize a brand new visualization tool based on this mechanism.
- Comprehensive Grammar - G2 rejects a chart typology in favor of marks, transforms, scales, coordinates, and compositions. In addition to static visual representations, it's possible to declare data-driven animations and apply well-designed action-based interactions to plots as well.
- Powerful Renderer - There is a powerful renderer G under G2 to generate web-based visualizations using Canvas, SVG or WebGL. The plenty of plugins it has benefit G2 from rendering charts with novel styles such as hand-drawn and fully embracing the ecosystem of D3.
🔨 Getting Started
G2 is usually installed via a package manager such as npm or Yarn.
$ npm install @antv/g2$ yarn add @antv/g2The Chart object then can be imported from G2.
<div id="container"></div>import { Chart } from '@antv/g2';
// A tabular data to be visualized.
const data = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 },
];
// Instantiate a new chart.
const chart = new Chart({
container: 'container',
});
// Specify visualization.
chart.options({
// Create an interval mark and add it to the chart.
type: 'interval',
// Bind data for this mark.
data: data,
encode: {
// Assign genre column to x position channel.
x: 'genre',
// Assign sold column to y position channel.
y: 'sold',
// Assign genre column to color channel.
color: 'genre',
},
});
// Render visualization.
chart.render();If all goes well, you can get the following lovely bar chart!
🌍 Ecosystem
- g2-react - The lightweight React component for G2, without extra features.
- g2-extensions - The one-stop shop for official G2 extensions, such as 3d visualization, automated visual analytics, etc.
- ant-design-charts - The React chart library, based on G2, G6, X6, L7Plot.
- More...
📮 Contributing
This project exists thanks to all the people who contribute.
And thank you to all our backers! 🙏
- Issues - report bugs or request features
- Contributing Guide - help build G2
- Discussions - discuss on GitHub or in DingTalk group(30233731, 35686967, 44788198)
📑 Paper
Bairui Su, Zhiwei Wang, Zhifeng Lin, Xiaojuan Liao, Zihan Zhou, Minfeng Zhu, Wei Chen. G2: A customizable web-based framework for authoring interactive visualizations. Visual Informatics, 2026.
@article{su2026g2,
author={Bairui Su, Zhiwei Wang, Zhifeng Lin, Xiaojuan Liao, Zihan Zhou, Minfeng Zhu, Wei Chen},
title={G2: A customizable web-based framework for authoring interactive visualizations},
journal={Visual Informatics},
year={2026},
url={https://doi.org/10.1016/j.visinf.2026.100307}
}📄 License
MIT@AntV.
Overview (`site/README.md`)
G2 website
Use Node.js 22.12 or newer. Install the repository dependencies, then install and start the site:
pnpm install
cd site
pnpm install
pnpm startThe site uses Astro and @antv/astro-theme-antv. G2 imports resolve to the repository's src/index.ts, so examples use the code being developed.
Documents
Keep static documents in docs/**/*.zh.md and docs/**/*.en.md. Use .mdx when a document needs a component, and import that component explicitly. Use lowercase, hyphenated filenames for public routes. Chinese and English pages live under /zh/ and /en/.
For a demo used only in one document, keep its source in MDX:
import { Demo } from '@antv/astro-theme-antv/components';
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container' });
chart.interval().data([{ name: 'A', value: 10 }]).encode('x', 'name').encode('y', 'value');
chart.render();
`} />code is a static JavaScript template literal. Escape backslashes, backticks and ${ as in any template literal; do not interpolate MDX expressions into demo source. Use ordinary fenced code blocks for code that should only be displayed.
Keep examples shared by multiple documents in an adjacent demos/ TypeScript module and reference them with <Demo src="manual/introduction/demos/what-is-g2-en-2" />. src is relative to docs, without .ts; provide either code or src.
The shared component is exported by @antv/astro-theme-antv/components; G2 supplies its package dependency map; data previews use table from @antv/astro-theme-antv/table without extra configuration. Document demos run in an iframe that is replaced on rerun. Pass the container to table, for example await table(data, document.getElementById('container')!). The theme strips TypeScript types and loads the local G2 source as native ES modules and provides source editing, copy, a stable preview height and a 400 ms debounce. Source is present in the initial HTML; JavaScript collapses it by default and reveals the left toolbar on hover/focus. Use open for an expanded editor and height for the preview viewport.
The document's initial HTML and page-level Markdown both contain complete demo source alongside its explanation. Embedded demos use iframe srcdoc; they do not generate individual example pages or source endpoints. Direct HTTP requests do not require executing a preview to obtain source.
Chart discovery and related-chart cards read document frontmatter (category, similar, screenshot) from the Astro content collection. The theme editor lives in src/theme-editor and mounts as a React island.
Examples
Gallery examples remain in examples/<category>/<group>/demo/, registered by meta.json. Localized group titles and order come from index.zh.md and index.en.md. The shared theme builds their gallery, source view and isolated preview routes.
pnpm build generates the static site in dist. Deployment copies site/CNAME into that directory.
AI-readable exports
The theme's content.agentComponents configuration expands both inline and shared
Demo source into fenced TypeScript in /<locale>/<document>.md and/llms-full.txt. Card becomes a text link with its description. Interactive-only
components link to the original page; the website rendering is unchanged.
Site Docs Theme.En (`site/docs/theme.en.mdx`)
title: Theme editor template: page sidebar: hidden: true
import ThemeEditor from '../src/components/ThemeEditor.astro';
Site Docs Theme.Zh (`site/docs/theme.zh.mdx`)
title: 主题编辑器 template: page sidebar: hidden: true
import ThemeEditor from '../src/components/ThemeEditor.astro';
Site Docs Charts Arcdiagram.En (`site/docs/charts/arcdiagram.en.mdx`)
title: Arc Diagram sidebar: { icon: 'link' } order: 1 screenshot: 'https://zos.alipayobjects.com/rmsportal/qpgXANQpfnLyYgQqnjNf.png' category: ['relation'] similar: ['chord', 'sankey', 'network']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Arc Diagrams
An arc diagram is a variation of the node-link method, which refers to a visual layout representation of node-link layouts that use nodes to represent objects and lines (or edges) to represent relationships. Based on this concept, arc diagrams adopt a one-dimensional layout approach, where nodes are arranged along a linear axis or in a circular pattern, and arcs are used to express the linking relationships between nodes. While this method cannot express the global structure of a graph like two-dimensional layouts can, it can clearly present ring and bridge structures when nodes are well-ordered.
Other Names: Arc diagram
Components of an Arc Diagram
Linear Arc Diagram
| Chart Type | Linear Arc Diagram |
|---|---|
| Suitable Data | List: A set of node data (containing node id field), a set of link data (containing source node field and target node field) |
| Function | Represents linking relationships between data |
| Data-to-Visual Mapping | Node coordinates (automatically calculated) field mapped to node position on coordinate axisLink coordinates (automatically calculated) mapped to semicircle arc vertex coordinate axis positionCategorical data in nodes can also be color-coded for enhanced distinction |
| Suitable Data Volume | No less than 2 data entries |
Circular Arc Diagram
| Chart Type | Circular Arc Diagram |
|---|---|
| Suitable Data | List: A set of node data (containing node id field), a set of link data (containing source node field and target node field) |
| Function | Represents linking relationships between data |
| Data-to-Visual Mapping | Node coordinates (automatically calculated) field mapped to node position on coordinate axisLink coordinates (automatically calculated) mapped to Bézier curve vertex coordinate axis position with circle center as control pointCategorical data in nodes can also be color-coded for enhanced distinction |
| Suitable Data Volume | No less than 5 node data entries |
Use Cases of Arc Diagrams
Suitable Use Cases
Example 1: Expressing relationships between data and the importance of relationships
The network shown below represents character relationships in Victor Hugo's classic novel "Les Misérables".
Node Data:
| name | group | id |
|---|---|---|
| Myriel | 1 | 0 |
| ... | ... | ... |
Link Data:
| source | target | value |
|---|---|---|
| 1 | 0 | 1 |
| ... | ... | ... |
Description:
- The
groupfield usescolorto distinguish different node types - The
valuefield usesarc thicknessto represent relationship strength
Example 2: Circular layout for displaying complex relationship networks
Using a polar coordinate system, the data from Example 1 can be rendered as a circular arc diagram, which is more suitable for displaying network data with large numbers of nodes and complex relationships.
Unsuitable Use Cases
Example 1: Not suitable for representing hierarchical structures
Arc diagrams use linear or circular one-dimensional layouts and cannot effectively express hierarchical relationships in data. For data with obvious hierarchical structures, tree diagrams or organizational charts are more appropriate.
Example 2: Not suitable for handling too many nodes
When there are too many nodes, arc diagrams become crowded and difficult to read, with serious line overlap affecting readability. In such cases, force-directed graphs or other network graph layouts should be considered.
Comparing Arc Diagrams to Other Charts
Arc Diagrams and [Chord Charts](/en/charts/chord/)
- Arc diagrams use standard linear layout for nodes, where node weights determine node size but do not affect position
- Arc diagram connections can use weights to control line width, with uniform thickness
- Arc diagram connections are drawn overlapping on top of nodes
- Chord charts use weight-based linear layout for nodes, where node weights determine both node size and position
- Chord chart connections use source and target weights to control line width, with non-uniform thickness
- In chord charts, node width equals the sum of connection widths, with connections laid out flat at nodes without overlap
Arc Diagrams and [Sankey Diagrams](/en/charts/sankey/)
- Arc diagrams are primarily used to represent relational connections between nodes, without expressing flow or data direction
- Sankey diagrams are specifically used to represent data flow, where connection width represents flow volume with clear directionality
- Arc diagrams use curved connections that are visually more elegant
- Sankey diagrams use straight or curved connections that more intuitively express directional relationships
Similar Charts
- Chord Charts - Used to represent relationships and flows between multiple entities
- Sankey Diagrams - Used to represent data flows and energy transfers
- Network Graphs - Used to represent complex network relationship structures
Similar Charts
Categories
Site Docs Charts Arcdiagram.Zh (`site/docs/charts/arcdiagram.zh.mdx`)
title: 弧长连接图 sidebar: { icon: 'link' } order: 1 screenshot: 'https://zos.alipayobjects.com/rmsportal/qpgXANQpfnLyYgQqnjNf.png' category: ['relation'] similar: ['chord', 'sankey', 'network']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
弧长连接图的简介
弧长连接图是节点-链接法的一个变种,节点-链接法是指用节点表示对象,用线(或边)表示关系的节点-链接布局(node-link)的一种可视化布局表示。弧长连接图在此概念的基础上,采用一维布局方式,即节点沿某个线性轴或环状排列,用圆弧表达节点之间的链接关系。这种方法不能像二维布局那样表达图的全局结构,但在节点良好排序后可清晰的呈现环和桥的结构。
英文名:Arc diagram
弧长连接图的构成
线性弧长连接图
| 图表类型 | 线性弧长连接图 |
|---|---|
| 适合的数据 | 列表:一组节点数据(包含节点 id 字段)、一组链接数据(包含源节点字段和目标节点字段) |
| 功能 | 表示数据之间的链接关系 |
| 数据与图形的映射 | 节点的坐标(自动计算)字段映射到节点的坐标轴的位置链接的坐标(自动计算)映射到半圆弧的顶点坐标轴位置节点中的分类数据也可以设置颜色增强区分度 |
| 适合的数据条数 | 不少于 2 条数据 |
环形弧长连接图
| 图表类型 | 环形弧长连接图 |
|---|---|
| 适合的数据 | 列表:一组节点数据(包含节点 id 字段)、一组链接数据(包含源节点字段和目标节点字段) |
| 功能 | 表示数据之间的链接关系 |
| 数据与图形的映射 | 节点的坐标(自动计算)字段映射到节点的坐标轴的位置链接的坐标(自动计算)映射到以圆心为控制点的贝塞尔曲线的顶点坐标轴位置节点中的分类数据也可以设置颜色增强区分度 |
| 适合的数据条数 | 不少于 5 条节点数据 |
弧长连接图的应用场景
适合的场景
例子 1: 表达数据之间的关系,以及关系的重要性
下图这个网络代表了维克多·雨果的经典小说"Les Misérables"中的人物关系。
节点数据:
| name | group | id |
|---|---|---|
| Myriel | 1 | 0 |
| ... | ... | ... |
链接数据:
| source | target | value |
|---|---|---|
| 1 | 0 | 1 |
| ... | ... | ... |
说明:
group字段,使用了颜色用于区分不同的节点类型value字段,使用弧线粗细表示关系的强度
例子 2: 环形布局展示复杂关系网络
使用极坐标系可以将例 1 的数据绘制成环形弧长连接图,更适合展示具有大量节点和复杂关系的网络数据。
不适合的场景
例子 1: 不适合表示层次结构
弧长连接图采用线性或环形的一维布局,无法有效表达数据的层次关系,对于具有明显层级结构的数据,树形图或组织架构图更为合适。
例子 2: 不适合处理过多节点
当节点数量过多时,弧长连接图会变得拥挤难读,连线重叠严重,影响可读性。此时应考虑使用力导向图或其他网络图布局。
弧长连接图与其他图表的对比
弧长连接图和[和弦图](/zh/charts/chord/)
- 弧长连接图的节点使用标准线性布局,节点权重决定节点大小但不影响位置
- 弧长连接图的连线可以使用权重控制线宽,粗细均匀
- 弧长连接图的连线重叠绘制在节点上
- 和弦图的节点使用权重线性布局,节点权重即决定节点大小,又决定节点位置
- 和弦图的连线使用源权重和目标权重控制线宽,粗细非均匀
- 和弦图的节点宽度为连线宽度之和,节点处的连线平铺不重叠
弧长连接图和[桑基图](/zh/charts/sankey/)
- 弧长连接图主要用于表示节点之间的关系连接,不体现流量或数据流向
- 桑基图专门用于表示数据流,连线宽度表示流量大小,具有明确的流向
- 弧长连接图采用弧形连线,视觉上更加优雅
- 桑基图采用直线或曲线连接,更直观地表达流向关系
相似图表
相似图表
分类
Site Docs Charts Area.En (`site/docs/charts/area.en.mdx`)
title: Area Chart sidebar: { icon: 'area' } order: 3 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*ZxtyTrhyN4sAAAAAAAAAAAAADmJ7AQ/original' category: ['trend'] similar: ['line', 'stacked-area']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Area Charts
Area charts build upon line charts by filling the area between the line and the coordinate axis, emphasizing the magnitude of change in trends. Area charts can better showcase the peaks and valleys in trend changes, using the visual effect of filled regions to emphasize how quantities change over time.
Area charts are particularly suitable for displaying continuous time series data, intuitively expressing the trends of data changes while emphasizing changes in total volume within certain intervals through the visual effect of the filled area.
When you need to display data from multiple series simultaneously, you can use stacked area charts or percentage stacked area charts to compare the proportion of each category in the total and how these proportions change over time.
Other Names: Area Chart, Area Graph
Components of an Area Chart
Basic Area Chart
| Chart Type | Basic Area Chart |
|---|---|
| Suitable Data | Time series data: one ordered/continuous data field (usually time), one continuous data field |
| Function | Display data trends over time or ordered dimensions |
| Data-to-Visual Mapping | Time field mapped to horizontal axis positionValue field mapped to vertical axis heightArea fill emphasizes the degree of data change |
| Suitable Scenarios | Trend changes of a single data series over time |
Stacked Area Chart
| Chart Type | Stacked Area Chart |
|---|---|
| Suitable Data | Multi-series time data: one ordered/continuous data field (usually time), one continuous data field, one categorical data field |
| Function | Display trends of multiple data series over time and their stacked total |
| Data-to-Visual Mapping | Time field mapped to horizontal axis positionValue field mapped to vertical axis heightCategory field mapped to different colors and stacked areas |
| Suitable Scenarios | Comparison of multiple data series and their total over time |
Use Cases of Area Charts
Suitable Use Cases
Example 1: Suitable for displaying trends in continuous time series
The chart below is an area chart of stock price trends, showing how a company's stock price changes over time.
| date | close |
|---|---|
| 2015/1/5 | 121.73 |
| 2015/1/6 | 115.07 |
| 2015/1/7 | 116.75 |
| ... | ... |
Notes:
- The
datefield is mapped to the horizontal axis position, indicating the chronological order - The
closefield is mapped to the vertical axis height and filled area, showing price trends over time - Both area fill and line are used to enhance the visual effect, making it easier to observe trend changes
Example 2: Suitable for displaying stacked trends of multiple data series
Stacked area charts can show changes in multiple data series over time, as well as their sum trend. The chart below shows trends in unemployment numbers across different industries.
Notes:
- The
datefield is mapped to the horizontal axis, representing the time dimension - The
unemployedfield is mapped to the vertical axis, representing the number of unemployed people - The
industryfield is mapped to color, distinguishing different industries - The
stackYtransformation is used to display the data series in a stacked manner
Example 3: Percentage stacked area chart for displaying proportion changes
When you need to display how each category's proportion of the total changes over time, percentage stacked area charts are a very suitable choice.
Notes:
- Combining
stackYandnormalizeYtransformations to standardize stacked data as percentages - The vertical axis is formatted to display percentages, more intuitively showing proportion changes in each region
Unsuitable Use Cases
Example 1: Not suitable for comparing precise individual values
Area charts display data changes through filled regions and are not suitable for scenarios requiring precise comparisons of individual values. If the main purpose is to compare specific values across different categories, bar or column charts would be better choices.
Example 2: May cause visual confusion when data fluctuates dramatically
When multiple data series fluctuate dramatically and intersect frequently, using stacked area charts may lead to visual confusion, making it difficult to distinguish specific trend changes in each series. In such cases, consider using multiple line charts or small multiples instead.
Extensions of Area Charts
Range Area Chart
Range area charts can represent upper and lower limits of data, commonly used to show data uncertainty or fluctuation ranges.
Notes:
- Using
y: ['low', 'high']to specify the upper and lower bounds of the range - The data range uses fill color with lower opacity to highlight the uncertainty range
Difference Area Chart
Difference area charts are used to compare two data series, highlighting the difference areas between them.
Notes:
- Using
transform: [{ type: 'diffY' }]to achieve the difference effect - Color encoding distinguishes between the two data series and highlights the difference area between them
Comparing Area Charts to Other Charts
Area Charts, [Line Charts](/en/charts/line/), and [Pie Charts](/en/charts/pie/)
- Area charts and line charts are both suitable for showing trend changes in continuous data
- Area charts emphasize the visual effect of quantity through filled areas, making them more suitable for showing changes in total volume
- Line charts are more suitable for showing accurate change trajectories and comparing multiple data lines
- Pie charts focus on showing proportion relationships at a specific point in time, rather than changes over time
Area Charts and [Stacked Area Charts](/en/charts/stacked-area/)
- Basic area charts are suitable for trend display of a single data series
- Stacked area charts are suitable for displaying multiple data series and their sum
Similar Charts
Categories
Site Docs Charts Area.Zh (`site/docs/charts/area.zh.mdx`)
title: 面积图 sidebar: { icon: 'area' } order: 3 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*ZxtyTrhyN4sAAAAAAAAAAAAADmJ7AQ/original' category: ['trend'] similar: ['line', 'stacked-area']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
面积图的简介
面积图是在折线图的基础上,将折线与坐标轴之间的区域进行填充,用于强调数量的变化趋势。面积图可以更好地展示趋势变化中的峰谷,使用填充区域的视觉效果,强调数量随时间变化的程度。
面积图特别适合展示连续的时间序列数据,可以直观地表达数据变化的趋势,同时通过面积的视觉效果,强调总量在某个区间内的变化情况。
当需要同时展示多个序列的数据时,可以使用堆叠面积图或者百分比堆叠面积图,用于比较各个类别的数据在总数中的占比及其随时间的变化。
英文名:Area Chart, Area Graph
面积图的构成
基础面积图
| 图表类型 | 基础面积图 |
|---|---|
| 适合的数据 | 时间序列数据:一个有序/连续数据字段(通常是时间)、一个连续数据字段 |
| 功能 | 展示数据随时间或有序维度的变化趋势 |
| 数据与图形的映射 | 时间字段映射到横轴的位置数值字段映射到纵轴的高度面积填充强调数据变化的程度 |
| 适合的场景 | 单一数据系列随时间的变化趋势 |
堆叠面积图
| 图表类型 | 堆叠面积图 |
|---|---|
| 适合的数据 | 多序列时间数据:一个有序/连续数据字段(通常是时间)、一个连续数据字段、一个分类数据字段 |
| 功能 | 展示多个数据系列随时间变化的趋势及其叠加总量 |
| 数据与图形的映射 | 时间字段映射到横轴的位置数值字段映射到纵轴的高度分类字段映射到不同的颜色和堆叠区域 |
| 适合的场景 | 多数据系列及其总量随时间的变化趋势对比 |
面积图的应用场景
适合的场景
例子 1: 适合展示连续时间序列的趋势
下图是一个股票价格走势的面积图,展示了某公司股票价格随时间的变化趋势。
| date(日期) | close(收盘价) |
|---|---|
| 2015/1/5 | 121.73 |
| 2015/1/6 | 115.07 |
| 2015/1/7 | 116.75 |
| ... | ... |
说明 :
date字段,映射到横轴的位置,表示时间的先后顺序close字段,映射到纵轴的高度和填充面积,展示了价格随时间的变化趋势- 同时使用面积填充和线条,增强了视觉效果,方便观察变化趋势
例子 2: 适合展示多个数据系列的堆叠趋势
堆叠面积图可以同时展示多个数据系列随时间的变化,以及它们的总和趋势。下图展示了不同行业失业人数的变化趋势。
说明:
date字段映射到横轴,表示时间维度unemployed字段映射到纵轴,表示失业人数industry字段映射到颜色,区分不同行业- 使用
stackY转换将各系列数据堆叠显示
例子 3: 百分比堆叠面积图展示占比变化
当需要展示各类别在总体中的占比随时间的变化时,百分比堆叠面积图是非常合适的选择。
说明:
- 组合使用
stackY和normalizeY转换,将堆叠数据标准化为百分比 - 纵轴格式化为百分比显示,更直观地表示各区域的占比变化
不适合的场景
例子 1: 不适合比较精确的单一数值
面积图通过填充区域的方式展示数据变化,不适合用于需要精确比较单一数值的场景。如果主要目的是比较不同类别的具体数值,柱状图或条形图会是更好的选择。
例子 2: 数据波动剧烈时可能造成视觉混乱
当多个数据系列波动剧烈且交叉频繁时,使用堆叠面积图可能会导致视觉混乱,难以辨别各个系列的具体变化趋势。这种情况下,可以考虑使用多条折线图或小型多图表示。
面积图的扩展
区间面积图
区间面积图可以表示数据的上下限范围,通常用于表示数据的不确定性或波动范围。
说明:
- 使用
'y', ['low', 'high']指定区间的上下界 - 数据区间使用透明度较低的填充色,突出显示不确定性范围
差分面积图
差分面积图用于比较两个数据系列,突出它们之间的差异区域。
说明:
- 使用
transform: [{ type: 'diffY' }]实现差分效果 - 颜色编码区分了两个数据系列,并突出了它们的差异区域
面积图与其他图表的对比
面积图和[折线图](/zh/charts/line/)
- 面积图和折线图都适合展示连续数据的变化趋势
- 面积图通过填充区域强调数量的视觉效果,更适合展示总量变化
- 折线图更适合展示准确的变化轨迹和多条数据线的比较
面积图和[柱状图](/zh/charts/bar/)、[饼图](/zh/charts/pie/)
- 面积图侧重展示随时间变化的趋势和总量,强调变化过程
- 柱状图侧重于不同分类之间数值大小的比较,强调对比关系
- 饼图侧重展示在特定时间点上的占比关系,而非随时间的变化
面积图与[堆叠面积图](/zh/charts/stacked-area/)
- 基础面积图适合单一数据系列的趋势展示
- 堆叠面积图适合多数据系列及其总和的展示
相似图表
分类
Site Docs Charts Bar.En (`site/docs/charts/bar.en.mdx`)
title: Bar Chart sidebar: { icon: 'column' } order: 2 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*kvZLSLxjnkIAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison'] similar: ['histogram', 'multi-set-bar', 'stacked-bar', 'radial-bar']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Bar Charts
A typical bar chart, also known as a column chart, uses vertical or horizontal bars to display comparisons between different categories. One axis represents the categories being compared, while the other axis denotes the corresponding values.
Unlike histograms, bar charts cannot show changes in data across a continuous range. Instead, they represent categorical data and answer the question: "How many are there in each category?"
It’s important to note that bar charts can become cluttered when displaying too many categories, leading to overlapping labels and legibility issues. We'll demonstrate this below.
English Names: Column Chart, Bar Chart
Components of a Bar Chart
Vertical Bar Chart
| Chart Type | Vertical Bar Chart |
|---|---|
| Suitable Data | A dataset containing one categorical field and one numerical field |
| Functionality | Compares the size of numerical values across categories |
| Data Mapping | Categorical data maps to the horizontal axis positionNumerical data maps to bar heightCategorical data can also map to color for better category distinction |
| Data Size Limit | Recommended for no more than 12 data points |
Horizontal Bar Chart
| Chart Type | Horizontal Bar Chart |
|---|---|
| Suitable Data | A dataset containing one categorical field and one numerical field |
| Functionality | Compares the size of numerical values across categories |
| Data Mapping | Categorical data maps to the vertical axisNumerical data maps to bar width |
| Data Size Limit | Recommended for no more than 30 data points |
Use Cases for Bar Charts
Appropriate Use Cases
Example 1: Comparing Categorical Data
The chart below compares the sales of different game genres.
| Genre | Sales |
|---|---|
| Sports | 27,500 |
| Strategy | 11,500 |
| Action | 6,000 |
| Shooter | 3,500 |
| Other | 1,500 |
Explanation:
- The
genrefield maps to both position and color, differentiating game categories. - The
soldfield maps to the bar length to represent sales volume.
Inappropriate Use Cases
Example 1: Too Many Categories for a Vertical Bar Chart
When comparing population sizes across provinces, too many categories can cause text overlap issues, making labels harder to read. In such cases, horizontal bar charts are more effective.
| Province | Population |
|---|---|
| Beijing | 19,612,368 |
| Tianjin | 12,938,693 |
| Hebei | 71,854,210 |
| ... | ... |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ province: 'Beijing', population: 19612368 },
{ province: 'Tianjin', population: 12938693 },
{ province: 'Hebei', population: 71854210 },
{ province: 'Shanxi', population: 27500000 },
{ province: 'Inner Mongolia', population: 24706291 },
{ province: 'Liaoning', population: 43746323 },
{ province: 'Jilin', population: 27452815 },
{ province: 'Heilongjiang', population: 38313991 },
{ province: 'Shanghai', population: 23019196 },
{ province: 'Jiangsu', population: 78660941 },
{ province: 'Zhejiang', population: 54426891 },
{ province: 'Anhui', population: 59500468 },
{ province: 'Fujian', population: 36894217 },
{ province: 'Jiangxi', population: 44567797 },
{ province: 'Shandong', population: 95792719 },
{ province: 'Henan', population: 94029939 },
{ province: 'Hubei', population: 57237727 },
{ province: 'Hunan', population: 65700762 },
{ province: 'Guangdong', population: 104320459 },
{ province: 'Guangxi', population: 46023761 },
{ province: 'Hainan', population: 8671485 },
{ province: 'Chongqing', population: 28846170 },
{ province: 'Sichuan', population: 80417528 },
{ province: 'Guizhou', population: 34748556 },
{ province: 'Yunnan', population: 45966766 },
{ province: 'Tibet', population: 3002165 },
{ province: 'Shaanxi', population: 37327379 },
{ province: 'Gansu', population: 25575263 },
{ province: 'Qinghai', population: 5626723 },
],
encode: { x: 'province', y: 'population' },
axis: {
y: {
title: null,
},
x: {
title: null,
labelFontSize: 12,
size: 100, // Size must be set
labelAutoEllipsis: {
suffix: '..',
minLength: 8,
maxLength: 12,
},
labelAutoWrap: {
wordWrapWidth: 80,
maxLines: 2,
recoverWhenFailed: true,
},
labelAutoRotate: {
optionalAngles: [0, 45, 90], // Attempt to rotate by 0 degrees, 45 degrees, or 90 degrees
recoverWhenFailed: true, // If rotation fails, revert to the default angle
},
labelAutoHide: {
keepHeader: true, // Retain the first tick label
keepTail: true, // Retain the last tick label
},
}, },
interaction: [
{
type: 'elementHighlight',
background: true,
region: true,
},
],
});
chart.render();
`} />
Switching to a horizontal bar chart makes labels easier to read, as shown below:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ province: 'Beijing', population: 19612368 },
{ province: 'Tianjin', population: 12938693 },
{ province: 'Hebei', population: 71854210 },
{ province: 'Shanxi', population: 27500000 },
{ province: 'Inner Mongolia', population: 24706291 },
{ province: 'Liaoning', population: 43746323 },
{ province: 'Jilin', population: 27452815 },
{ province: 'Heilongjiang', population: 38313991 },
{ province: 'Shanghai', population: 23019196 },
{ province: 'Jiangsu', population: 78660941 },
{ province: 'Zhejiang', population: 54426891 },
{ province: 'Anhui', population: 59500468 },
{ province: 'Fujian', population: 36894217 },
{ province: 'Jiangxi', population: 44567797 },
{ province: 'Shandong', population: 95792719 },
{ province: 'Henan', population: 94029939 },
{ province: 'Hubei', population: 57237727 },
{ province: 'Hunan', population: 65700762 },
{ province: 'Guangdong', population: 104320459 },
{ province: 'Guangxi', population: 46023761 },
{ province: 'Hainan', population: 8671485 },
{ province: 'Chongqing', population: 28846170 },
{ province: 'Sichuan', population: 80417528 },
{ province: 'Guizhou', population: 34748556 },
{ province: 'Yunnan', population: 45966766 },
{ province: 'Tibet', population: 3002165 },
{ province: 'Shaanxi', population: 37327379 },
{ province: 'Gansu', population: 25575263 },
{ province: 'Qinghai', population: 5626723 },
],
encode: { x: 'province', y: 'population' },
coordinate: { transform: [{ type: 'transpose' }] },
axis: {
y: {
title: null,
},
x: {
title: null,
},
},
interaction: [
{
type: 'elementHighlight',
background: true,
region: true,
},
],
});
chart.render();
`} />
Example 2: Not Suitable for Trends
Bar charts use bar length to compare categorical data but are not effective for showing continuous trends.
For instance, a bar chart is less ideal for showing daily stock prices for September 2015 compared to a line chart or area chart.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
data: [
{ day: '2015/9/1', share: 10 },
{ day: '2015/9/2', share: 12 },
{ day: '2015/9/3', share: 11 },
{ day: '2015/9/4', share: 15 },
{ day: '2015/9/5', share: 20 },
{ day: '2015/9/6', share: 22 },
{ day: '2015/9/7', share: 21 },
{ day: '2015/9/8', share: 25 },
{ day: '2015/9/9', share: 31 },
{ day: '2015/9/10', share: 32 },
{ day: '2015/9/11', share: 28 },
{ day: '2015/9/12', share: 29 },
{ day: '2015/9/13', share: 40 },
{ day: '2015/9/14', share: 41 },
{ day: '2015/9/15', share: 45 },
{ day: '2015/9/16', share: 50 },
{ day: '2015/9/17', share: 65 },
{ day: '2015/9/18', share: 45 },
{ day: '2015/9/19', share: 50 },
{ day: '2015/9/20', share: 51 },
{ day: '2015/9/21', share: 65 },
{ day: '2015/9/22', share: 60 },
{ day: '2015/9/23', share: 62 },
{ day: '2015/9/24', share: 65 },
{ day: '2015/9/25', share: 45 },
{ day: '2015/9/26', share: 55 },
{ day: '2015/9/27', share: 59 },
{ day: '2015/9/28', share: 52 },
{ day: '2015/9/29', share: 53 },
{ day: '2015/9/30', share: 40 },
],
encode: { x: 'day', y: 'share' },
axis: {
y: {
title: null,
},
x: {
title: null,
tickFilter: (_, i) => i % 2 !== 0, // Filter the tick marks on the x-axis to display only every other tick.
},
},
children: [
{
type: 'area',
style: {
opacity: 0.6,
},
},
{
type: 'line',
style: {
lineWidth: 3,
},
},
],
});
chart.render();
`} />
Comparing Bar Charts to Other Charts
Bar Charts, [Line Charts](/en/charts/line/), and [Pie Charts](/en/charts/pie/)
- Bar charts are primarily used to compare data (such as size or values) across multiple categories.
- Line charts are mainly used to show trends in continuous data (e.g., time) or ordered categories.
- Pie charts are used to display the proportion of each category relative to the whole.
Bar Charts and Nightingale Charts (Rose Diagrams)
- A Nightingale chart (rose diagram) compares data using the size of the radius.
- A bar chart compares data based on the length of the bars.
Related Charts
Categories
Site Docs Charts Bar.Zh (`site/docs/charts/bar.zh.mdx`)
title: 柱状图 sidebar: { icon: 'column' } order: 2 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*kvZLSLxjnkIAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison'] similar: ['histogram', 'multi-set-bar', 'stacked-bar', 'radial-bar']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
柱状图的简介
典型的柱状图(又名条形图),使用垂直或水平的柱子显示类别之间的数值比较。其中一个轴表示需要对比的分类维度,另一个轴代表相应的数值。
柱状图有别于直方图,柱状图无法显示数据在一个区间内的连续变化趋势。柱状图描述的是分类数据,回答的是每一个分类中“有多少?”这个问题。
需要注意的是,当柱状图显示的分类很多时会导致分类名层叠等显示问题,下面我们会举例说明。
英文名:Column chart, Bar chart
柱状图的构成
纵向柱状图
| 图表类型 | 纵向柱状图 |
|---|---|
| 适合的数据 | 列表:一个分类数据字段、一个连续数据字段 |
| 功能 | 对比分类数据的数值大小 |
| 数据与图形的映射 | 分类数据字段映射到横轴的位置连续数据字段映射到矩形的高度 分类数据也可以设置颜色增强分类的区分度 |
| 适合的数据条数 | 不超过 12 条数据 |
横向柱状图 (条形图)
| 图表类型 | 横向柱状图 |
|---|---|
| 适合的数据 | 列表:一个分类数据字段、一个连续数据字段 |
| 功能 | 对比分类数据的数值大小 |
| 数据与图形的映射 | 分类数据字段映射到纵轴的位置连续数据字段映射到矩形的宽度 |
| 适合的数据条数 | 不超过 30 条数据 |
柱状图的应用场景
适合的场景
例子 1: 适合应用到分类数据对比
下图是一个游戏销量的图表,展示不同游戏类型的销量对比。
| genre(游戏类型) | sold(销售量) |
|---|---|
| Sports | 27,500 |
| Strategy | 11,500 |
| Action | 6,000 |
| Shooter | 3,500 |
| Other | 1,500 |
说明 :
genre字段,同时使用了位置和颜色用于区分不同的游戏类型sold字段,使用矩形的长度,表示销售量的大小
不适合的场景
例子 1: 分类太多不适合使用纵向柱状图
如对比不同省份的人口数量。分类情况过多时,柱状图的文本为了排布合理,需要进行旋转,不利于阅读,相比于纵向柱状图,横向柱状图更适用于此类分类较多的场景。
| province(省份) | population(人口数量) |
|---|---|
| 北京市 | 19,612,368 |
| 天津市 | 12,938,693 |
| 河北省 | 71,854,210 |
| ... | ... |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ province: '北京市', population: 19612368 },
{ province: '天津市', population: 12938693 },
{ province: '河北省', population: 71854210 },
{ province: '山西省', population: 27500000 },
{ province: '内蒙古自治区', population: 24706291 },
{ province: '辽宁省', population: 43746323 },
{ province: '吉林省', population: 27452815 },
{ province: '黑龙江省', population: 38313991 },
{ province: '上海市', population: 23019196 },
{ province: '江苏省', population: 78660941 },
{ province: '浙江省', population: 54426891 },
{ province: '安徽省', population: 59500468 },
{ province: '福建省', population: 36894217 },
{ province: '江西省', population: 44567797 },
{ province: '山东省', population: 95792719 },
{ province: '河南省', population: 94029939 },
{ province: '湖北省', population: 57237727 },
{ province: '湖南省', population: 65700762 },
{ province: '广东省', population: 104320459 },
{ province: '广西壮族自治区', population: 46023761 },
{ province: '海南省', population: 8671485 },
{ province: '重庆市', population: 28846170 },
{ province: '四川省', population: 80417528 },
{ province: '贵州省', population: 34748556 },
{ province: '云南省', population: 45966766 },
{ province: '西藏自治区', population: 3002165 },
{ province: '陕西省', population: 37327379 },
{ province: '甘肃省', population: 25575263 },
{ province: '青海省', population: 5626723 },
],
encode: { x: 'province', y: 'population' },
axis: {
y: {
title: null,
},
x: {
title: null,
labelFontSize: 12,
size: 100, // 必须设置 size
labelAutoEllipsis: {
suffix: '..',
minLength: 8,
maxLength: 12,
},
labelAutoWrap: {
wordWrapWidth: 80,
maxLines: 2,
recoverWhenFailed: true,
},
labelAutoRotate: {
optionalAngles: [0, 45, 90], // 尝试旋转 0 度、45 度、90 度
recoverWhenFailed: true, // 如果旋转后无法解决问题,恢复到默认角度
},
labelAutoHide: {
keepHeader: true, // 保留第一个刻度值
keepTail: true, // 保留最后一个刻度值
},
}, },
interaction: [
{
type: 'elementHighlight',
background: true,
region: true,
},
],
});
chart.render();
`} />
使用横向柱状图,文本可以横向排布,便于用户的阅读,效果如下:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ province: '北京市', population: 19612368 },
{ province: '天津市', population: 12938693 },
{ province: '河北省', population: 71854210 },
{ province: '山西省', population: 27500000 },
{ province: '内蒙古自治区', population: 24706291 },
{ province: '辽宁省', population: 43746323 },
{ province: '吉林省', population: 27452815 },
{ province: '黑龙江省', population: 38313991 },
{ province: '上海市', population: 23019196 },
{ province: '江苏省', population: 78660941 },
{ province: '浙江省', population: 54426891 },
{ province: '安徽省', population: 59500468 },
{ province: '福建省', population: 36894217 },
{ province: '江西省', population: 44567797 },
{ province: '山东省', population: 95792719 },
{ province: '河南省', population: 94029939 },
{ province: '湖北省', population: 57237727 },
{ province: '湖南省', population: 65700762 },
{ province: '广东省', population: 104320459 },
{ province: '广西壮族自治区', population: 46023761 },
{ province: '海南省', population: 8671485 },
{ province: '重庆市', population: 28846170 },
{ province: '四川省', population: 80417528 },
{ province: '贵州省', population: 34748556 },
{ province: '云南省', population: 45966766 },
{ province: '西藏自治区', population: 3002165 },
{ province: '陕西省', population: 37327379 },
{ province: '甘肃省', population: 25575263 },
{ province: '青海省', population: 5626723 },
],
encode: { x: 'province', y: 'population' },
coordinate: { transform: [{ type: 'transpose' }] },
axis: {
y: {
title: null,
},
x: {
title: null,
},
},
interaction: [
{
type: 'elementHighlight',
background: true,
region: true,
},
],
});
chart.render();
`} />
例子 2: 不适合表示趋势
柱状图使用矩形的长度(宽度)来对比分类数据的大小,非常方便临近的数据进行大小的对比,不适合展示连续数据的趋势。下图本想展示 ACME 这只股票在 2015 年 9 月份整个月的每日的价格走势,但是效果不尽人意。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
data: [
{ day: '2015/9/1', share: 10 },
{ day: '2015/9/2', share: 12 },
{ day: '2015/9/3', share: 11 },
{ day: '2015/9/4', share: 15 },
{ day: '2015/9/5', share: 20 },
{ day: '2015/9/6', share: 22 },
{ day: '2015/9/7', share: 21 },
{ day: '2015/9/8', share: 25 },
{ day: '2015/9/9', share: 31 },
{ day: '2015/9/10', share: 32 },
{ day: '2015/9/11', share: 28 },
{ day: '2015/9/12', share: 29 },
{ day: '2015/9/13', share: 40 },
{ day: '2015/9/14', share: 41 },
{ day: '2015/9/15', share: 45 },
{ day: '2015/9/16', share: 50 },
{ day: '2015/9/17', share: 65 },
{ day: '2015/9/18', share: 45 },
{ day: '2015/9/19', share: 50 },
{ day: '2015/9/20', share: 51 },
{ day: '2015/9/21', share: 65 },
{ day: '2015/9/22', share: 60 },
{ day: '2015/9/23', share: 62 },
{ day: '2015/9/24', share: 65 },
{ day: '2015/9/25', share: 45 },
{ day: '2015/9/26', share: 55 },
{ day: '2015/9/27', share: 59 },
{ day: '2015/9/28', share: 52 },
{ day: '2015/9/29', share: 53 },
{ day: '2015/9/30', share: 40 },
],
encode: { x: 'day', y: 'share' },
axis: {
y: {
title: null,
},
x: {
title: null,
tickFilter: (_, i) => i % 2 !== 0, // 过滤 x 轴刻度线,只显示每隔 1 个刻度线
},
},
children: [
{
type: 'area',
style: {
opacity: 0.6,
},
},
{
type: 'line',
style: {
lineWidth: 3,
},
},
],
});
chart.render();
`} />
柱状图与其他图表的对比
柱状图和[折线图](/zh/charts/line/)、[饼图](/zh/charts/pie/)
- 柱状图主要用于多个分类间的数据(大小、数值)的对比
- 折线图主要用于展示连续数值(例如时间)或者有序分类的变化趋势
- 饼图主要是展示分类之间的占比情况
柱状图和南丁格尔图(玫瑰图)
- 南丁格尔图(玫瑰图)通过半径的大小来对比数据
- 柱状图根据矩形的长度来对比数据
相似图表
分类
Site Docs Charts Bi Directional Bar.En (`site/docs/charts/bi-directional-bar.en.mdx`)
title: Bi-directional Bar Chart sidebar: { icon: 'bar' } order: 4 screenshot: 'https://zos.alipayobjects.com/rmsportal/CyErnoithFpAiLIqgfac.png' category: ['comparison'] similar: ['bar', 'multi-set-bar', 'radial-bar', 'stacked-bar']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Bi-directional Bar Chart
Bi-directional Bar Chart (also known as Positive-Negative Bar Chart) uses positive and negative bars to display numerical comparisons between categories. The categorical axis represents the dimensions to be compared, while the continuous axis represents the corresponding values. There are two cases: one where the positive and negative scales are completely symmetrical, and another where they are inversely symmetrical (i.e., opposites).
Other Names: Bi-Directional Bar,Bi-Directional Column
Composition of Bi-directional Bar Chart
| Chart Type | Bi-directional Bar Chart |
|---|---|
| Suitable Data | List: one categorical field, two continuous fields |
| Function | Compare numerical values across categories |
| Data Mapping | Categorical field maps to position on categorical axis; one continuous field maps to length of positive bars; another continuous field maps to length of negative bars; positive/negative data can be distinguished by color or shape; categorical data can use color to enhance distinction |
| Recommended Data Count | No more than 30 items horizontally, 12 items vertically |
Use Cases of Bi-directional Bar Chart
Suitable Use Cases
Example 1: Positive-Negative Category Comparison
The chart below simulates completion status of tasks by different departments in a company, with completed counts shown as positive bars and uncompleted counts as negative bars.
| Department | Group | Completed | Uncompleted |
|---|---|---|---|
| Dept 0 | Group0 | 37 | 9 |
| ... | ... | ... | ... |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
});
const data = [
{ department: 'Dept 0', group: 'Group0', people: 37, type: 'completed' },
{ department: 'Dept 0', group: 'Group0', people: 9, type: 'uncompleted' },
{ department: 'Dept 0', group: 'Group1', people: 27, type: 'completed' },
{ department: 'Dept 0', group: 'Group1', people: 10, type: 'uncompleted' },
{ department: 'Dept 1', group: 'Group2', people: 37, type: 'completed' },
{ department: 'Dept 1', group: 'Group2', people: 19, type: 'uncompleted' },
{ department: 'Dept 1', group: 'Group3', people: 37, type: 'completed' },
{ department: 'Dept 1', group: 'Group3', people: 29, type: 'uncompleted' },
{ department: 'Dept 2', group: 'Group4', people: 20, type: 'completed' },
{ department: 'Dept 2', group: 'Group4', people: 2, type: 'uncompleted' },
{ department: 'Dept 2', group: 'Group5', people: 40, type: 'completed' },
{ department: 'Dept 2', group: 'Group5', people: 10, type: 'uncompleted' },
{ department: 'Dept 3', group: 'Group6', people: 25, type: 'completed' },
{ department: 'Dept 3', group: 'Group6', people: 3, type: 'uncompleted' },
{ department: 'Dept 3', group: 'Group7', people: 55, type: 'completed' },
{ department: 'Dept 3', group: 'Group7', people: 8, type: 'uncompleted' },
];
const range = ['#7593ed', '#95e3b0', '#6c7893', '#e7c450', '#7460eb'];
chart.options({
type: 'interval',
coordinate: { transform: [{ type: 'transpose' }] },
autoFit: true,
data: data,
encode: {
x: 'group',
y: (d) => (d.type === 'completed' ? d.people : -d.people),
color: 'department',
},
scale: {
x: { padding: 0.5 },
color: {
type: 'ordinal',
range,
},
},
axis: {
x: { title: '' },
y: {
labelFormatter: (d) => {
return Math.abs(d);
},
},
},
style: {
fill: ({ type }, i, data) => {
if (type === 'uncompleted') {
return 'transparent';
}
},
stroke: (d, i, data, ...re) => {
const { type } = d;
if (type === 'uncompleted') {
return range[i / 2];
}
},
lineWidth: 2,
},
tooltip: {
title: (d) => {
return `${d.department}-${d.group}`;
},
items: [
(d, i, data, column) => ({
name: d.type === 'completed' ? 'Completed' : 'Uncompleted',
value: d.people,
}),
],
},
});
chart.render();
`} />
Explanation:
- Used
colorto distinguish different departments - Used
shape(hollow vs solid) to distinguish completed vs uncompleted counts - Used
positionto distinguish different groups
Unsuitable Use Cases
Bi-directional bar charts are not suitable for data without opposite meanings
Extensions of Bi-directional Bar Chart
Example 1: Stacked Bi-directional Bar Chart
The chart below shows statistics of agreement levels for different types of people on a certain question, divided into five levels: Strongly disagree, Disagree, Neither agree nor disagree, Agree and Strongly agree. The negative levels are shown as negative bars with different colors. Sample data
| type | Strongly agree | Agree | Neither agree nor disagree | Disagree | Strongly disagree |
|---|---|---|---|---|---|
| Question 1 | 11.7 | 59.9 | 18.5 | 9.1 | 0.7 |
| ... | ... | ... | ... | ... | ... |
Explanation:
- Used
colorto distinguish different agreement levels - Used
positionto distinguish different questions
Comparing Bi-directional Bar Chart to Other Charts
Bi-directional Bar Chart vs [Bar Chart](/en/charts/bar/)
- Bar charts can only plot on one axis, with each bar representing one data point
- Bi-directional bar charts contain both positive and negative axis, with each bar potentially representing both positive and negative data
Similar Charts
Categories
Site Docs Charts Bi Directional Bar.Zh (`site/docs/charts/bi-directional-bar.zh.mdx`)
title: 双向柱状图 sidebar: { icon: 'bar' } order: 4 screenshot: 'https://zos.alipayobjects.com/rmsportal/CyErnoithFpAiLIqgfac.png' category: ['comparison'] similar: ['bar', 'multi-set-bar', 'radial-bar', 'stacked-bar']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
双向柱状图的简介
双向柱状图(又名正负条形图),使用正向和反向的柱子显示类别之间的数值比较。其中分类轴表示需要对比的分类维度,连续轴代表相应的数值,分为两种情况,一种是正向刻度值与反向刻度值完全对称,另一种是正向刻度值与反向刻度值反向对称,即互为相反数。
英文名:Bi-Directional Bar,Bi-Directional Column
双向柱状图的构成
| 图表类型 | 双向柱状图 |
|---|---|
| 适合的数据 | 列表:一个分类数据字段、两个连续数据字段 |
| 功能 | 对比分类数据的数值大小 |
| 数据与图形的映射 | 分类数据字段映射到分类轴的位置;一个连续数据字段映射到正向矩形的长度;另一个连续数据字段映射到反向矩形的长度;正反向数据可以设置颜色或形状(shape)增强区分度;分类数据可以设置颜色增强分类的区分度 |
| 适合的数据条数 | 横向不超过 30 条数据、纵向不超过 12 条数据 |
双向柱状图的应用场景
适合的场景
例子 1: 正反分类数据对比
下图是模拟某个公司各个部门对某项任务的完成情况数据的对比图,完成人数使用正向柱状图表示、未完成人数使用反向柱状图表示。
| 部门 | 小组 | 完成人数 | 未完成人数 |
|---|---|---|---|
| 部门 0 | 组名 0 | 37 | 9 |
| ... | ... | ... | ... |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
});
const data = [
{ department: '部门 0', group: '组名0', people: 37, type: 'completed' },
{ department: '部门 0', group: '组名0', people: 9, type: 'uncompleted' },
{ department: '部门 0', group: '组名1', people: 27, type: 'completed' },
{ department: '部门 0', group: '组名1', people: 10, type: 'uncompleted' },
{ department: '部门 1', group: '组名2', people: 37, type: 'completed' },
{ department: '部门 1', group: '组名2', people: 19, type: 'uncompleted' },
{ department: '部门 1', group: '组名3', people: 37, type: 'completed' },
{ department: '部门 1', group: '组名3', people: 29, type: 'uncompleted' },
{ department: '部门 2', group: '组名4', people: 20, type: 'completed' },
{ department: '部门 2', group: '组名4', people: 2, type: 'uncompleted' },
{ department: '部门 2', group: '组名5', people: 40, type: 'completed' },
{ department: '部门 2', group: '组名5', people: 10, type: 'uncompleted' },
{ department: '部门 3', group: '组名6', people: 25, type: 'completed' },
{ department: '部门 3', group: '组名6', people: 3, type: 'uncompleted' },
{ department: '部门 3', group: '组名7', people: 55, type: 'completed' },
{ department: '部门 3', group: '组名7', people: 8, type: 'uncompleted' },
];
const range = ['#7593ed', '#95e3b0', '#6c7893', '#e7c450', '#7460eb'];
chart.options({
type: 'interval',
coordinate: { transform: [{ type: 'transpose' }] },
autoFit: true,
data: data,
encode: {
x: 'group',
y: (d) => (d.type === 'completed' ? d.people : -d.people),
color: 'department',
},
scale: {
x: { padding: 0.5 },
color: {
type: 'ordinal',
range,
},
},
axis: {
x: { title: '' },
y: {
labelFormatter: (d) => {
return Math.abs(d);
},
},
},
style: {
fill: ({ type }, i, data) => {
if (type === 'uncompleted') {
return 'transparent';
}
},
stroke: (d, i, data, ...re) => {
const { type } = d;
if (type === 'uncompleted') {
return range[i / 2];
}
},
lineWidth: 2,
},
tooltip: {
title: (d) => {
return `${d.department}-${d.group}`;
},
items: [
(d, i, data, column) => ({
name: d.type === 'completed' ? '完成' : '未完成',
value: d.people,
}),
],
},
});
chart.render();
`} />
说明 :
- 使用了
颜色用于区分不同的部门 - 使用了
形状(空心和实心)用于区分完成人数和未完成人数 - 使用了
位置用于区分不同小组
不适合的场景
双向柱状图不适合不含相反含义的数据
双向柱状图的扩展
例子 1: 层叠双向柱状图
下图展示了不同类型的人群对某个问题的同意程度的统计数据,分为非常不同意、不同意、没意见、同意和非常同意五种程度,其中非常不同意、不同意和没意见作为反向柱状图,不同程度用不同颜色来表示。虚构数据
| type | Strongly agree | Agree | Neither agree nor disagree | Disagree | Strongly disagree |
|---|---|---|---|---|---|
| Question 1 | 11.7 | 59.9 | 18.5 | 9.1 | 0.7 |
| ... | ... | ... | ... | ... | ... |
说明 :
- 使用了
颜色用于区分不同程度 - 使用了
位置用于区分不同问题
双向柱状图与其他图表的对比
双向柱状图和[柱状图](/zh/charts/bar/)
- 柱状图只能绘制在同一个坐标轴内,每个柱子只能表示一个数据
- 双向柱状图包含正向和反向两个坐标轴,每个柱子可以表示一个正向数据和一个反向数据
相似图表
分类
Site Docs Charts Boxplot.En (`site/docs/charts/boxplot.en.mdx`)
title: Box Plot sidebar: { icon: 'bar' } order: 3 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*yeZuSY9YIEAAAAAAAAAAAAAADmJ7AQ/original' category: ['distribution', 'comparison'] similar: ['histogram', 'bar', 'scatter']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Box Charts
A box plot (also known as a box-and-whisker plot) is a statistical chart used to display the distribution of a dataset. It shows five important statistical values: minimum, first quartile (Q1), median (Q2), third quartile (Q3), and maximum, while clearly identifying outliers in the data.
The box plot's design is simple and clear. Through the combination of boxes and whiskers, it allows for quick understanding of data's central tendency, dispersion, and skewed distribution, making it an important tool in statistical analysis and data exploration.
Other Names: Box-and-Whisker Plot, Box Chart
Components of a Box Chart
Basic Box Plot
| Chart Type | Box Plot |
|---|---|
| Suitable Data | One categorical data field and one continuous data field |
| Functionality | Display data distribution, identify outliers, compare data distributions across different groups |
| Data Mapping | Categorical data maps to horizontal axis positionContinuous data automatically calculates statistics mapped to box componentsOutliers displayed as scatter points |
| Data Size Limit | At least 5-10 data points per group recommended |
The main components of a box plot include:
- Box: A rectangular area from the first quartile (Q1) to the third quartile (Q3), containing the middle 50% of the data
- Median line: A horizontal line inside the box representing the median (Q2) of the data
- Whiskers: Line segments extending from the box, typically extending to the farthest data point within 1.5 times the interquartile range (IQR)
- Outliers: Data points beyond the whisker range, displayed as individual point markers
Use Cases of Box Charts
Suitable Use Cases
Use Case 1: Data Distribution Analysis
Box plots are ideal tools for analyzing data distribution, quickly identifying central tendency, dispersion, and skewed distribution of data.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/penguins.json',
},
encode: {
x: 'species',
y: 'flipper_length_mm',
color: 'species',
},
axis: {
y: {
title: 'Flipper Length (mm)',
},
x: {
title: 'Penguin Species',
},
},
});
chart.render();
`} />
Use Case 2: Outlier Detection
Box plots can visually display outliers in data, helping to identify data points that require further investigation.
Use Case 3: Multi-group Data Comparison
By displaying multiple box plots side by side, you can effectively compare data distribution differences between different groups.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/penguins.json',
},
encode: {
x: 'species',
y: 'flipper_length_mm',
color: 'sex',
series: 'sex',
},
axis: {
y: {
title: 'Flipper Length (mm)',
},
x: {
title: 'Penguin Species',
},
},
});
chart.render();
`} />
Unsuitable Use Cases
Use Case 1: Insufficient Data
When each group has fewer than 5 data points, box plots have limited statistical significance. In such cases, scatter plots or bar charts are recommended.
Use Case 2: Displaying Precise Values
Box plots focus on showing overall characteristics of data distribution and are not suitable for scenarios requiring precise values. In such cases, tables or bar charts should be used.
Use Case 3: Time Series Analysis
For trend analysis of time series data, line charts or area charts are more appropriate.
Extensions of Box Charts
Grouped Box Plots
By setting different colors and series, you can compare data distributions across multiple dimensions within the same chart.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/penguins.json',
},
encode: {
x: 'species',
y: 'body_mass_g',
color: 'sex',
series: 'sex',
},
axis: {
y: {
title: 'Body Mass (g)',
},
x: {
title: 'Penguin Species',
},
},
});
chart.render();
`} />
Horizontal Box Plots
When category labels are too long, horizontal box plots can be used to improve readability.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
coordinate: { transform: [{ type: 'transpose' }] },
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/morley.json',
transform: [{ type: 'filter', callback: (d) => d.Expt <= 3 }],
},
encode: {
x: 'Expt',
y: 'Speed',
color: 'Expt',
},
axis: {
x: {
title: 'Speed of Light Measurement',
},
y: {
title: 'Experiment Number',
},
},
});
chart.render();
`} />
Box Plots Without Outliers
In certain scenarios, outliers can be hidden to focus only on the overall data distribution.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/morley.json',
},
encode: {
x: 'Expt',
y: 'Speed',
},
style: {
point: false,
boxFill: '#52c41a',
boxFillOpacity: 0.4,
},
axis: {
y: {
title: 'Speed of Light Measurement',
},
x: {
title: 'Experiment Number',
},
},
});
chart.render();
`} />
Comparing Box Charts to Other Charts
Box Charts and [Histograms](/en/charts/histogram/)
- Box charts primarily display statistical summaries (five-number summary) of data, suitable for quick comparison across multiple groups
- Histograms show the specific distribution shape of data, suitable for distribution analysis of a single variable
Box Charts and [Bar Charts](/en/charts/bar/)
- Box charts are suitable for displaying data distribution and statistical characteristics
- Bar charts are primarily used to compare numerical values across different categories
Box Charts and [Scatter Plots](/en/charts/scatter-plot/)
- Box charts are suitable for displaying distribution overviews of grouped data
- Scatter plots are suitable for showing specific data point distributions and correlations
Similar Charts
Categories
Site Docs Charts Boxplot.Zh (`site/docs/charts/boxplot.zh.mdx`)
title: 箱形图 sidebar: { icon: 'bar' } order: 3 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*yeZuSY9YIEAAAAAAAAAAAAAADmJ7AQ/original' category: ['distribution', 'comparison'] similar: ['histogram', 'bar', 'scatter']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
箱形图的简介
箱形图(Box Plot),又称盒须图、盒式图或箱线图,是一种用于展示一组数据分布情况的统计图表。它能够显示数据的五个重要统计量:最小值、下四分位数(Q1)、中位数(Q2)、上四分位数(Q3)和最大值,同时可以清楚地识别出数据中的异常值。
箱形图的设计简洁明了,通过箱体和须线的组合,可以快速了解数据的集中趋势、离散程度和偏态分布,是统计分析和数据探索中的重要工具。
英文名:Box Plot, Box-and-Whisker Plot
其他名称:盒须图、盒式图、箱线图
箱形图的构成
基础箱形图
| 图表类型 | 箱形图 |
|---|---|
| 适合的数据 | 一个分类数据字段、一个连续数据字段 |
| 功能 | 展示数据分布情况,识别异常值,比较不同分组的数据分布 |
| 数据与图形的映射 | 分类数据字段映射到横轴位置连续数据字段自动计算统计值映射到箱体各部分异常值显示为散点 |
| 适合的数据条数 | 每个分组建议至少有 5-10 个数据点 |
箱形图的主要组成部分包括:
- 箱体:从下四分位数(Q1)到上四分位数(Q3)的矩形区域,包含了中间 50%的数据
- 中位线:箱体内部的水平线,表示数据的中位数(Q2)
- 须线:从箱体延伸出的线段,通常延伸到 1.5 倍四分位距(IQR)范围内的最远数据点
- 异常值:超出须线范围的数据点,以单独的点标记显示
箱形图的应用场景
适合的场景
场景 1:数据分布分析
箱形图是分析数据分布的理想工具,能够快速识别数据的集中趋势、离散程度和偏态分布。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/penguins.json',
},
encode: {
x: 'species',
y: 'flipper_length_mm',
color: 'species',
},
axis: {
y: {
title: '鳍长 (mm)',
},
x: {
title: '企鹅种类',
},
},
});
chart.render();
`} />
场景 2:异常值检测
箱形图能够直观地显示数据中的异常值,帮助识别需要进一步调查的数据点。
场景 3:多组数据比较
通过并排显示多个箱形图,可以有效地比较不同组别间的数据分布差异。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/penguins.json',
},
encode: {
x: 'species',
y: 'flipper_length_mm',
color: 'sex',
series: 'sex',
},
axis: {
y: {
title: '鳍长 (mm)',
},
x: {
title: '企鹅种类',
},
},
});
chart.render();
`} />
不适合的场景
场景 1:数据量过少
当每个分组的数据点少于 5 个时,箱形图的统计意义不大,建议使用散点图或条形图。
场景 2:展示精确数值
箱形图侧重于显示数据分布的整体特征,不适合需要精确数值的场景,此时应使用表格或条形图。
场景 3:时间序列分析
箱形图的扩展
分组箱形图
通过设置不同的颜色和系列,可以在同一图表中比较多个维度的数据分布。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/penguins.json',
},
encode: {
x: 'species',
y: 'body_mass_g',
color: 'sex',
series: 'sex',
},
axis: {
y: {
title: '体重 (g)',
},
x: {
title: '企鹅种类',
},
},
});
chart.render();
`} />
横向箱形图
当分类标签过长时,可以使用横向箱形图来提高可读性。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
coordinate: { transform: [{ type: 'transpose' }] },
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/morley.json',
transform: [{ type: 'filter', callback: (d) => d.Expt <= 3 }],
},
encode: {
x: 'Expt',
y: 'Speed',
color: 'Expt',
},
axis: {
x: {
title: '光速测量值',
},
y: {
title: '实验编号',
},
},
});
chart.render();
`} />
无异常点箱形图
在某些场景下,可以隐藏异常点,只关注数据的整体分布。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'boxplot',
autoFit: true,
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/morley.json',
},
encode: {
x: 'Expt',
y: 'Speed',
},
style: {
point: false,
boxFill: '#52c41a',
boxFillOpacity: 0.4,
},
axis: {
y: {
title: '光速测量值',
},
x: {
title: '实验编号',
},
},
});
chart.render();
`} />
箱形图与其他图表的对比
箱形图和[直方图](/zh/charts/histogram/)
- 箱形图主要展示数据的统计摘要(五数概括),适合快速比较多个分组
- 直方图展示数据的具体分布形状,适合单个变量的分布分析
箱形图和[柱状图](/zh/charts/bar/)
- 箱形图适合展示数据的分布情况和统计特征
- 柱状图主要用于比较不同分类的数值大小
箱形图和[散点图](/zh/charts/scatter-plot/)
- 箱形图适合展示分组数据的分布概览
- 散点图适合展示具体数据点的分布和相关关系
相似图表
分类
Site Docs Charts Bubble Chart.En (`site/docs/charts/bubble-chart.en.mdx`)
title: Bubble Chart sidebar: { icon: 'scatter' } order: 2 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*z8JFRLxrs_IAAAAAAAAAAAAADmJ7AQ/original' category: ['relation', 'distribution'] similar: ['scatter', 'bubble-map']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Bubble Charts
A bubble chart is a multivariate chart that is a variant of scatter plots and can also be considered a combination of scatter plots and percentage area charts.
The most basic use of bubble charts is to use three values to determine each data series. Like scatter plots, bubble charts map two-dimensional data values to coordinate points on a Cartesian coordinate system, where the X and Y axis represent different two dimensions of data. However, unlike scatter plots, each bubble in a bubble chart has categorical information (they are displayed next to points or as legends). The area of each bubble represents the third numerical data. Additionally, different colors can be used to distinguish categorical data or other numerical data, or brightness or transparency can be used. When representing time-dimensional data, the time dimension can be used as one dimension in the rectangular coordinate system, or combined with animation to show how data changes over time.
Bubble charts are typically used to compare and display relationships between different categories of dots (which we call bubbles here) through the position and area size of bubbles. From an overall perspective, bubble charts can be used to analyze correlations in data.
It should be noted that bubble charts have limited data size capacity, as too many bubbles will make the chart difficult to read. However, this can be compensated by adding some interactive behaviors: hiding some information and displaying it when the mouse clicks or hovers, or adding an option to reorganize or filter grouping categories.
Additionally, the size of bubbles is mapped to area rather than radius or diameter. This is because if it were based on radius or diameter, the size of circles would not only change exponentially but also lead to visual errors.
Other Names: Bubble Chart
Components of a Bubble Chart
Basic Bubble Chart
| Chart Type | Basic Bubble Chart |
|---|---|
| Suitable Data | Multidimensional data: at least two continuous data fields (X, Y axis) and one numerical data field (bubble size) |
| Function | Display relationships between multiple variables, discover data patterns and correlations |
| Data-to-Visual Mapping | Two continuous variables mapped to XY coordinatesThird variable mapped to bubble sizeOptional categorical variable mapped to bubble color or shape |
| Suitable Data Count | Usually not exceeding 100 data points; too many will lead to chart crowding |
| Visual Design Suggestions | Use semi-transparent bubbles to avoid overlap occlusionBubble size range should be moderate, avoiding too large or too smallAdd grid lines to assist in reading coordinate values |
Logarithmic Bubble Chart
| Chart Type | Logarithmic Bubble Chart |
|---|---|
| Suitable Data | Datasets with extreme value differences requiring logarithmic transformation |
| Function | Handling data with large spans, such as population data, GDP data, etc. |
| Data-to-Visual Mapping | Same as basic bubble chart but using logarithmic scaleTwo continuous variables mapped to XY coordinatesThird variable mapped to bubble size through logarithmic transformation |
| Usage Scenario | When data exhibits exponential growth or value ranges spanning multiple orders of magnitude |
| Implementation Method | Using scale: { size: { type: 'log', range: [4, 20] } } to configure logarithmic scale |
| Considerations | Should clearly indicate the use of logarithmic transformation in legends or labels to avoid misleading readers |
Use Cases of Bubble Charts
Suitable Use Cases
Bubble charts are most suitable for the following scenarios:
- Multidimensional Data Analysis - When needing to analyze relationships between three or more variables simultaneously
- Feature Cluster Comparison - Discovering grouping patterns and outliers in data
- Resource Allocation Visualization - Displaying resource distribution under multidimensional metrics
- Risk and Opportunity Analysis - Decision support considering multiple factors simultaneously
Example 1: **Economic and Population Health Indicator Analysis**
The following chart shows the relationship between GDP per capita, life expectancy, and population size of different countries, while using colors to distinguish different continents, effectively presenting four dimensions of data in one chart.
| country | GDP (per capita) | lifeExpectancy | population | continent |
|---|---|---|---|---|
| China | 12547 | 76.9 | 1403500365 | Asia |
| United States | 59532 | 78.5 | 321773631 | Americas |
| India | 6427 | 68.3 | 1324517249 | Asia |
| Japan | 38428 | 83.9 | 127141000 | Asia |
| Germany | 46136 | 81.0 | 82695000 | Europe |
| ... | ... | ... | ... | ... |
Analysis:
- The
GDPfield is mapped to the X axis, representing a country's GDP per capita, showing that developed countries are concentrated on the right - The
LifeExpectancyfield is mapped to the Y axis, representing citizens' life expectancy, allowing observation of a positive correlation between GDP per capita and life expectancy - The
Populationfield is mapped to bubble size, processed with a logarithmic scale, making populous countries like China and India clearly visible - The
continentfield is mapped to color, showing the cluster distribution of countries from different continents
Insights: Through this chart, we can intuitively observe:
- A positive correlation between economic level and health level
- No necessary connection between population size and economic development
- Differences in development patterns among countries from different continents
Unsuitable Use Cases
Example 1: Too Many Data Points or Excessive Bubble Overlap
When data points exceed 100 or bubbles seriously overlap, bubble charts may become chaotic and difficult to read. In such cases, consider using heat maps or faceted charts.
Below is an example of a bubble chart with numerous data points; as the number of data points increases, the overlap between bubbles makes the chart difficult to interpret:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
// Generate 200 random data points
const data = Array.from({ length: 200 }, () => ({
x: Math.random() * 100,
y: Math.random() * 100,
size: Math.random() * 20 + 5,
category: ['A', 'B', 'C', 'D'][Math.floor(Math.random() * 4)],
}));
chart.options({
type: 'point',
autoFit: true,
data,
encode: {
x: 'x',
y: 'y',
size: 'size',
color: 'category',
},
style: {
fillOpacity: 0.3,
lineWidth: 1,
},
});
chart.render();
`} />
Example 2: Only Two Variables Need Comparison
When only comparing the relationship between two variables, a scatter plot is more concise and effective than a bubble chart. The third variable (bubble size) in a bubble chart, if unnecessary, would increase cognitive burden.
Example 3: Displaying Time Series Trend Data
Bubble charts are not suitable for displaying time series trend data. For data that needs to show trends over time, line charts or area charts are better choices.
Below is an example using a line chart instead of a bubble chart to display time series data:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'line',
autoFit: true,
data: [
{ day: '2015/9/1', share: 10, volume: 1200 },
{ day: '2015/9/5', share: 20, volume: 2100 },
{ day: '2015/9/10', share: 32, volume: 3400 },
{ day: '2015/9/15', share: 45, volume: 2900 },
{ day: '2015/9/20', share: 51, volume: 4100 },
{ day: '2015/9/25', share: 45, volume: 3800 },
{ day: '2015/9/30', share: 40, volume: 2700 },
],
encode: { x: 'day', y: 'share' },
axis: {
y: {
title: 'Stock Price',
},
x: {
title: 'Date',
},
},
style: {
lineWidth: 3,
},
});
chart.render();
`} />
If a third dimension of information is indeed needed in time series data, you can use a time series bubble chart with size encoding:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'point',
autoFit: true,
data: [
{ day: '2015/9/1', share: 10, volume: 1200 },
{ day: '2015/9/5', share: 20, volume: 2100 },
{ day: '2015/9/10', share: 32, volume: 3400 },
{ day: '2015/9/15', share: 45, volume: 2900 },
{ day: '2015/9/20', share: 51, volume: 4100 },
{ day: '2015/9/25', share: 45, volume: 3800 },
{ day: '2015/9/30', share: 40, volume: 2700 },
],
encode: {
x: 'day',
y: 'share',
size: 'volume',
},
scale: {
size: { range: [10, 40] },
},
style: {
fillOpacity: 0.6,
stroke: '#1890ff',
fill: '#1890ff',
},
axis: {
y: { title: 'Stock Price' },
x: { title: 'Date' },
},
});
chart.render();
`} />
Comparing Bubble Charts to Other Charts
Bubble Charts, [Scatter Plots](/en/charts/scatter-plot/), and [Heat Maps](/en/charts/heatmap/)
| Chart Type | Main Features | Suitable Scenarios | Data Dimensions |
|---|---|---|---|
| Bubble Chart | Encodes additional dimension through point size | Multivariate relationship analysis | 3-4 variables (X, Y, size, color) |
| Scatter Plot | Only displays point positions | Two-dimensional correlation analysis | 2-3 variables (X, Y, color) |
| Heat Map | Displays density or value through color intensity | Showing distribution density | 3 variables (X, Y, color intensity) |
Bubble Charts, [Scatter Maps](/en/charts/dot-map/), and [Bubble Maps](/en/charts/bubble-map/)
| Chart Type | Coordinate System | Data Constraints | Application Scenarios |
|---|---|---|---|
| Bubble Chart | Abstract coordinate system | Can use any values as XY coordinates | Multidimensional data relationship visualization |
| Bubble Map | Geographic coordinate system | Point positions constrained by geographic coordinates | Multivariate analysis in geographic data |
| Scatter Map | Geographic coordinate system | Point positions constrained by geographic coordinates | Simple distribution of geographic locations |
Similar Charts
Categories
Site Docs Charts Bubble Chart.Zh (`site/docs/charts/bubble-chart.zh.mdx`)
title: 气泡图 sidebar: { icon: 'scatter' } order: 2 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*z8JFRLxrs_IAAAAAAAAAAAAADmJ7AQ/original' category: ['relation', 'distribution'] similar: ['scatter', 'bubble-map']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
气泡图的简介
气泡图是一种多变量图表,是散点图的变体,也可以认为是散点图和百分比区域图的组合。
气泡图最基本的用法是使用三个值来确定每个数据序列,和散点图一样,气泡图将两个维度的数据值分别映射为笛卡尔坐标系上的坐标点,其中 X 和 Y 轴分别代表不同的两个维度的数据,但是不同于散点图的是,气泡图的每个气泡都有分类信息(他们显示在点旁边或者作为图例)。每一个气泡的面积代表第三个数值数据。另外还可以使用不同的颜色来区分分类数据或者其他的数值数据,或者使用亮度或者透明度。表示时间维度的数据时,可以将时间维度作为直角坐标系中的一个维度,或者结合动画来表现数据随着时间的变化情况。
气泡图通常用于比较和展示不同类别圆点(这里我们称为气泡)之间的关系,通过气泡的位置以及面积大小。从整体上看,气泡图可用于分析数据之间的相关性。
需要注意的是,气泡图的数据大小容量有限,气泡太多会使图表难以阅读。但是可以通过增加一些交互行为弥补:隐藏一些信息,当鼠标点击或者悬浮时显示,或者添加一个选项用于重组或者过滤分组类别。
另外,气泡的大小是映射到面积而不是半径或者直径绘制的。因为如果是基于半径或者直径的话,圆的大小不仅会呈指数级变化,而且还会导致视觉误差。
英文名:Bubble Chart
气泡图的构成
基础气泡图
| 图表类型 | 基础气泡图 |
|---|---|
| 适合的数据 | 多维度数据:至少两个连续型数据字段(X、Y 轴)和一个数值型数据字段(气泡大小) |
| 功能 | 展示多个变量之间的关系,发现数据模式和相关性 |
| 数据与图形的映射 | 两个连续变量映射到 XY 坐标第三个变量映射到气泡的大小可选的分类型变量映射到气泡的颜色或形状 |
| 适合的数据条数 | 通常不超过 100 个数据点,过多会导致图表拥挤 |
| 视觉设计建议 | 使用半透明气泡避免重叠遮挡气泡大小范围应适中,避免过大或过小添加网格线辅助阅读坐标值 |
对数气泡图
| 图表类型 | 对数气泡图 |
|---|---|
| 适合的数据 | 数值范围差异极大的数据集,需要对数变换来展示 |
| 功能 | 处理数据跨度很大的情况,如人口数据、GDP 数据等 |
| 数据与图形的映射 | 与基础气泡图相同,但采用对数比例尺两个连续变量映射到 XY 坐标第三个变量通过对数映射到气泡的大小 |
| 使用场景 | 当数据出现指数增长或数值范围跨越多个数量级时 |
| 实现方法 | 使用scale: { size: { type: 'log', range: [4, 20] } }配置对数比例尺 |
| 注意事项 | 应在图例或标签中明确指出使用了对数变换,避免误导读者 |
气泡图的应用场景
适合的场景
气泡图最适合用于以下几类场景:
- 多维数据分析 - 当需要同时分析三个或更多变量之间的关系
- 比较特征聚类 - 发现数据中的分组模式和异常值
- 资源分配可视化 - 展示多维度指标下的资源分布
- 风险与机会分析 - 同时考虑多个因素的决策辅助
示例 1: **经济与人口健康指标分析**
下图展示了不同国家人均 GDP、预期寿命与人口数量的关系,同时用颜色区分了不同大洲,有效地在一个图表中展现了四个维度的数据。
| country(国家) | GDP(人均 GDP) | lifeExpectancy(预期寿命) | population(人口) | continent(大洲) |
|---|---|---|---|---|
| China | 12547 | 76.9 | 1403500365 | Asia |
| United States | 59532 | 78.5 | 321773631 | Americas |
| India | 6427 | 68.3 | 1324517249 | Asia |
| Japan | 38428 | 83.9 | 127141000 | Asia |
| Germany | 46136 | 81.0 | 82695000 | Europe |
| ... | ... | ... | ... | ... |
分析 :
GDP字段映射到 X 轴,表示国家人均 GDP,可以看出发达国家集中在右侧LifeExpectancy字段映射到 Y 轴,表示国民预期寿命,能够观察到人均 GDP 与预期寿命有正相关性Population字段映射到气泡大小,通过对数比例尺处理,使得中国、印度等人口大国清晰可见continent字段映射到颜色,可以看出不同大洲国家的聚类分布
洞察:通过此图,我们可以直观地观察到:
- 经济水平与健康水平的正相关关系
- 人口规模与经济发展之间并无必然联系
- 不同大洲国家的发展模式存在差异
不适合的场景
例子 1: 数据点过多或气泡重叠过度
当数据点超过 100 个或气泡严重重叠时,气泡图可能变得混乱难以阅读。在这种情况下,可以考虑使用热力图或分面图表。
以下是一个包含大量数据点的气泡图示例,可以看到随着数据点的增加,气泡之间的重叠让图表变得难以解读:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
// 生成200个随机数据点
const data = Array.from({ length: 200 }, () => ({
x: Math.random() * 100,
y: Math.random() * 100,
size: Math.random() * 20 + 5,
category: ['A', 'B', 'C', 'D'][Math.floor(Math.random() * 4)],
}));
chart.options({
type: 'point',
autoFit: true,
data,
encode: {
x: 'x',
y: 'y',
size: 'size',
color: 'category',
},
style: {
fillOpacity: 0.3,
lineWidth: 1,
},
});
chart.render();
`} />
例子 2: 只有两个变量需要比较
当只需比较两个变量之间的关系时,散点图比气泡图更简洁有效。气泡图的第三个变量(气泡大小)如果没有必要,反而会增加认知负担。
例子 3: 展示趋势变化的时序数据
气泡图不适合展示时序趋势数据。对于需要展示随时间变化趋势的数据,折线图或面积图是更好的选择。
下面是一个不使用气泡图而使用折线图展示时序数据的例子:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'line',
autoFit: true,
data: [
{ day: '2015/9/1', share: 10, volume: 1200 },
{ day: '2015/9/5', share: 20, volume: 2100 },
{ day: '2015/9/10', share: 32, volume: 3400 },
{ day: '2015/9/15', share: 45, volume: 2900 },
{ day: '2015/9/20', share: 51, volume: 4100 },
{ day: '2015/9/25', share: 45, volume: 3800 },
{ day: '2015/9/30', share: 40, volume: 2700 },
],
encode: { x: 'day', y: 'share' },
axis: {
y: {
title: '股价',
},
x: {
title: '日期',
},
},
style: {
lineWidth: 3,
},
});
chart.render();
`} />
如果确实需要在时序数据中加入第三个维度的信息,可以使用带有大小编码的时间序列气泡图:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'point',
autoFit: true,
data: [
{ day: '2015/9/1', share: 10, volume: 1200 },
{ day: '2015/9/5', share: 20, volume: 2100 },
{ day: '2015/9/10', share: 32, volume: 3400 },
{ day: '2015/9/15', share: 45, volume: 2900 },
{ day: '2015/9/20', share: 51, volume: 4100 },
{ day: '2015/9/25', share: 45, volume: 3800 },
{ day: '2015/9/30', share: 40, volume: 2700 },
],
encode: {
x: 'day',
y: 'share',
size: 'volume',
},
scale: {
size: { range: [10, 40] },
},
style: {
fillOpacity: 0.6,
stroke: '#1890ff',
fill: '#1890ff',
},
axis: {
y: { title: '股价' },
x: { title: '日期' },
},
});
chart.render();
`} />
气泡图与其他图表的对比
气泡图和[散点图](/zh/charts/scatter-plot/)、[热力图](/zh/charts/heatmap/)
| 图表类型 | 主要特点 | 适用场景 | 数据维度 |
|---|---|---|---|
| 气泡图 | 通过点的大小编码额外维度 | 多变量关系分析 | 3-4 个变量(X、Y、大小、颜色) |
| 散点图 | 仅展示点的位置 | 二维相关性分析 | 2-3 个变量(X、Y、颜色) |
| 热力图 | 通过颜色深浅展示密度或量值 | 展示分布密度 | 3 个变量(X、Y、颜色强度) |
气泡图和[散点地图](/zh/charts/dot-map/)、[气泡地图](/zh/charts/bubble-map/)
| 图表类型 | 坐标系统 | 数据约束 | 应用场景 |
|---|---|---|---|
| 气泡图 | 抽象坐标系 | 可使用任意数值作为 XY 坐标 | 多维数据关系可视化 |
| 气泡地图 | 地理坐标系 | 点位置受地理坐标约束 | 地理数据中多变量分析 |
| 散点地图 | 地理坐标系 | 点位置受地理坐标约束 | 地理位置的简单分布 |
气泡图最佳实践
设计建议
气泡大小选择
- 设置合适的气泡大小范围,避免过大导致重叠,或过小导致难以辨认
- 使用半透明填充色,降低重叠区域的视觉干扰
数据处理
- 当气泡大小差异过大时,考虑使用对数比例尺
- 适当筛选数据,避免图表过于拥挤
标签和交互
- 添加悬停交互,显示详细数据信息
- 对重要数据点添加标签,但避免标签过多造成混乱
代码示例:添加悬停交互的气泡图
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'point',
autoFit: true,
data: [
{ x: 10, y: 20, size: 20, category: 'A', name: '项目1' },
{ x: 20, y: 40, size: 35, category: 'A', name: '项目2' },
{ x: 30, y: 30, size: 15, category: 'B', name: '项目3' },
{ x: 40, y: 60, size: 40, category: 'B', name: '项目4' },
{ x: 50, y: 50, size: 25, category: 'C', name: '项目5' },
],
encode: {
x: 'x',
y: 'y',
size: 'size',
color: 'category',
shape: 'point',
},
style: {
fillOpacity: 0.6,
lineWidth: 1,
},
tooltip: {
items: [
{ field: 'name', name: '项目名称' },
{ field: 'x', name: 'X值' },
{ field: 'y', name: 'Y值' },
{ field: 'size', name: '大小' },
],
},
interaction: [{ type: 'tooltip' }, { type: 'elementHighlight' }],
});
chart.render();
`} />
相似图表
分类
Site Docs Charts Bubble Map.En (`site/docs/charts/bubble-map.en.mdx`)
title: Bubble Map sidebar: { icon: 'map' } order: 3 screenshot: 'https://t.alipayobjects.com/images/T1exRjXb4XXXXXXXXX.png' category: ['map', 'comparison'] similar: ['scatter-plot', 'dot-map', 'choropleth-map']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Note: G2 5.0 does not directly support complete map background functionality. This page primarily provides concept introduction. For actual applications, additional map components and data need to be imported.
Introduction to Bubble Maps
A Bubble Map is a visualization chart that uses bubbles (circles) on a geographic map to represent data size at different geographic locations. The size of the bubble typically represents the magnitude of a value, the position represents geographic coordinates, and colors can be used to distinguish different categories or represent another dimension of values.
Bubble Maps are more suitable for comparing geographically related data than Choropleth Maps. The main disadvantage is that when there are too many large bubbles on the map, they may overlap and affect data display, so this needs to be considered when creating the chart.
Other Names: Bubble Chart Map, Geographic Bubble Chart
Components of a Bubble Map
Basic Bubble Map
| Chart Type | Bubble Map |
|---|---|
| Suitable Data | Data containing geographic coordinates (longitude and latitude) and one or more numeric fields |
| Function | Display geographic distribution and value relationships on a geographic background |
| Data Mapping | Longitude/latitude fields mapped to map positionNumeric field mapped to bubble sizeCategory field can be mapped to colorOther values can be mapped to color intensity |
| Data Volume | Recommended not to exceed 100 data points to avoid bubble overlap affecting readability |
The main components of a Bubble Map include:
- Geographic Background: Provides a map background with geographic coordinate system, such as world map, country map, etc.
- Bubbles: Circular markers where position represents geographic coordinates and size represents the magnitude of values
- Color Encoding: Uses different colors to distinguish categories or represent value ranges
- Legend: Explains the meaning of bubble size and color
Use Cases of Bubble Maps
Suitable Use Cases
Case 1: Geographic Data Distribution Analysis
Bubble Maps are ideal tools for analyzing data with geographic attributes, clearly showing the distribution pattern of data across geographic space.
Case 2: Regional Comparison Analysis
Through comparison of bubble size and color, different regions' data differences can be effectively compared.
Case 3: Multi-dimensional Geographic Data Display
Bubble Maps can simultaneously display multiple dimensions of information including location, value size, and category.
Unsuitable Use Cases
Case 1: Too Many Data Points Causing Overlap
When there are too many data points on the map, bubbles may overlap and affect clear data display. In such cases, heat maps or dot density maps should be considered.
Case 2: Lack of Geographic Coordinate Information
For data without latitude and longitude information, geocoding conversion is needed first, or other chart types should be considered.
Case 3: Precise Value Display
Bubble Maps focus on showing geographic distribution trends of data and are not suitable for scenarios requiring precise values. Tables or other precise display methods should be used in such cases.
Extensions of Bubble Maps
Multi-layer Bubble Maps
By setting different layers and transparency levels, multiple data series can be displayed on the same map.
Bubble Maps with Map Backgrounds
Combining geographic boundary data provides richer geographic background information.
Time Series Bubble Maps
Showing changes in bubbles over time through animation.
Comparing Bubble Maps to Other Charts
Bubble Maps and [Scatter Charts](/en/charts/scatter-plot/)
- Bubble Maps use geographic coordinate systems, suitable for displaying geospatial data
- Scatter Charts use Cartesian coordinate systems, suitable for displaying correlations between two continuous variables
Bubble Maps and [Choropleth Maps](/en/charts/choropleth-map/)
- Bubble Maps use bubble size to represent values, allowing precise comparison of values across different regions
- Choropleth Maps use color intensity to represent value ranges, suitable for displaying overall distribution patterns of data
Bubble Maps and [Dot Charts](/en/charts/scatter-plot/)
- Bubble Maps incorporate geographic information, where position has geographic significance
- Regular dot charts' positions only represent data dimensions without geographic attributes
Implementing Bubble Maps in G2 5.0
In G2 5.0, we can implement bubble maps by drawing point on geoView. Here are two practical examples:
Example 1: London Population Distribution Bubble Map
Based on London map data, showing the population distribution across different areas:
<Demo code={`import { Chart } from '@antv/g2';
import { feature } from 'topojson-client';
Promise.all([
fetch('https://assets.antv.antgroup.com/g2/londonBoroughs.json').then((res) =>
res.json(),
),
fetch('https://assets.antv.antgroup.com/g2/londonCentroids.json').then(
(res) => res.json(),
),
]).then((values) => {
const [londonBoroughs, londonCentroids] = values;
const london = feature(
londonBoroughs,
londonBoroughs.objects.boroughs,
).features;
// Add simulated population and GDP data to centroid data
const bubbleData = londonCentroids.map((d, index) => ({
...d,
name: d.name || `Area ${index + 1}`, // Ensure each data point has a name
population: Math.floor(Math.random() * 500000) + 100000, // 100K-600K population
gdp: Math.floor(Math.random() * 50000) + 20000, // 20K-70K GDP
category: ['Business', 'Residential', 'Industrial', 'Mixed'][
Math.floor(Math.random() * 4)
],
}));
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'geoView',
children: [
{
type: 'geoPath',
data: london,
style: {
fill: 'lightgray',
stroke: 'white',
lineWidth: 1,
},
},
{
type: 'point',
data: bubbleData,
encode: {
x: 'cx',
y: 'cy',
size: 'population',
color: 'category',
shape: 'point',
},
style: {
opacity: 0.7,
stroke: 'white',
lineWidth: 1,
},
scale: {
size: {
range: [4, 30],
},
color: {
range: ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'],
},
},
tooltip: {
title: 'name',
items: [
{
name: 'Population',
channel: 'size',
valueFormatter: (value) =>
`${value ? value.toLocaleString() : 'N/A'} people`,
},
{
name: 'GDP',
field: 'gdp',
valueFormatter: (value) =>
`${value ? value.toLocaleString() : 'N/A'} million`,
},
{ name: 'Type', field: 'category' },
],
},
},
],
});
chart.render();
});
`} />
Example 2: Global Major Cities GDP Bubble Map
Displaying GDP distribution of major cities worldwide:
<Demo code={`import { Chart } from '@antv/g2';
// Global major cities data - ensuring data completeness
const worldCities = [
{
name: 'Beijing',
lng: 116.4074,
lat: 39.9042,
gdp: 4027,
population: 2154,
region: 'Asia',
},
{
name: 'Shanghai',
lng: 121.4737,
lat: 31.2304,
gdp: 4321,
population: 2424,
region: 'Asia',
},
{
name: 'New York',
lng: -74.0059,
lat: 40.7128,
gdp: 1700,
population: 851,
region: 'North America',
},
{
name: 'Los Angeles',
lng: -118.2437,
lat: 34.0522,
gdp: 710,
population: 397,
region: 'North America',
},
{
name: 'London',
lng: -0.1276,
lat: 51.5074,
gdp: 653,
population: 898,
region: 'Europe',
},
{
name: 'Tokyo',
lng: 139.6917,
lat: 35.6895,
gdp: 1617,
population: 1396,
region: 'Asia',
},
{
name: 'Paris',
lng: 2.3522,
lat: 48.8566,
gdp: 709,
population: 1068,
region: 'Europe',
},
{
name: 'Berlin',
lng: 13.405,
lat: 52.52,
gdp: 147,
population: 367,
region: 'Europe',
},
{
name: 'Sydney',
lng: 151.2093,
lat: -33.8688,
gdp: 337,
population: 518,
region: 'Oceania',
},
{
name: 'Toronto',
lng: -79.3832,
lat: 43.6532,
gdp: 324,
population: 294,
region: 'North America',
},
{
name: 'Seoul',
lng: 126.978,
lat: 37.5665,
gdp: 779,
population: 969,
region: 'Asia',
},
{
name: 'Singapore',
lng: 103.8198,
lat: 1.3521,
gdp: 340,
population: 584,
region: 'Asia',
},
{
name: 'Chicago',
lng: -87.6298,
lat: 41.8781,
gdp: 689,
population: 271,
region: 'North America',
},
{
name: 'Frankfurt',
lng: 8.6821,
lat: 50.1109,
gdp: 731,
population: 75,
region: 'Europe',
},
{
name: 'Hong Kong',
lng: 114.1694,
lat: 22.3193,
gdp: 365,
population: 745,
region: 'Asia',
},
{
name: 'Mumbai',
lng: 72.8777,
lat: 19.076,
gdp: 310,
population: 1284,
region: 'Asia',
},
{
name: 'São Paulo',
lng: -46.6333,
lat: -23.5505,
gdp: 430,
population: 1252,
region: 'South America',
},
{
name: 'Mexico City',
lng: -99.1332,
lat: 19.4326,
gdp: 411,
population: 912,
region: 'North America',
},
].map((city) => ({
...city,
// Data validation and formatting
name: city.name || 'Unknown City',
lng: typeof city.lng === 'number' ? city.lng : 0,
lat: typeof city.lat === 'number' ? city.lat : 0,
gdp: typeof city.gdp === 'number' ? city.gdp : 0,
population: typeof city.population === 'number' ? city.population : 0,
region: city.region || 'Unknown Region',
}));
// Simplified global map outline data
const worldOutline = [
{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [
[
[-180, -60],
[180, -60],
[180, 75],
[-180, 75],
[-180, -60],
],
],
},
},
];
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'geoView',
children: [
{
type: 'geoPath',
data: worldOutline,
style: {
fill: '#f0f0f0',
stroke: '#d0d0d0',
lineWidth: 1,
},
},
{
type: 'point',
data: worldCities,
encode: {
x: 'lng',
y: 'lat',
size: 'gdp',
color: 'region',
shape: 'point',
},
style: {
opacity: 0.8,
stroke: 'white',
lineWidth: 2,
},
scale: {
size: {
range: [8, 40],
},
color: {
range: [
'#1f77b4',
'#ff7f0e',
'#2ca02c',
'#d62728',
'#9467bd',
'#8c564b',
],
},
},
tooltip: {
title: 'name',
items: [
{
name: 'GDP',
channel: 'size',
valueFormatter: (value) => `${value || 0} billion USD`,
},
{
name: 'Population',
field: 'population',
valueFormatter: (value) => `${value || 0} million`,
},
{ name: 'Region', field: 'region' },
],
},
},
],
});
chart.render();
`} />
Key Points
Essential elements for creating bubble maps with G2 5.0:
- Use geoView: Create a geographic coordinate system view with
type: 'geoView' - Point marks: Use
type: 'point'in children to draw bubbles - Encoding mapping:
- Map
x,yto longitude and latitude coordinates in theencodeobject - Map
sizeto numeric values - Map
colorto categories or values
- Map
- Style settings: Set opacity, stroke, etc. through the
styleobject - Scale configuration: Control bubble size and color ranges through the
scaleobject - Interactive features: Add
tooltipandlabelsto enhance user experience - Multi-layer structure: Use the
childrenarray to simultaneously draw map background and bubble layers
Similar Charts
Categories
Notes
About Map Background Display
For actual applications, to properly display map backgrounds, you need to:
- Import map projection components
- Load complete GeoJSON map data
- Use correct transform configuration
Site Docs Charts Bubble Map.Zh (`site/docs/charts/bubble-map.zh.mdx`)
title: 带气泡的地图 sidebar: { icon: 'map' } order: 3 screenshot: 'https://t.alipayobjects.com/images/T1exRjXb4XXXXXXXXX.png' category: ['map', 'comparison'] similar: ['scatter-plot', 'dot-map', 'choropleth-map']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
注意:G2 5.0 目前不直接支持完整的地图背景功能,本页面主要提供概念介绍。在实际应用中,需要额外引入地图组件和数据。
带气泡的地图的简介
带气泡的地图(Bubble Map)是一种在地理地图上使用气泡(圆圈)来表示不同地理位置数据大小的可视化图表。气泡的大小通常表示数值的大小,位置表示地理坐标,颜色可以用来区分不同的分类或表示另一个数值维度。
带气泡的地图比分级统计图更适用于比较带地理信息的数据的大小。它的主要缺点是当地图上的气泡过多过大时,气泡间会相互遮盖而影响数据展示,所以在绘制时需要考虑这点。
英文名:Bubble Map
其他名称:气泡图地图、地理气泡图
带气泡的地图的构成
基础带气泡的地图
| 图表类型 | 带气泡的地图 |
|---|---|
| 适合的数据 | 包含地理坐标(经纬度)的数据和一个或多个数值字段 |
| 功能 | 在地理背景上展示数据的地理分布和数值大小关系 |
| 数据与图形的映射 | 经纬度字段映射到地图位置数值字段映射到气泡大小分类字段可映射到颜色其他数值可映射到颜色深度 |
| 适合的数据条数 | 建议不超过 100 个数据点,避免气泡重叠影响阅读 |
带气泡的地图的主要组成部分包括:
- 地理背景:提供地理坐标系统的地图背景,如世界地图、国家地图等
- 气泡:圆形标记,位置表示地理坐标,大小表示数值大小
- 颜色编码:用不同颜色区分分类或表示数值范围
- 图例:说明气泡大小和颜色的含义
带气泡的地图的应用场景
适合的场景
场景 1:地理数据分布分析
带气泡的地图是分析具有地理属性数据的理想工具,能够直观展示数据在地理空间上的分布规律。
场景 2:区域对比分析
通过气泡大小和颜色的对比,可以有效地比较不同地区间的数据差异。
场景 3:多维地理数据展示
带气泡的地图可以同时展示位置、数值大小、分类等多个维度的信息。
不适合的场景
场景 1:数据点过多导致重叠
当地图上的数据点过多时,气泡间会相互遮盖,影响数据的清晰展示,此时应考虑使用热力图或点密度图。
场景 2:缺乏地理坐标信息
对于没有经纬度信息的数据,需要先进行地理编码转换,或考虑使用其他图表类型。
场景 3:精确数值展示
带气泡的地图侧重于显示数据的地理分布趋势,不适合需要精确数值的场景,此时应使用表格或其他精确展示方式。
带气泡的地图的扩展
多层带气泡的地图
通过设置不同的层级和透明度,可以在同一地图上展示多个数据系列。
带地图底图的气泡图
结合地理边界数据,提供更丰富的地理背景信息。
时间序列带气泡的地图
通过动画展示气泡随时间的变化。
带气泡的地图与其他图表的对比
带气泡的地图和[散点图](/zh/charts/scatter-plot/)
- 带气泡的地图使用地理坐标系统,适合展示地理空间数据
- 散点图使用笛卡尔坐标系,适合展示两个连续变量的相关关系
带气泡的地图和[分级统计图](/zh/charts/choropleth-map/)
- 带气泡的地图使用气泡大小表示数值,可以精确比较不同地区的数值大小
- 分级统计图使用颜色深浅表示数值范围,适合展示数据的整体分布模式
带气泡的地图和[点图](/zh/charts/scatter-plot/)
- 带气泡的地图结合了地理信息,位置具有地理意义
- 普通点图位置仅表示数据维度,不具备地理属性
在 G2 5.0 中实现带气泡的地图
在 G2 5.0 中,我们可以通过在 geoView 上绘制 point 来实现带气泡的地图。以下是两个实际可用的示例:
示例 1:伦敦人口分布气泡图
基于伦敦地图数据,展示各区域的人口分布情况:
<Demo code={`import { Chart } from '@antv/g2';
import { feature } from 'topojson-client';
Promise.all([
fetch('https://assets.antv.antgroup.com/g2/londonBoroughs.json').then((res) =>
res.json(),
),
fetch('https://assets.antv.antgroup.com/g2/londonCentroids.json').then(
(res) => res.json(),
),
]).then((values) => {
const [londonBoroughs, londonCentroids] = values;
const london = feature(
londonBoroughs,
londonBoroughs.objects.boroughs,
).features;
// 为中心点数据添加模拟的人口和GDP数据
const bubbleData = londonCentroids.map((d, index) => ({
...d,
name: d.name || `区域${index + 1}`, // 确保每个数据点都有名称
population: Math.floor(Math.random() * 500000) + 100000, // 10万-60万人口
gdp: Math.floor(Math.random() * 50000) + 20000, // 2万-7万GDP
category: ['商业区', '住宅区', '工业区', '混合区'][
Math.floor(Math.random() * 4)
],
}));
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'geoView',
children: [
{
type: 'geoPath',
data: london,
style: {
fill: 'lightgray',
stroke: 'white',
lineWidth: 1,
},
},
{
type: 'point',
data: bubbleData,
encode: {
x: 'cx',
y: 'cy',
size: 'population',
color: 'category',
shape: 'point',
},
style: {
opacity: 0.7,
stroke: 'white',
lineWidth: 1,
},
scale: {
size: {
range: [4, 30],
},
color: {
range: ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'],
},
},
tooltip: {
title: 'name',
items: [
{
name: '人口',
channel: 'size',
valueFormatter: (value) =>
`${value ? value.toLocaleString() : 'N/A'}人`,
},
{
name: 'GDP',
field: 'gdp',
valueFormatter: (value) =>
`${value ? value.toLocaleString() : 'N/A'}万元`,
},
{ name: '类型', field: 'category' },
],
},
},
],
});
chart.render();
});
`} />
示例 2:全球主要城市 GDP 气泡图
展示世界主要城市的 GDP 分布:
<Demo code={`import { Chart } from '@antv/g2';
// 全球主要城市数据 - 确保数据完整性
const worldCities = [
{
name: '北京',
lng: 116.4074,
lat: 39.9042,
gdp: 4027,
population: 2154,
region: '亚洲',
},
{
name: '上海',
lng: 121.4737,
lat: 31.2304,
gdp: 4321,
population: 2424,
region: '亚洲',
},
{
name: '纽约',
lng: -74.0059,
lat: 40.7128,
gdp: 1700,
population: 851,
region: '北美',
},
{
name: '洛杉矶',
lng: -118.2437,
lat: 34.0522,
gdp: 710,
population: 397,
region: '北美',
},
{
name: '伦敦',
lng: -0.1276,
lat: 51.5074,
gdp: 653,
population: 898,
region: '欧洲',
},
{
name: '东京',
lng: 139.6917,
lat: 35.6895,
gdp: 1617,
population: 1396,
region: '亚洲',
},
{
name: '巴黎',
lng: 2.3522,
lat: 48.8566,
gdp: 709,
population: 1068,
region: '欧洲',
},
{
name: '柏林',
lng: 13.405,
lat: 52.52,
gdp: 147,
population: 367,
region: '欧洲',
},
{
name: '悉尼',
lng: 151.2093,
lat: -33.8688,
gdp: 337,
population: 518,
region: '大洋洲',
},
{
name: '多伦多',
lng: -79.3832,
lat: 43.6532,
gdp: 324,
population: 294,
region: '北美',
},
{
name: '首尔',
lng: 126.978,
lat: 37.5665,
gdp: 779,
population: 969,
region: '亚洲',
},
{
name: '新加坡',
lng: 103.8198,
lat: 1.3521,
gdp: 340,
population: 584,
region: '亚洲',
},
{
name: '芝加哥',
lng: -87.6298,
lat: 41.8781,
gdp: 689,
population: 271,
region: '北美',
},
{
name: '法兰克福',
lng: 8.6821,
lat: 50.1109,
gdp: 731,
population: 75,
region: '欧洲',
},
{
name: '香港',
lng: 114.1694,
lat: 22.3193,
gdp: 365,
population: 745,
region: '亚洲',
},
{
name: '孟买',
lng: 72.8777,
lat: 19.076,
gdp: 310,
population: 1284,
region: '亚洲',
},
{
name: '圣保罗',
lng: -46.6333,
lat: -23.5505,
gdp: 430,
population: 1252,
region: '南美',
},
{
name: '墨西哥城',
lng: -99.1332,
lat: 19.4326,
gdp: 411,
population: 912,
region: '北美',
},
].map((city) => ({
...city,
// 数据验证和格式化
name: city.name || '未知城市',
lng: typeof city.lng === 'number' ? city.lng : 0,
lat: typeof city.lat === 'number' ? city.lat : 0,
gdp: typeof city.gdp === 'number' ? city.gdp : 0,
population: typeof city.population === 'number' ? city.population : 0,
region: city.region || '未知地区',
}));
// 简化的全球地图轮廓数据
const worldOutline = [
{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [
[
[-180, -60],
[180, -60],
[180, 75],
[-180, 75],
[-180, -60],
],
],
},
},
];
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'geoView',
children: [
{
type: 'geoPath',
data: worldOutline,
style: {
fill: '#f0f0f0',
stroke: '#d0d0d0',
lineWidth: 1,
},
},
{
type: 'point',
data: worldCities,
encode: {
x: 'lng',
y: 'lat',
size: 'gdp',
color: 'region',
shape: 'point',
},
style: {
opacity: 0.8,
stroke: 'white',
lineWidth: 2,
},
scale: {
size: {
range: [8, 40],
},
color: {
range: [
'#1f77b4',
'#ff7f0e',
'#2ca02c',
'#d62728',
'#9467bd',
'#8c564b',
],
},
},
tooltip: {
title: 'name',
items: [
{
name: 'GDP',
channel: 'size',
valueFormatter: (value) => `${value || 0}亿美元`,
},
{
name: '人口',
field: 'population',
valueFormatter: (value) => `${value || 0}万人`,
},
{ name: '地区', field: 'region' },
],
},
},
],
});
chart.render();
`} />
核心要点
使用 G2 5.0 创建带气泡的地图的关键要素:
- 使用 geoView: 通过
type: 'geoView'创建地理坐标系统的视图 - point 标记: 在 children 中使用
type: 'point'来绘制气泡 - 编码映射:
- 在
encode对象中映射x,y到经纬度坐标 size映射到数值大小color映射到分类或数值
- 在
- 样式设置: 通过
style对象设置透明度、描边等 - 比例尺配置: 通过
scale对象控制气泡大小和颜色范围 - 交互功能: 添加
tooltip和labels提升用户体验 - 多层结构: 使用
children数组可以同时绘制地图背景和气泡层
相似图表
分类
注意事项
关于地图背景显示
在实际应用中,要正确显示地图背景,需要:
- 引入地图投影组件
- 加载完整的 GeoJSON 地图数据
- 使用正确的 transform 配置
Site Docs Charts Bullet.En (`site/docs/charts/bullet.en.mdx`)
title: Bullet Chart sidebar: { icon: 'bar' } order: 22 screenshot: 'https://zos.alipayobjects.com/rmsportal/XVYqTvtBBwzoSSHDDrQb.png' category: ['comparison', 'distribution'] similar: ['bar', 'multi-set-bar', 'stacked-bar']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Bullet Charts
A Bullet Chart is a linear chart type originally designed by data visualization expert Stephen Few as a more compact and information-rich alternative to traditional dashboard gauges. Bullet charts can simultaneously display actual values, target values, and performance ranges within a limited space, clearly showing the completion rate and performance status through comparison.
The design philosophy of bullet charts is to maximize the data-ink ratio, displaying the most useful information in the smallest space, making them particularly suitable for dashboard and performance monitoring scenarios.
English Names: Bullet Chart
Other Names: Progress Bar Chart, Target Comparison Chart, Bullet Graph
Components of a Bullet Chart
Basic Bullet Chart
| Chart Type | Bullet Chart |
|---|---|
| Suitable Data | One categorical data field, one continuous data field (actual value), one target value, optional performance ranges |
| Functionality | Display comparison between actual and target values, evaluate performance levels |
| Data Mapping | Categorical data field maps to vertical axis positionContinuous data field maps to bar lengthTarget value maps to marker linePerformance ranges map to background color bands |
| Data Size Limit | Single or multiple indicators, recommended not to exceed 10 |
The main components of a bullet chart include:
- Actual Value Bar: Represented by a thick, dark-colored bar showing the current actual achieved value
- Target Value Marker: Represented by a vertical line or other marker, indicating the target to be achieved
- Performance Ranges: Background uses color bands of different shades, typically divided into poor, good, and excellent ranges
- Scale Axis: Provides numerical reference to help readers understand specific numerical values
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const data = [
{
title: 'Sales Completion Rate',
ranges: 100,
measures: 80,
target: 85,
},
];
chart.options({
type: 'view',
coordinate: { transform: [{ type: 'transpose' }] },
children: [
{
type: 'interval',
data,
encode: { x: 'title', y: 'ranges', color: '#f0efff' },
style: { maxWidth: 30 },
axis: {
y: {
grid: true,
gridLineWidth: 2,
title: 'Completion Rate (%)',
},
x: {
title: false,
},
},
},
{
type: 'interval',
data,
encode: { x: 'title', y: 'measures', color: '#5B8FF9' },
style: { maxWidth: 20 },
label: {
text: 'measures',
position: 'right',
textAlign: 'left',
dx: 5,
formatter: (d) => `${d}%`,
},
},
{
type: 'point',
data,
encode: {
x: 'title',
y: 'target',
shape: 'line',
color: '#3D76DD',
size: 8,
},
tooltip: {
title: false,
items: [
{
channel: 'y',
name: 'Target Value',
valueFormatter: (d) => `${d}%`,
},
],
},
},
],
});
chart.render();
`} />
Use Cases for Bullet Charts
Appropriate Use Cases
Scenario 1: Performance Indicator Monitoring
Bullet charts are ideal tools for displaying performance indicator completion status, clearly comparing actual performance with target requirements.
Scenario 2: Budget Execution Tracking
Bullet charts can effectively display budget execution status, including actual expenditure, budget targets, and warning ranges.
Scenario 3: Resource Utilization Monitoring
Through bullet charts, you can intuitively understand the usage of various resources and identify overused or underutilized resources.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const resourceData = [
{
resource: 'CPU Usage',
ranges: 100,
measures: 65,
target: 80,
},
{
resource: 'Memory Usage',
ranges: 100,
measures: 45,
target: 70,
},
{
resource: 'Disk Usage',
ranges: 100,
measures: 88,
target: 85,
},
{
resource: 'Network Bandwidth',
ranges: 100,
measures: 72,
target: 75,
},
];
chart.options({
type: 'view',
coordinate: { transform: [{ type: 'transpose' }] },
children: [
{
type: 'interval',
data: resourceData,
encode: { x: 'resource', y: 'ranges', color: '#f5f5f5' },
style: { maxWidth: 30 },
},
{
type: 'interval',
data: resourceData,
encode: {
x: 'resource',
y: 'measures',
color: (d) => (d.measures > d.target ? '#ff7875' : '#52c41a'),
},
style: { maxWidth: 20 },
label: {
text: 'measures',
position: 'right',
textAlign: 'left',
dx: 5,
formatter: (d) => `${d}%`,
},
},
{
type: 'point',
data: resourceData,
encode: {
x: 'resource',
y: 'target',
shape: 'line',
color: '#1890ff',
size: 6,
},
axis: {
y: {
grid: true,
title: 'Usage Rate (%)',
},
x: {
title: 'System Resources',
},
},
},
],
});
chart.render();
`} />
Inappropriate Use Cases
Scenario 1: Time Trend Analysis
Bullet charts primarily display status comparisons at a specific point in time and are not suitable for showing trends over time. Line charts should be used in such cases.
Scenario 2: Part-to-Whole Relationships
If you need to show the proportional relationship of parts to the whole, pie charts or donut charts are more appropriate.
Scenario 3: Large Data Volume
When displaying a large number of indicators, bullet charts can cause visual confusion. It's recommended to use grouped displays or other chart types.
Extensions of Bullet Charts
Multi-dimensional Bullet Charts
Display the performance of multiple related indicators through grouping, facilitating horizontal comparison.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const multiData = [
{
department: 'Sales',
indicator: 'Sales Revenue',
ranges: 100,
measures: 85,
target: 90,
},
{
department: 'Sales',
indicator: 'Customer Count',
ranges: 100,
measures: 92,
target: 85,
},
{
department: 'Marketing',
indicator: 'Brand Awareness',
ranges: 100,
measures: 78,
target: 80,
},
{
department: 'Marketing',
indicator: 'Marketing ROI',
ranges: 100,
measures: 88,
target: 85,
},
];
chart.options({
type: 'view',
coordinate: { transform: [{ type: 'transpose' }] },
children: [
{
type: 'interval',
data: multiData,
encode: { x: 'indicator', y: 'ranges', color: '#f0f0f0' },
style: { maxWidth: 30 },
},
{
type: 'interval',
data: multiData,
encode: { x: 'indicator', y: 'measures', color: 'department' },
style: { maxWidth: 20 },
label: {
text: 'measures',
position: 'right',
textAlign: 'left',
dx: 5,
},
},
{
type: 'point',
data: multiData,
encode: {
x: 'indicator',
y: 'target',
shape: 'line',
color: '#666',
size: 6,
},
axis: {
y: {
grid: true,
title: 'Completion Rate',
},
x: {
title: 'Key Indicators',
},
},
},
],
});
chart.render();
`} />
Layered Performance Ranges
Provide more detailed performance evaluation criteria through background ranges of different color shades.
Vertical Bullet Charts
When space is limited or special layouts are needed, vertical bullet charts can be used.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const verticalData = [
{
metric: 'Q1 Sales',
ranges: 100,
measures: 80,
target: 85,
},
{
metric: 'Q2 Sales',
ranges: 100,
measures: 92,
target: 88,
},
{
metric: 'Q3 Sales',
ranges: 100,
measures: 76,
target: 90,
},
];
chart.options({
type: 'view',
children: [
{
type: 'interval',
data: verticalData,
encode: { x: 'metric', y: 'ranges', color: '#f0f0f0' },
style: { maxWidth: 30 },
},
{
type: 'interval',
data: verticalData,
encode: { x: 'metric', y: 'measures', color: '#52c41a' },
style: { maxWidth: 20 },
label: {
text: 'measures',
position: 'top',
textAlign: 'center',
dy: -5,
},
},
{
type: 'point',
data: verticalData,
encode: {
x: 'metric',
y: 'target',
shape: 'line',
color: '#ff4d4f',
size: 6,
},
axis: {
y: {
grid: true,
title: 'Sales (10k CNY)',
},
x: {
title: 'Quarter',
},
},
},
],
});
chart.render();
`} />
Comparison with Other Charts
Bullet Chart vs [Bar Chart](/en/charts/bar/)
- Bullet charts add target values and performance ranges to bar charts, providing richer comparison dimensions
- Bar charts are mainly used to compare numerical values across different categories, while bullet charts focus on comparing actual values with target values
Bullet Chart vs [Gauge Chart](/en/charts/gauge/)
- Bullet charts save more space than gauge charts and can display more information in the same space
- Gauge charts more intuitively display the status of a single indicator, while bullet charts are more suitable for multi-indicator comparison
Bullet Chart vs [Progress Chart](/en/charts/gauge/)
- Bullet charts provide more contextual information, including target values and performance ranges
- Progress charts mainly show completion progress, while bullet charts can show the quality of performance
Similar Charts
Category
Site Docs Charts Bullet.Zh (`site/docs/charts/bullet.zh.mdx`)
title: 子弹图 sidebar: { icon: 'bar' } order: 22 screenshot: 'https://zos.alipayobjects.com/rmsportal/XVYqTvtBBwzoSSHDDrQb.png' category: ['comparison', 'distribution'] similar: ['bar', 'multi-set-bar', 'stacked-bar']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
子弹图的简介
子弹图(Bullet Chart)是一种线性的图表类型,最初由数据可视化专家 Stephen Few 设计,旨在替代传统的仪表盘而提供更加紧凑和信息丰富的可视化形式。子弹图能够在有限的空间内同时展示实际值、目标值和表现区间,通过对比的方式清晰地显示指标的完成度和表现情况。
子弹图的设计理念是最大化数据墨水比(data-ink ratio),在最小的空间内展示最多的有用信息,特别适合用于仪表板和绩效监控场景。
英文名:Bullet Chart
其他名称:进度条图、目标比较图、弹丸图
子弹图的构成
基础子弹图
| 图表类型 | 子弹图 |
|---|---|
| 适合的数据 | 一个分类数据字段、一个连续数据字段(实际值)、一个目标值、可选的表现区间 |
| 功能 | 展示实际值与目标值的对比,评估表现等级 |
| 数据与图形的映射 | 分类数据字段映射到纵轴位置连续数据字段映射到条形长度目标值映射到标记线表现区间映射到背景色带 |
| 适合的数据条数 | 单个或多个指标,建议不超过 10 个 |
子弹图的主要组成部分包括:
- 实际值条形:用短粗的深色条形表示,展示当前实际达到的数值
- 目标值标记:用垂直线或其他标记表示,代表需要达成的目标
- 表现区间:背景使用不同深浅的色带表示,通常分为差、良、优等区间
- 刻度轴:提供数值参考,帮助读者理解具体的数值大小
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const data = [
{
title: '销售完成率',
ranges: 100,
measures: 80,
target: 85,
},
];
chart.options({
type: 'view',
coordinate: { transform: [{ type: 'transpose' }] },
children: [
{
type: 'interval',
data,
encode: { x: 'title', y: 'ranges', color: '#f0efff' },
style: { maxWidth: 30 },
axis: {
y: {
grid: true,
gridLineWidth: 2,
title: '完成率 (%)',
},
x: {
title: false,
},
},
},
{
type: 'interval',
data,
encode: { x: 'title', y: 'measures', color: '#5B8FF9' },
style: { maxWidth: 20 },
label: {
text: 'measures',
position: 'right',
textAlign: 'left',
dx: 5,
formatter: (d) => `${d}%`,
},
},
{
type: 'point',
data,
encode: {
x: 'title',
y: 'target',
shape: 'line',
color: '#3D76DD',
size: 8,
},
tooltip: {
title: false,
items: [
{ channel: 'y', name: '目标值', valueFormatter: (d) => `${d}%` },
],
},
},
],
});
chart.render();
`} />
子弹图的应用场景
适合的场景
场景 1:业绩指标监控
子弹图是展示业绩指标完成情况的理想工具,能够清晰地对比实际表现与目标要求。
场景 2:预算执行跟踪
子弹图能够有效地显示预算的执行情况,包括实际支出、预算目标和预警区间。
场景 3:资源利用率监控
通过子弹图可以直观地了解各类资源的使用情况,识别过度使用或利用不足的资源。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const resourceData = [
{
resource: 'CPU使用率',
ranges: 100,
measures: 65,
target: 80,
},
{
resource: '内存使用率',
ranges: 100,
measures: 45,
target: 70,
},
{
resource: '磁盘使用率',
ranges: 100,
measures: 88,
target: 85,
},
{
resource: '网络带宽',
ranges: 100,
measures: 72,
target: 75,
},
];
chart.options({
type: 'view',
coordinate: { transform: [{ type: 'transpose' }] },
children: [
{
type: 'interval',
data: resourceData,
encode: { x: 'resource', y: 'ranges', color: '#f5f5f5' },
style: { maxWidth: 30 },
},
{
type: 'interval',
data: resourceData,
encode: {
x: 'resource',
y: 'measures',
color: (d) => (d.measures > d.target ? '#ff7875' : '#52c41a'),
},
style: { maxWidth: 20 },
label: {
text: 'measures',
position: 'right',
textAlign: 'left',
dx: 5,
formatter: (d) => `${d}%`,
},
},
{
type: 'point',
data: resourceData,
encode: {
x: 'resource',
y: 'target',
shape: 'line',
color: '#1890ff',
size: 6,
},
axis: {
y: {
grid: true,
title: '使用率 (%)',
},
x: {
title: '系统资源',
},
},
},
],
});
chart.render();
`} />
不适合的场景
场景 1:时间趋势分析
子弹图主要展示某个时点的状态对比,不适合展示随时间变化的趋势,此时应使用折线图。
场景 2:部分与整体关系
如果需要展示各部分占整体的比例关系,饼图或环形图更为合适。
场景 3:数据量过大
当需要展示大量指标时,子弹图会导致视觉混乱,建议使用分组展示或其他图表类型。
子弹图的扩展
多维子弹图
通过分组显示多个相关指标的表现情况,便于横向对比。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const multiData = [
{
department: '销售部',
indicator: '销售额',
ranges: 100,
measures: 85,
target: 90,
},
{
department: '销售部',
indicator: '客户数',
ranges: 100,
measures: 92,
target: 85,
},
{
department: '市场部',
indicator: '品牌知名度',
ranges: 100,
measures: 78,
target: 80,
},
{
department: '市场部',
indicator: '营销投入ROI',
ranges: 100,
measures: 88,
target: 85,
},
];
chart.options({
type: 'view',
coordinate: { transform: [{ type: 'transpose' }] },
children: [
{
type: 'interval',
data: multiData,
encode: { x: 'indicator', y: 'ranges', color: '#f0f0f0' },
style: { maxWidth: 30 },
},
{
type: 'interval',
data: multiData,
encode: { x: 'indicator', y: 'measures', color: 'department' },
style: { maxWidth: 20 },
label: {
text: 'measures',
position: 'right',
textAlign: 'left',
dx: 5,
},
},
{
type: 'point',
data: multiData,
encode: {
x: 'indicator',
y: 'target',
shape: 'line',
color: '#666',
size: 6,
},
axis: {
y: {
grid: true,
title: '完成度',
},
x: {
title: '关键指标',
},
},
},
],
});
chart.render();
`} />
分层表现区间
通过不同颜色深浅的背景区间,提供更细致的表现评估标准。
垂直子弹图
在空间受限或需要特殊布局时,可以使用垂直方向的子弹图。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const verticalData = [
{
metric: 'Q1销售',
ranges: 100,
measures: 80,
target: 85,
},
{
metric: 'Q2销售',
ranges: 100,
measures: 92,
target: 88,
},
{
metric: 'Q3销售',
ranges: 100,
measures: 76,
target: 90,
},
];
chart.options({
type: 'view',
children: [
{
type: 'interval',
data: verticalData,
encode: { x: 'metric', y: 'ranges', color: '#f0f0f0' },
style: { maxWidth: 30 },
},
{
type: 'interval',
data: verticalData,
encode: { x: 'metric', y: 'measures', color: '#52c41a' },
style: { maxWidth: 20 },
label: {
text: 'measures',
position: 'top',
textAlign: 'center',
dy: -5,
},
},
{
type: 'point',
data: verticalData,
encode: {
x: 'metric',
y: 'target',
shape: 'line',
color: '#ff4d4f',
size: 6,
},
axis: {
y: {
grid: true,
title: '销售额 (万元)',
},
x: {
title: '季度',
},
},
},
],
});
chart.render();
`} />
子弹图与其他图表的对比
子弹图和[条形图](/zh/charts/bar/)
- 子弹图在条形图的基础上增加了目标值和表现区间,提供更丰富的对比维度
- 条形图主要用于比较不同分类的数值大小,而子弹图侧重于实际值与目标值的对比
子弹图和[仪表盘](/zh/charts/gauge/)
- 子弹图比仪表盘更节省空间,能在相同空间内展示更多信息
- 仪表盘更直观地展示单个指标的状态,子弹图更适合多指标对比
子弹图和[进度条](/zh/charts/gauge/)
- 子弹图提供了更多的上下文信息,包括目标值和表现区间
- 进度条主要展示完成进度,子弹图能展示表现的优劣程度
相似图表
分类
Site Docs Charts Chord.En (`site/docs/charts/chord.en.mdx`)
title: Chord Diagram sidebar: { icon: 'net' } order: 38 screenshot: 'https://zos.alipayobjects.com/rmsportal/wqqqDPsmjjToaWvrNFMY.png' category: ['relation'] similar: ['radar-chart', 'radial-bar', 'sankey', 'arcdiagram']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Chord Diagrams
A Chord Diagram is a visualization method that displays the relationships between data in a matrix. Nodes are arranged radially around a circle, connected by weighted arcs that represent the relationships and flow between different entities. It's particularly effective for showing mutual relationships and flows between multiple entities.
Chord diagrams can intuitively display complex relationship networks between multiple nodes, especially suitable for visualizing bidirectional flow data such as population migration, trade flows, fund transfers, software dependencies, and other scenarios.
Other Names: Chord Chart, Chord Graph
Components of a Chord Diagram
| Chart Type | Chord Diagram |
|---|---|
| Suitable Data | Node dataset (optional), edge dataset: source node, target node, flow value |
| Function | Observe node relationships, display bidirectional flow relationships between multiple entities |
| Data-to-Visual Mapping | Weight mapped to node and edge widthSource and target nodes mapped to arc positions on circleNodes can be distinguished by color |
| Suitable Data Volume | Two or more node groups, optimal with 5-15 nodes |
Components of a Chord Diagram
- Outer Arcs: Arc segments on the circle representing different categories or nodes, with arc length reflecting total flow of the node
- Chords: Curves connecting different outer arcs, representing relationships between nodes, with curve thickness indicating flow magnitude
- Labels: Text descriptions identifying each node
- Colors: Used to distinguish different nodes or flow directions
Use Cases of Chord Diagrams
Suitable Use Cases
Example 1: Suitable for displaying flow relationships
The following chart shows population flow between different cities, clearly displaying bidirectional flow relationships between cities through a chord diagram.
| source (Source City) | target (Target City) | value (Population Flow) |
|---|---|---|
| Beijing | Shanghai | 100,000 |
| Beijing | Guangzhou | 80,000 |
| Shanghai | Beijing | 70,000 |
| Shanghai | Guangzhou | 90,000 |
| Guangzhou | Shenzhen | 120,000 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'chord',
autoFit: true,
data: {
value: {
links: [
{ source: 'Beijing', target: 'Shanghai', value: 100 },
{ source: 'Beijing', target: 'Guangzhou', value: 80 },
{ source: 'Beijing', target: 'Shenzhen', value: 60 },
{ source: 'Shanghai', target: 'Beijing', value: 70 },
{ source: 'Shanghai', target: 'Guangzhou', value: 90 },
{ source: 'Shanghai', target: 'Shenzhen', value: 50 },
{ source: 'Guangzhou', target: 'Beijing', value: 40 },
{ source: 'Guangzhou', target: 'Shanghai', value: 85 },
{ source: 'Guangzhou', target: 'Shenzhen', value: 120 },
{ source: 'Shenzhen', target: 'Beijing', value: 35 },
{ source: 'Shenzhen', target: 'Shanghai', value: 45 },
{ source: 'Shenzhen', target: 'Guangzhou', value: 110 },
],
},
},
layout: { nodeWidthRatio: 0.05 },
scale: {
color: {
type: 'ordinal',
range: ['#5B8FF9', '#5AD8A6', '#F6BD16', '#E86452'],
},
},
style: {
labelFontSize: 12,
labelFill: '#333',
linkFillOpacity: 0.6,
},
tooltip: {
items: [
{ field: 'source', name: 'Source City' },
{ field: 'target', name: 'Target City' },
{ field: 'value', name: 'Population Flow' },
],
},
interaction: [
{
type: 'elementHighlight',
background: true,
},
],
});
chart.render();
`} />
Example 2: Displaying software dependencies
The following chart shows dependency relationships between software packages. Each node represents an independent package, and each edge shows the dependency relationship between packages. The thickness of edges indicates the strength of dependencies.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'chord',
autoFit: true,
data: {
value: {
links: [
{ source: 'vis.core', target: 'vis.data', value: 85 },
{ source: 'vis.core', target: 'vis.event', value: 45 },
{ source: 'vis.core', target: 'vis.util', value: 120 },
{ source: 'vis.data', target: 'vis.core', value: 30 },
{ source: 'vis.data', target: 'vis.util', value: 60 },
{ source: 'vis.event', target: 'vis.core', value: 25 },
{ source: 'vis.event', target: 'vis.data', value: 40 },
{ source: 'vis.util', target: 'vis.core', value: 15 },
{ source: 'vis.render', target: 'vis.core', value: 95 },
{ source: 'vis.render', target: 'vis.util', value: 55 },
{ source: 'vis.layout', target: 'vis.core', value: 75 },
{ source: 'vis.layout', target: 'vis.util', value: 35 },
],
},
},
layout: { nodeWidthRatio: 0.05 },
scale: {
color: {
type: 'ordinal',
range: ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd'],
},
},
style: {
labelFontSize: 11,
labelFill: '#333',
linkFillOpacity: 0.6,
},
tooltip: {
items: [
{ field: 'source', name: 'Source Package' },
{ field: 'target', name: 'Target Package' },
{ field: 'value', name: 'Dependency Strength' },
],
},
interaction: [
{
type: 'elementHighlight',
background: true,
},
],
});
chart.render();
`} />
Description:
- Nodes represent different software package modules
- Edge thickness indicates the strength of dependency relationships
- Colors distinguish different packages, making it easier to identify circular dependencies
Unsuitable Use Cases
Example 1: Too many nodes leading to poor readability
When the number of nodes exceeds 15, chord diagrams become crowded and difficult to read, with severely overlapping connection lines.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
// Simulate data for 20 provinces, too many nodes leading to poor readability
const provinces = [
'Beijing',
'Shanghai',
'Guangzhou',
'Shenzhen',
'Hangzhou',
'Nanjing',
'Wuhan',
'Chengdu',
'Xian',
'Chongqing',
'Tianjin',
'Suzhou',
'Qingdao',
'Dalian',
'Xiamen',
'Ningbo',
'Changsha',
'Zhengzhou',
'Jinan',
'Fuzhou',
];
const data = [];
provinces.forEach((source, i) => {
provinces.forEach((target, j) => {
if (i !== j && Math.random() > 0.7) {
data.push({
source,
target,
value: Math.floor(Math.random() * 50) + 10,
});
}
});
});
chart.options({
type: 'chord',
autoFit: true,
data: {
value: {
links: data.slice(0, 40), // Only take first 40 data points for demo
},
},
layout: { nodeWidthRatio: 0.05 },
style: {
labelFontSize: 8, // Smaller font to accommodate more labels
labelFill: '#666',
linkFillOpacity: 0.5,
},
});
chart.render();
`} />
Example 2: Not suitable for displaying hierarchical relationships
Chord diagrams are mainly used to show relationships between equal nodes and are not suitable for displaying data with obvious hierarchical structures.
Comparing Chord Diagrams to Other Charts
Chord Diagrams and Radar Charts
- Chord diagrams are mainly used to display bidirectional flow relationships between nodes, emphasizing connections and flows
- Radar charts are mainly used for multi-dimensional data comparison, displaying values across dimensions through polygons
Chord Diagrams and Area Charts
- Chord diagrams display relationship networks through circular layout and connecting arcs, suitable for flow data
- Area charts display numerical trends through filled areas, suitable for time series data
Similar Charts
Categories
Site Docs Charts Chord.Zh (`site/docs/charts/chord.zh.mdx`)
title: 和弦图 sidebar: { icon: 'net' } order: 38 screenshot: 'https://zos.alipayobjects.com/rmsportal/wqqqDPsmjjToaWvrNFMY.png' category: ['relation'] similar: ['radar-chart', 'radial-bar', 'sankey', 'arcdiagram']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
和弦图的简介
和弦图(Chord Diagram)是一种显示矩阵中数据间相互关系的可视化方法,节点数据沿圆周径向排列,节点之间使用带权重(有宽度)的弧线链接。特别适合展示多个实体之间的相互关系和流量。
和弦图能够直观地展示多个节点之间的复杂关系网络,特别适用于展示双向流动数据,如人口迁移、贸易流向、资金往来、软件依赖关系等场景。
英文名:Chord Diagram
和弦图的构成
| 图表类型 | 和弦图 |
|---|---|
| 适合的数据 | 节点数据集(可选)、边数据集:源节点、目标节点、流量值 |
| 功能 | 观察节点关系,展示多个实体间的双向流动关系 |
| 数据与图形的映射 | 权重映射到节点和边的宽度源节点和目标节点映射到圆周上的弧段位置节点可以用颜色区分 |
| 适合的数据条数 | 节点数据两组以上,5-15 个节点效果最佳 |
和弦图的组成部分
- 外圆弧(Outer Arcs):圆周上的弧段,代表各个分类或节点,弧段长度反映节点的总流量
- 连接弧(Chords):连接不同外圆弧的曲线,表示节点间的关系,弧线粗细表示流量大小
- 标签(Labels):标识各个节点的文字说明
- 颜色(Colors):用于区分不同的节点或流向
和弦图的应用场景
适合的场景
例子 1: 适合应用到流量关系展示
下图展示了不同城市之间的人口流动情况,通过和弦图可以清晰地看到各城市间的双向流动关系。
| source(源城市) | target(目标城市) | value(流动人口) |
|---|---|---|
| 北京 | 上海 | 100,000 |
| 北京 | 广州 | 80,000 |
| 上海 | 北京 | 70,000 |
| 上海 | 广州 | 90,000 |
| 广州 | 深圳 | 120,000 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'chord',
autoFit: true,
data: {
value: {
links: [
{ source: '北京', target: '上海', value: 100 },
{ source: '北京', target: '广州', value: 80 },
{ source: '北京', target: '深圳', value: 60 },
{ source: '上海', target: '北京', value: 70 },
{ source: '上海', target: '广州', value: 90 },
{ source: '上海', target: '深圳', value: 50 },
{ source: '广州', target: '北京', value: 40 },
{ source: '广州', target: '上海', value: 85 },
{ source: '广州', target: '深圳', value: 120 },
{ source: '深圳', target: '北京', value: 35 },
{ source: '深圳', target: '上海', value: 45 },
{ source: '深圳', target: '广州', value: 110 },
],
},
},
layout: { nodeWidthRatio: 0.05 },
scale: {
color: {
type: 'ordinal',
range: ['#5B8FF9', '#5AD8A6', '#F6BD16', '#E86452'],
},
},
style: {
labelFontSize: 12,
labelFill: '#333',
linkFillOpacity: 0.6,
},
tooltip: {
items: [
{ field: 'source', name: '源城市' },
{ field: 'target', name: '目标城市' },
{ field: 'value', name: '流动人口' },
],
},
interaction: [
{
type: 'elementHighlight',
background: true,
},
],
});
chart.render();
`} />
例子 2: 展示软件依赖关系
下图展示了软件包之间的依赖关系,每个节点表示一个独立的包,每条边展示了包与包之间的依赖关系。边的粗细表示依赖的强度。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'chord',
autoFit: true,
data: {
value: {
links: [
{ source: 'vis.core', target: 'vis.data', value: 85 },
{ source: 'vis.core', target: 'vis.event', value: 45 },
{ source: 'vis.core', target: 'vis.util', value: 120 },
{ source: 'vis.data', target: 'vis.core', value: 30 },
{ source: 'vis.data', target: 'vis.util', value: 60 },
{ source: 'vis.event', target: 'vis.core', value: 25 },
{ source: 'vis.event', target: 'vis.data', value: 40 },
{ source: 'vis.util', target: 'vis.core', value: 15 },
{ source: 'vis.render', target: 'vis.core', value: 95 },
{ source: 'vis.render', target: 'vis.util', value: 55 },
{ source: 'vis.layout', target: 'vis.core', value: 75 },
{ source: 'vis.layout', target: 'vis.util', value: 35 },
],
},
},
layout: { nodeWidthRatio: 0.05 },
scale: {
color: {
type: 'ordinal',
range: ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd'],
},
},
style: {
labelFontSize: 11,
labelFill: '#333',
linkFillOpacity: 0.6,
},
tooltip: {
items: [
{ field: 'source', name: '依赖包' },
{ field: 'target', name: '目标包' },
{ field: 'value', name: '依赖强度' },
],
},
interaction: [
{
type: 'elementHighlight',
background: true,
},
],
});
chart.render();
`} />
说明:
- 节点表示不同的软件包模块
- 边的粗细表示依赖关系的强度
- 颜色用于区分不同的包,便于识别循环依赖
不适合的场景
例子 1: 节点过多导致可读性差
当节点数量超过 15 个时,和弦图会变得拥挤难读,连接线重叠严重。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
// 模拟20个省份的数据,节点过多导致可读性差
const provinces = [
'北京',
'上海',
'广州',
'深圳',
'杭州',
'南京',
'武汉',
'成都',
'西安',
'重庆',
'天津',
'苏州',
'青岛',
'大连',
'厦门',
'宁波',
'长沙',
'郑州',
'济南',
'福州',
];
const data = [];
provinces.forEach((source, i) => {
provinces.forEach((target, j) => {
if (i !== j && Math.random() > 0.7) {
data.push({
source,
target,
value: Math.floor(Math.random() * 50) + 10,
});
}
});
});
chart.options({
type: 'chord',
autoFit: true,
data: {
value: {
links: data.slice(0, 40), // 只取前40条数据演示
},
},
layout: { nodeWidthRatio: 0.05 },
style: {
labelFontSize: 8, // 字体变小以适应更多标签
labelFill: '#666',
linkFillOpacity: 0.5,
},
});
chart.render();
`} />
例子 2: 不适合展示层次关系
和弦图主要用于展示平等节点间的关系,不适合展示有明显层次结构的数据。
和弦图的扩展
自定义颜色和样式
下图展示了某个时段用户使用 Uber 软件在美国旧金山各个城市之间乘车交通的情况。图中的节点表示城市,节点大小表示了交通流量的多少,从图中可以看出,交通行为主要发生在几个主要城市之间。
以下是使用自定义颜色和样式的和弦图示例:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'chord',
autoFit: true,
data: {
value: {
links: [
{ source: '中国', target: '美国', value: 4200 },
{ source: '中国', target: '日本', value: 3200 },
{ source: '中国', target: '韩国', value: 2800 },
{ source: '美国', target: '中国', value: 1200 },
{ source: '美国', target: '墨西哥', value: 6100 },
{ source: '日本', target: '中国', value: 1400 },
{ source: '日本', target: '韩国', value: 800 },
{ source: '韩国', target: '中国', value: 1100 },
],
},
},
layout: { nodeWidthRatio: 0.05 },
scale: {
color: {
type: 'ordinal',
range: ['#5B8FF9', '#5AD8A6', '#F6BD16', '#E86452'],
},
},
style: {
labelFontSize: 14,
labelFontWeight: 'bold',
labelFill: '#000',
linkFillOpacity: 0.7,
},
tooltip: {
items: [
{ field: 'source', name: '出口国' },
{ field: 'target', name: '进口国' },
{ field: 'value', name: '贸易额(亿美元)' },
],
},
interaction: [
{
type: 'elementHighlight',
background: true,
},
],
});
chart.render();
`} />
和弦图与其他图表的对比
和弦图和雷达图
- 和弦图主要用于展示节点间的双向流动关系,强调连接和流量
- 雷达图主要用于多维度数据比较,通过多边形展示各维度的值
和弦图和面积图
- 和弦图通过圆形布局和连接弧展示关系网络,适合展示流动数据
- 面积图通过填充区域展示数值变化趋势,适合时间序列数据
相似图表
分类
Site Docs Charts Choropleth Map.En (`site/docs/charts/choropleth-map.en.mdx`)
title: Choropleth Map sidebar: { icon: 'map' } order: 10 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*vcI7RqX24U0AAAAAAAAAAAAADmJ7AQ/original' category: ['map'] similar: ['bubble-map', 'heatmap']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
A Choropleth Map is a type of map that uses visual symbols (usually colors, shading, or hatching of varying density) to represent the distribution of a range of values on map subdivisions. Within multiple small subdivision units (administrative divisions or other subdivision units) of the entire mapping area, classifications are made according to the quantitative (relative) indicators of each subdivision, and corresponding color grades or hatching of different densities are used to reflect the concentration or development level distribution differences of phenomena in each area. It is most commonly seen in the visualization of election and census data, which are organized by geographic regions such as provinces and cities.
Introduction to Choropleth Maps
This method is also called color-graded statistical mapping because it commonly uses color grades for representation. The quantity of each subdivision on the map is represented using different color grades, with typical methods including: (1) mixed gradient from one color to another; (2) single-tone gradient; (3) transparent to opaque; (4) light to dark; (5) using a complete color spectrum variation. Choropleth maps rely on colors to express the inherent patterns in data, so choosing appropriate colors is very important. When the data value range is large or the data types are diverse, choosing appropriate color mapping can be quite challenging.
Choropleth maps' biggest problem is the asymmetry between data distribution and geographic region size. Usually, large amounts of data are concentrated in densely populated areas, while sparsely populated areas occupy most of the screen space. Using large amounts of screen space to represent small portions of data is very uneconomical in terms of space utilization. This asymmetry often causes users to misunderstand the data and cannot help users accurately distinguish and compare data values in different subdivisions on the map.
Other Names: Thematic Map, Shaded Map
Components of a Choropleth Map
| Chart Type | Choropleth Map |
|---|---|
| Suitable Data | One categorical field, one continuous field |
| Function | Compare numerical values of categorical data |
| Data-to-Visual Mapping | One categorical field maps to geographic locations on the mapAnother continuous field maps to color |
| Suitable Data Volume | Based on actual geographic location information, no limit |
Use Cases of Choropleth Maps
Suitable Use Cases
Choropleth maps are mostly used to reflect phenomena that are planar but sparsely distributed, such as population density, the ratio of sown area of a certain crop, and per capita income.
Example 1: Geographic Regional Data Visualization
The figure below shows the population distribution of US states. The main population distribution is reflected by the color depth. It is clear that California and Texas have the largest populations. It also shows the global gender ratio distribution in 2015, where the value represents the number of males per 100 females. It can be seen that in European and American countries, women generally slightly outnumber men. This phenomenon is particularly prominent in the former Soviet Union region, while the Middle East has more men than women.
| Data Type | Region/Country | Value | Description |
|---|---|---|---|
| Population | California | 38802500 | CA |
| Population | Texas | 26956958 | TX |
| Population | Florida | 19893297 | FL |
| ... | ... | ... | ... |
| Gender Ratio | Russia | 86.8 | Males per 100 females |
| Gender Ratio | China | 106.3 | Males per 100 females |
| Gender Ratio | Japan | 94.7 | Males per 100 females |
| ... | ... | ... | ... |
<Demo code={`import { Chart } from '@antv/g2';
import { feature } from 'topojson-client';
// Load map and data
Promise.all([
fetch('https://assets.antv.antgroup.com/g2/us-10m.json').then((res) =>
res.json(),
),
fetch('https://assets.antv.antgroup.com/g2/unemployment2.json').then((res) =>
res.json(),
),
]).then(([us, unemployment]) => {
const counties = feature(us, us.objects.counties).features;
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'geoPath',
coordinate: {
type: 'albersUsa', // Use US-specific map projection
},
data: {
value: counties,
transform: [
{
type: 'join',
join: unemployment,
on: ['id', 'id'],
select: ['rate'],
},
],
},
scale: {
color: {
palette: 'ylGnBu', // Use yellow-to-blue gradient palette
unknown: '#fff', // Display unknown data as white
},
},
encode: {
color: 'rate', // Map unemployment rate to color channel
},
legend: {
color: {
layout: { justifyContent: 'center' }, // Adjust legend layout
},
},
style: {
stroke: '#666',
strokeWidth: 0.5,
},
tooltip: {
title: (d) => d.properties.name,
items: [{ field: 'rate', name: 'Unemployment Rate' }],
},
});
chart.render();
});
`} />
Note:
- The numeric field is mapped to color, representing the size of the data.
- The name of the geographic area determines where the area is drawn on the map.
- For smaller blocks, because the value is also smaller, the rendered color is also lighter, making these blocks difficult to see on the map. This is also a limitation of choropleth maps.
Unsuitable Use Cases
- Displaying Precise Values: Choropleth maps are mainly used to show the relative size and distribution trend of data, and are not suitable for scenarios that require precise numerical reading.
- Excessive Differences in Regional Area: When the regional area differences are very large, the larger area will visually dominate, even if its corresponding value is small, which may mislead users. At this time, consider using other types of maps such as bubble maps.
- Data Not Geographically Relevant: If the data is not directly related to geographic location, using a choropleth map is meaningless.
Example 1: 2008 US Presidential Election Results
Election visualization can easily give users the illusion of asymmetry between data distribution and geographic area size. States won by Democratic candidate Obama and Republican candidate McCain are represented in blue and red, respectively. From the map, it appears that the Republican Party received more votes than the Democratic Party because the red area occupies a larger area. However, in the US presidential election, the final result depends on the number of electoral votes obtained by the candidate. Each state has a different number of electoral votes, and the candidate who wins in a state will receive all the electoral votes of that state. At this time, it is recommended to use a dot map.
| State | Electoral Votes | Obama Votes | McCain Votes |
|---|---|---|---|
| Alabama | 9 | 813479 | 1266546 |
| Arizona | 10 | 1034707 | 638017 |
| Arkansas | 6 | 422310 | 638017 |
Comparing Choropleth Maps to Other Charts
Choropleth Maps and [Bubble Maps](/en/charts/bubble-map/)
- Choropleth Maps: Maps numerical values to the color of map areas, suitable for displaying the distribution of continuous data.
- Bubble Maps: Displays a bubble on the map area, with the size of the bubble representing the numerical value, suitable for displaying discrete point data or avoiding misleading when regional area differences are large.
Choropleth maps can often lead to misjudgment, as large areas may have small numerical values (population, electoral votes, etc.).
Choropleth Maps and [Dot Maps](/en/charts/dot-map/)
- Dot Maps: Mainly used to display data at a specific longitude and latitude, while choropleth maps are used to display statistical values for a certain area.
- Dot Maps: Can display a large amount of data values, while choropleth maps are limited by the display area.
Similar Charts
Categories
Site Docs Charts Choropleth Map.Zh (`site/docs/charts/choropleth-map.zh.mdx`)
title: 分级统计地图 sidebar: { icon: 'map' } order: 10 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*vcI7RqX24U0AAAAAAAAAAAAADmJ7AQ/original' category: ['map'] similar: ['bubble-map', 'heatmap']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
分级统计地图是一种在地图分区上使用视觉符号(通常是颜色、阴影或者不同疏密的晕线)来表示一个范围值的分布情况的地图。在整个制图区域的若干个小的区划单元内(行政区划或者其他区划单位),根据各分区的数量(相对)指标进行分级,并用相应色级或不同疏密的晕线,反映各区现象的集中程度或发展水平的分布差别,最常见于选举和人口普查数据的可视化,这些数据以省、市等地理区域为单位。
分级统计地图的简介
此法因常用色级表示,所以也叫色级统计图法。地图上每个分区的数量使用不同的色级表示,较典型的方法有:(1)一个颜色到另一个颜色混合渐变;(2)单一的色调渐变;(3)透明到不透明;(4)明到暗;(5)用一个完整的色谱变化。Choropleth 地图依靠颜色等来表现数据内在的模式,因此选择合适的颜色非常重要,当数据的值域大或者数据的类型多样时,选择合适的颜色映射相当有挑战性。
Choropleth 地图最大的问题在于数据分布和地理区域大小的不对称。通常大量数据集中于人口密集的区域,而人口稀疏的地区却占有大多数的屏幕空间,用大量的屏幕空间来表示小部分数据的做法对空间的利用非常不经济,这种不对称还常常会造成用户对数据的错误理解,不能很好地帮助用户准确得区分和比较地图上各个分区的数据值。
英文名:Choropleth Map
分级统计地图的构成
| 图表类型 | 分级统计地图 |
|---|---|
| 适合的数据 | 一个分类字段,一个连续字段 |
| 功能 | 对比分类数据的数值大小 |
| 数据与图形的映射 | 一个分类字段映射到地图的地理位置另一个连续字段映射到颜色 |
| 适合的数据条数 | 根据实际地理位置信息,暂无限制 |
分级统计地图的应用场景
适合的场景
分级统计地图较多的是反映呈面状但属分散分布的现象,如反映人口密度、某农作物播种面积的比、人均收入等。
例子 1: 地理区域数据可视化
下图展示了美国各州的人口分布,通过颜色的深浅反映了人口的主要分布情况,能很明显看出 California、Texas 两大州人口最多。同时也展示了 2015 年全球人口性别比例分布,其中数值表示的是每 100 位女性对应的男性数量。可以看出在欧美国家,普遍是女性略多于男性,在前苏联地区这种现象尤为突出,而中东地区却是男多女少。
| 数据类型 | 地区/国家 | 数值 | 说明 |
|---|---|---|---|
| 人口数 | California | 38802500 | CA |
| 人口数 | Texas | 26956958 | TX |
| 人口数 | Florida | 19893297 | FL |
| 性别比例 | Russia | 86.8 | 每 100 女性对应的男性数 |
| 性别比例 | China | 106.3 | 每 100 女性对应的男性数 |
| 性别比例 | Japan | 94.7 | 每 100 女性对应的男性数 |
| ... | ... | ... | ... |
<Demo code={`import { Chart } from '@antv/g2';
import { feature } from 'topojson-client';
// 加载地图和数据
Promise.all([
fetch('https://assets.antv.antgroup.com/g2/us-10m.json').then((res) =>
res.json(),
),
fetch('https://assets.antv.antgroup.com/g2/unemployment2.json').then((res) =>
res.json(),
),
]).then(([us, unemployment]) => {
const counties = feature(us, us.objects.counties).features;
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'geoPath',
coordinate: {
type: 'albersUsa', // 使用美国地图的专用投影
},
data: {
value: counties,
transform: [
{
type: 'join',
join: unemployment,
on: ['id', 'id'],
select: ['rate'],
},
],
},
scale: {
color: {
palette: 'ylGnBu', // 使用从黄到蓝的渐变色板
unknown: '#fff', // 未知数据显示为白色
},
},
encode: {
color: 'rate', // 将失业率映射到颜色通道
},
legend: {
color: {
layout: { justifyContent: 'center' }, // 调整图例布局
},
},
style: {
stroke: '#666',
strokeWidth: 0.5,
},
tooltip: {
title: (d) => d.properties.name,
items: [{ field: 'rate', name: '失业率' }],
},
});
chart.render();
});
`} />
说明:
- 数值字段映射到颜色,表示数据的大小
- 地理区域名称决定了在其所在的地理位置绘制区域
- 对于面积较小的区块,因为数值也较小,所以渲染的颜色也浅,导致这些区块在图上很难被看见,这也是分级统计地图的局限性
不适合的场景
- 展示精确数值:分级统计地图主要用于展示数据的相对大小和分布趋势,不适合需要精确数值读取的场景。
- 区域面积差异过大:当区域面积差异很大时,面积较大的区域在视觉上会占据主导地位,即使其对应的数值较小,也可能给用户带来误导。此时可以考虑使用气泡地图等其他类型的地图。
- 数据不具有地理相关性:如果数据与地理位置没有直接关系,使用分级统计地图没有意义。
例子 1: 2008 年美国总统大选结果
选举可视化很容易给用户造成数据分布和地理区域大小不对称的错觉。民主党候选人奥巴马和共和党候选人麦凯恩胜出的州分别用蓝色和红色表示。从图上看,共和党比民主党获得了更多的投票,因为红色的区域所占的面积更大。但是在美国总统大选中,最后的结果是看候选人获得的选举人票数,每个州拥有的选举人票数是不一样的,在一个州获胜的选举人将得到该州的全部选举人票。这个时候推荐使用点描法地图。
| State(州) | 选举人票数 | 奥巴马得票 | 麦凯恩得票 |
|---|---|---|---|
| Alabama | 9 | 813479 | 1266546 |
| Arizona | 10 | 1034707 | 638017 |
| Arkansas | 6 | 422310 | 638017 |
分级统计地图与其他图表的对比
分级统计地图与气泡地图
- 分级统计地图:将数值映射到地图区域的颜色上,适合展示连续型数据的分布。
- 气泡地图:在地图区域上显示一个气泡,气泡的大小表示数值的大小,适合展示离散点数据或在区域面积差异较大时避免误导。
分级统计地图经常会带来误判,面积大的区域可能数值(人口数、选举人票等)比较小。
分级统计地图与点描法地图
- 点描法地图:主要用于显示某个经纬度上的数据,而分级统计地图用于显示某个区域的统计值。
- 点描法地图:可以显示大量的数据值,而分级统计地图受显示区域的限制。
相似图表
分类
Site Docs Charts Color Map.En (`site/docs/charts/color-map.en.mdx`)
title: Color Map sidebar: { icon: 'heatmap' } order: 2 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*F8DLSYJAyKQAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison', 'distribution'] similar: ['heatmap', 'treemap']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Color Map
A typical color map is a visualization chart that uses color to encode numerical data. It divides a rectangular area into a grid, with each grid cell representing an intersection point of categorical data, using color depth to indicate the magnitude of values. Unlike heat maps, color maps are typically used to display relationships between discrete categorical data rather than continuous data distributions.
Color maps are particularly suitable for showing relationships and patterns between multiple categorical variables, such as sales of different products across different time periods, or temperature changes across different regions over different years. Through color encoding, users can quickly identify high and low value areas and overall distribution patterns in the dataset.
It's important to note that when there are too many categories in a color map, it may lead to label overlap and readability issues, which we'll illustrate with examples below.
Other Names: Color Block Chart
Components
Basic Color Map
| Chart Type | Basic Color Map |
|---|---|
| Suitable Data | Datasets with two categorical dimensions and one numerical dimension |
| Function | Display relationships between two categorical dimensions and one numerical variable |
| Data-to-Visual Mapping | Two categorical data dimensions mapped to grid rows and columnsNumerical data mapped to color depthText labels can be added to display specific values |
| Suitable Data Count | Usually no more than 20 categories per dimension, with total cells recommended not to exceed 400 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'cell',
autoFit: true,
data: [
{ month: 'January', product: 'Product A', sales: 123 },
{ month: 'January', product: 'Product B', sales: 231 },
{ month: 'January', product: 'Product C', sales: 145 },
{ month: 'February', product: 'Product A', sales: 132 },
{ month: 'February', product: 'Product B', sales: 112 },
{ month: 'February', product: 'Product C', sales: 178 },
{ month: 'March', product: 'Product A', sales: 99 },
{ month: 'March', product: 'Product B', sales: 288 },
{ month: 'March', product: 'Product C', sales: 133 },
{ month: 'April', product: 'Product A', sales: 181 },
{ month: 'April', product: 'Product B', sales: 223 },
{ month: 'April', product: 'Product C', sales: 141 },
{ month: 'May', product: 'Product A', sales: 152 },
{ month: 'May', product: 'Product B', sales: 219 },
{ month: 'May', product: 'Product C', sales: 109 },
{ month: 'June', product: 'Product A', sales: 167 },
{ month: 'June', product: 'Product B', sales: 187 },
{ month: 'June', product: 'Product C', sales: 255 },
],
coordinate: {
type: 'cartesian',
},
legend: {
color: {
position: 'right',
flipPage: false,
},
},
scale: {
color: {
palette: 'rdBu',
offset: (t) => 1 - t,
},
},
encode: {
x: 'month',
y: 'product',
color: 'sales',
link: 'sales',
},
style: {
inset: 1,
},
labels: [
{
text: 'sales',
style: {
fill: (d) => (d.sales > 200 ? '#fff' : '#000'),
},
},
],
});
chart.render();
`} />
Color Map with Conditional Formatting
| Chart Type | Color Map with Conditional Formatting |
|---|---|
| Suitable Data | Datasets that need to highlight specific thresholds or ranges |
| Function | Apply different color encodings based on different value ranges, highlighting key data points |
| Data-to-Visual Mapping | In addition to basic color map mappings, custom color intervals and boundary markers can be added |
| Usage Suggestions | Add clear legend explanations for different color intervalsUse contrasting colors to represent different data statesAvoid using too many color intervals which can cause confusion |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const data = [
{ month: 'January', product: 'Product A', sales: 123, target: 150 },
{ month: 'January', product: 'Product B', sales: 231, target: 200 },
{ month: 'January', product: 'Product C', sales: 145, target: 150 },
{ month: 'February', product: 'Product A', sales: 132, target: 150 },
{ month: 'February', product: 'Product B', sales: 112, target: 200 },
{ month: 'February', product: 'Product C', sales: 178, target: 150 },
{ month: 'March', product: 'Product A', sales: 99, target: 150 },
{ month: 'March', product: 'Product B', sales: 288, target: 200 },
{ month: 'March', product: 'Product C', sales: 133, target: 150 },
{ month: 'April', product: 'Product A', sales: 181, target: 150 },
{ month: 'April', product: 'Product B', sales: 223, target: 200 },
{ month: 'April', product: 'Product C', sales: 141, target: 150 },
{ month: 'May', product: 'Product A', sales: 152, target: 150 },
{ month: 'May', product: 'Product B', sales: 219, target: 200 },
{ month: 'May', product: 'Product C', sales: 109, target: 150 },
{ month: 'June', product: 'Product A', sales: 167, target: 150 },
{ month: 'June', product: 'Product B', sales: 187, target: 200 },
{ month: 'June', product: 'Product C', sales: 255, target: 150 },
];
// Calculate performance status for each cell
const processedData = data.map((d) => ({
...d,
// Calculate ratio to target
performance: d.sales / d.target,
// Add status label
status:
d.sales < d.target * 0.8
? 'Below Target'
: d.sales < d.target
? 'Near Target'
: d.sales < d.target * 1.2
? 'Met Target'
: 'Exceeded Target',
}));
chart.options({
type: 'cell',
autoFit: true,
data: processedData,
coordinate: {
type: 'cartesian',
},
legend: {
color: {
position: 'right',
flipPage: false,
},
},
scale: {
color: {
type: 'threshold',
domain: [0.8, 1, 1.2],
range: ['#F4664A', '#FAAD14', '#30BF78', '#0891B2'],
},
},
encode: {
x: 'month',
y: 'product',
color: 'performance',
},
style: {
inset: 1,
},
labels: [
{
text: (d) => `${d.sales}/${d.target}`,
style: {
fill: (d) => (d.performance > 0.95 ? '#fff' : '#000'),
textAlign: 'center',
fontSize: 11,
},
},
],
});
chart.render();
`} />
Use Cases of Color Maps
Suitable Use Cases
Example 1: Hangzhou Metro Fare Chart
The chart below is a simulation of Hangzhou Metro fare chart. This color map shows the fare relationship between different metro stations, with color depth representing different fare levels. You can quickly identify fare zones and the cost of traveling between any two stations.
| from | to | price |
|---|---|---|
| Xianghu | Binhe Road | 2 |
| Xianghu | Xixing | 3 |
| ... | ... | ... |
<Demo height={524} code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 500,
});
// Metro stations on Line 1
const sites = [
'Xianghu',
'Binkang Road',
'Xixing',
'Binhe Road',
'Jiangling Road',
'Jinjiang',
'Wujiang Road',
'Chengzhan',
"Ding'an Road",
'Longxiang Bridge',
'Fengqi Road',
'Wulin Square',
'West Lake Cultural Square',
'Datieguan',
'East Railway Station',
'Zhalongkou',
'Pengbu',
'Qibao',
'Jiuhe Road',
'Jiubao',
'Passenger Transport Center',
'Xiaxi West',
'Jinsha Lake',
'Gaosha Road',
'Wenze Road',
];
// Generate metro fare data
const data = [];
for (let i = 0; i < sites.length; i++) {
for (let j = sites.length - 1; j >= i; j--) {
let price = 0;
const step = Math.abs(j - i);
if (step <= 2) {
price = 2;
} else if (step <= 4) {
price = 3;
} else if (step <= 7) {
price = 4;
} else if (step <= 13) {
price = 5;
} else if (step <= 16) {
price = 6;
} else if (step <= 21) {
price = 7;
} else {
price = 8;
}
data.push({ from: sites[i], to: sites[j], price: price });
}
}
chart.options({
type: 'cell',
autoFit: true,
data,
coordinate: {
type: 'cartesian',
},
legend: {
color: {
position: 'right',
title: 'Fare (CNY)',
flipPage: false,
},
},
scale: {
color: {
domain: [2, 3, 4, 5, 6, 7, 8],
range: [
'#ffffcc',
'#c7e9b4',
'#7fcdbb',
'#41b6c4',
'#2c7fb8',
'#253494',
'#081d58',
],
},
from: {
values: sites,
},
to: {
values: sites.slice().reverse(),
},
},
axis: {
x: {
title: false,
grid: false,
tickLine: false,
labelRotate: -Math.PI / 4,
labelOffset: 5,
},
y: {
title: false,
grid: false,
tickLine: false,
},
},
encode: {
x: 'from',
y: 'to',
color: 'price',
},
style: {
inset: 1,
stroke: '#fff',
strokeWidth: 1,
},
labels: [
{
text: 'price',
style: {
fill: (d) => (d.price > 5 ? '#fff' : '#000'),
textAlign: 'center',
fontSize: 10,
},
},
],
});
chart.render();
`} />
Analysis:
- Station names are mapped to the
xandyaxis to determine position - Fare prices are mapped to color depth
- Fare data is simulated and only represents general relationships
- The color map makes it easy to identify fare zones and travel costs between stations
Example 2: Exam Score Analysis
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const students = [
'Alex',
'Ben',
'Charlie',
'David',
'Emma',
'Frank',
'Grace',
'Helen',
];
const subjects = [
'Math',
'English',
'Physics',
'Chemistry',
'Biology',
'History',
];
// Generate score data
const data = [];
students.forEach((student) => {
subjects.forEach((subject) => {
// Random score between 50-100
const score = Math.floor(Math.random() * 51) + 50;
data.push({
student,
subject,
score,
});
});
});
chart.options({
type: 'cell',
autoFit: true,
data,
coordinate: {
type: 'cartesian',
},
legend: {
color: {
position: 'right',
flipPage: false,
title: 'Score',
},
},
scale: {
color: {
domain: [60, 70, 80, 90],
range: ['#F4664A', '#FAAD14', '#30BF78', '#0891B2', '#5B8FF9'],
},
},
encode: {
x: 'subject',
y: 'student',
color: 'score',
},
style: {
inset: 1,
},
labels: [
{
text: 'score',
style: {
fill: (d) => (d.score > 85 ? '#fff' : '#000'),
textAlign: 'center',
},
},
],
});
chart.render();
`} />
Unsuitable Use Cases
Example 1: Too Few Data Points
When a dataset has only a few category intersections, a color map may not be the best choice. In such cases, a simple table or bar chart might be more intuitive.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
// Very few data points
const data = [
{ region: 'East', year: '2022', value: 125 },
{ region: 'West', year: '2022', value: 87 },
];
chart.options({
type: 'cell',
autoFit: true,
data,
encode: {
x: 'year',
y: 'region',
color: 'value',
},
style: {
inset: 1,
},
labels: [
{
text: 'value',
},
],
});
chart.render();
`} />
In this case, using a bar chart would be more intuitive:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ region: 'East', year: '2022', value: 125 },
{ region: 'West', year: '2022', value: 87 },
],
encode: {
x: 'region',
y: 'value',
color: 'region',
},
labels: [
{
text: 'value',
position: 'top',
},
],
});
chart.render();
`} />
Example 2: Need to Show Precise Trend Changes
When you need to show precise changes in trends over time, a color map is not as intuitive as a line chart. Below is an example of using a color map to show monthly data changes, but this situation is better suited for a line chart.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const months = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
const data = months.map((month, index) => ({
month,
metric: 'Sales',
value: 100 + Math.sin(index / 2) * 50 + Math.random() * 10,
}));
chart.options({
type: 'cell',
autoFit: true,
data,
encode: {
x: 'month',
y: 'metric',
color: 'value',
},
style: {
inset: 1,
},
labels: [
{
text: (d) => d.value.toFixed(0),
},
],
});
chart.render();
`} />
Using a line chart is more suitable for showing trends:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const months = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
const data = months.map((month, index) => ({
month,
value: 100 + Math.sin(index / 2) * 50 + Math.random() * 10,
}));
chart.options({
type: 'line',
autoFit: true,
data,
encode: {
x: 'month',
y: 'value',
},
style: {
lineWidth: 2,
point: {
fill: '#1890ff',
r: 4,
},
},
labels: [
{
text: (d) => d.value.toFixed(0),
position: 'top',
},
],
});
chart.render();
`} />
Comparing Color Maps to Other Charts
Color Maps, [Heat Maps](/en/charts/heatmap/), and [Treemaps](/en/charts/treemap/)
| Chart Type | Main Features | Suitable Scenarios | Data Requirements |
|---|---|---|---|
| Color Map | Uses a regular grid to show intersections of two categorical dimensions | Comparing relationships between categorical data | Two categorical dimensions and one numerical dimension |
| Heat Map | Can use continuous scales, showing spatial distribution of data | Displaying spatial density or intensity distribution | Usually requires continuous or near-continuous data |
| Treemap | Displays hierarchical data through nested rectangles | Representing proportional relationships in hierarchical data | Requires a clear hierarchical structure |
Best Practices for Color Maps
Design Suggestions
Color Selection
- Use sequential color palettes to represent changes in continuous data magnitude
- Use diverging color palettes to represent deviation from a center value
- Add clear legends and explanations for colors
Grid Design
- Keep grid cell sizes consistent to ensure readability
- Add value labels in cells to enhance precision
- Consider adding spaces between cells to improve distinction
Labels and Interaction
- Add labels for important data points
- Add hover interactions to display detailed information
- Consider adding sorting functionality for easier data comparison
Similar Charts
Categories
Site Docs Charts Color Map.Zh (`site/docs/charts/color-map.zh.mdx`)
title: 色块图 sidebar: { icon: 'heatmap' } order: 2 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*F8DLSYJAyKQAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison', 'distribution'] similar: ['heatmap', 'treemap']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
色块图的简介
典型的色块图,是一种使用颜色编码数值数据的可视化图表。它将矩形区域划分为网格,每个网格单元代表一组分类数据的交叉点,通过颜色的深浅表示数值的大小。与热力图不同,色块图通常用于显示离散分类数据之间的关系,而不是连续的数据分布。
色块图特别适合展示多个分类变量之间的关系和模式,例如不同时间段内不同产品的销售额、不同地区不同年份的气温变化等。通过颜色编码,用户可以快速识别出数据集中的高低值区域和整体分布模式。
需要注意的是,当色块图中的分类过多时,可能会导致标签重叠和可读性下降的问题,下面我们会举例说明。
英文名:Color Map, Color Block Chart
色块图的构成
基础色块图
| 图表类型 | 基础色块图 |
|---|---|
| 适合的数据 | 具有两个分类维度和一个数值维度的数据集 |
| 功能 | 展示两个分类维度和一个数值变量之间的关系 |
| 数据与图形的映射 | 两个分类数据维度映射到网格的行和列数值数据映射到颜色深浅可以添加文本标签显示具体数值 |
| 适合的数据条数 | 每个维度通常不超过 20 个分类,总单元格数建议不超过 400 个 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'cell',
autoFit: true,
data: [
{ month: '一月', product: '产品A', sales: 123 },
{ month: '一月', product: '产品B', sales: 231 },
{ month: '一月', product: '产品C', sales: 145 },
{ month: '二月', product: '产品A', sales: 132 },
{ month: '二月', product: '产品B', sales: 112 },
{ month: '二月', product: '产品C', sales: 178 },
{ month: '三月', product: '产品A', sales: 99 },
{ month: '三月', product: '产品B', sales: 288 },
{ month: '三月', product: '产品C', sales: 133 },
{ month: '四月', product: '产品A', sales: 181 },
{ month: '四月', product: '产品B', sales: 223 },
{ month: '四月', product: '产品C', sales: 141 },
{ month: '五月', product: '产品A', sales: 152 },
{ month: '五月', product: '产品B', sales: 219 },
{ month: '五月', product: '产品C', sales: 109 },
{ month: '六月', product: '产品A', sales: 167 },
{ month: '六月', product: '产品B', sales: 187 },
{ month: '六月', product: '产品C', sales: 255 },
],
coordinate: {
type: 'cartesian',
},
legend: {
color: {
position: 'right',
flipPage: false,
},
},
scale: {
color: {
palette: 'rdBu',
offset: (t) => 1 - t,
},
},
encode: {
x: 'month',
y: 'product',
color: 'sales',
link: 'sales',
},
style: {
inset: 1,
},
labels: [
{
text: 'sales',
style: {
fill: (d) => (d.sales > 200 ? '#fff' : '#000'),
},
},
],
});
chart.render();
`} />
带条件格式的色块图
| 图表类型 | 带条件格式的色块图 |
|---|---|
| 适合的数据 | 需要突出显示特定阈值或范围的数据集 |
| 功能 | 根据数据值的不同范围应用不同的颜色编码,突出显示关键数据点 |
| 数据与图形的映射 | 除基础色块图的映射外,还可以添加自定义的颜色区间和边界标记 |
| 使用建议 | 为不同颜色区间添加清晰的图例说明使用对比鲜明的颜色表示不同的数据状态避免使用过多的颜色区间造成混淆 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const data = [
{ month: '一月', product: '产品A', sales: 123, target: 150 },
{ month: '一月', product: '产品B', sales: 231, target: 200 },
{ month: '一月', product: '产品C', sales: 145, target: 150 },
{ month: '二月', product: '产品A', sales: 132, target: 150 },
{ month: '二月', product: '产品B', sales: 112, target: 200 },
{ month: '二月', product: '产品C', sales: 178, target: 150 },
{ month: '三月', product: '产品A', sales: 99, target: 150 },
{ month: '三月', product: '产品B', sales: 288, target: 200 },
{ month: '三月', product: '产品C', sales: 133, target: 150 },
{ month: '四月', product: '产品A', sales: 181, target: 150 },
{ month: '四月', product: '产品B', sales: 223, target: 200 },
{ month: '四月', product: '产品C', sales: 141, target: 150 },
{ month: '五月', product: '产品A', sales: 152, target: 150 },
{ month: '五月', product: '产品B', sales: 219, target: 200 },
{ month: '五月', product: '产品C', sales: 109, target: 150 },
{ month: '六月', product: '产品A', sales: 167, target: 150 },
{ month: '六月', product: '产品B', sales: 187, target: 200 },
{ month: '六月', product: '产品C', sales: 255, target: 150 },
];
// 计算每个单元格的性能状态
const processedData = data.map((d) => ({
...d,
// 计算与目标的比例
performance: d.sales / d.target,
// 添加状态标签
status:
d.sales < d.target * 0.8
? '不达标'
: d.sales < d.target
? '接近目标'
: d.sales < d.target * 1.2
? '达标'
: '超额完成',
}));
chart.options({
type: 'cell',
autoFit: true,
data: processedData,
coordinate: {
type: 'cartesian',
},
legend: {
color: {
position: 'right',
flipPage: false,
},
},
scale: {
color: {
type: 'threshold',
domain: [0.8, 1, 1.2],
range: ['#F4664A', '#FAAD14', '#30BF78', '#0891B2'],
},
},
encode: {
x: 'month',
y: 'product',
color: 'performance',
},
style: {
inset: 1,
},
labels: [
{
text: (d) => `${d.sales}/${d.target}`,
style: {
fill: (d) => (d.performance > 0.95 ? '#fff' : '#000'),
textAlign: 'center',
fontSize: 11,
},
},
],
});
chart.render();
`} />
色块图的应用场景
适合的场景
例子 1: 杭州地铁票价图
下图是模拟的杭州地铁票价图。这个色块图展示了不同地铁站点之间的票价关系,通过颜色深浅表示不同的票价级别。可以快速识别票价区间以及任意两站间的出行成本。
| from(起点) | to(终点) | price(票价) |
|---|---|---|
| 湘湖 | 滨和路 | 2 |
| 湘湖 | 西兴 | 3 |
| ... | ... | ... |
<Demo height={524} code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 500,
});
// 地铁1号线站点
const sites = [
'湘湖',
'滨康路',
'西兴',
'滨和路',
'江陵路',
'近江',
'婺江路',
'城站',
'定安路',
'龙翔桥',
'凤起路',
'武林广场',
'西湖文化广场',
'打铁关',
'火车东站',
'闸弄口',
'彭埠',
'七堡',
'九和路',
'九堡',
'客运中心',
'下沙西',
'金沙湖',
'高沙路',
'文泽路',
];
// 生成地铁票价数据
const data = [];
for (let i = 0; i < sites.length; i++) {
for (let j = sites.length - 1; j >= i; j--) {
let price = 0;
const step = Math.abs(j - i);
if (step <= 2) {
price = 2;
} else if (step <= 4) {
price = 3;
} else if (step <= 7) {
price = 4;
} else if (step <= 13) {
price = 5;
} else if (step <= 16) {
price = 6;
} else if (step <= 21) {
price = 7;
} else {
price = 8;
}
data.push({ from: sites[i], to: sites[j], price: price });
}
}
chart.options({
type: 'cell',
autoFit: true,
data,
coordinate: {
type: 'cartesian',
},
legend: {
color: {
position: 'right',
title: '票价(元)',
flipPage: false,
},
},
scale: {
color: {
domain: [2, 3, 4, 5, 6, 7, 8],
range: [
'#ffffcc',
'#c7e9b4',
'#7fcdbb',
'#41b6c4',
'#2c7fb8',
'#253494',
'#081d58',
],
},
from: {
values: sites,
},
to: {
values: sites.slice().reverse(),
},
},
axis: {
x: {
title: false,
grid: false,
tickLine: false,
labelRotate: -Math.PI / 4,
labelOffset: 5,
},
y: {
title: false,
grid: false,
tickLine: false,
},
},
encode: {
x: 'from',
y: 'to',
color: 'price',
},
style: {
inset: 1,
stroke: '#fff',
strokeWidth: 1,
},
labels: [
{
text: 'price',
style: {
fill: (d) => (d.price > 5 ? '#fff' : '#000'),
textAlign: 'center',
fontSize: 10,
},
},
],
});
chart.render();
`} />
分析:
- 站名映射到了
x、y轴,以确定位置 - 票价映射到颜色深浅
- 票价数据是模拟的,仅表示大概情况
- 色块图便于快速识别票价区间和站点间的出行成本
例子 2: 考试成绩分析
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const students = [
'张三',
'李四',
'王五',
'赵六',
'钱七',
'孙八',
'周九',
'吴十',
];
const subjects = ['语文', '数学', '英语', '物理', '化学', '生物'];
// 生成成绩数据
const data = [];
students.forEach((student) => {
subjects.forEach((subject) => {
// 随机生成50-100之间的成绩
const score = Math.floor(Math.random() * 51) + 50;
data.push({
student,
subject,
score,
});
});
});
chart.options({
type: 'cell',
autoFit: true,
data,
coordinate: {
type: 'cartesian',
},
legend: {
color: {
position: 'right',
flipPage: false,
title: '分数',
},
},
scale: {
color: {
domain: [60, 70, 80, 90],
range: ['#F4664A', '#FAAD14', '#30BF78', '#0891B2', '#5B8FF9'],
},
},
encode: {
x: 'subject',
y: 'student',
color: 'score',
},
style: {
inset: 1,
},
labels: [
{
text: 'score',
style: {
fill: (d) => (d.score > 85 ? '#fff' : '#000'),
textAlign: 'center',
},
},
],
});
chart.render();
`} />
不适合的场景
例子 1: 数据点过少
当数据集只有少量的分类交叉点时,色块图可能不是最佳选择,这种情况下简单的表格或条形图可能更为直观。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
// 只有很少的数据点
const data = [
{ region: '东部', year: '2022', value: 125 },
{ region: '西部', year: '2022', value: 87 },
];
chart.options({
type: 'cell',
autoFit: true,
data,
encode: {
x: 'year',
y: 'region',
color: 'value',
},
style: {
inset: 1,
},
labels: [
{
text: 'value',
},
],
});
chart.render();
`} />
这种情况下,使用柱状图会更加直观:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ region: '东部', year: '2022', value: 125 },
{ region: '西部', year: '2022', value: 87 },
],
encode: {
x: 'region',
y: 'value',
color: 'region',
},
labels: [
{
text: 'value',
position: 'top',
},
],
});
chart.render();
`} />
例子 2: 需要展示精确趋势变化
当需要展示随时间的精确变化趋势时,色块图不如折线图直观。以下是一个使用色块图展示月度数据变化的例子,但这种情况更适合使用折线图。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const months = [
'一月',
'二月',
'三月',
'四月',
'五月',
'六月',
'七月',
'八月',
'九月',
'十月',
'十一月',
'十二月',
];
const data = months.map((month, index) => ({
month,
metric: '销售额',
value: 100 + Math.sin(index / 2) * 50 + Math.random() * 10,
}));
chart.options({
type: 'cell',
autoFit: true,
data,
encode: {
x: 'month',
y: 'metric',
color: 'value',
},
style: {
inset: 1,
},
labels: [
{
text: (d) => d.value.toFixed(0),
},
],
});
chart.render();
`} />
使用折线图更适合展示趋势:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const months = [
'一月',
'二月',
'三月',
'四月',
'五月',
'六月',
'七月',
'八月',
'九月',
'十月',
'十一月',
'十二月',
];
const data = months.map((month, index) => ({
month,
value: 100 + Math.sin(index / 2) * 50 + Math.random() * 10,
}));
chart.options({
type: 'line',
autoFit: true,
data,
encode: {
x: 'month',
y: 'value',
},
style: {
lineWidth: 2,
point: {
fill: '#1890ff',
r: 4,
},
},
labels: [
{
text: (d) => d.value.toFixed(0),
position: 'top',
},
],
});
chart.render();
`} />
色块图与其他图表的对比
色块图和[热力图](/zh/charts/heatmap/)、[矩形树图](/zh/charts/treemap/)
| 图表类型 | 主要特点 | 适用场景 | 数据要求 |
|---|---|---|---|
| 色块图 | 使用规则网格展示两个分类维度的交叉 | 分类数据之间的关系对比 | 两个分类维度和一个数值维度 |
| 热力图 | 可以使用连续尺度,展示数据的空间分布 | 展示空间密度或强度分布 | 通常需要连续的或近似连续的数据 |
| 矩形树图 | 通过嵌套矩形展示层次结构数据 | 表示层次数据的比例关系 | 需要有明确的层次结构 |
色块图最佳实践
设计建议
颜色选择
- 使用顺序色板表示连续数据的大小变化
- 使用发散色板表示与中心值的偏离程度
- 为颜色添加明确的图例和说明
网格设计
- 保持网格单元大小一致,确保可读性
- 在单元格中添加数值标签,增强精确度
- 考虑在单元格之间添加间距,提高辨识度
标签和交互
- 为重要数据点添加标签
- 添加悬停交互,显示详细信息
- 考虑添加排序功能,便于数据比较
色块图的扩展
色块图可以通过多种方式进行扩展,使其更适应不同的数据可视化需求:
- 分层色块图:在传统色块图基础上添加层级结构,使用嵌套矩形表示层次关系。
- 交互式色块图:增加悬停、点击等交互功能,允许用户探索详细信息。
- 动态色块图:通过动画展示随时间变化的数据模式,适合时间序列数据的可视化。
- 带聚类的色块图:结合聚类算法,自动对行或列进行重新排序,以便更容易识别相似模式。
- 带边界标记的色块图:在特定条件下为色块添加边框或标记,突出显示重要信息。
相似图表
分类
Site Docs Charts Contourline.En (`site/docs/charts/contourline.en.mdx`)
title: Contour Line Chart sidebar: { icon: 'map' } order: 18 screenshot: 'https://t.alipayobjects.com/images/T1EwViXkXbXXXXXXXX.png' category: ['distribution'] similar: ['heatmap', 'choropleth-map']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Contour Line Charts
A contour line chart displays closed curves connecting points of equal value on a map or data visualization. The most common example is topographic maps where contour lines connect points of equal elevation, with numbers marked on the lines indicating the elevation height. Contour lines can be classified into four types based on their function: index contours, intermediate contours, supplementary contours, and auxiliary contours.
Beyond topographic maps, contour lines are widely used in data visualization to display three-dimensional data distribution on a two-dimensional plane, such as temperature distribution, pressure distribution, probability density distribution, etc. Contour lines generally do not intersect, but sometimes they may coincide. All points on the same contour line have the same value. In areas where contour lines are sparse, the value changes gradually; where contour lines are dense, the value changes steeply.
Other Names: Contour Plot, Isoline Chart, Level Curve Chart
Components of a Contour Line Chart
| Chart Type | Contour Line Chart |
|---|---|
| Suitable Data | Three-dimensional data: two continuous variables (X, Y coordinates) and one numerical variable (Z value) |
| Function | Display distribution patterns and value changes of continuous data on a two-dimensional plane |
| Data-to-Visual Mapping | X coordinate maps to horizontal axis positionY coordinate maps to vertical axis positionZ value shown through contour line levels and labelsOptionally use color to represent value magnitude |
| Suitable Data Volume | Continuous two-dimensional grid data; more data points result in smoother contour lines |
Use Cases of Contour Line Charts
Suitable Use Cases
- Terrain Representation: The classic application, using contour lines to represent elevation, clearly showing topographic features like mountains and valleys.
- Meteorological Data: Displaying spatial variations in temperature distribution, pressure distribution, precipitation distribution, and other meteorological elements.
- Scientific Research: Showing two-dimensional distributions of electric fields, magnetic fields, concentrations, etc. in physics, chemistry, biology, and other fields.
- Business Analysis: Displaying the spatial distribution of market share, population density, consumption levels, etc.
- Probability Density: Showing the distribution patterns of two-dimensional probability density functions in statistics.
Unsuitable Use Cases
- Discrete Data: Contour lines require continuous value distributions and are not suitable for displaying discrete categorical data.
- Time Series: Contour lines are primarily used for spatial distribution and are not suitable for showing changes over time.
- Precise Value Reading: While values can be labeled, contour lines are mainly used to show trends and patterns, not for precise value reading.
- Sparse Data Points: When data points are too sparse, contour lines generated through interpolation may not be accurate enough.
Here is a typical application scenario for contour line charts:
Terrain Elevation Distribution Map. The chart below shows the elevation distribution of a mountainous area. Through contour lines, you can intuitively see the distribution of peaks, valleys, and slopes. Dense contour lines indicate steep slopes, while sparse contour lines indicate gentle terrain.
<Demo code={`import { Chart } from '@antv/g2';
// Simulate terrain elevation data
const terrainData = [];
for (let x = 0; x <= 50; x += 2) {
for (let y = 0; y <= 50; y += 2) {
// Simulate mountain terrain: elevation distribution of two peaks
const elevation1 = 100 * Math.exp(-((x - 15) ** 2 + (y - 15) ** 2) / 200);
const elevation2 = 80 * Math.exp(-((x - 35) ** 2 + (y - 35) ** 2) / 150);
const elevation = elevation1 + elevation2 + 10; // Base elevation
terrainData.push({ x, y, elevation });
}
}
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'cell',
data: terrainData,
encode: {
x: 'x',
y: 'y',
color: 'elevation',
},
style: {
stroke: '#333',
strokeWidth: 0.5,
inset: 0.5,
},
scale: {
color: {
palette: 'viridis',
type: 'sequential',
},
},
legend: {
color: {
length: 300,
layout: { justifyContent: 'center' },
labelFormatter: (value) => `${Math.round(value)}m`,
},
},
tooltip: {
title: 'Elevation Information',
items: [
{ field: 'x', name: 'Longitude' },
{ field: 'y', name: 'Latitude' },
{
field: 'elevation',
name: 'Elevation',
valueFormatter: (value) => `${Math.round(value)}m`,
},
],
},
});
chart.render();
`} />
This example demonstrates:
- Using grid cells to simulate contour line effects, displaying terrain elevation distribution
- Using color gradients to represent different elevation heights, creating a contour line-like visual effect
- Providing interactive hover tooltips showing specific location and elevation information
- Using appropriate color mapping (viridis palette) to enhance visual effects
- Adding strokes to highlight grid boundaries, enhancing contour line visual perception
Contour Line Chart Extensions
Contour Outline Chart
Using lines to draw contour outlines, closer to traditional topographic map representation.
<Demo height={424} code={`import { Chart } from '@antv/g2';
// Generate contour line data
const generateContourLines = () => {
const lines = [];
const levels = [20, 40, 60, 80, 100]; // Contour line levels
levels.forEach((level, index) => {
// Generate circular lines for each contour level
const points = [];
const centerX = 25;
const centerY = 25;
const baseRadius = 5 + index * 4;
for (let angle = 0; angle <= 360; angle += 5) {
const radian = (angle * Math.PI) / 180;
const radius = baseRadius + Math.sin((angle * Math.PI) / 45) * 2; // Add some variation
const x = centerX + radius * Math.cos(radian);
const y = centerY + radius * Math.sin(radian);
points.push({ x, y, level, lineId: \`line_\${level}\` });
}
lines.push(...points);});
return lines;
};
const contourLines = generateContourLines();
const chart = new Chart({
container: 'container',
autoFit: true,
height: 400,
});
chart.options({
type: 'line',
data: contourLines,
encode: {
x: 'x',
y: 'y',
color: 'level',
series: 'lineId',
},
style: {
strokeWidth: 2,
strokeOpacity: 0.8,
},
scale: {
color: {
type: 'sequential',
palette: 'oranges',
},
x: { nice: true },
y: { nice: true },
},
axis: {
x: { title: 'Distance (km)' },
y: { title: 'Distance (km)' },
},
legend: {
color: {
title: 'Elevation (m)',
layout: { justifyContent: 'center' },
},
},
tooltip: {
title: 'Contour Information',
items: [
{
field: 'level',
name: 'Elevation',
valueFormatter: (value) => `${value}m`,
},
],
},
});
chart.render();
`} />
- 3D Contour Lines: Combining three-dimensional visualization technology to create three-dimensional contour charts that more intuitively display spatial data distribution.
- Dynamic Contour Lines: Using animation to show data changes over time, such as the temporal evolution of meteorological data.
- Interactive Annotation: Allowing users to click on contour lines to view specific values or dynamically adjust contour line intervals.
- Multi-layer Overlay: Overlaying contour lines from multiple data layers in the same chart, such as simultaneously displaying temperature and pressure distributions.
Comparing Contour Line Charts to Other Charts
Contour Line Charts and [Heatmaps](/en/charts/heatmap/)
- Contour Line Charts: Use lines to represent areas of equal value, emphasizing value continuity and gradient changes, suitable for showing gradual trends.
- Heatmaps: Use color filling to represent value magnitude, more intuitively showing absolute value size and spatial distribution patterns.
Contour Line Charts and [Scatter Plots](/en/charts/scatter-plot/)
- Contour Line Charts: Display continuous distribution data patterns, generating smooth isolines through interpolation.
- Scatter Plots: Display discrete data point distributions, maintaining data originality without interpolation processing.
Contour Line Charts and Topographic Maps
- Contour Line Charts: Pure data visualization tools that can be used for any two-dimensional continuous data.
- Topographic Maps: Specifically for geographic information, including roads, rivers, buildings, and other geographic elements in addition to contour lines.
Similar Charts
Categories
Site Docs Charts Contourline.Zh (`site/docs/charts/contourline.zh.mdx`)
title: 等高线图 sidebar: { icon: 'map' } order: 18 screenshot: 'https://t.alipayobjects.com/images/T1EwViXkXbXXXXXXXX.png' category: ['distribution'] similar: ['heatmap', 'choropleth-map']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
等高线图的简介
等高线图是通过连接地图上相同数值的点得到的闭合曲线图。最常见的是地形图上海拔高度相等的各点所连成的等高线,在等高线上标注的数字为该等高线的海拔高度。等高线按其作用不同,可分为首曲线、计曲线、间曲线与助曲线四种。
除地形图之外,等高线也广泛应用于数据可视化中,用于显示二维平面上的三维数据分布,如温度分布、气压分布、概率密度分布等。等高线一般不相交,但有时可能会重合。在同一等高线上的各点数值相同。在等高线稀疏的地方,数值变化较缓;而在等高线稠密的地方,数值变化较陡。
英文名:Contour Line, Contour Plot
等高线图的构成
| 图表类型 | 等高线图 |
|---|---|
| 适合的数据 | 三维数据:两个连续变量(X、Y 坐标)和一个数值变量(Z 值) |
| 功能 | 显示二维平面上连续数据的分布模式和数值变化 |
| 数据与图形的映射 | X 坐标映射到横轴位置Y 坐标映射到纵轴位置Z 值通过等高线的层次和标注显示可选择性地用颜色表示数值大小 |
| 适合的数据条数 | 连续的二维网格数据,数据点越多,等高线越平滑 |
等高线图的应用场景
适合的场景
- 地形表示:最经典的应用,用等高线表示海拔高度,清晰展示山脉、谷地等地形特征。
- 气象数据:显示温度分布、气压分布、降雨量分布等气象要素的空间变化。
- 科学研究:在物理学、化学、生物学等领域显示电场、磁场、浓度等二维分布。
- 商业分析:展示市场份额、人口密度、消费水平等在地理空间上的分布。
- 概率密度:在统计学中显示二维概率密度函数的分布形态。
不适合的场景
- 离散数据:等高线需要连续的数值分布,不适合显示离散的分类数据。
- 时间序列:等高线主要用于空间分布,不适合显示时间维度的变化。
- 精确数值读取:虽然可以标注数值,但等高线主要用于显示趋势和模式,不适合精确读取具体数值。
- 数据点稀疏:当数据点过于稀疏时,插值生成的等高线可能不够准确。
以下是一个典型的等高线图应用场景:
地形海拔分布图。 下图展示了某山区的海拔高度分布,通过等高线可以直观地看出山峰、山谷和坡度的分布情况。等高线密集的地方表示坡度陡峭,等高线稀疏的地方表示地势平缓。
<Demo code={`import { Chart } from '@antv/g2';
// 模拟地形高程数据
const terrainData = [];
for (let x = 0; x <= 50; x += 2) {
for (let y = 0; y <= 50; y += 2) {
// 模拟山峰地形:两个山峰的高程分布
const elevation1 = 100 * Math.exp(-((x - 15) ** 2 + (y - 15) ** 2) / 200);
const elevation2 = 80 * Math.exp(-((x - 35) ** 2 + (y - 35) ** 2) / 150);
const elevation = elevation1 + elevation2 + 10; // 基础海拔
terrainData.push({ x, y, elevation });
}
}
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'cell',
data: terrainData,
encode: {
x: 'x',
y: 'y',
color: 'elevation',
},
style: {
stroke: '#333',
strokeWidth: 0.5,
inset: 0.5,
},
scale: {
color: {
palette: 'viridis',
type: 'sequential',
},
},
legend: {
color: {
length: 300,
layout: { justifyContent: 'center' },
labelFormatter: (value) => `${Math.round(value)}m`,
},
},
tooltip: {
title: '海拔信息',
items: [
{ field: 'x', name: '经度' },
{ field: 'y', name: '纬度' },
{
field: 'elevation',
name: '海拔',
valueFormatter: (value) => `${Math.round(value)}m`,
},
],
},
});
chart.render();
`} />
这个例子展示了:
- 使用网格单元格(cell)模拟等高线效果,显示地形海拔分布
- 通过颜色渐变表示不同的海拔高度,形成类似等高线的视觉效果
- 提供交互式的悬停提示显示具体位置和海拔信息
- 使用合适的色彩映射(viridis 色板)来增强视觉效果
- 添加描边来突出网格边界,增强等高线的视觉感知
等高线图的扩展
等高线轮廓图
使用线条绘制等高线轮廓,更接近传统地形图的表现形式。
<Demo height={424} code={`import { Chart } from '@antv/g2';
// 生成等高线数据
const generateContourLines = () => {
const lines = [];
const levels = [20, 40, 60, 80, 100]; // 等高线级别
levels.forEach((level, index) => {
// 为每个等高线级别生成环形线条
const points = [];
const centerX = 25;
const centerY = 25;
const baseRadius = 5 + index * 4;
for (let angle = 0; angle <= 360; angle += 5) {
const radian = (angle * Math.PI) / 180;
const radius = baseRadius + Math.sin((angle * Math.PI) / 45) * 2; // 添加一些变化
const x = centerX + radius * Math.cos(radian);
const y = centerY + radius * Math.sin(radian);
points.push({ x, y, level, lineId: \`line_\${level}\` });
}
lines.push(...points);});
return lines;
};
const contourLines = generateContourLines();
const chart = new Chart({
container: 'container',
autoFit: true,
height: 400,
});
chart.options({
type: 'line',
data: contourLines,
encode: {
x: 'x',
y: 'y',
color: 'level',
series: 'lineId',
},
style: {
strokeWidth: 2,
strokeOpacity: 0.8,
},
scale: {
color: {
type: 'sequential',
palette: 'oranges',
},
x: { nice: true },
y: { nice: true },
},
axis: {
x: { title: '距离 (km)' },
y: { title: '距离 (km)' },
},
legend: {
color: {
title: '海拔高度 (m)',
layout: { justifyContent: 'center' },
},
},
tooltip: {
title: '等高线信息',
items: [
{ field: 'level', name: '海拔', valueFormatter: (value) => `${value}m` },
],
},
});
chart.render();
`} />
- 3D 等高线:结合三维可视化技术,可以创建立体的等高线图,更直观地展示数据的空间分布。
- 动态等高线:通过动画展示数据随时间的变化,如气象数据的时间演变。
- 交互式标注:允许用户点击等高线查看具体数值,或者动态调整等高线的间隔。
- 多层叠加:在同一图表中叠加多个数据层的等高线,如同时显示温度和气压分布。
等高线图与其他图表的对比
等高线图与热力图
- 等高线图:通过线条表示数值相等的区域,强调数值的连续性和梯度变化,适合显示渐变趋势。
- 热力图:通过颜色填充表示数值大小,更直观地显示数值的绝对大小和空间分布模式。
等高线图与散点图
- 等高线图:显示连续分布的数据模式,通过插值生成平滑的等值线。
- 散点图:显示离散数据点的分布,保持数据的原始性,不进行插值处理。
等高线图与地形图
- 等高线图:纯粹的数据可视化工具,可用于任何二维连续数据。
- 地形图:专门用于地理信息,除等高线外还包含道路、河流、建筑等地理要素。
相似图表
分类
Site Docs Charts Distributioncurve.En (`site/docs/charts/distributioncurve.en.mdx`)
title: Distribution Curve sidebar: { icon: 'area' } order: 2 screenshot: 'https://t.alipayobjects.com/images/T1BjJkXcxgXXXXXXXX.png' category: ['distribution'] similar: ['line', 'violin', 'histogram']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Distribution Curve
A distribution curve is a statistical chart used to display the frequency distribution of data, intuitively reflecting the distribution density and central tendency of data across different value intervals through smooth curve forms. It is an important visualization tool for understanding data distribution characteristics and identifying data patterns.
Distribution curves are particularly suitable for exploratory data analysis, comparing distributions across multiple groups, data quality checking, and identifying statistical distribution characteristics, making them important tools in statistical analysis and data science.
English Name: Distribution Curve, Frequency Curve, Density Curve
Components of Distribution Curve
A distribution curve consists of the following elements:
- Horizontal axis: represents the independent variable
- Vertical axis: represents the dependent variable
- Distribution curve representing probability distribution
Application Scenarios for Distribution Curves
Suitable Scenarios
Example 1: Displaying distribution characteristics of normal distribution data
Distribution curves are very suitable for displaying normal distribution data, clearly showing the central tendency, symmetry, and distribution shape of the data.
<Demo code={`import { Chart } from '@antv/g2';
// Generate normal distribution data
const generateNormalData = (count, mean, std) => {
const data = [];
for (let i = 0; i < count; i++) {
// Use Box-Muller transform to generate normal distribution data
const u1 = Math.random();
const u2 = Math.random();
const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
data.push({ value: mean + std * z0 });
}
return data;
};
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'line',
data: {
value: generateNormalData(1000, 100, 15),
transform: [
{
type: 'custom',
callback: (data) => {
// Extract numerical data
const values = data.map(d => d.value).filter(v => !isNaN(v));
// Calculate data range
const min = Math.min(...values);
const max = Math.max(...values);
const binCount = 30;
const binWidth = (max - min) / binCount;
// Create bins
const bins = Array.from({ length: binCount }, (_, i) => ({
x0: min + i * binWidth,
x1: min + (i + 1) * binWidth,
count: 0,
}));
// Count frequency for each bin
values.forEach(value => {
const binIndex = Math.min(
Math.floor((value - min) / binWidth),
binCount - 1
);
bins[binIndex].count++;
});
// Calculate frequency density and generate curve data
const total = values.length;
return bins.map(bin => ({
x: (bin.x0 + bin.x1) / 2, // Bin center point
y: bin.count / total, // Frequency density
frequency: bin.count,
range: \`\${bin.x0.toFixed(1)}-\${bin.x1.toFixed(1)}\`,
}));
},
},
], },
encode: {
x: 'x',
y: 'y',
shape: 'smooth',
},
style: {
lineWidth: 3,
stroke: '#1890ff',
},
axis: {
x: { title: 'Measured Value' },
y: { title: 'Frequency Density' },
},
tooltip: {
title: (d) => `Range: ${d.range}`,
items: [
{ field: 'frequency', name: 'Frequency' },
{ field: 'y', name: 'Frequency Density', valueFormatter: '.3f' },
],
},
});
chart.render();
`} />
Description:
- Displays the classic bell-shaped normal distribution curve
- Clearly observes the symmetry and central tendency of the data
- Suitable for data analysis in quality control, biostatistics, psychological measurement, and other fields
Example 2: Comparative analysis of multiple group distributions
When comparing data distributions under different conditions or groups, distribution curves can intuitively show distribution differences between groups.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'line',
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/species.json',
transform: [
{
type: 'custom',
callback: (data) => {
// Group data by species
const groups = {};
data.forEach(d => {
if (!groups[d.species]) groups[d.species] = [];
groups[d.species].push(d.y);
});
const binCount = 20;
const results = [];
// Create distribution curve data for each species
Object.entries(groups).forEach(([species, values]) => {
const filteredValues = values.filter(v => !isNaN(v));
if (filteredValues.length === 0) return;
const min = Math.min(...filteredValues);
const max = Math.max(...filteredValues);
const binWidth = (max - min) / binCount;
// Create bins
const bins = Array.from({ length: binCount }, (_, i) => ({
x0: min + i * binWidth,
x1: min + (i + 1) * binWidth,
count: 0,
}));
// Count frequencies
filteredValues.forEach(value => {
const binIndex = Math.min(
Math.floor((value - min) / binWidth),
binCount - 1
);
bins[binIndex].count++;
});
// Generate curve data
const total = filteredValues.length;
bins.forEach(bin => {
results.push({
x: (bin.x0 + bin.x1) / 2,
y: bin.count / total,
species,
frequency: bin.count,
range: \`\${bin.x0.toFixed(2)}-\${bin.x1.toFixed(2)}\`,
});
});
});
return results;
},
},
], },
encode: {
x: 'x',
y: 'y',
color: 'species',
shape: 'smooth',
},
style: {
lineWidth: 2,
strokeOpacity: 0.8,
},
axis: {
x: { title: 'Petal Length' },
y: { title: 'Frequency Density' },
},
legend: {
color: {
title: 'Species',
position: 'right',
},
},
tooltip: {
title: (d) => `${d.species} - Range: ${d.range}`,
items: [
{ field: 'frequency', name: 'Frequency' },
{ field: 'y', name: 'Frequency Density', valueFormatter: '.3f' },
],
},
});
chart.render();
`} />
Description:
- Compares distribution characteristics of multiple groups through curves of different colors
- Facilitates identification of distribution centers, shapes, and dispersion of each group
- Suitable for A/B testing analysis, experimental control group comparisons, market segmentation analysis, and other scenarios
Unsuitable Scenarios
Example 1: Poor effectiveness with insufficient data
When there are too few data points, binning statistics may not be accurate enough, and the generated distribution curve may not accurately reflect true distribution characteristics.
<Demo height={274} code={`import { Chart } from '@antv/g2';
// Simulate small amount of data
const smallData = [
12, 15, 13, 14, 16, 18, 11, 17, 15, 13
];
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 250,
});
chart.options({
type: 'point',
data: smallData.map((value, index) => ({ index: index + 1, value })),
encode: {
x: 'index',
y: 'value',
size: 6,
},
style: {
fill: '#1890ff',
fillOpacity: 0.8,
},
axis: {
x: { title: 'Data Point Index' },
y: { title: 'Value' },
},
title: 'Scatter plot recommended for small datasets',
});
chart.render();
`} />
Problem Description:
- When there are too few data points (less than 30), each interval has too little data after binning
- The generated distribution curve may show artificial fluctuations and irregular shapes
- Cannot accurately reflect true data distribution characteristics
- Recommend using scatter plots, box plots, or increasing data collection
Example 2: Discrete categorical data is not applicable
For discrete categorical data, continuous distribution curves have no practical meaning because there is no continuity relationship between categories.
<Demo height={274} code={`import { Chart } from '@antv/g2';
// Discrete categorical data
const discreteData = [
{ category: 'Product A', sales: 45 },
{ category: 'Product B', sales: 67 },
{ category: 'Product C', sales: 33 },
{ category: 'Product D', sales: 52 },
{ category: 'Product E', sales: 28 },
];
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 250,
});
chart.options({
type: 'interval',
data: discreteData,
encode: {
x: 'category',
y: 'sales',
color: 'category',
},
style: {
fillOpacity: 0.8,
},
axis: {
x: { title: 'Product Category' },
y: { title: 'Sales Quantity' },
},
title: 'Bar chart recommended for categorical data',
});
chart.render();
`} />
Problem Description:
- No continuity relationship exists between categorical data; forcing connections would be misleading
- Distribution curves cannot express the true meaning of categorical data
- Bar charts can more accurately express comparison relationships in categorical data
- Suitable for using discrete chart types such as bar charts and pie charts
Comparison with Other Charts
Distribution Curve vs [Histogram](/en/charts/histogram/)
- Distribution curves display continuous frequency distribution through smooth curves, emphasizing overall trends
- Histograms display frequency distribution through rectangular bars with clear interval boundaries
- Distribution curves are more suitable for displaying overall distribution shape and trend identification
- Histograms are more suitable for precise frequency statistics and interval analysis
Distribution Curve vs [Violin Plot](/en/charts/violin/)
- Distribution curves focus on displaying the curve shape of frequency distribution
- Violin plots combine density distribution with statistical summary information from box plots
- Distribution curves are more suitable for pure distribution shape analysis and multi-group comparisons
- Violin plots are more suitable for scenarios requiring statistical summary information
Distribution Curve vs [Line Chart](/en/charts/line/)
- Distribution curves are based on frequency statistics, displaying data distribution characteristics
- Line charts show data change trends over time or sequence
- Distribution curves are suitable for statistical analysis and distribution exploration
- Line charts are suitable for time series analysis and trend tracking
Similar Charts
Category
Site Docs Charts Distributioncurve.Zh (`site/docs/charts/distributioncurve.zh.mdx`)
title: 分布曲线图 sidebar: { icon: 'area' } order: 2 screenshot: 'https://t.alipayobjects.com/images/T1BjJkXcxgXXXXXXXX.png' category: ['distribution'] similar: ['line', 'violin', 'histogram']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
分布曲线图的简介
分布曲线图是一种用于展示数据频率分布的统计图表,通过平滑的曲线形式直观地反映数据在不同数值区间的分布密度和集中趋势。它是理解数据分布特征、识别数据模式的重要可视化工具。
分布曲线图特别适合用于探索性数据分析、多组数据分布比较、数据质量检查以及统计分布特征识别等场景,是统计分析和数据科学中的重要工具。
英文名:Distribution Curve, Frequency Curve, Density Curve
分布曲线图的构成
分布曲线图由以下元素构成:
- 横轴:表示自变量
- 纵轴:表示因变量
- 表示概率分布的分布曲线
分布曲线图的应用场景
适合的场景
例子 1: 展示正态分布数据的分布特征
分布曲线图非常适合展示正态分布数据,能够清晰地显示数据的集中趋势、对称性和分布形态。
<Demo code={`import { Chart } from '@antv/g2';
// 生成正态分布数据
const generateNormalData = (count, mean, std) => {
const data = [];
for (let i = 0; i < count; i++) {
// 使用Box-Muller变换生成正态分布数据
const u1 = Math.random();
const u2 = Math.random();
const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
data.push({ value: mean + std * z0 });
}
return data;
};
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'line',
data: {
value: generateNormalData(1000, 100, 15),
transform: [
{
type: 'custom',
callback: (data) => {
// 提取数值数据
const values = data.map(d => d.value).filter(v => !isNaN(v));
// 计算数据范围
const min = Math.min(...values);
const max = Math.max(...values);
const binCount = 30;
const binWidth = (max - min) / binCount;
// 创建分箱
const bins = Array.from({ length: binCount }, (_, i) => ({
x0: min + i * binWidth,
x1: min + (i + 1) * binWidth,
count: 0,
}));
// 统计每个分箱的频数
values.forEach(value => {
const binIndex = Math.min(
Math.floor((value - min) / binWidth),
binCount - 1
);
bins[binIndex].count++;
});
// 计算频率密度并生成曲线数据
const total = values.length;
return bins.map(bin => ({
x: (bin.x0 + bin.x1) / 2, // 区间中心点
y: bin.count / total, // 频率密度
frequency: bin.count,
range: \`\${bin.x0.toFixed(1)}-\${bin.x1.toFixed(1)}\`,
}));
},
},
], },
encode: {
x: 'x',
y: 'y',
shape: 'smooth',
},
style: {
lineWidth: 3,
stroke: '#1890ff',
},
axis: {
x: { title: '测量值' },
y: { title: '频率密度' },
},
tooltip: {
title: (d) => `区间: ${d.range}`,
items: [
{ field: 'frequency', name: '频数' },
{ field: 'y', name: '频率密度', valueFormatter: '.3f' },
],
},
});
chart.render();
`} />
说明:
- 展示了经典的钟形正态分布曲线
- 可以清晰观察到数据的对称性和集中趋势
- 适合质量控制、生物统计、心理测量等领域的数据分析
例子 2: 多组数据分布比较分析
当需要比较不同条件或分组下的数据分布时,分布曲线图能够直观地展示各组间的分布差异。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'line',
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/species.json',
transform: [
{
type: 'custom',
callback: (data) => {
// 按物种分组数据
const groups = {};
data.forEach(d => {
if (!groups[d.species]) groups[d.species] = [];
groups[d.species].push(d.y);
});
const binCount = 20;
const results = [];
// 为每个物种创建分布曲线数据
Object.entries(groups).forEach(([species, values]) => {
const filteredValues = values.filter(v => !isNaN(v));
if (filteredValues.length === 0) return;
const min = Math.min(...filteredValues);
const max = Math.max(...filteredValues);
const binWidth = (max - min) / binCount;
// 创建分箱
const bins = Array.from({ length: binCount }, (_, i) => ({
x0: min + i * binWidth,
x1: min + (i + 1) * binWidth,
count: 0,
}));
// 统计频数
filteredValues.forEach(value => {
const binIndex = Math.min(
Math.floor((value - min) / binWidth),
binCount - 1
);
bins[binIndex].count++;
});
// 生成曲线数据
const total = filteredValues.length;
bins.forEach(bin => {
results.push({
x: (bin.x0 + bin.x1) / 2,
y: bin.count / total,
species,
frequency: bin.count,
range: \`\${bin.x0.toFixed(2)}-\${bin.x1.toFixed(2)}\`,
});
});
});
return results;
},
},
], },
encode: {
x: 'x',
y: 'y',
color: 'species',
shape: 'smooth',
},
style: {
lineWidth: 2,
strokeOpacity: 0.8,
},
axis: {
x: { title: '花瓣长度' },
y: { title: '频率密度' },
},
legend: {
color: {
title: '物种',
position: 'right',
},
},
tooltip: {
title: (d) => `${d.species} - 区间: ${d.range}`,
items: [
{ field: 'frequency', name: '频数' },
{ field: 'y', name: '频率密度', valueFormatter: '.3f' },
],
},
});
chart.render();
`} />
说明:
- 通过不同颜色的曲线比较多个分组的分布特征
- 便于识别各组数据的分布中心、形态和离散程度
- 适合A/B测试分析、实验对照组比较、市场细分分析等场景
不适合的场景
例子 1: 数据量过少时效果不佳
当数据点过少时,分箱统计可能不够准确,生成的分布曲线可能不能准确反映真实的分布特征。
<Demo height={274} code={`import { Chart } from '@antv/g2';
// 模拟少量数据
const smallData = [
12, 15, 13, 14, 16, 18, 11, 17, 15, 13
];
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 250,
});
chart.options({
type: 'point',
data: smallData.map((value, index) => ({ index: index + 1, value })),
encode: {
x: 'index',
y: 'value',
size: 6,
},
style: {
fill: '#1890ff',
fillOpacity: 0.8,
},
axis: {
x: { title: '数据点序号' },
y: { title: '数值' },
},
title: '数据量少时建议使用散点图',
});
chart.render();
`} />
问题说明:
- 数据点太少(少于30个)时,分箱后每个区间的数据过少
- 生成的分布曲线可能出现人工的波动和不规律的形状
- 无法准确反映真实的数据分布特征
- 建议改用散点图、箱形图或增加数据收集
例子 2: 离散型分类数据不适用
对于离散的分类数据,连续的分布曲线没有实际意义,因为分类之间不存在连续性关系。
<Demo height={274} code={`import { Chart } from '@antv/g2';
// 离散分类数据
const discreteData = [
{ category: '产品A', sales: 45 },
{ category: '产品B', sales: 67 },
{ category: '产品C', sales: 33 },
{ category: '产品D', sales: 52 },
{ category: '产品E', sales: 28 },
];
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 250,
});
chart.options({
type: 'interval',
data: discreteData,
encode: {
x: 'category',
y: 'sales',
color: 'category',
},
style: {
fillOpacity: 0.8,
},
axis: {
x: { title: '产品类别' },
y: { title: '销售数量' },
},
title: '分类数据建议使用柱状图',
});
chart.render();
`} />
问题说明:
- 分类数据之间没有连续性关系,强行连接会产生误导
- 分布曲线无法表达分类数据的真实含义
- 柱状图能更准确地表达分类数据的比较关系
- 适合使用柱状图、饼图等离散图表类型
分布曲线图与其他图表的对比
分布曲线图和[直方图](/zh/charts/histogram/)
- 分布曲线图通过平滑的曲线展示连续的频率分布,强调整体趋势
- 直方图通过矩形柱状图展示频数分布,具有明确的区间边界
- 分布曲线图更适合展示分布的整体形态和趋势识别
- 直方图更适合精确的频数统计和区间分析
分布曲线图和[小提琴图](/zh/charts/violin/)
- 分布曲线图专注于展示频率分布的曲线形态
- 小提琴图结合了密度分布和箱形图的统计摘要信息
- 分布曲线图更适合纯粹的分布形态分析和多组比较
- 小提琴图更适合需要统计摘要信息的场景
分布曲线图和[折线图](/zh/charts/line/)
- 分布曲线图基于频率统计,展示数据的分布特征
- 折线图展示数据随时间或顺序的变化趋势
- 分布曲线图适合统计分析和分布探索
- 折线图适合时间序列分析和趋势追踪
相似图表
分类
Site Docs Charts Donut Chart.En (`site/docs/charts/donut-chart.en.mdx`)
title: Donut Chart sidebar: { icon: 'pie' } order: 6 screenshot: 'https://os.alipayobjects.com/rmsportal/LviFnOknmSGUCHZ.png' category: ['proportion'] similar: ['pie', 'rose', 'radial-bar']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Donut Charts
A donut chart (also known as a doughnut chart) is essentially a pie chart with its center area removed. Donut charts encourage us to focus more on arc length rather than area, making it relatively simple to compare different donut charts.
While donut charts and pie charts are similar in terms of data representation, donut charts have their unique advantages:
- Better Comparison: Pie charts have strong visual unity, causing viewers to focus on comparing the proportional relationships between slices within a single chart. However, when comparing two pie charts side by side, pie charts make it difficult to compare across different charts. Donut charts solve this problem.
- Better Space Utilization: Donut charts can utilize their hollow center area to display text information such as titles, totals, or other important data.
Other Names: Doughnut Chart
Components of a Donut Chart
| Chart Type | Donut Chart |
|---|---|
| Suitable Data | A dataset containing one categorical field and one numerical field |
| Functionality | Compare the size of numerical values across categories |
| Data Mapping | Categorical data maps to arc colorsNumerical data maps to arc anglesProportional relationships shown by arc size |
| Data Size Limit | Recommended for no more than 9 data points |
Use Cases of Donut Charts
Suitable Use Cases
Example 1: Displaying Categorical Proportions
This usage is similar to pie charts. The chart below shows sales data from a gaming company:
| Genre | Sales |
|---|---|
| Sports | 27,500 |
| Strategy | 11,500 |
| Action | 6,000 |
| Shooter | 3,500 |
| Other | 1,500 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
transform: [{ type: 'stackY' }], // Add stackY transform
data: [
{ genre: 'Sports', sold: 27500 },
{ genre: 'Strategy', sold: 11500 },
{ genre: 'Action', sold: 6000 },
{ genre: 'Shooter', sold: 3500 },
{ genre: 'Other', sold: 1500 },
],
coordinate: { type: 'theta', innerRadius: 0.5 },
encode: { y: 'sold', color: 'genre' },
legend: {
color: { position: 'bottom', layout: { justifyContent: 'center' } },
},
labels: [
{
text: 'genre',
style: {
fontWeight: 'bold',
},
},
{
text: (d, i, data) => {
const total = data.reduce((acc, curr) => acc + curr.sold, 0);
const percent = ((d.sold / total) * 100).toFixed(2);
return `${percent}%`;
},
style: {
fontSize: 10,
dy: 12,
},
},
],
});
chart.render();
`} />
Explanation:
- The
genrefield maps tocolorto distinguish different game types - The
soldfield maps toangleto represent the proportion of sales - Using
coordinate: { type: 'theta', innerRadius: 0.5 }creates the donut effect
Example 2: Displaying Additional Information in the Center
The hollow center area of donut charts can be used to display totals, titles, or other important information:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const data = [
{ type: 'Mobile', value: 54.2 },
{ type: 'Desktop', value: 32.1 },
{ type: 'Tablet', value: 13.7 },
];
const total = data.reduce((acc, curr) => acc + curr.value, 0);
chart.options({
type: 'interval',
autoFit: true,
data,
coordinate: { type: 'theta', innerRadius: 0.6 },
encode: { y: 'value', color: 'type' },
style: { stroke: '#fff', lineWidth: 2 },
legend: {
color: { position: 'bottom', layout: { justifyContent: 'center' } },
},
labels: [
{
text: (d) => `${d.value}%`,
style: {
fontWeight: 'bold',
fontSize: 12,
},
},
],
});
chart.render();
`} />
Unsuitable Use Cases
Example 1: Too Many Categories
The chart below shows population proportions by province. Due to the excessive number of categories, it's difficult to clearly compare population data across provinces. In such cases, we recommend using bar charts.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ province: 'Beijing', population: 19612368 },
{ province: 'Tianjin', population: 12938693 },
{ province: 'Hebei', population: 71854210 },
{ province: 'Shanxi', population: 27500000 },
{ province: 'Inner Mongolia', population: 24706291 },
{ province: 'Liaoning', population: 43746323 },
{ province: 'Jilin', population: 27452815 },
{ province: 'Heilongjiang', population: 38313991 },
{ province: 'Shanghai', population: 23019196 },
{ province: 'Jiangsu', population: 78660941 },
{ province: 'Zhejiang', population: 54426891 },
{ province: 'Anhui', population: 59500468 },
{ province: 'Fujian', population: 36894217 },
{ province: 'Jiangxi', population: 44567797 },
{ province: 'Shandong', population: 95792719 },
{ province: 'Henan', population: 94029939 },
{ province: 'Hubei', population: 57237727 },
{ province: 'Hunan', population: 65700762 },
{ province: 'Guangdong', population: 104320459 },
{ province: 'Guangxi', population: 46023761 },
{ province: 'Hainan', population: 8671485 },
{ province: 'Chongqing', population: 28846170 },
{ province: 'Sichuan', population: 80417528 },
{ province: 'Guizhou', population: 34748556 },
{ province: 'Yunnan', population: 45966766 },
{ province: 'Tibet', population: 3002165 },
{ province: 'Shaanxi', population: 37327379 },
{ province: 'Gansu', population: 25575263 },
{ province: 'Qinghai', population: 5626723 },
],
coordinate: { type: 'theta', innerRadius: 0.4 },
encode: { y: 'population', color: 'province' },
legend: false, // Too many categories, disable legend
labels: false, // Too many categories, disable labels
});
chart.render();
`} />
Explanation: The chart above has too many categories, making colors difficult to distinguish and labels severely overlapping, making it unsuitable for donut charts.
Example 2: Similar Proportions Among Categories
In the chart below, different game genres have similar sales volumes with very small angular differences, making donut charts unsuitable. In this case, bar charts would be more appropriate.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ genre: 'Sports', sold: 15000 },
{ genre: 'Strategy', sold: 14900 },
{ genre: 'Action', sold: 15050 },
{ genre: 'Shooter', sold: 13000 },
{ genre: 'Other', sold: 13900 },
],
coordinate: { type: 'theta', innerRadius: 0.5 },
encode: { y: 'sold', color: 'genre' },
legend: {
color: { position: 'bottom', layout: { justifyContent: 'center' } },
},
labels: [
{
text: (d, i, data) => {
const total = data.reduce((acc, curr) => acc + curr.sold, 0);
const percent = ((d.sold / total) * 100).toFixed(2);
return `${percent}%`;
},
style: {
fontSize: 10,
},
},
],
});
chart.render();
`} />
Explanation: Each category in the chart above has a proportion close to 20%, with very small differences that are difficult to clearly compare through angular sizes.
Extensions of Donut Charts
Faceted Donut Charts
Using G2's faceting functionality, grouped data can be rendered as multiple donut charts. The chart below shows the profit proportions of the world's largest 1000 banks by region in 2007 and 2011:
| Year | Region | Profit (Billion USD) |
|---|---|---|
| 2007 | Asia Pacific | 1485.54 |
| 2007 | Africa & Middle East | 330.12 |
| 2007 | Latin America | 196.5 |
| ... | ... | ... |
| 2011 | Asia Pacific | 4107.18 |
| 2011 | Africa & Middle East | 495.3 |
| 2011 | Latin America | 495.3 |
| ... | ... | ... |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'facetRect',
autoFit: true,
data: [
{ year: '2007', area: 'Asia Pacific', profit: 1485.54 },
{ year: '2007', area: 'Western Europe', profit: 3631.32 },
{ year: '2007', area: 'North America', profit: 2083.9 },
{ year: '2007', area: 'Africa & Middle East', profit: 330.12 },
{ year: '2007', area: 'Central & Eastern Europe', profit: 141.48 },
{ year: '2007', area: 'Latin America', profit: 196.5 },
{ year: '2011', area: 'Asia Pacific', profit: 4107.18 },
{ year: '2011', area: 'Western Europe', profit: 480.06 },
{ year: '2011', area: 'North America', profit: 1783.08 },
{ year: '2011', area: 'Africa & Middle East', profit: 495.3 },
{ year: '2011', area: 'Central & Eastern Europe', profit: 259.08 },
{ year: '2011', area: 'Latin America', profit: 495.3 },
],
encode: { x: 'year' },
children: [
{
type: 'interval',
transform: [{ type: 'stackY' }], // Add stackY transform
coordinate: { type: 'theta', innerRadius: 0.5 },
encode: { y: 'profit', color: 'area' },
legend: {
color: { position: 'bottom', layout: { justifyContent: 'center' } },
},
labels: [
{
text: (d, i, data) => {
const total = data.reduce((acc, curr) => acc + curr.profit, 0);
const percent = ((d.profit / total) * 100).toFixed(1);
return `${percent}%`;
},
style: {
fontSize: 10,
},
},
],
},
],
});
chart.render();
`} />
Comparing Donut Charts to Other Charts
Donut Charts and [Pie Charts](/en/charts/pie/)
- Similarities: Both are used to display proportional relationships of categorical data
- Differences:
- Donut charts have a hollow center that can accommodate additional information
- Donut charts emphasize arc length (circumference), while pie charts emphasize area
- Donut charts perform better when comparing multiple charts
Donut Charts and [Bar Charts](/en/charts/bar/)
- Donut Charts: Better suited for showing proportional relationships, emphasizing part-to-whole relationships
- Bar Charts: Better suited for precise numerical comparisons, especially when value differences are small
Donut Charts and [Nightingale Charts (Rose Diagrams)](/en/charts/rose/)
- Donut Charts: Represent values through angles, with fixed inner radius
- Nightingale Charts: Represent values through radius, making value differences easier to distinguish
Similar Charts
Categories
Site Docs Charts Donut Chart.Zh (`site/docs/charts/donut-chart.zh.mdx`)
title: 环图 sidebar: { icon: 'pie' } order: 6 screenshot: 'https://os.alipayobjects.com/rmsportal/LviFnOknmSGUCHZ.png' category: ['proportion'] similar: ['pie', 'rose', 'radial-bar']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
环图的简介
环图(又叫做甜甜圈图),其本质是饼图将中间区域挖空。环图采用了让我们更关注长度而不是面积的做法,这样我们就能相对简单的对比不同的环图。
虽然环图和饼图在数据表达上很相似,但环图还是有它独特的优点:
- 更好的对比性:饼图的整体性太强,我们会将注意力集中在比较饼图内各个扇形之间占整体比重的关系。但如果我们将两个饼图放在一起,饼图很难同时对比两个图。环图解决了这个问题。
- 空间利用率更高:环图可以使用它的空心区域显示文本信息,比如标题、总数等。
英文名:Donut Chart
环图的构成
| 图表类型 | 环图 |
|---|---|
| 适合的数据 | 列表:一个分类数据字段、一个连续数据字段 |
| 功能 | 对比分类数据的数值大小 |
| 数据与图形的映射 | 分类数据字段映射到环形的颜色连续数据字段映射到环形的角度 |
| 适合的数据条数 | 不超过 9 条数据 |
环图的应用场景
适合的场景
例子 1: 展示分类的占比情况
这种用法与饼图类似,下图是一个游戏公司的销售情况:
| genre(游戏类型) | sold(销售量) |
|---|---|
| Sports | 27,500 |
| Strategy | 11,500 |
| Action | 6,000 |
| Shooter | 3,500 |
| Other | 1,500 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
transform: [{ type: 'stackY' }], // 添加堆叠转换
data: [
{ genre: 'Sports', sold: 27500 },
{ genre: 'Strategy', sold: 11500 },
{ genre: 'Action', sold: 6000 },
{ genre: 'Shooter', sold: 3500 },
{ genre: 'Other', sold: 1500 },
],
coordinate: { type: 'theta', innerRadius: 0.5 },
encode: { y: 'sold', color: 'genre' },
legend: {
color: { position: 'bottom', layout: { justifyContent: 'center' } },
},
labels: [
{
text: 'genre',
style: {
fontWeight: 'bold',
},
},
{
text: (d, i, data) => {
const total = data.reduce((acc, curr) => acc + curr.sold, 0);
const percent = ((d.sold / total) * 100).toFixed(2);
return `${percent}%`;
},
style: {
fontSize: 10,
dy: 12,
},
},
],
});
chart.render();
`} />
说明:
genre字段映射到颜色,用于区分不同的游戏类型sold字段映射到角度,表示销售量占比的大小- 使用
coordinate: { type: 'theta', innerRadius: 0.5 }创建环图效果
例子 2: 在中心区域显示额外信息
环图的空心区域可以用来显示总数、标题或其他重要信息:
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
const data = [
{ type: '移动端', value: 54.2 },
{ type: '桌面端', value: 32.1 },
{ type: '平板端', value: 13.7 },
];
const total = data.reduce((acc, curr) => acc + curr.value, 0);
chart.options({
type: 'interval',
autoFit: true,
transform: [{ type: 'stackY' }], // 添加堆叠转换
data,
coordinate: { type: 'theta', innerRadius: 0.6 },
encode: { y: 'value', color: 'type' },
style: { stroke: '#fff', lineWidth: 2 },
legend: {
color: { position: 'bottom', layout: { justifyContent: 'center' } },
},
labels: [
{
text: (d) => `${d.value}%`,
style: {
fontWeight: 'bold',
fontSize: 12,
},
},
],
});
chart.render();
`} />
不适合的场景
例子 1: 分类过多的场景
下图是各个省的人口的占比情况,因为这张图上包含的分类过多,很难清晰对比各个省份的人口数据占比情况,所以这种情况下,我们推荐使用柱状图。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
transform: [{ type: 'stackY' }], // 添加堆叠转换
data: [
{ province: '北京市', population: 19612368 },
{ province: '天津市', population: 12938693 },
{ province: '河北省', population: 71854210 },
{ province: '山西省', population: 27500000 },
{ province: '内蒙古自治区', population: 24706291 },
{ province: '辽宁省', population: 43746323 },
{ province: '吉林省', population: 27452815 },
{ province: '黑龙江省', population: 38313991 },
{ province: '上海市', population: 23019196 },
{ province: '江苏省', population: 78660941 },
{ province: '浙江省', population: 54426891 },
{ province: '安徽省', population: 59500468 },
{ province: '福建省', population: 36894217 },
{ province: '江西省', population: 44567797 },
{ province: '山东省', population: 95792719 },
{ province: '河南省', population: 94029939 },
{ province: '湖北省', population: 57237727 },
{ province: '湖南省', population: 65700762 },
{ province: '广东省', population: 104320459 },
{ province: '广西壮族自治区', population: 46023761 },
{ province: '海南省', population: 8671485 },
{ province: '重庆市', population: 28846170 },
{ province: '四川省', population: 80417528 },
{ province: '贵州省', population: 34748556 },
{ province: '云南省', population: 45966766 },
{ province: '西藏自治区', population: 3002165 },
{ province: '陕西省', population: 37327379 },
{ province: '甘肃省', population: 25575263 },
{ province: '青海省', population: 5626723 },
],
coordinate: { type: 'theta', innerRadius: 0.4 },
encode: { y: 'population', color: 'province' },
legend: false, // 分类太多,关闭图例
labels: false, // 分类太多,关闭标签
});
chart.render();
`} />
说明:上图中分类过多,颜色难以区分,标签重叠严重,不适合使用环图。
例子 2: 分类占比差别不明显的场景
下图中游戏公司的不同种类游戏的销售量相近,角度差异很小,不太适合使用环图,此时可以使用柱状图。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
transform: [{ type: 'stackY' }], // 添加堆叠转换
data: [
{ genre: 'Sports', sold: 15000 },
{ genre: 'Strategy', sold: 14900 },
{ genre: 'Action', sold: 15050 },
{ genre: 'Shooter', sold: 13000 },
{ genre: 'Other', sold: 13900 },
],
coordinate: { type: 'theta', innerRadius: 0.5 },
encode: { y: 'sold', color: 'genre' },
legend: {
color: { position: 'bottom', layout: { justifyContent: 'center' } },
},
labels: [
{
text: (d, i, data) => {
const total = data.reduce((acc, curr) => acc + curr.sold, 0);
const percent = ((d.sold / total) * 100).toFixed(2);
return `${percent}%`;
},
style: {
fontSize: 10,
},
},
],
});
chart.render();
`} />
说明:上图中各个分类的占比都接近 20%,差异很小,难以通过角度清晰地对比数值大小。
环图的扩展
分面环图
使用 G2 的分面功能,可以将分组数据绘制成多个环图。下图展示了全球最大 1000 家银行所在地区在 2007 年和 2011 年的利润总额占比情况:
| 年份 | 地区 | 利润总额(亿美金) |
|---|---|---|
| 2007 | 亚太地区 | 1485.54 |
| 2007 | 非洲及中东 | 330.12 |
| 2007 | 拉丁美洲 | 196.5 |
| …… | …… | …… |
| 2011 | 亚太地区 | 4107.18 |
| 2011 | 非洲及中东 | 495.3 |
| 2011 | 拉丁美洲 | 495.3 |
| …… | …… | …… |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'facetRect',
autoFit: true,
data: [
{ year: '2007', area: '亚太地区', profit: 1485.54 },
{ year: '2007', area: '西欧', profit: 3631.32 },
{ year: '2007', area: '北美', profit: 2083.9 },
{ year: '2007', area: '非洲及中东', profit: 330.12 },
{ year: '2007', area: '中欧和东欧', profit: 141.48 },
{ year: '2007', area: '拉丁美洲', profit: 196.5 },
{ year: '2011', area: '亚太地区', profit: 4107.18 },
{ year: '2011', area: '西欧', profit: 480.06 },
{ year: '2011', area: '北美', profit: 1783.08 },
{ year: '2011', area: '非洲及中东', profit: 495.3 },
{ year: '2011', area: '中欧和东欧', profit: 259.08 },
{ year: '2011', area: '拉丁美洲', profit: 495.3 },
],
encode: { x: 'year' },
children: [
{
type: 'interval',
transform: [{ type: 'stackY' }], // 添加堆叠转换
coordinate: { type: 'theta', innerRadius: 0.5 },
encode: { y: 'profit', color: 'area' },
legend: {
color: { position: 'bottom', layout: { justifyContent: 'center' } },
},
labels: [
{
text: (d, i, data) => {
const total = data.reduce((acc, curr) => acc + curr.profit, 0);
const percent = ((d.profit / total) * 100).toFixed(1);
return `${percent}%`;
},
style: {
fontSize: 10,
},
},
],
},
],
});
chart.render();
`} />
环图与其他图表的对比
环图和[饼图](/zh/charts/pie/)
- 相似性:都用于展示分类数据的占比关系
- 区别:
- 环图中心留空,可以放置额外信息
- 环图更强调弧长(周长),饼图更强调面积
- 环图在多图对比时效果更好
环图和[柱状图](/zh/charts/bar/)
- 环图:更适合展示占比关系,强调部分与整体的关系
- 柱状图:更适合展示精确的数值对比,特别是数值差异较小的情况
环图和[南丁格尔玫瑰图](/zh/charts/rose/)
- 环图:通过角度表示数值,内径固定
- 南丁格尔玫瑰图:通过半径表示数值,更容易区分数值差异
相似图表
分类
Site Docs Charts Dot Map.En (`site/docs/charts/dot-map.en.mdx`)
title: Dot Map sidebar: { icon: 'map' } order: 2 screenshot: 'https://gw.alipayobjects.com/zos/rmsportal/dpmTuGGpBkGJidrRZFyy.png' category: ['distribution', 'map'] similar: ['bubble-map', 'choropleth-map', 'scatter']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Dot Maps
A dot map is a geographic visualization method that represents data distribution density and patterns through densely distributed dots on a geographic map. Each dot typically represents a certain quantity of statistical units (such as population, economic activity, agricultural output, etc.), and the distribution density of dots intuitively reflects the concentration and distribution characteristics of data in geographic space.
The greatest advantage of dot maps is their ability to intuitively display spatial distribution patterns of data. Through the density of dots, you can quickly identify data concentration areas and sparse regions. Compared to choropleth maps, dot maps can more precisely show the continuous distribution characteristics of data within geographic space, avoiding the impact of administrative boundary divisions on data presentation.
Dot maps are widely used in population distribution analysis, economic activity density display, natural resource distribution, disease transmission analysis, and many other geographic data visualization scenarios.
English Name: Dot Map, Dot Density Map
Components of Dot Maps
| Chart Type | Basic Dot Map |
|---|---|
| Suitable Data | Data containing geographic coordinates (longitude and latitude) and numerical fields |
| Function | Display data distribution density and patterns in geographic space |
| Data-to-Graphics Mapping | Longitude and latitude fields map to map positionsNumerical fields affect the number or density of dotsCategorical fields can map to colorsOther attributes can map to shapes |
| Suitable Data Volume | Suitable for medium to large amounts of data points (typically 100-10,000 dots) |
The main components of a basic dot map include:
- Geographic Background: Provides the geographic coordinate system's map background, such as world maps, country maps, regional maps, etc.
- Dot Markers: Dots representing data units, positioned according to geographic coordinates
- Dot Density: The distribution density of dots reflects the spatial distribution patterns of data
- Color Encoding: Different colors distinguish data categories or numerical ranges
Application Scenarios for Dot Maps
Suitable Scenarios
Example 1: US Airport Distribution Dot Map
Based on real US map data and airport location data, showing the geographic distribution of airports across the United States.
<Demo code={`/**
- Airport Distribution Dot Map Based on Real US Map Data
*/
import { Chart } from '@antv/g2';
import { feature } from 'topojson-client';
Promise.all([
fetch('https://assets.antv.antgroup.com/g2/us-10m.json').then((res) =>
res.json(),
),
fetch('https://assets.antv.antgroup.com/g2/airports.json').then((res) =>
res.json(),
),
]).then((values) => {
const [us, airports] = values;
const states = feature(us, us.objects.states).features;
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'geoView',
coordinate: { type: 'albersUsa' },
children: [
{
type: 'geoPath',
data: states,
style: {
fill: '#f5f5f5',
stroke: '#d0d0d0',
lineWidth: 1,
},
},
{
type: 'point',
data: airports,
encode: {
x: 'longitude',
y: 'latitude',
color: '#1890ff',
shape: 'point',
size: 2,
},
style: {
opacity: 0.8,
},
tooltip: {
title: 'name',
items: [
{ name: 'Airport Code', field: 'iata' },
{ name: 'Longitude', field: 'longitude' },
{ name: 'Latitude', field: 'latitude' },
],
},
},
],
});
chart.render();
});
`} />
Description:
- Uses real US map TopoJSON data and airport coordinate data
- Through dot distribution density, you can observe that airports are mainly concentrated on the East Coast, West Coast, and Great Lakes region
albersUsaprojection is suitable for displaying geographic data of the continental United States
Example 2: US Ethnic Distribution Dot Map
Note: The following example uses fictional ethnic distribution data for demonstration purposes
<Demo code={`/**
- Fictional Data: US Ethnic Distribution Dot Map
- Note: This example uses fictional ethnic distribution data for demonstration
*/
import { Chart } from '@antv/g2';
import { feature } from 'topojson-client';
Promise.all([
fetch('https://assets.antv.antgroup.com/g2/us-10m.json').then((res) =>
res.json(),
),
]).then((values) => {
const [us] = values;
const states = feature(us, us.objects.states).features;
// Fictional ethnic distribution data for major US cities (for demonstration only)
const ethnicGroups = [
{ type: 'White', ratio: 0.6, color: '#1890ff' },
{ type: 'Hispanic', ratio: 0.18, color: '#52c41a' },
{ type: 'African American', ratio: 0.13, color: '#faad14' },
{ type: 'Asian', ratio: 0.06, color: '#f5222d' },
{ type: 'Others', ratio: 0.03, color: '#722ed1' },
];
// Coordinates of major US cities (with fictional population data)
const cities = [
{ name: 'New York', lng: -74.0059, lat: 40.7128, population: 850 },
{ name: 'Los Angeles', lng: -118.2437, lat: 34.0522, population: 400 },
{ name: 'Chicago', lng: -87.6298, lat: 41.8781, population: 270 },
{ name: 'Houston', lng: -95.3698, lat: 29.7604, population: 230 },
{ name: 'Philadelphia', lng: -75.1652, lat: 39.9526, population: 160 },
{ name: 'Phoenix', lng: -112.074, lat: 33.4484, population: 170 },
{ name: 'San Antonio', lng: -98.4936, lat: 29.4241, population: 150 },
{ name: 'San Diego', lng: -117.1611, lat: 32.7157, population: 140 },
{ name: 'Dallas', lng: -96.797, lat: 32.7767, population: 130 },
{ name: 'San Jose', lng: -121.8863, lat: 37.3382, population: 100 },
{ name: 'Austin', lng: -97.7431, lat: 30.2672, population: 95 },
{ name: 'Detroit', lng: -83.0458, lat: 42.3314, population: 67 },
{ name: 'Miami', lng: -80.1918, lat: 25.7617, population: 47 },
{ name: 'Seattle', lng: -122.3321, lat: 47.6062, population: 75 },
{ name: 'Denver', lng: -104.9903, lat: 39.7392, population: 72 },
];
// Generate fictional ethnic distribution dot data
const ethnicData = [];
cities.forEach((city) => {
ethnicGroups.forEach((group) => {
// Calculate number of dots based on ethnic ratio and city population
const pointCount = Math.floor((city.population * group.ratio) / 10); // One dot per 100,000 people
for (let i = 0; i < pointCount; i++) {
// Randomly distribute dots around the city, different ethnicities have different clustering patterns
let angle = Math.random() * 2 * Math.PI;
let distance = Math.random() * 1.5; // Distributed within 1.5 degrees
// Simulate different ethnic clustering characteristics
if (group.type === 'Asian') {
// Asians tend to cluster in specific areas
distance = Math.random() * 0.8;
} else if (group.type === 'Hispanic') {
// Hispanics are more concentrated in southern cities
if (city.lat < 35) distance = Math.random() * 0.6;
}
ethnicData.push({
city: city.name,
lng: city.lng + Math.cos(angle) * distance,
lat: city.lat + Math.sin(angle) * distance,
ethnicity: group.type,
value: 10, // Each dot represents 100,000 people
});
}
});});
const chart = new Chart({
container: 'container',
autoFit: true,
});
const groups = ['White', 'Hispanic', 'African American', 'Asian', 'Others'];
chart.options({
type: 'geoView',
coordinate: { type: 'albersUsa' },
children: [
{
type: 'geoPath',
data: states,
style: {
fill: '#f5f5f5',
stroke: '#d0d0d0',
lineWidth: 1,
},
},
{
type: 'point',
data: ethnicData,
encode: {
x: 'lng',
y: 'lat',
color: 'ethnicity',
shape: 'ethnicity',
size: 2,
},
style: {
opacity: 0.7,
stroke: 'white',
lineWidth: 0.5,
},
scale: {
color: {
domain: groups,
range: ['#1890ff', '#52c41a', '#faad14', '#f5222d', '#722ed1'],
},
shape: {
domain: groups,
range: ['point', 'square', 'triangle', 'diamond', 'cross'],
},
},
tooltip: {
title: 'city',
items: [
{ name: 'Ethnicity', field: 'ethnicity' },
{
name: 'Population',
field: 'value',
valueFormatter: (v) => `${v}0k people`,
},
],
},
},
],
});
chart.render();
});`} />
Description:
- Uses fictional ethnic distribution data to show population composition in major US cities
- Different colors and shapes represent different ethnic groups
- Through dot distribution density, you can observe ethnic distribution characteristics and clustering patterns in various regions
- Simulates real ethnic geographic distribution patterns, such as Asian clustering on the West Coast and Hispanic concentration in the South
Unsuitable Scenarios
Example 1: Not Suitable for Precise Numerical Comparison
Dot maps focus on displaying distribution patterns and density, and are not suitable for scenarios requiring precise comparison of specific numerical values. If you need to accurately compare numerical sizes across different regions, you should use choropleth maps or bubble maps.
Example 2: Not Suitable for Displaying Continuous Surface Data
For continuously changing surface data such as temperature and precipitation, the discrete nature of dot maps cannot well represent the continuity of data. In such cases, consider using heatmaps or contour maps.
Comparison with Other Charts
Dot Maps vs [Bubble Maps](/en/charts/bubble-map/)
- Dot maps use dense small dots to represent data distribution, suitable for showing distribution patterns and density
- Bubble maps use circles of different sizes to represent numerical values, suitable for precise comparison of data magnitudes across different regions
- Dot maps are more suitable for showing continuous distribution, while bubble maps are more suitable for showing discrete data points
Dot Maps vs [Choropleth Maps](/en/charts/choropleth-map/)
- Dot maps represent data characteristics through dot distribution density, not limited by administrative divisions
- Choropleth maps represent data ranges through regional colors, related to administrative boundary divisions
- Dot maps are more suitable for showing continuous spatial distribution, while choropleth maps are more suitable for showing comparisons between regions
Similar Charts
Category
Site Docs Charts Dot Map.Zh (`site/docs/charts/dot-map.zh.mdx`)
title: 点描法地图 sidebar: { icon: 'map' } order: 2 screenshot: 'https://gw.alipayobjects.com/zos/rmsportal/dpmTuGGpBkGJidrRZFyy.png' category: ['distribution', 'map'] similar: ['bubble-map', 'choropleth-map', 'scatter']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
点描法地图的简介
点描法地图是一种通过在地理地图上分布密集的点来表示数据分布密度和模式的地理可视化方法。每个点通常代表一定数量的统计单位(如人口、经济活动、农业产量等),点的分布密度直观反映了数据在地理空间上的集中程度和分布特征。
点描法地图最大的优势在于能够直观地展示数据的空间分布模式,通过点的密集程度可以快速识别数据的聚集区域和稀疏区域。与分级统计图相比,点描法地图能够更细致地展示数据在地理空间内的连续分布特征,避免了行政区划边界对数据展示的影响。
点描法地图广泛应用于人口分布分析、经济活动密度展示、自然资源分布、疾病传播分析等多种地理数据可视化场景。
英文名:Dot Map, Dot Density Map
点描法地图的构成
| 图表类型 | 基础点描法地图 |
|---|---|
| 适合的数据 | 包含地理坐标(经纬度)的数据和数值字段 |
| 功能 | 展示数据在地理空间上的分布密度和模式 |
| 数据与图形的映射 | 经纬度字段映射到地图位置数值字段影响点的数量或密度分类字段可映射到颜色其他属性可映射到形状 |
| 适合的数据条数 | 适合中等到大量数据点(通常 100-10000 个点) |
基础点描法地图的主要组成部分包括:
- 地理背景:提供地理坐标系统的地图背景,如世界地图、国家地图、区域地图等
- 点标记:表示数据单位的点,位置对应地理坐标
- 点密度:点的分布密度反映数据的空间分布模式
- 颜色编码:用不同颜色区分数据分类或数值范围
点描法地图的应用场景
适合的场景
例子 1: 美国机场分布点描法地图
基于真实的美国地图数据和机场位置数据,展示全美机场的地理分布情况。
<Demo code={`/**
- 基于真实美国地图数据的机场分布点描法地图
*/
import { Chart } from '@antv/g2';
import { feature } from 'topojson-client';
Promise.all([
fetch('https://assets.antv.antgroup.com/g2/us-10m.json').then((res) =>
res.json(),
),
fetch('https://assets.antv.antgroup.com/g2/airports.json').then((res) =>
res.json(),
),
]).then((values) => {
const [us, airports] = values;
const states = feature(us, us.objects.states).features;
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'geoView',
coordinate: { type: 'albersUsa' },
children: [
{
type: 'geoPath',
data: states,
style: {
fill: '#f5f5f5',
stroke: '#d0d0d0',
lineWidth: 1,
},
},
{
type: 'point',
data: airports,
encode: {
x: 'longitude',
y: 'latitude',
color: '#1890ff',
shape: 'point',
size: 2,
},
style: {
opacity: 0.8,
},
tooltip: {
title: 'name',
items: [
{ name: '机场代码', field: 'iata' },
{ name: '经度', field: 'longitude' },
{ name: '纬度', field: 'latitude' },
],
},
},
],
});
chart.render();
});
`} />
说明:
- 使用真实的美国地图 TopoJSON 数据和机场坐标数据
- 通过点的分布密度可以观察到机场主要集中在东海岸、西海岸和五大湖地区
albersUsa投影适合展示美国本土的地理数据
例子 2: 美国人种分布点描法地图
注意:以下示例使用虚构的人种分布数据用于演示目的
<Demo code={`/**
- 虚构数据:美国人种分布点描法地图
- 注意:本示例使用虚构的人种分布数据用于演示
*/
import { Chart } from '@antv/g2';
import { feature } from 'topojson-client';
Promise.all([
fetch('https://assets.antv.antgroup.com/g2/us-10m.json').then((res) =>
res.json(),
),
]).then((values) => {
const [us] = values;
const states = feature(us, us.objects.states).features;
// 虚构的美国主要城市人种分布数据(仅用于演示)
const ethnicGroups = [
{ type: '白人', ratio: 0.6, color: '#1890ff' },
{ type: '西班牙裔', ratio: 0.18, color: '#52c41a' },
{ type: '非裔美国人', ratio: 0.13, color: '#faad14' },
{ type: '亚裔', ratio: 0.06, color: '#f5222d' },
{ type: '其他', ratio: 0.03, color: '#722ed1' },
];
// 美国主要城市坐标(虚构人口数据)
const cities = [
{ name: '纽约', lng: -74.0059, lat: 40.7128, population: 850 },
{ name: '洛杉矶', lng: -118.2437, lat: 34.0522, population: 400 },
{ name: '芝加哥', lng: -87.6298, lat: 41.8781, population: 270 },
{ name: '休斯顿', lng: -95.3698, lat: 29.7604, population: 230 },
{ name: '费城', lng: -75.1652, lat: 39.9526, population: 160 },
{ name: '凤凰城', lng: -112.074, lat: 33.4484, population: 170 },
{ name: '圣安东尼奥', lng: -98.4936, lat: 29.4241, population: 150 },
{ name: '圣地亚哥', lng: -117.1611, lat: 32.7157, population: 140 },
{ name: '达拉斯', lng: -96.797, lat: 32.7767, population: 130 },
{ name: '圣何塞', lng: -121.8863, lat: 37.3382, population: 100 },
{ name: '奥斯汀', lng: -97.7431, lat: 30.2672, population: 95 },
{ name: '底特律', lng: -83.0458, lat: 42.3314, population: 67 },
{ name: '迈阿密', lng: -80.1918, lat: 25.7617, population: 47 },
{ name: '西雅图', lng: -122.3321, lat: 47.6062, population: 75 },
{ name: '丹佛', lng: -104.9903, lat: 39.7392, population: 72 },
];
// 生成虚构的人种分布点数据
const ethnicData = [];
cities.forEach((city) => {
ethnicGroups.forEach((group) => {
// 根据人种比例和城市人口计算点数
const pointCount = Math.floor((city.population * group.ratio) / 10); // 每10万人一个点
for (let i = 0; i < pointCount; i++) {
// 在城市周围随机分布点,不同人种有不同的聚集模式
let angle = Math.random() * 2 * Math.PI;
let distance = Math.random() * 1.5; // 1.5度范围内分布
// 模拟不同人种的聚集特征
if (group.type === '亚裔') {
// 亚裔倾向于聚集在特定区域
distance = Math.random() * 0.8;
} else if (group.type === '西班牙裔') {
// 西班牙裔在南部城市更集中
if (city.lat < 35) distance = Math.random() * 0.6;
}
ethnicData.push({
city: city.name,
lng: city.lng + Math.cos(angle) * distance,
lat: city.lat + Math.sin(angle) * distance,
ethnicity: group.type,
value: 10, // 每个点代表10万人
});
}
});});
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'geoView',
coordinate: { type: 'albersUsa' },
children: [
{
type: 'geoPath',
data: states,
style: {
fill: '#f5f5f5',
stroke: '#d0d0d0',
lineWidth: 1,
},
},
{
type: 'point',
data: ethnicData,
encode: {
x: 'lng',
y: 'lat',
color: 'ethnicity',
shape: 'ethnicity',
size: 2,
},
style: {
opacity: 0.7,
stroke: 'white',
lineWidth: 0.5,
},
scale: {
color: {
domain: ['白人', '西班牙裔', '非裔美国人', '亚裔', '其他'],
range: ['#1890ff', '#52c41a', '#faad14', '#f5222d', '#722ed1'],
},
shape: {
domain: ['白人', '西班牙裔', '非裔美国人', '亚裔', '其他'],
range: ['point', 'square', 'triangle', 'diamond', 'cross'],
},
},
tooltip: {
title: 'city',
items: [
{ name: '人种', field: 'ethnicity' },
{ name: '人口', field: 'value', valueFormatter: (v) => `${v}万人` },
],
},
},
],
});
chart.render();
});
`} />
说明:
- 使用虚构的人种分布数据展示美国主要城市的人口构成
- 不同颜色和形状代表不同人种群体
- 通过点的分布密度可以观察各地区的人种分布特征和聚集模式
- 模拟了真实的人种地理分布规律,如亚裔在西海岸聚集、西班牙裔在南部更集中等
不适合的场景
例子 1: 不适合精确数值比较
点描法地图侧重于显示分布模式和密度,不适合需要精确比较具体数值的场景。如果需要精确对比不同地区的数值大小,应使用分级统计地图或带气泡的地图。
例子 2: 不适合展示连续表面数据
对于温度、降水量等连续变化的表面数据,点描法地图的离散特性无法很好地表现数据的连续性,此时应考虑使用热力图或等高线图。
点描法地图与其他图表的对比
点描法地图与[带气泡的地图](/zh/charts/bubble-map/)
- 点描法地图使用密集的小点表示数据分布,适合展示分布模式和密度
- 气泡地图使用大小不同的圆圈表示数值大小,适合精确比较不同地区的数据量级
- 点描法地图更适合展示连续分布,气泡地图更适合展示离散的数据点
点描法地图与[分级统计地图](/zh/charts/choropleth-map/)
- 点描法地图通过点的分布密度表示数据特征,不受行政区划限制
- 分级统计图通过区域颜色表示数据范围,与行政区划边界相关
- 点描法地图更适合展示连续的空间分布,分级统计图更适合展示区域间的对比
相似图表
分类
Site Docs Charts Funnel.En (`site/docs/charts/funnel.en.mdx`)
title: Funnel Chart sidebar: { icon: 'polygon' } order: 10 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*9GDLQpMor0oAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison', 'flow'] similar: ['sankey']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Funnel Charts
A funnel chart is a specialized visualization used to represent data flow through different stages of a business process. Named after its resemblance to a physical funnel, it displays data quantities across successive stages, typically with a wide top and narrow bottom, reflecting the process of data loss or conversion.
Funnel charts are particularly suited for visualizing conversion rates in business processes, such as sales pipelines, user registration flows, or marketing funnels. Through funnel charts, you can intuitively observe data changes across various stages and identify critical conversion points or bottlenecks.
Each layer in a funnel chart represents a stage in the process, with the width or area of the layer typically proportional to the quantity of data at that stage, clearly reflecting the data loss during the conversion process.
Other Names: Funnel Diagram, Sales Funnel
Components of a Funnel Chart
Basic Funnel Chart
| Chart Type | Basic Funnel Chart |
|---|---|
| Suitable Data | Ordered categorical data: a categorical field for process stages and a value field for each stage |
| Function | Display data flow and conversion rates across stages of a business process |
| Data-to-Visual Mapping | Stage field mapped to funnel layersValue field mapped to layer width or areaColors distinguish different stages |
| Suitable Scenarios | Analyzing conversions and identifying loss points in multi-stage processes |
Use Cases of Funnel Charts
Suitable Use Cases
Example 1: Sales Process Conversion Analysis
The chart below shows the conversion across different stages of a sales funnel, from initial leads to final deals.
| stage | value |
|---|---|
| Visits | 8043 |
| Inquiries | 2136 |
| Quotes | 908 |
| Negotiations | 691 |
| Deals | 527 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
data: [
{ stage: 'Visits', value: 8043 },
{ stage: 'Inquiries', value: 2136 },
{ stage: 'Quotes', value: 908 },
{ stage: 'Negotiations', value: 691 },
{ stage: 'Deals', value: 527 },
],
encode: {
x: 'stage',
y: 'value',
color: 'stage',
shape: 'funnel',
},
coordinate: { transform: [{ type: 'transpose' }] },
transform: [
{
type: 'symmetryY',
},
],
scale: {
color: {
palette: 'spectral',
},
},
style: {
labelText: (d) => `${d.stage}: ${d.value}`,
},
animate: { enter: { type: 'fadeIn' } },
axis: false,
labels: [
{
text: (d) => `${d.stage}\n${d.value}`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
legend: false,
});
chart.render();
`} />
Explanation:
- The
stagefield is mapped to each layer of the funnel, representing different stages of the sales process - The
valuefield is mapped to the width of each layer, intuitively showing the conversion from the top to the bottom of the funnel - Through the funnel shape, you can clearly see the conversion rates and loss between stages
Example 2: Website Traffic Conversion Analysis
Funnel charts can effectively analyze the conversion of website traffic from visits to final actions, helping identify key points of user drop-off.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
data: [
{ stage: 'Homepage Visit', value: 100000, percent: '100%' },
{ stage: 'Product Search', value: 60000, percent: '60%' },
{ stage: 'Product Detail View', value: 30000, percent: '30%' },
{ stage: 'Add to Cart', value: 10000, percent: '10%' },
{ stage: 'Completed Purchase', value: 5000, percent: '5%' },
],
encode: {
x: 'stage',
y: 'value',
color: 'stage',
shape: 'funnel',
},
coordinate: { transform: [{ type: 'transpose' }] },
transform: [
{
type: 'symmetryY',
},
],
scale: {
color: {
palette: 'blues',
},
},
style: {
labelText: (d) => `${d.stage}: ${d.percent}`,
},
animate: { enter: { type: 'fadeIn' } },
axis: false,
labels: [
{
text: (d) => `${d.stage}\n${d.percent}`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
legend: false,
});
chart.render();
`} />
Explanation:
- Each layer represents a different stage of website traffic conversion
- The width of each layer reflects the number of users at that stage
- By comparing differences between adjacent layers, you can identify major points of user drop-off
- Percentage labels provide intuitive visualization of conversion effectiveness
Example 3: Comparative Funnel Charts for Different Channels
When you need to compare conversion effectiveness across different channels or time periods, comparative funnel charts are useful for analysis.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
data: [
{ stage: 'Visits', value: 8043, category: 'Channel A' },
{ stage: 'Inquiries', value: 2136, category: 'Channel A' },
{ stage: 'Quotes', value: 908, category: 'Channel A' },
{ stage: 'Negotiations', value: 691, category: 'Channel A' },
{ stage: 'Deals', value: 527, category: 'Channel A' },
{ stage: 'Visits', value: 6841, category: 'Channel B' },
{ stage: 'Inquiries', value: 2761, category: 'Channel B' },
{ stage: 'Quotes', value: 1098, category: 'Channel B' },
{ stage: 'Negotiations', value: 624, category: 'Channel B' },
{ stage: 'Deals', value: 487, category: 'Channel B' },
],
axis: false,
children: [
{
type: 'interval',
region: { start: { x: 0, y: 0 }, end: { x: 0.48, y: 1 } },
transform: [
{ type: 'filter', callback: (d) => d.category === 'Channel A' },
],
encode: {
x: 'stage',
y: 'value',
color: 'stage',
shape: 'funnel',
},
coordinate: { transform: [{ type: 'transpose' }] },
transform: [
{
type: 'symmetryY',
},
],
scale: {
color: { palette: 'spectral' },
},
style: {
labelText: (d) => `${d.value}`,
},
animate: { enter: { type: 'fadeIn' } },
axis: false,
labels: [
{
text: (d) => `${d.value}`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
title: 'Channel A',
},
{
type: 'interval',
region: { start: { x: 0.52, y: 0 }, end: { x: 1, y: 1 } },
transform: [
{ type: 'filter', callback: (d) => d.category === 'Channel B' },
],
encode: {
x: 'stage',
y: 'value',
color: 'stage',
shape: 'funnel',
},
coordinate: { transform: [{ type: 'transpose' }] },
transform: [
{
type: 'symmetryY',
},
],
scale: {
color: { palette: 'spectral' },
},
style: {
labelText: (d) => `${d.value}`,
},
animate: { enter: { type: 'fadeIn' } },
axis: false,
labels: [
{
text: (d) => `${d.value}`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
title: 'Channel B',
},
],
legend: false,
});
chart.render();
`} />
Explanation:
- Side-by-side display of conversion funnels for two channels allows for intuitive comparison
- Consistent color coding for corresponding stages facilitates comparison
- You can clearly observe differences in conversion efficiency across channels at various stages
Example 4: Intuitive and Visual Chart Form, Often Used to Display Hierarchical Structures or Distribution Proportions
Company hierarchy pyramid structure, where employees are divided into multiple levels based on their rank, with significant differences in population proportions, responsibilities, and authority across levels, intuitively reflecting the hierarchical differentiation within the company.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
coordinate: {
transform: [{ type: 'transpose' }],
},
data: [
{ text: 'Top Level', value: 5 },
{ text: 'Upper Middle', value: 10 },
{ text: 'Middle', value: 20 },
{ text: 'Lower Middle', value: 25 },
{ text: 'Bottom Level', value: 40 },
],
transform: [
{
type: 'symmetryY',
},
],
axis: {
x: false,
y: false,
},
style: {
reverse: true,
},
encode: {
x: 'text',
y: 'value',
color: 'text',
shape: 'pyramid',
},
scale: {
x: { paddingOuter: 0, paddingInner: 0 },
color: { type: 'ordinal' },
},
labels: [
{
text: (d) => d.text,
position: "inside"
},
{
text: (d) => d.value + "%",
position: "inside",
style: { dy: 15 }
},
]
})
chart.render();
`} />
Explanation:
- Uses
reverse: trueto change the narrowing position of the funnel chart - Population proportions should decrease layer by layer, reflecting the "wide bottom, narrow top" structure
- Population percentages for each level are clearly labeled, facilitating comparison of quantities or proportions between different groups
- Pyramid shape intuitively displays hierarchical distribution and stratification characteristics
Unsuitable Use Cases
Example 1: Not Suitable for Unordered Data or Data Without Clear Hierarchy
The essence of a funnel chart is to display conversion in an ordered process. If the data has no clear sequence or hierarchical relationship, using a funnel chart can be misleading. For such data, bar charts or pie charts might be more appropriate choices.
Example 2: Not Suitable for Data with Fluctuating or Increasing Values Across Stages
Funnel charts typically express a decreasing process from more to less. If there are stages where values increase compared to previous stages (e.g., user numbers increasing due to marketing campaigns), traditional funnel charts may not be suitable, and other chart forms should be considered.
Extensions of Funnel Charts
Comparative Funnel Chart
Comparative funnel charts can more clearly show comparisons between two different processes or entities, helping to identify differences and advantages between different approaches.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container' });
const label = {
text: 'visitor',
position: 'inside',
transform: [{ type: 'contrastReverse' }],
};
chart.options({
type: 'view',
autoFit: true,
data: [
{ action: 'Visit', visitor: 500, site: 'Site1' },
{ action: 'Browse', visitor: 400, site: 'Site1' },
{ action: 'Interact', visitor: 300, site: 'Site1' },
{ action: 'Order', visitor: 200, site: 'Site1' },
{ action: 'Complete', visitor: 100, site: 'Site1' },
{ action: 'Visit', visitor: 550, site: 'Site2' },
{ action: 'Browse', visitor: 420, site: 'Site2' },
{ action: 'Interact', visitor: 280, site: 'Site2' },
{ action: 'Order', visitor: 150, site: 'Site2' },
{ action: 'Complete', visitor: 80, site: 'Site2' },
],
scale: {
x: { padding: 0 },
color: { range: ['#0050B3', '#1890FF', '#40A9FF', '#69C0FF', '#BAE7FF'] },
},
coordinate: { transform: [{ type: 'transpose' }] },
axis: false,
children: [
{
type: 'interval',
data: {
transform: [{ type: 'filter', callback: (d) => d.site === 'Site1' }],
},
encode: { x: 'action', y: 'visitor', color: 'action', shape: 'funnel' },
style: { stroke: '#FFF' },
animate: { enter: { type: 'fadeIn' } },
labels: [
label,
{
text: 'action',
position: 'right',
dx: (d) => {
return d.action === 'Complete' ? 48 : 16;
},
},
],
},
{
type: 'interval',
data: {
transform: [{ type: 'filter', callback: (d) => d.site === 'Site2' }],
},
encode: {
x: 'action',
y: (d) => -d.visitor,
color: 'action',
shape: 'funnel',
},
style: { stroke: '#FFF' },
animate: { enter: { type: 'fadeIn' } },
labels: [label],
},
],
});
chart.render();`} />
Explanation:
- Horizontal comparative layout displays the conversion funnel effects of two sites
- Upper and lower funnels separately show data from different sites for intuitive comparison
- Uses y-axis negative value transformation to achieve reversed display of the lower funnel, creating a mirrored comparison effect
- Same color coding and label configuration ensures consistency in comparison
Pyramid Funnel Chart
Pyramid funnel charts are a variant that displays conversion processes through symmetrical pyramid shapes, better highlighting the conversion rate changes at each stage.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container' });
chart.options({
type: 'interval',
autoFit: true,
paddingRight: 80,
data: {
type: 'inline',
value: [
{ action: 'Browse Website', pv: 50000 },
{ action: 'Add to Cart', pv: 35000 },
{ action: 'Generate Order', pv: 25000 },
{ action: 'Pay Order', pv: 15000 },
{ action: 'Complete Transaction', pv: 8000 },
],
transform: [
{
type: 'custom',
callback: (data) =>
data.map((d) => ({
...d,
rate: d.pv / data[0].pv,
})),
},
],
},
encode: { x: 'action', y: 'pv', color: 'action', shape: 'pyramid' },
transform: [{ type: 'symmetryY' }],
scale: { x: { padding: 0 } },
coordinate: { transform: [{ type: 'transpose' }] },
animate: { enter: { type: 'fadeIn' } },
axis: false,
legend: { color: { position: 'bottom' } },
labels: [
{ text: (d) => `${d.action} ${d.pv}`, textAlign: 'left' },
{
text: (d) => `${(d.rate * 100).toFixed(1)}%`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
});
chart.render();
`} />
Explanation:
- Uses
shape: "pyramid"to create symmetrical pyramid shape for better visual balance - Implements symmetrical pyramid layout through
symmetryYtransformation - Automatically calculates and displays conversion rate percentages for each stage
- Horizontal display facilitates reading label information, especially suitable for scenarios with longer stage names
Comparing Funnel Charts to Other Charts
Funnel Charts and [Pyramid Charts](/en/examples/general/funnel/pyramid/)
- Funnel charts are typically used to show data loss processes, with values decreasing from top to bottom
- Pyramid charts are more commonly used for hierarchical structures or symmetric data comparison between two sides
- Though similar in shape, they have different application scenarios and data characteristics
Funnel Charts and [Bar Charts](/en/charts/bar/)
- Funnel charts emphasize process conversion and the continuous relationship between stages
- Bar charts are better for direct comparison of values between different categories
- When detailed analysis of process conversion is needed, funnel charts provide more intuitive visual effects
Funnel Charts and [Pie Charts](/en/charts/pie/)
- Funnel charts display ordered stages in a process and their relationships
- Pie charts show proportion relationships within a whole, without emphasizing order
- When focusing on conversion between stages rather than simple proportions, funnel charts are the better choice
Similar Charts
Categories
Site Docs Charts Funnel.Zh (`site/docs/charts/funnel.zh.mdx`)
title: 漏斗图 sidebar: { icon: 'polygon' } order: 10 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*9GDLQpMor0oAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison', 'flow'] similar: ['sankey']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
漏斗图的简介
漏斗图是一种特殊的可视化图表,用于展示业务过程中数据在不同阶段的流转情况。它因形状类似漏斗而得名,从上到下依次展示各个阶段的数据量,通常上宽下窄,反映数据流失或转化的过程。
漏斗图特别适合用于可视化业务流程中的转化率,例如销售流程、用户注册流程或营销漏斗等。通过漏斗图,可以直观地观察到各个阶段的数据变化,识别出关键的转化环节或瓶颈。
漏斗图的每一层代表流程中的一个阶段,层的宽度或面积通常与该阶段的数据量成正比,从而清晰地反映出转化过程中的数据损失情况。
英文名:Funnel Chart, Funnel Diagram
漏斗图的构成
基础漏斗图
| 图表类型 | 基础漏斗图 |
|---|---|
| 适合的数据 | 有序分类数据:表示流程各阶段的分类字段、每个阶段的数值字段 |
| 功能 | 展示业务流程各阶段的数据流转和转化率 |
| 数据与图形的映射 | 分类字段映射到漏斗的各层数值字段映射到漏斗各层的宽度或面积颜色区分不同阶段 |
| 适合的场景 | 分析多阶段流程中的转化情况和流失节点 |
漏斗图的应用场景
适合的场景
例子 1: 适合展示销售流程的转化分析
下图展示了销售漏斗中从获取潜在客户到最终成交的各个阶段转化情况。
| stage(阶段) | value(数量) |
|---|---|
| 访问 | 8043 |
| 咨询 | 2136 |
| 报价 | 908 |
| 议价 | 691 |
| 成交 | 527 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
data: [
{ stage: '访问', value: 8043 },
{ stage: '咨询', value: 2136 },
{ stage: '报价', value: 908 },
{ stage: '议价', value: 691 },
{ stage: '成交', value: 527 },
],
encode: {
x: 'stage',
y: 'value',
color: 'stage',
shape: 'funnel',
},
coordinate: { transform: [{ type: 'transpose' }] },
transform: [
{
type: 'symmetryY',
},
],
scale: {
color: {
palette: 'spectral',
},
},
style: {
labelText: (d) => `${d.stage}: ${d.value}`,
},
animate: { enter: { type: 'fadeIn' } },
axis: false,
labels: [
{
text: (d) => `${d.stage}\n${d.value}`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
legend: false,
});
chart.render();
`} />
说明 :
stage字段映射到漏斗的各个层级,表示销售流程的不同阶段value字段映射到各层的宽度,直观展示了从漏斗顶部到底部的转化情况- 通过漏斗形状,可以清晰地看出各阶段之间的转化率和流失情况
例子 2: 适合展示网站流量转化分析
漏斗图可以有效地分析网站流量从访问到最终行为的转化过程,帮助识别用户流失的关键环节。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
data: [
{ stage: '浏览首页', value: 100000, percent: '100%' },
{ stage: '搜索产品', value: 60000, percent: '60%' },
{ stage: '查看商品详情', value: 30000, percent: '30%' },
{ stage: '加入购物车', value: 10000, percent: '10%' },
{ stage: '完成购买', value: 5000, percent: '5%' },
],
encode: {
x: 'stage',
y: 'value',
color: 'stage',
shape: 'funnel',
},
coordinate: { transform: [{ type: 'transpose' }] },
transform: [
{
type: 'symmetryY',
},
],
scale: {
color: {
palette: 'blues',
},
},
style: {
labelText: (d) => `${d.stage}: ${d.percent}`,
},
animate: { enter: { type: 'fadeIn' } },
axis: false,
labels: [
{
text: (d) => `${d.stage}\n${d.percent}`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
legend: false,
});
chart.render();
`} />
说明:
- 每一层代表网站流量转化的不同阶段
- 层的宽度反映了该阶段的用户数量
- 通过比较相邻层的差异,可以发现用户流失的主要环节
- 添加了转化百分比的标签,更直观地展示转化效果
例子 3: 对比漏斗图展示不同渠道的转化效果
当需要比较不同渠道或时期的转化效果时,可以使用对比漏斗图进行分析。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
data: [
{ stage: '访问', value: 8043, category: '渠道A' },
{ stage: '咨询', value: 2136, category: '渠道A' },
{ stage: '报价', value: 908, category: '渠道A' },
{ stage: '议价', value: 691, category: '渠道A' },
{ stage: '成交', value: 527, category: '渠道A' },
{ stage: '访问', value: 6841, category: '渠道B' },
{ stage: '咨询', value: 2761, category: '渠道B' },
{ stage: '报价', value: 1098, category: '渠道B' },
{ stage: '议价', value: 624, category: '渠道B' },
{ stage: '成交', value: 487, category: '渠道B' },
],
axis: false,
children: [
{
type: 'interval',
region: { start: { x: 0, y: 0 }, end: { x: 0.48, y: 1 } },
transform: [{ type: 'filter', callback: (d) => d.category === '渠道A' }],
encode: {
x: 'stage',
y: 'value',
color: 'stage',
shape: 'funnel',
},
coordinate: { transform: [{ type: 'transpose' }] },
transform: [
{
type: 'symmetryY',
},
],
scale: {
color: { palette: 'spectral' },
},
style: {
labelText: (d) => `${d.value}`,
},
animate: { enter: { type: 'fadeIn' } },
axis: false,
labels: [
{
text: (d) => `${d.value}`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
title: '渠道A',
},
{
type: 'interval',
region: { start: { x: 0.52, y: 0 }, end: { x: 1, y: 1 } },
transform: [{ type: 'filter', callback: (d) => d.category === '渠道B' }],
encode: {
x: 'stage',
y: 'value',
color: 'stage',
shape: 'funnel',
},
coordinate: { transform: [{ type: 'transpose' }] },
transform: [
{
type: 'symmetryY',
},
],
scale: {
color: { palette: 'spectral' },
},
style: {
labelText: (d) => `${d.value}`,
},
animate: { enter: { type: 'fadeIn' } },
axis: false,
labels: [
{
text: (d) => `${d.value}`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
title: '渠道B',
},
],
legend: false,
});
chart.render();
`} />
说明:
- 左右并排展示两个渠道的转化漏斗,实现直观对比
- 通过相同的颜色编码对应相同的阶段,便于比较
- 可以清晰地观察到不同渠道在各个阶段的转化效率差异
例子 4:直观、形象的图表形式,常用于展示层级结构或分布比例
公司职级金字塔结构,根据职级高低将员工划分为多个层级,各层级在人数比例、职责与权限上存在显著差异,直观体现了公司内部的层级分化情况。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
coordinate: {
transform: [{ type: 'transpose' }],
},
data: [
{ text: '顶层', value: 5 },
{ text: '中上层', value: 10 },
{ text: '中等', value: 20 },
{ text: '中下层', value: 25 },
{ text: '底层', value: 40 },
],
transform: [
{
type: 'symmetryY',
},
],
axis: {
x: false,
y: false,
},
style: {
reverse: true,
},
encode: {
x: 'text',
y: 'value',
color: 'text',
shape: 'pyramid',
},
scale: {
x: { paddingOuter: 0, paddingInner: 0 },
color: { type: 'ordinal' },
},
labels: [
{
text: (d) => d.text,
position: "inside"
},
{
text: (d) => d.value + "%",
position: "inside",
style: { dy: 15 }
},
]
})
chart.render();
`} />
说明:
- 使用
reverse: true改变漏斗图收口位置 - 人数比例应逐层递减,反映“底宽顶尖”的结构
- 各层级人口占比清晰标注,便于比较不同群体的数量或比例
- 金字塔形状直观展现阶层分布和分层特点
不适合的场景
例子 1: 不适合展示无序或无明显层级关系的数据
漏斗图的本质是展示有序流程的转化过程,如果数据没有明确的先后顺序或层级关系,使用漏斗图会造成误导。对于这类数据,柱状图或饼图可能是更合适的选择。
例子 2: 不适合展示各阶段数值波动或增长的数据
漏斗图通常表达的是数据从多到少的递减过程。如果流程中存在某些阶段的数值大于前一阶段(例如营销活动导致用户数增加),使用传统漏斗图会显得不合适,此时可以考虑使用其他图表形式。
漏斗图的扩展
对比漏斗图
对比漏斗图可以更清晰地展示两个不同流程或实体的转化效果对比,帮助识别不同方案之间的差异和优劣。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container' });
const label = {
text: 'visitor',
position: 'inside',
transform: [{ type: 'contrastReverse' }],
};
chart.options({
type: 'view',
autoFit: true,
data: [
{ action: '访问', visitor: 500, site: '站点1' },
{ action: '浏览', visitor: 400, site: '站点1' },
{ action: '交互', visitor: 300, site: '站点1' },
{ action: '下单', visitor: 200, site: '站点1' },
{ action: '完成', visitor: 100, site: '站点1' },
{ action: '访问', visitor: 550, site: '站点2' },
{ action: '浏览', visitor: 420, site: '站点2' },
{ action: '交互', visitor: 280, site: '站点2' },
{ action: '下单', visitor: 150, site: '站点2' },
{ action: '完成', visitor: 80, site: '站点2' },
],
scale: {
x: { padding: 0 },
color: { range: ['#0050B3', '#1890FF', '#40A9FF', '#69C0FF', '#BAE7FF'] },
},
coordinate: { transform: [{ type: 'transpose' }] },
axis: false,
children: [
{
type: 'interval',
data: {
transform: [{ type: 'filter', callback: (d) => d.site === '站点1' }],
},
encode: { x: 'action', y: 'visitor', color: 'action', shape: 'funnel' },
style: { stroke: '#FFF' },
animate: { enter: { type: 'fadeIn' } },
labels: [
label,
{
text: 'action',
position: 'right',
dx: (d) => {
return d.action === '完成' ? 48 : 16;
},
},
],
},
{
type: 'interval',
data: {
transform: [{ type: 'filter', callback: (d) => d.site === '站点2' }],
},
encode: {
x: 'action',
y: (d) => -d.visitor,
color: 'action',
shape: 'funnel',
},
style: { stroke: '#FFF' },
animate: { enter: { type: 'fadeIn' } },
labels: [label],
},
],
});
chart.render();`} />
说明:
- 使用水平对比的布局展示两个站点的转化漏斗效果
- 上下两个漏斗分别展示不同站点的数据,便于直观对比
- 通过 y 轴负值变换实现下方漏斗的反向展示,形成镜像对比效果
- 相同的颜色编码和标签配置确保对比的一致性
金字塔漏斗图
金字塔形漏斗图是一种变体,通过对称的金字塔形状展示转化流程,能够更突出各阶段的转化率变化。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({ container: 'container' });
chart.options({
type: 'interval',
autoFit: true,
paddingRight: 80,
data: {
type: 'inline',
value: [
{ action: '浏览网站', pv: 50000 },
{ action: '放入购物车', pv: 35000 },
{ action: '生成订单', pv: 25000 },
{ action: '支付订单', pv: 15000 },
{ action: '完成交易', pv: 8000 },
],
transform: [
{
type: 'custom',
callback: (data) =>
data.map((d) => ({
...d,
rate: d.pv / data[0].pv,
})),
},
],
},
encode: { x: 'action', y: 'pv', color: 'action', shape: 'pyramid' },
transform: [{ type: 'symmetryY' }],
scale: { x: { padding: 0 } },
coordinate: { transform: [{ type: 'transpose' }] },
animate: { enter: { type: 'fadeIn' } },
axis: false,
legend: { color: { position: 'bottom' } },
labels: [
{ text: (d) => `${d.action} ${d.pv}`, textAlign: 'left' },
{
text: (d) => `${(d.rate * 100).toFixed(1)}%`,
position: 'inside',
transform: [{ type: 'contrastReverse' }],
},
],
});
chart.render();
`} />
说明:
- 使用
shape: "pyramid"创建对称的金字塔形状,视觉效果更加平衡 - 通过
symmetryY变换实现上下对称的金字塔布局 - 自动计算并显示每个阶段的转化率百分比
- 横向展示便于阅读标签信息,特别适合阶段名称较长的场景
漏斗图与其他图表的对比
漏斗图和[柱状图](/zh/charts/bar/)
- 漏斗图强调的是流程转化和各阶段的连续关系
- 柱状图更适合直接比较不同类别间的数值大小
- 当需要详细分析流程转化时,漏斗图能提供更直观的视觉效果
漏斗图和[饼图](/zh/charts/pie/)
- 漏斗图展示的是有序流程中的各个阶段及其关系
- 饼图展示的是整体中各部分的占比关系,不强调顺序
- 当关注各阶段间的转化而非单纯的占比时,漏斗图是更好的选择
相似图表
分类
Site Docs Charts Gantt.En (`site/docs/charts/gantt.en.mdx`)
title: Gantt Chart sidebar: { icon: 'bar' } order: 25 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*hyB5RIY-qcMAAAAAAAAAAAAADmJ7AQ/original' category: ['time', 'comparison', 'trend'] similar: ['bar', 'stacked-bar', 'area']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Gantt Charts
A Gantt chart is a project management tool that graphically displays the sequence and duration of specific project activities through an activity list and time scale. The underlying concept of a Gantt chart is simple, basically a bar chart where the horizontal axis represents time, the vertical axis represents activities (projects), and the bars represent the planned and actual activity completion status over the entire period.
Gantt charts display the intrinsic relationships between projects, progress, and other time-related system developments as they progress over time through bar charts. This type of chart vividly expresses the start and end times of various tasks in a project plan and the interrelationships between tasks through task lists and time scales.
Gantt charts are one of the most important tools in project management, widely used in project planning, task scheduling, resource management, and other scenarios.
English Name: Gantt Chart
Components of Gantt Charts
| Chart Type | Basic Gantt Chart |
|---|---|
| Suitable Data | Project data: one task name field, one start time field, one end time field |
| Function | Display time scheduling and execution progress of project tasks |
| Data to Graphics Mapping | Task name field maps to vertical axis positionStart time and end time fields map to bar start and end positionsTask duration maps to bar length |
| Suitable Data Volume | No more than 20 tasks |
Application Scenarios for Gantt Charts
Suitable Scenarios
Example 1: Suitable for Project Progress Management
The following chart is a Gantt chart for an event planning project, showing the time scheduling and dependencies of different tasks.
| name (Task Name) | startTime (Start Time) | endTime (End Time) |
|---|---|---|
| Event Planning | 1 | 4 |
| Venue Logistics Planning | 3 | 13 |
| Select Vendors | 5 | 8 |
| Venue Rental | 9 | 13 |
| Book Catering Service | 10 | 14 |
| Hire Event Decoration Team | 12 | 17 |
| Rehearsal | 14 | 16 |
| Event Celebration | 17 | 18 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ name: 'Event Planning', startTime: 1, endTime: 4 },
{ name: 'Venue Logistics Planning', startTime: 3, endTime: 13 },
{ name: 'Select Vendors', startTime: 5, endTime: 8 },
{ name: 'Venue Rental', startTime: 9, endTime: 13 },
{ name: 'Book Catering Service', startTime: 10, endTime: 14 },
{ name: 'Hire Event Decoration Team', startTime: 12, endTime: 17 },
{ name: 'Rehearsal', startTime: 14, endTime: 16 },
{ name: 'Event Celebration', startTime: 17, endTime: 18 },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'name',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
axis: {
x: {
title: 'Tasks',
},
y: {
title: 'Time (Days)',
},
},
interaction: [
{
type: 'elementHighlight',
background: true,
},
],
});
chart.render();
`} />
Explanation:
- The
namefield maps to the horizontal axis position to distinguish different tasks - The
startTimeandendTimefields map to theyandy1channels, representing the start and end times of tasks - The
colorchannel uses task names to distinguish each task with different colors - Uses
transposecoordinate transformation to convert the vertical time axis to horizontal
Example 2: Suitable for Displaying Project Progress with Time-based Animation
Animation effects can more vividly demonstrate the time sequence and execution process of project tasks.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ name: 'Requirements Analysis', startTime: 1, endTime: 5, phase: 'Planning Phase' },
{ name: 'System Design', startTime: 4, endTime: 10, phase: 'Design Phase' },
{ name: 'Frontend Development', startTime: 8, endTime: 20, phase: 'Development Phase' },
{ name: 'Backend Development', startTime: 10, endTime: 22, phase: 'Development Phase' },
{ name: 'Integration Testing', startTime: 18, endTime: 25, phase: 'Testing Phase' },
{ name: 'System Deployment', startTime: 24, endTime: 28, phase: 'Deployment Phase' },
{ name: 'User Acceptance', startTime: 26, endTime: 30, phase: 'Acceptance Phase' },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'phase',
enterDuration: (d) => (d.endTime - d.startTime) * 200,
enterDelay: (d) => d.startTime * 100,
},
coordinate: {
transform: [{ type: 'transpose' }],
},
scale: {
enterDuration: {
range: [0, 5000],
},
},
axis: {
x: {
title: 'Project Tasks',
},
y: {
title: 'Time (Weeks)',
},
},
legend: {
color: {
title: 'Project Phase',
},
},
});
chart.render();
`} />
Explanation:
- The
phasefield maps to color to distinguish project phases with different colors enterDurationandenterDelaychannels implement time-based animation effects- Animation duration is proportional to task duration, delay time is proportional to start time
Example 3: Suitable for Multi-project Comparison Gantt Charts
When comparing the execution of multiple projects, grouped Gantt charts can be used.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ project: 'Project A', task: 'Design', startTime: 1, endTime: 5 },
{ project: 'Project A', task: 'Development', startTime: 4, endTime: 12 },
{ project: 'Project A', task: 'Testing', startTime: 10, endTime: 15 },
{ project: 'Project B', task: 'Design', startTime: 2, endTime: 6 },
{ project: 'Project B', task: 'Development', startTime: 5, endTime: 14 },
{ project: 'Project B', task: 'Testing', startTime: 12, endTime: 16 },
{ project: 'Project C', task: 'Design', startTime: 3, endTime: 8 },
{ project: 'Project C', task: 'Development', startTime: 7, endTime: 16 },
{ project: 'Project C', task: 'Testing', startTime: 14, endTime: 18 },
],
encode: {
x: (d) => `${d.project}-${d.task}`,
y: 'startTime',
y1: 'endTime',
color: 'project',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
axis: {
x: {
title: 'Project Tasks',
labelTransform: 'rotate(45)',
},
y: {
title: 'Time (Weeks)',
},
},
legend: {
color: {
title: 'Project',
},
},
});
chart.render();
`} />
Explanation:
- Combines
projectandtaskfields to create unique identifiers serieschannel is used to stack different tasks at the same position- Labels rotated 45 degrees to avoid overlap
Example 4: Suitable for Gantt Charts with Milestones
In project management, milestones are important time points that can be highlighted with different markers.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
children: [
{
type: 'interval',
data: [
{ name: 'Market Research', startTime: 1, endTime: 4, type: 'Task' },
{ name: 'Product Design', startTime: 3, endTime: 8, type: 'Task' },
{ name: 'Technical Development', startTime: 6, endTime: 15, type: 'Task' },
{ name: 'Internal Testing', startTime: 14, endTime: 18, type: 'Task' },
{ name: 'Marketing Promotion', startTime: 17, endTime: 22, type: 'Task' },
{ name: 'Official Launch', startTime: 20, endTime: 24, type: 'Task' },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'type',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
},
{
type: 'point',
data: [
{ name: 'Research Complete', time: 4, milestone: 'Milestone' },
{ name: 'Design Approved', time: 8, milestone: 'Milestone' },
{ name: 'Development Complete', time: 15, milestone: 'Milestone' },
{ name: 'Product Launch', time: 24, milestone: 'Milestone' },
],
encode: {
x: 'name',
y: 'time',
shape: 'diamond',
color: 'milestone',
size: 8,
},
coordinate: {
transform: [{ type: 'transpose' }],
},
},
],
axis: {
x: {
title: 'Project Activities',
},
y: {
title: 'Time (Weeks)',
},
},
legend: {
color: {
title: 'Type',
},
},
});
chart.render();
`} />
Explanation:
- Uses composite view combining interval and point graphics
- Interval displays task time periods, point displays milestone nodes
- Milestones use diamond shapes for highlighting
Unsuitable Scenarios
Example 1: Not suitable for displaying data without clear time dimensions
Gantt charts are mainly used to display time-related projects or tasks. For categorical comparisons without time dimensions, other chart types like bar charts should be used.
Example 2: Not suitable for displaying overly fine-grained time data
When there are too many tasks or the time granularity is too fine, Gantt charts become crowded and difficult to read. Data aggregation or other visualization methods should be considered.
Example 3: Not suitable for displaying continuous numerical change trends
Gantt charts mainly display discrete task time periods. For continuous numerical changes, line charts or area charts should be used.
Extended Usage of Gantt Charts
Gantt Charts with Progress Display
Colors or fill patterns can be used to show task completion progress.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
children: [
{
type: 'interval',
data: [
{ name: 'Requirements Analysis', startTime: 1, endTime: 5, progress: 100 },
{ name: 'UI Design', startTime: 3, endTime: 8, progress: 80 },
{ name: 'Frontend Development', startTime: 6, endTime: 15, progress: 60 },
{ name: 'Backend Development', startTime: 8, endTime: 16, progress: 40 },
{ name: 'Testing & Acceptance', startTime: 14, endTime: 18, progress: 0 },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'lightgray',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
style: {
fillOpacity: 0.3,
},
},
{
type: 'interval',
data: [
{ name: 'Requirements Analysis', startTime: 1, currentTime: 5, progress: 100 },
{ name: 'UI Design', startTime: 3, currentTime: 6.6, progress: 80 },
{ name: 'Frontend Development', startTime: 6, currentTime: 11.4, progress: 60 },
{ name: 'Backend Development', startTime: 8, currentTime: 11.2, progress: 40 },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'currentTime',
color: (d) =>
d.progress >= 100 ? 'green' : d.progress >= 50 ? 'orange' : 'red',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
},
],
axis: {
x: {
title: 'Project Tasks',
},
y: {
title: 'Time (Weeks)',
},
},
});
chart.render();
`} />
Gantt Charts with Dependencies
Lines or arrows can be used to show dependencies between tasks.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
children: [
{
type: 'interval',
data: [
{ name: 'Task A', startTime: 1, endTime: 5, id: 'A' },
{ name: 'Task B', startTime: 5, endTime: 10, id: 'B' },
{ name: 'Task C', startTime: 8, endTime: 15, id: 'C' },
{ name: 'Task D', startTime: 15, endTime: 20, id: 'D' },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'name',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
},
{
type: 'link',
data: [
{ source: 'Task A', target: 'Task B', x1: 5, x2: 5 },
{ source: 'Task B', target: 'Task C', x1: 10, x2: 8 },
{ source: 'Task C', target: 'Task D', x1: 15, x2: 15 },
],
encode: {
x: 'source',
y: 'x1',
x1: 'target',
y1: 'x2',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
style: {
stroke: '#666',
strokeWidth: 2,
lineDash: [4, 4],
},
},
],
axis: {
x: {
title: 'Project Tasks',
},
y: {
title: 'Time (Weeks)',
},
},
});
chart.render();
`} />
Visual Storytelling
Comparison with Other Charts
Gantt Charts vs [Bar Charts](/en/charts/bar/)
- Gantt charts are mainly used to display task scheduling and project progress
- Bar charts are mainly used to compare numerical values across different categories
Gantt Charts vs [Line Charts](/en/charts/line/)
- Gantt charts display task duration and interrelationships
- Line charts mainly display continuous trends of values over time
Gantt Charts vs [Area Charts](/en/charts/area/)
- Gantt charts use discrete bars to display task time periods
- Area charts use continuous filled areas to display trends of values over time
Similar Charts
Category
Site Docs Charts Gantt.Zh (`site/docs/charts/gantt.zh.mdx`)
title: 甘特图 sidebar: { icon: 'bar' } order: 25 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*hyB5RIY-qcMAAAAAAAAAAAAADmJ7AQ/original' category: ['time', 'comparison', 'trend'] similar: ['bar', 'stacked-bar', 'area']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
甘特图的简介
甘特图是一种项目管理工具,以图示的方式通过活动列表和时间刻度表示出特定项目的顺序与持续时间。甘特图内在思想简单,基本是一条线条图,横轴表示时间,纵轴表示活动(项目),线条表示在整个期间上计划和实际的活动完成情况。
甘特图通过条状图来显示项目、进度和其他时间相关的系统进展的内在关系随着时间进展的情况。这种图表通过任务列表和时间刻度形象地表达了项目计划中各项任务的起止时间以及任务之间的相互关系。
甘特图是项目管理中最重要的工具之一,广泛应用于项目规划、任务调度、资源管理等场景中。
英文名:Gantt Chart
甘特图的构成
| 图表类型 | 基础甘特图 |
|---|---|
| 适合的数据 | 项目数据:一个任务名称字段、一个开始时间字段、一个结束时间字段 |
| 功能 | 展示项目任务的时间安排和执行进度 |
| 数据与图形的映射 | 任务名称字段映射到纵轴的位置开始时间和结束时间字段映射到条形的起止位置任务持续时间映射到条形的长度 |
| 适合的数据条数 | 不超过 20 个任务 |
甘特图的应用场景
适合的场景
例子 1: 适合应用到项目进度管理
下图是一个活动策划项目的甘特图,展示了不同任务的时间安排和依赖关系。
| name(任务名称) | startTime(开始时间) | endTime(结束时间) |
|---|---|---|
| 活动策划 | 1 | 4 |
| 场地物流规划 | 3 | 13 |
| 选择供应商 | 5 | 8 |
| 租赁场地 | 9 | 13 |
| 预定餐饮服务商 | 10 | 14 |
| 租赁活动装饰团队 | 12 | 17 |
| 彩排 | 14 | 16 |
| 活动庆典 | 17 | 18 |
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ name: '活动策划', startTime: 1, endTime: 4 },
{ name: '场地物流规划', startTime: 3, endTime: 13 },
{ name: '选择供应商', startTime: 5, endTime: 8 },
{ name: '租赁场地', startTime: 9, endTime: 13 },
{ name: '预定餐饮服务商', startTime: 10, endTime: 14 },
{ name: '租赁活动装饰团队', startTime: 12, endTime: 17 },
{ name: '彩排', startTime: 14, endTime: 16 },
{ name: '活动庆典', startTime: 17, endTime: 18 },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'name',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
axis: {
x: {
title: '任务',
},
y: {
title: '时间(天)',
},
},
interaction: [
{
type: 'elementHighlight',
background: true,
},
],
});
chart.render();
`} />
说明:
name字段映射到横轴位置,用于区分不同任务startTime和endTime字段映射到y和y1通道,表示任务的起止时间color通道使用任务名称,用不同颜色区分各个任务- 使用
transpose坐标变换,将垂直方向的时间轴转换为水平方向
例子 2: 适合展示带有时序动画的项目进度
通过动画效果可以更生动地展示项目任务的时间顺序和执行过程。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ name: '需求分析', startTime: 1, endTime: 5, phase: '规划阶段' },
{ name: '系统设计', startTime: 4, endTime: 10, phase: '设计阶段' },
{ name: '前端开发', startTime: 8, endTime: 20, phase: '开发阶段' },
{ name: '后端开发', startTime: 10, endTime: 22, phase: '开发阶段' },
{ name: '集成测试', startTime: 18, endTime: 25, phase: '测试阶段' },
{ name: '系统部署', startTime: 24, endTime: 28, phase: '部署阶段' },
{ name: '用户验收', startTime: 26, endTime: 30, phase: '验收阶段' },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'phase',
enterDuration: (d) => (d.endTime - d.startTime) * 200,
enterDelay: (d) => d.startTime * 100,
},
coordinate: {
transform: [{ type: 'transpose' }],
},
scale: {
enterDuration: {
range: [0, 5000],
},
},
axis: {
x: {
title: '项目任务',
},
y: {
title: '时间(周)',
},
},
legend: {
color: {
title: '项目阶段',
},
},
});
chart.render();
`} />
说明:
phase字段映射到颜色,用不同颜色区分项目阶段enterDuration和enterDelay通道实现时序动画效果- 动画持续时间与任务持续时间成正比,延迟时间与开始时间成正比
例子 3: 适合展示多项目对比的甘特图
当需要对比多个项目的执行情况时,可以使用分组甘特图。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ project: '项目A', task: '设计', startTime: 1, endTime: 5 },
{ project: '项目A', task: '开发', startTime: 4, endTime: 12 },
{ project: '项目A', task: '测试', startTime: 10, endTime: 15 },
{ project: '项目B', task: '设计', startTime: 2, endTime: 6 },
{ project: '项目B', task: '开发', startTime: 5, endTime: 14 },
{ project: '项目B', task: '测试', startTime: 12, endTime: 16 },
{ project: '项目C', task: '设计', startTime: 3, endTime: 8 },
{ project: '项目C', task: '开发', startTime: 7, endTime: 16 },
{ project: '项目C', task: '测试', startTime: 14, endTime: 18 },
],
encode: {
x: (d) => `${d.project}-${d.task}`,
y: 'startTime',
y1: 'endTime',
color: 'project',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
axis: {
x: {
title: '项目任务',
labelTransform: 'rotate(45)',
},
y: {
title: '时间(周)',
},
},
legend: {
color: {
title: '项目',
},
},
});
chart.render();
`} />
说明:
- 组合
project和task字段创建唯一的标识符 series通道用于在同一位置堆叠不同任务- 标签旋转 45 度以避免重叠
例子 4: 适合展示带有里程碑的甘特图
在项目管理中,里程碑是重要的时间节点,可以通过不同的标记来突出显示。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
children: [
{
type: 'interval',
data: [
{ name: '市场调研', startTime: 1, endTime: 4, type: '任务' },
{ name: '产品设计', startTime: 3, endTime: 8, type: '任务' },
{ name: '技术开发', startTime: 6, endTime: 15, type: '任务' },
{ name: '内测试运行', startTime: 14, endTime: 18, type: '任务' },
{ name: '市场推广', startTime: 17, endTime: 22, type: '任务' },
{ name: '正式发布', startTime: 20, endTime: 24, type: '任务' },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'type',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
},
{
type: 'point',
data: [
{ name: '调研完成', time: 4, milestone: '里程碑' },
{ name: '设计确认', time: 8, milestone: '里程碑' },
{ name: '开发完成', time: 15, milestone: '里程碑' },
{ name: '产品发布', time: 24, milestone: '里程碑' },
],
encode: {
x: 'name',
y: 'time',
shape: 'diamond',
color: 'milestone',
size: 8,
},
coordinate: {
transform: [{ type: 'transpose' }],
},
},
],
axis: {
x: {
title: '项目活动',
},
y: {
title: '时间(周)',
},
},
legend: {
color: {
title: '类型',
},
},
});
chart.render();
`} />
说明:
- 使用复合视图(view)结合 interval 和 point 图形
- interval 展示任务时间段,point 展示里程碑节点
- 里程碑使用钻石形状(diamond)突出显示
不适合的场景
例子 1: 不适合展示没有明确时间维度的数据
甘特图主要用于展示时间相关的项目或任务,对于没有时间维度的分类对比,应该使用柱状图等其他图表类型。
例子 2: 不适合展示过于细粒度的时间数据
当任务过多或时间粒度过细时,甘特图会变得拥挤难以阅读。此时应该考虑数据聚合或使用其他可视化方式。
例子 3: 不适合展示连续性的数值变化趋势
甘特图主要展示离散的任务时间段,对于连续性的数值变化应该使用折线图或面积图。
甘特图的扩展用法
带有进度显示的甘特图
可以通过颜色或填充模式来显示任务的完成进度。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
children: [
{
type: 'interval',
data: [
{ name: '需求分析', startTime: 1, endTime: 5, progress: 100 },
{ name: 'UI设计', startTime: 3, endTime: 8, progress: 80 },
{ name: '前端开发', startTime: 6, endTime: 15, progress: 60 },
{ name: '后端开发', startTime: 8, endTime: 16, progress: 40 },
{ name: '测试验收', startTime: 14, endTime: 18, progress: 0 },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'lightgray',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
style: {
fillOpacity: 0.3,
},
},
{
type: 'interval',
data: [
{ name: '需求分析', startTime: 1, currentTime: 5, progress: 100 },
{ name: 'UI设计', startTime: 3, currentTime: 6.6, progress: 80 },
{ name: '前端开发', startTime: 6, currentTime: 11.4, progress: 60 },
{ name: '后端开发', startTime: 8, currentTime: 11.2, progress: 40 },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'currentTime',
color: (d) =>
d.progress >= 100 ? 'green' : d.progress >= 50 ? 'orange' : 'red',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
},
],
axis: {
x: {
title: '项目任务',
},
y: {
title: '时间(周)',
},
},
});
chart.render();
`} />
带有依赖关系的甘特图
可以通过连线或箭头来显示任务之间的依赖关系。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
children: [
{
type: 'interval',
data: [
{ name: '任务A', startTime: 1, endTime: 5, id: 'A' },
{ name: '任务B', startTime: 5, endTime: 10, id: 'B' },
{ name: '任务C', startTime: 8, endTime: 15, id: 'C' },
{ name: '任务D', startTime: 15, endTime: 20, id: 'D' },
],
encode: {
x: 'name',
y: 'startTime',
y1: 'endTime',
color: 'name',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
},
{
type: 'link',
data: [
{ source: '任务A', target: '任务B', x1: 5, x2: 5 },
{ source: '任务B', target: '任务C', x1: 10, x2: 8 },
{ source: '任务C', target: '任务D', x1: 15, x2: 15 },
],
encode: {
x: 'source',
y: 'x1',
x1: 'target',
y1: 'x2',
},
coordinate: {
transform: [{ type: 'transpose' }],
},
style: {
stroke: '#666',
strokeWidth: 2,
lineDash: [4, 4],
},
},
],
axis: {
x: {
title: '项目任务',
},
y: {
title: '时间(周)',
},
},
});
chart.render();
`} />
可视化叙事
甘特图与其他图表的对比
甘特图和[柱状图](/zh/charts/bar/)
- 甘特图主要用于展示任务的时间安排和项目进度
- 柱状图主要用于对比不同类别的数值大小
甘特图和[折线图](/zh/charts/line/)
- 甘特图展示任务的持续时间和相互关系
- 折线图主要展示数值随时间的连续变化趋势
甘特图和[面积图](/zh/charts/area/)
- 甘特图使用离散的条形展示任务时间段
- 面积图使用连续的填充区域展示数值随时间的变化趋势
相似图表
分类
Site Docs Charts Gauge.En (`site/docs/charts/gauge.en.mdx`)
title: Gauge Chart sidebar: { icon: 'gauge' } order: 15 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*hpjTRr6LM7IAAAAAAAAAAAAADmJ7AQ/original' category: ['interval'] similar: ['pie']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Gauge Charts
A gauge chart is a semicircular or circular visualization that displays data within a specified range. It uses a pointer and scale to simulate physical gauges (such as speedometers or pressure gauges), intuitively expressing the relationship between the data value and target values or thresholds.
Gauge charts are particularly suitable for displaying progress, completion rates, or single values within a certain range. Different value ranges can be distinguished by colors, enhancing data readability and warning effects.
In data visualization, gauge charts are commonly used to represent key performance indicators (KPIs), goal achievement, system status monitoring, etc., helping users quickly understand how data performs against preset targets.
Other Names: Dial Chart, Speedometer Chart
Components of a Gauge Chart
Basic Gauge Chart
| Chart Type | Basic Gauge Chart |
|---|---|
| Suitable Data | Single value data: current value, target/total value, optional thresholds |
| Function | Display data position within a specified range using pointer and scale |
| Data-to-Visual Mapping | Current value maps to pointer positionTotal value defines scale rangeOptional thresholds map to color sections |
| Suitable Scenarios | Expressing completion degree or status of a single metric within a target range |
Use Cases of Gauge Charts
Suitable Use Cases
Example 1: Suitable for showing goal completion progress
The gauge chart below shows the completion status of a scoring metric, with a current score of 120 out of a total of 400.
Explanation:
targetrepresents the current score, mapped to the pointer position on the gaugetotalrepresents the total score, defining the scale range of the gaugenamerepresents the name of this metric- The gauge chart intuitively shows the proportion of the current score in the total through pointer position
Example 2: Suitable for multi-threshold status monitoring
Gauge charts can clearly show which range the data falls into by setting multiple thresholds and different colors, suitable for system status monitoring, performance evaluation, and other scenarios.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'gauge',
data: {
value: {
target: 159,
total: 400,
name: 'score',
thresholds: [100, 200, 400],
},
},
scale: {
color: {
range: ['#F4664A', '#FAAD14', 'green'],
},
},
style: {
textContent: (target, total) =>
`Score: ${target}\nPercentage: ${((target / total) * 100).toFixed(0)}%`,
},
legend: false,
});
chart.render();
`} />
Explanation:
- Three ranges are set using
thresholds: 0-100, 100-200, and 200-400 - Different colors map to each range: red for low scores, yellow for medium scores, green for high scores
- The text content is customized to display both the score and percentage of the total
- Color changes intuitively reflect the status range of the data
Example 3: Customizing gauge chart styles
Gauge charts support highly customizable styles that can be adjusted based on business requirements.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'gauge',
data: {
value: {
target: 159,
total: 400,
name: 'score',
thresholds: [100, 200, 400],
},
},
scale: {
color: {
range: ['#F4664A', '#FAAD14', 'green'],
},
},
style: {
arcShape: 'round',
arcLineWidth: 2,
arcStroke: '#fff',
textContent: (target, total) =>
`Score: ${target}\nPercentage: ${((target / total) * 100).toFixed(0)}%`,
},
legend: false,
});
chart.render();
`} />
Explanation:
arcShape: 'round'sets the arc shape to have rounded cornersarcLineWidthandarcStrokeset the line width and border color of the arc- The pointer and text position automatically adapt to the gauge layout
- Rounded corners and subtle style adjustments make the gauge more modern and aesthetically pleasing
Unsuitable Use Cases
Example 1: Not suitable for multi-dimensional data comparison
Gauge charts are primarily suitable for displaying a single metric value within a certain range and are not suitable for direct comparison of multi-dimensional data. If you need to compare data across multiple categories or dimensions, bar charts or radar charts might be better choices.
Example 2: Not suitable for time-series trends
Gauge charts display static data at a specific moment and cannot effectively express how data changes over time. For data that needs to show changes over time, line charts or area charts are more appropriate.
Extensions of Gauge Charts
Custom Pointer Shape
Gauge charts support customizing the pointer shape, allowing you to adjust the pointer style according to business scenarios, making the chart more personalized.
<Demo code={`import { Chart } from '@antv/g2';
import { Path } from '@antv/g';
const chart = new Chart({
container: 'container',
autoFit: true,
});
function getOrigin(points) {
if (points.length === 1) return points[0];
const [[x0, y0, z0 = 0], [x2, y2, z2 = 0]] = points;
return [(x0 + x2) / 2, (y0 + y2) / 2, (z0 + z2) / 2];
}
// Custom pointer shape
const customShape = (style) => {
return (points, value, coordinate, theme) => {
// Get the center coordinates of geometric points
const [x, y] = getOrigin(points);
const [cx, cy] = coordinate.getCenter();
// Calculate pointer direction angle
const angle = Math.atan2(y - cy, x - cx);
const length = 100; // Pointer length
const width = 8; // Pointer base width
// Construct triangular pointer path
return new Path({
style: {
d: [
['M', cx + Math.cos(angle) * length, cy + Math.sin(angle) * length], // Top point
[
'L',
cx + Math.cos(angle + Math.PI / 2) * width,
cy + Math.sin(angle + Math.PI / 2) * width,
], // Bottom left point
[
'L',
cx + Math.cos(angle - Math.PI / 2) * width,
cy + Math.sin(angle - Math.PI / 2) * width,
], // Bottom right point
['Z'], // Close path
],
fill: '#30BF78', // Fill color
},
});
};
};
chart.options({
type: 'gauge',
data: {
value: {
target: 159,
total: 424,
name: 'score',
},
},
style: {
pointerShape: customShape,
pinShape: false,
textContent: (target, total) => {
return `Score: ${target}\nPercentage: ${((target / total) * 100).toFixed(
0,
)}%`;
},
},
});
chart.render();
`} />
Explanation:
pointerShapecustomizes the gauge pointer shape as a trianglepinShape: falseremoves the circle at the center of the pointer- You can fully control the appearance, color, and size of the pointer according to business requirements
Comparing Gauge Charts to Other Charts
Gauge Charts and [Pie Charts](/en/charts/pie/)
- Gauge charts focus on showing the position of a single value within a target range, emphasizing the relationship between data and targets or thresholds
- Pie charts focus on showing the proportion of multiple parts within a whole
- When only concerned with the relationship between a single value and the total, gauge charts provide a more prominent and intuitive representation
Gauge Charts, [Bar Charts](/en/charts/bar/)
- Gauge charts are suitable for displaying a single data point relative to a fixed range, emphasizing completion degree
- Bar charts are more suitable for comparing numerical differences between multiple categories
- For scenarios requiring precise comparison of multiple values, bar charts are usually a better choice
Similar Charts
Categories
Site Docs Charts Gauge.Zh (`site/docs/charts/gauge.zh.mdx`)
title: 仪表盘 sidebar: { icon: 'gauge' } order: 15 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*hpjTRr6LM7IAAAAAAAAAAAAADmJ7AQ/original' category: ['interval'] similar: ['pie']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
仪表盘的简介
仪表盘是一种半圆或圆形的可视化图表,用于展示数据在指定范围内的位置。它通过指针和刻度的方式,模拟物理仪表(如速度表、压力表)的显示效果,直观地表达数据值相对于目标值或阈值的位置关系。
仪表盘特别适合显示进度、完成率或者在一定范围内的单一数值,可以通过颜色区分不同的数值区间,增强数据的可读性和警示效果。
在数据可视化中,仪表盘常用于表现关键绩效指标(KPI)、目标达成情况、系统状态监控等,能够帮助用户快速理解数据在预设目标中的表现。
英文名:Gauge Chart, Dial Chart
仪表盘的构成
基础仪表盘
| 图表类型 | 基础仪表盘 |
|---|---|
| 适合的数据 | 单一数值数据:当前值、目标值或总值、可选的阈值 |
| 功能 | 展示数据在指定范围内的位置,通过指针和刻度表示数值 |
| 数据与图形的映射 | 当前值映射到指针位置总值定义刻度范围可选的阈值映射为颜色分区 |
| 适合的场景 | 表达单一指标在目标值范围内的完成度或状态 |
仪表盘的应用场景
适合的场景
例子 1: 适合展示目标完成进度
下面的仪表盘展示了一个评分指标的完成情况,当前得分为 120,总分为 400。
说明 :
target表示当前的得分,映射到仪表盘的指针位置total表示总分,定义了仪表盘的刻度范围name表示该指标的名称- 仪表盘通过指针位置直观展示了当前得分在总分中的比例
例子 2: 适合展示多阈值状态监控
仪表盘可以通过设置多个阈值和不同颜色,清晰地展示数据落在哪个区间,适用于系统状态监控、性能评估等场景。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'gauge',
data: {
value: {
target: 159,
total: 400,
name: 'score',
thresholds: [100, 200, 400],
},
},
scale: {
color: {
range: ['#F4664A', '#FAAD14', 'green'],
},
},
style: {
textContent: (target, total) =>
`得分:${target}\n占比:${((target / total) * 100).toFixed(0)}%`,
},
legend: false,
});
chart.render();
`} />
说明:
- 通过
thresholds设置了三个区间:0-100、100-200 和 200-400 - 使用不同的颜色映射了各个区间:红色表示低分区间,黄色表示中等区间,绿色表示高分区间
- 自定义了文本内容,同时显示得分和占总分的百分比
- 颜色的变化直观地反映了数据所处的状态区间
例子 3: 自定义仪表盘样式
仪表盘支持高度的样式自定义,可以根据业务需求调整外观和交互方式。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'gauge',
data: {
value: {
target: 159,
total: 400,
name: 'score',
thresholds: [100, 200, 400],
},
},
scale: {
color: {
range: ['#F4664A', '#FAAD14', 'green'],
},
},
style: {
arcShape: 'round',
arcLineWidth: 2,
arcStroke: '#fff',
textContent: (target, total) =>
`得分:${target}\n占比:${((target / total) * 100).toFixed(0)}%`,
},
legend: false,
});
chart.render();
`} />
说明:
- 使用
arcShape: 'round'设置了圆弧的形状为圆角 - 通过
arcLineWidth和arcStroke设置了圆弧的线宽和边框颜色 - 指针和文本的位置自动适应仪表盘的布局
- 圆角设计和细微的样式调整使仪表盘更加现代化和美观
不适合的场景
例子 1: 不适合展示多维度数据比较
仪表盘主要适合展示单一指标值在一定范围内的位置,不适合用于多维度数据的直接比较。如果需要比较多个类别或维度的数据,柱状图、雷达图等可能是更好的选择。
例子 2: 不适合展示时间序列趋势
仪表盘展示的是某一时刻的静态数据,无法有效地表达数据随时间的变化趋势。对于需要展示随时间变化的数据,折线图或面积图更为适合。
仪表盘的扩展
自定义指针形状
仪表盘支持自定义指针的形状,可以根据业务场景调整指针的样式,使图表更具个性化。
<Demo code={`import { Chart } from '@antv/g2';
import { Path } from '@antv/g';
const chart = new Chart({
container: 'container',
autoFit: true,
});
function getOrigin(points) {
if (points.length === 1) return points[0];
const [[x0, y0, z0 = 0], [x2, y2, z2 = 0]] = points;
return [(x0 + x2) / 2, (y0 + y2) / 2, (z0 + z2) / 2];
}
// 自定义指针形状
const customShape = (style) => {
return (points, value, coordinate, theme) => {
// 获取几何点中心坐标
const [x, y] = getOrigin(points);
const [cx, cy] = coordinate.getCenter();
// 计算指针方向角度
const angle = Math.atan2(y - cy, x - cx);
const length = 100; // 指针长度
const width = 8; // 指针底部宽度
// 构造指针三角形路径
return new Path({
style: {
d: [
['M', cx + Math.cos(angle) * length, cy + Math.sin(angle) * length], // 顶点
[
'L',
cx + Math.cos(angle + Math.PI / 2) * width,
cy + Math.sin(angle + Math.PI / 2) * width,
], // 底部左点
[
'L',
cx + Math.cos(angle - Math.PI / 2) * width,
cy + Math.sin(angle - Math.PI / 2) * width,
], // 底部右点
['Z'], // 闭合路径
],
fill: '#30BF78', // 填充色
},
});
};
};
chart.options({
type: 'gauge',
data: {
value: {
target: 159,
total: 424,
name: 'score',
},
},
style: {
pointerShape: customShape,
pinShape: false,
textContent: (target, total) => {
return `得分:${target}\n占比:${((target / total) * 100).toFixed(0)}%`;
},
},
});
chart.render();
`} />
说明:
- 使用
pointerShape自定义了仪表盘的指针形状为三角形 - 通过
pinShape: false移除了指针中心的圆点 - 可以根据业务需求完全控制指针的外观、颜色和尺寸
仪表盘与其他图表的对比
仪表盘和[饼图](/zh/charts/pie/)
- 仪表盘侧重展示单一数值在目标范围中的位置,强调数据与目标或阈值的关系
- 饼图侧重于展示多个部分在整体中的占比关系
- 当只关注单一值与总体的关系时,仪表盘提供更突出和直观的表现形式
仪表盘和[柱状图](/zh/charts/bar/)
- 仪表盘适合展示单一数据点相对于固定范围的位置,强调完成度
- 柱状图更适合比较多个类别之间的数值大小差异
- 对于需要精确比较多个数值的场景,柱状图通常是更好的选择
相似图表
分类
Site Docs Charts Heatmap.En (`site/docs/charts/heatmap.en.mdx`)
title: Heatmap sidebar: { icon: 'heatmap' } order: 7 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*ze7gSYylw_QAAAAAAAAAAAAADmJ7AQ/original' category: ['distribution', 'comparison'] similar: ['histogram', 'contourline', 'scatter', 'bubble']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Heatmaps
A heatmap is a visualization technique that uses color intensity to map the density or magnitude of two-dimensional data, excelling at revealing distribution patterns, clusters, and anomalies. Heatmaps map two categorical or continuous fields (such as x, y) to coordinate axis and a third numerical field (such as value) to a color gradient, forming a grid-like matrix of colored cells. Typically, cool colors (like blue) represent low values and warm colors (like red) represent high values.
Heatmaps are particularly suitable for displaying the distribution characteristics of large amounts of data points. Through color variations, they intuitively reflect density or intensity changes in a dataset, helping to identify patterns and relationships. When displaying multi-dimensional data, heatmaps are more intuitive than bar charts or scatter plots, clearly showing areas of data concentration and sparsity at a glance.
Heatmaps are widely used in geographic spatial analysis, website user behavior research, correlation analysis in scientific research, and many other scenarios.
Other Names: Heat Map, Thermal Map
Components of a Heatmap
Heatmap with Unsmoothed Boundaries
| Chart Type | Heatmap with Unsmoothed Boundaries |
|---|---|
| Suitable Data | Three continuous fields |
| Function | Observe data distribution patterns |
| Data-to-Visual Mapping | Two continuous fields mapped to x-axis and y-axis respectively. One continuous metadata mapped to color |
| Suitable Data Volume | More than 30 data points |
Heatmap with Smoothed Boundaries
| Chart Type | Heatmap with Smoothed Boundaries |
|---|---|
| Suitable Data | Three continuous fields |
| Function | Display data distribution patterns, with statistical algorithms to predict data in unknown areas |
| Data-to-Visual Mapping | Two continuous fields mapped to x-axis and y-axis respectively. One continuous metadata mapped to color |
| Suitable Data Volume | More than 30 data points |
Use Cases of Heatmaps
Suitable Use Cases
Example 1: Suitable for displaying two-dimensional data distribution density
The heatmap below shows the temperature distribution in a two-dimensional space. Through color variations, you can intuitively see temperature differences across different areas.
Notes:
- The
gfield is mapped to the x-axis and thelfield to the y-axis, representing positions in two-dimensional space - The
tmpfield is mapped to color, representing the temperature value at each position - Background image and heat overlay provide an intuitive display of temperature distribution
Example 2: Suitable for displaying density distribution of scatter data
Density heatmaps can show concentration areas of scatter data. The example below shows the relationship between carat and price in a diamond dataset.
Notes:
- The
caratfield andpricefield are mapped to the x-axis and y-axis respectively - Kernel density estimation is used to calculate the density distribution of scatter points
- Density values are mapped to colors, creating a heat effect
- Original scatter data is overlaid, allowing simultaneous observation of data points and density distribution
Notes:
- Simulates user mouse position coordinates
xandydata - Uses
binXandbinYtransforms to group and count continuous position data - Heat effect intuitively reveals dense areas of mouse activity through color intensity
- Can intuitively identify interface areas that users focus on
Unsuitable Use Cases
Example 1: Not suitable for precise comparison of specific values
Heatmaps express value magnitude through color intensity, but human eyes perceive color less precisely than length. If accurate comparison of specific values is needed, bar charts or line charts are better choices.
Example 2: Not suitable for displaying a small number of discrete data points
When there are few data points, the density distribution advantage of heatmaps is not obvious. Using scatter plots directly may be clearer and more intuitive.
Extensions of Heatmaps
Threshold Heatmap
Threshold heatmaps divide continuous data into discrete color intervals based on preset threshold ranges, suitable for emphasizing data within specific ranges.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'cell',
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/salary.json',
},
encode: {
x: 'name',
y: 'department',
color: 'salary',
},
scale: {
color: {
type: 'threshold',
domain: [7000, 10000, 20000],
range: ['#C6E48B', '#7BC96F', '#239A3B', '#196127'],
},
},
});
chart.render();
`} />
Notes:
- Uses threshold scale to divide continuous data into discrete intervals
- Sets three thresholds at 7000, 10000, and 20000, dividing the data into four intervals
- Each interval is represented by a different color, making it easy to distinguish different salary levels
Comparing Heatmaps to Other Charts
Heatmaps and [Scatter Plots](/en/charts/scatter-plot/)
- Heatmaps emphasize data density and distribution patterns, intuitively showing data concentration areas through color gradients
- Scatter plots display each individual data point, more suitable for observing the distribution of individual data points and outliers
- Heatmaps are suitable for handling large amounts of data points, while scatter plots may face overlap issues with large data volumes
Heatmaps and [Bubble Charts](/en/charts/bubble-chart/)
- Heatmaps express data density or third-dimension values through color intensity
- Bubble charts express third-dimension values through bubble size while displaying specific data point positions
- Heatmaps are more suitable for showing continuous distributions and density patterns, while bubble charts are better for showing multi-dimensional relationships of discrete data points
Heatmaps and [Contour Lines](/en/charts/contourline/)
- Heatmaps use color intensity to represent value magnitude, providing intuitive visual comparison
- Contour lines connect points of equal value, more suitable for analyzing continuous change trends and gradients
- Heatmaps are better for showing density distribution of discrete data points, while contour lines are better for showing continuous surface change patterns
Heatmaps and [Histograms](/en/charts/histogram/)
- Heatmaps can display data distribution in two-dimensional space, suitable for analyzing relationships between two variables
- Histograms display frequency distribution of a single variable, more suitable for analyzing distribution characteristics of a single variable
- Heatmaps can be seen as an extension of two-dimensional histograms, using color instead of height to represent frequency or density
Similar Charts
Categories
Site Docs Charts Heatmap.Zh (`site/docs/charts/heatmap.zh.mdx`)
title: 热力图 sidebar: { icon: 'heatmap' } order: 7 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*ze7gSYylw_QAAAAAAAAAAAAADmJ7AQ/original' category: ['distribution', 'comparison'] similar: ['histogram', 'contourline', 'scatter', 'bubble']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
热力图的简介
热力图是一种通过颜色强度映射二维数据密度或数值大小的可视化图表,擅长揭示数据分布规律、聚类特征及异常点。热力图将两个分类/连续字段(如 x、y)映射为坐标轴,第三个数值字段(如 value)映射为颜色梯度,形成网格化的色块矩阵,通常冷色调(如蓝色)表示低值,暖色调(如红色)表示高值。
热力图特别适合展示大量数据点的分布特征,通过颜色的变化可以直观地反映数据集中的密度或强度变化,帮助识别数据中的模式和关系。在展示多维数据时,热力图比条形图或散点图更加直观,能够一目了然地显示数据的聚集区域和稀疏区域。
热力图广泛应用于地理空间分析、网站用户行为研究、科学研究中的相关性分析等多种场景。
英文名:Heatmap, Heat Map
热力图的构成
边界未经平滑处理的热力图
| 图表类型 | 边界未经平滑处理的热力图 |
|---|---|
| 适合的数据 | 三个连续字段 |
| 功能 | 观察数据的分布情况 |
| 数据与图形的映射 | 两个连续字段分别映射到 x 轴、y 轴。一个连续元数据映射到颜色 |
| 适合的数据条数 | 超过 30 条数据 |
边界经平滑处理的热力图
| 图表类型 | 边界经平滑处理的热力图 |
|---|---|
| 适合的数据 | 三个连续字段 |
| 功能 | 展示数据的分布情况,加上统计算法可预测未知区域数据 |
| 数据与图形的映射 | 两个连续字段分别映射到 x 轴、y 轴。一个连续元数据映射到颜色 |
| 适合的数据条数 | 超过 30 条数据 |
热力图的应用场景
适合的场景
例 1: 适合展示二维数据的分布密度
下面这张热力图展示了二维空间上的温度分布情况。通过颜色的变化可以直观地看出不同区域的温度差异。
说明:
g字段映射到 x 轴,l字段映射到 y 轴,表示二维空间中的位置tmp字段映射到颜色,表示每个位置点的温度值- 背景图像和热力叠加,直观展示温度分布情况
例 2: 适合展示散点数据的密度分布
密度热力图可以展示散点数据的集中区域,下面的例子展示了钻石数据集中克拉数和价格的分布关系。
说明:
carat字段和price字段分别映射到 x 轴和 y 轴- 使用核密度估计(kernel density estimation)计算散点的密度分布
- 密度值映射到颜色,形成热力效果
- 叠加原始散点数据,可以同时观察数据点和密度分布
不适合的场景
例 1: 不适合精确比较具体数值
热力图通过颜色强度表现数值大小,但人眼对颜色的感知不如对长度的感知精确。如果需要准确比较具体数值,柱状图或折线图是更好的选择。
例 2: 不适合展示少量离散数据点
当数据点较少时,热力图的密度分布优势不明显,直接使用散点图可能更为清晰直观。
热力图的扩展
阈值热力图
阈值热力图根据预设的阈值区间,将连续数据划分为离散的颜色区间,适合强调特定范围内的数据。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
// 生成模拟的二维网格数据
const data = [];
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
data.push({
x: i,
y: j,
value: Math.floor(Math.random() * 100),
});
}
}
chart.options({
type: 'cell',
data,
encode: {
x: 'x',
y: 'y',
color: 'value',
},
scale: {
color: {
type: 'threshold',
domain: [25, 50, 75],
range: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b'],
},
},
style: {
stroke: '#fff',
lineWidth: 1,
},
label: {
text: 'value',
style: {
fontSize: 10,
fill: '#000',
},
},
});
chart.render();
`} />
说明:
- 生成 10x10 的网格数据,模拟二维热力图数据结构
- 使用阈值(threshold)比例尺将连续数据划分为离散区间
- 设置了 25、50、75 三个阈值,将数据分为四个区间
- 每个区间使用不同的颜色表示,便于区分不同数值级别的分布
热力图与其他图表的对比
热力图与[散点图](/zh/charts/scatter-plot/)
- 热力图强调数据密度和分布模式,通过颜色梯度直观地展示数据集中区域
- 散点图展示每个独立的数据点,更适合观察个体数据点的分布和离群点
- 热力图适合处理大量数据点,散点图在数据量大时可能出现重叠问题
热力图与[气泡图](/zh/charts/bubble-chart/)
- 热力图通过颜色强度表现数据密度或第三维度的数值大小
- 气泡图通过气泡大小表现第三维度的数值,同时可以显示具体的数据点位置
- 热力图更适合展示连续分布和密度模式,气泡图更适合展示离散数据点的多维关系
热力图与[等高线图](/zh/charts/contourline/)
- 热力图使用颜色强度来表示数值大小,提供直观的视觉对比
- 等高线图使用等值线连接相同数值的点,更适合分析连续变化的趋势和梯度
- 热力图更适合展示离散数据点的密度分布,等高线图更适合展示连续表面的变化模式
热力图与[直方图](/zh/charts/histogram/)
- 热力图可以展示二维空间上的数据分布,适合分析两个变量之间的关系
- 直方图展示单一变量的频率分布,更适合分析单一变量的分布特征
- 热力图可以看作是二维直方图的扩展,用颜色替代了高度来表示频率或密度
相似图表
分类
Site Docs Charts Histogram.En (`site/docs/charts/histogram.en.mdx`)
title: Histogram Chart sidebar: { icon: 'column' } order: 2 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*WJFaSp1JLHQAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison', 'distribution'] similar: ['bar', 'boxplot', 'line', 'area']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Histogram Charts
A histogram is a chart that, while similar in shape to bar charts, has a completely different meaning. Histograms involve statistical concepts, first grouping data, then counting the number of data elements in each group. In a Cartesian coordinate system, the horizontal axis marks the endpoints of each group, the vertical axis represents frequency, and the height of each rectangle represents the corresponding frequency, called a frequency distribution histogram. Standard frequency distribution histograms require calculating frequency times class width to get the count for each group. Since the class width is fixed for the same histogram, using the vertical axis to directly represent counts, with each rectangle's height representing the corresponding number of data elements, preserves the distribution shape while intuitively showing the count for each group. All examples in this document use non-standard histograms with the vertical axis representing counts.
Related Concepts:
- Number of classes: When organizing statistical data, we divide data into several groups by different ranges, and the number of groups is called the number of classes
- Class width: The difference between the two endpoints of each group
- Frequency: The number of data elements in a group divided by the class width
Functions of Histograms:
- Can display the frequency or count distribution of each group
- Easy to show differences in frequency or count between groups
Through histograms, you can also observe and estimate which data is more concentrated and where abnormal or isolated data is distributed.
Other Names: Frequency Distribution Chart
How to Create a Histogram
Creating a histogram in G2 requires the following core elements:
1. Use rect Mark
Histograms need to use the rect mark rather than the interval mark. This is because:
- The rect mark supports both
xandx1channels, which can precisely represent the start and end positions of data intervals - Each rectangle spans from
xtox1, conforming to the mathematical definition of a histogram - The interval mark only supports a single
xvalue, with bars aligned at tick points, which is not suitable for representing continuous intervals
2. Use binX Transform
The binX transform is the key to creating histograms. Its functions are:
- Automatically divide continuous numerical data into multiple intervals (binning)
- Count the number of data points or other aggregate values in each interval
- Output the start position (
x) and end position (x1) of each interval
Basic Usage:
.transform({
type: 'binX',
y: 'count', // Count the number in each interval
thresholds: 20, // Optional: specify the number of bins
})3. Complete Example
import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'rect', // Use rect mark
data: {
type: 'fetch',
value: 'data.json',
},
encode: {
x: 'value', // Continuous numerical field
y: 'count', // Frequency
},
transform: [
{ type: 'binX', y: 'count' } // binX transform
],
});
chart.render();Components of a Histogram Chart
Frequency Distribution Histogram
| Chart Type | Frequency Distribution Histogram |
|---|---|
| Suitable Data | List: one continuous data field, one categorical field (optional) |
| Function | Show data distribution across different intervals |
| Data-to-Visual Mapping | Grouped data field (statistical result) mapped to horizontal axis positionFrequency field (statistical result) mapped to rectangle heightCategorical data can use color to enhance category distinction |
| Suitable Data Volume | No less than 50 data points |
Non-standard Histogram
| Chart Type | Non-standard Histogram |
|---|---|
| Suitable Data | List: one continuous data field, one categorical field (optional) |
| Function | Show data distribution across different intervals |
| Data-to-Visual Mapping | Grouped data field (statistical result) mapped to horizontal axis positionCount field (statistical result) mapped to rectangle heightCategorical data can use color to enhance category distinction |
| Suitable Data Volume | No less than 50 data points |
Use Cases of Histogram Charts
Suitable Use Cases
Example 1: Statistical Analysis of Data Distribution
The following chart shows a histogram of diamond weight distribution, displaying how diamond weights are distributed across different intervals.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://gw.alipayobjects.com/os/antvdemo/assets/data/diamond.json',
},
encode: {
x: 'carat',
y: 'count',
},
transform: [
{ type: 'binX', y: 'count' },
],
scale: {
y: { nice: true },
},
axis: {
x: { title: 'Diamond Weight (Carat)' },
y: { title: 'Frequency' },
},
style: {
fill: '#1890FF',
fillOpacity: 0.9,
},
});
chart.render();
`} />
Notes:
- Using
rectmark combined withbinXtransform to create the histogram binXtransform automatically bins thecaratfield and counts the frequency of each interval- Each rectangle spans a numerical interval (e.g., 0.2-0.3, 0.3-0.4), indicating that the data is continuously distributed
Example 2: Using Different Binning Methods
The key to histograms is how to divide data intervals (i.e., "binning"). Different binning methods affect the understanding of data distribution. The chart below uses a custom number of bins.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://gw.alipayobjects.com/os/antvdemo/assets/data/diamond.json',
},
encode: {
x: 'carat',
y: 'count',
},
transform: [
{ type: 'binX', y: 'count', thresholds: 30 }, // Specify number of bins
],
scale: {
y: { nice: true },
},
axis: {
x: { title: 'Diamond Weight (Carat)' },
y: { title: 'Frequency' },
},
style: {
fill: '#1890FF',
fillOpacity: 0.9,
},
});
chart.render();
`} />
Notes:
- Using
transform: { type: 'binX', thresholds: 30 }to specify 30 bins - The choice of bin number affects the display of distribution details; more bins can show more detailed distribution patterns
- Fewer bins can highlight the main distribution trends
Unsuitable Use Cases
Example 1: Not Suitable for Comparing Categorical Data
Histograms are designed for continuous numerical data distribution and are not suitable for comparing non-numerical categorical data. For counting statistics of categorical data, regular bar charts should be used instead.
Example 2: Not Suitable for Showing Time Series Trends
Histograms focus on showing data distribution characteristics rather than trends over time. If you need to display how data changes over time, line charts or area charts should be used instead.
Extensions of Histogram Charts
Multi-distribution Histogram
A multi-distribution histogram can display the distribution of multiple datasets in the same coordinate system, facilitating comparison of distribution characteristics between different datasets.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://gw.alipayobjects.com/os/antvdemo/assets/data/diamond.json',
transform: [
{
type: 'map',
callback: (d) => ({
...d,
group: d.cut === 'Ideal' ? 'Ideal' : 'Others',
}),
},
],
},
encode: {
x: 'price',
y: 'count',
color: 'group',
},
transform: [
{ type: 'binX', y: 'count', thresholds: 30, groupBy: ['group'] },
],
scale: {
y: { nice: true },
color: { range: ['#1890FF', '#FF6B3B'] },
},
axis: {
x: { title: 'Price (USD)' },
y: { title: 'Frequency' },
},
style: {
fillOpacity: 0.7,
},
legend: true,
});
chart.render();
`} />
Notes:
- Using
color: 'group'andgroupBy: ['group']to achieve multi-distribution comparison - Using different colors and transparencies to facilitate observation of distribution differences between groups
Comparing Histogram Charts to Other Charts
Histograms and [Bar Charts](/en/charts/bar/)
- Histograms are used to show the distribution of continuous numerical data, emphasizing the shape of data distribution
- Bar charts are used to compare numerical values across different categories or time points, emphasizing comparison
- Histograms have no gaps between bars, while bar charts have gaps between bars
Histograms and [Box Plots](/en/charts/boxplot/)
- Histograms show data concentration and dispersion through frequency distribution
- Box plots show data concentration and dispersion through quartiles, making it easier to identify outliers
- Histograms provide more detailed distribution patterns, while box plots provide more concise statistical summaries
Histograms, [Line Charts](/en/charts/line/), and [Area Charts](/en/charts/area/)
- Histograms focus on showing data distribution characteristics
- Line and area charts focus on showing data trends over time
- Histograms are suitable for single time-point data analysis, while line and area charts are suitable for continuous multi-time-point data analysis
Similar Charts
Categories
Site Docs Charts Histogram.Zh (`site/docs/charts/histogram.zh.mdx`)
title: 直方图 sidebar: { icon: 'column' } order: 2 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*WJFaSp1JLHQAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison', 'distribution'] similar: ['bar', 'boxplot', 'line', 'area']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
直方图的简介
直方图,形状类似柱状图却有着与柱状图完全不同的含义。直方图牵涉统计学的概念,首先要对数据进行分组,然后统计每个分组内数据元的数量。在平面直角坐标系中,横轴标出每个组的端点,纵轴表示频数,每个矩形的高代表对应的频数,称这样的统计图为频数分布直方图。频数分布直方图需要经过频数乘以组距的计算过程才能得出每个分组的数量,同一个直方图的组距是一个固定不变的值,所以如果直接用纵轴表示数量,每个矩形的高代表对应的数据元数量,既能保持分布状态不变,又能直观的看出每个分组的数量。本文的例子全部使用纵轴表示数量的非标准直方图绘制。
相关概念:
- 组数:在统计数据时,我们把数据按照不同的范围分成几个组,分成的组的个数称为组数
- 组距:每一组两个端点的差
- 频数:分组内的数据元的数量除以组距
直方图的作用:
- 能够显示各组频数或数量分布的情况
- 易于显示各组之间频数或数量的差别
通过直方图还可以观察和估计哪些数据比较集中,异常或者孤立的数据分布在何处。
英文名:Histogram
如何绘制直方图
在 G2 中绘制直方图需要使用以下核心要素:
1. 使用 rect 标记
直方图需要使用 rect 标记而非 interval 标记。这是因为:
- rect 标记支持
x和x1两个通道,可以精确表示数据区间的起始和结束位置 - 每个矩形会跨越从
x到x1的区间,符合直方图的数学定义 - interval 标记只支持单一的
x值,柱子会对齐在刻度点上,不适合表示连续区间
2. 使用 binX 转换
binX 转换是绘制直方图的关键,它的作用是:
- 自动将连续数值数据划分为多个区间(分箱)
- 统计每个区间内的数据数量或其他聚合值
- 输出每个区间的起始位置(
x)和结束位置(x1)
基本用法:
.transform({
type: 'binX',
y: 'count', // 统计每个区间的数量
thresholds: 20, // 可选:指定分箱数量
})3. 完整示例
import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'rect', // 使用 rect 标记
data: {
type: 'fetch',
value: 'data.json',
},
encode: {
x: 'value', // 连续数值字段
y: 'count', // 频数
},
transform: [
{ type: 'binX', y: 'count' } // binX 转换
],
});
chart.render();直方图的构成
频数分布直方图
| 图表类型 | 频数分布直方图 |
|---|---|
| 适合的数据 | 列表:一个连续数据字段、一个分类字段(可选) |
| 功能 | 展示数据在不同区间内的分布情况 |
| 数据与图形的映射 | 分组数据字段(统计结果)映射到横轴的位置频数字段(统计结果)映射到矩形的高度分类数据可以设置颜色增强分类的区分度 |
| 适合的数据条数 | 不低于 50 条数据 |
非标准的直方图
| 图表类型 | 非标准的直方图 |
|---|---|
| 适合的数据 | 列表:一个连续数据字段、一个分类字段(可选) |
| 功能 | 展示数据在不同区间内的分布情况 |
| 数据与图形的映射 | 分组数据字段(统计结果)映射到横轴的位置数量字段(统计结果)映射到矩形的高度分类数据可以设置颜色增强分类的区分度 |
| 适合的数据条数 | 不低于 50 条数据 |
直方图的应用场景
适合的场景
例子 1: 数据分布的统计分析
下图是一个钻石重量分布的直方图,展示了钻石重量在不同区间的分布情况。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://gw.alipayobjects.com/os/antvdemo/assets/data/diamond.json',
},
encode: {
x: 'carat',
y: 'count',
},
transform: [
{ type: 'binX', y: 'count' },
],
scale: {
y: { nice: true },
},
axis: {
x: { title: '钻石重量(克拉)' },
y: { title: '频数' },
},
style: {
fill: '#1890FF',
fillOpacity: 0.9,
},
});
chart.render();
`} />
说明:
- 使用
rect标记配合binX转换绘制直方图 binX转换自动将carat字段分箱,并统计每个区间的频数- 每个矩形跨越一个数值区间(如 0.2-0.3, 0.3-0.4),表示数据是连续分布的
例子 2: 使用不同的分箱方式
直方图的关键是如何划分数据区间(即"分箱"),不同的分箱方式会影响对数据分布的理解。下图使用了自定义的分箱数量。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://gw.alipayobjects.com/os/antvdemo/assets/data/diamond.json',
},
encode: {
x: 'carat',
y: 'count',
},
transform: [
{ type: 'binX', y: 'count', thresholds: 30 }, // 指定分箱数量
],
scale: {
y: { nice: true },
},
axis: {
x: { title: '钻石重量(克拉)' },
y: { title: '频数' },
},
style: {
fill: '#1890FF',
fillOpacity: 0.9,
},
});
chart.render();
`} />
说明:
- 使用
transform: { type: 'binX', thresholds: 30 }指定分箱数量为 30 - 分箱数量的选择会影响分布的细节展示,较多的箱数可以显示更细致的分布情况
- 较少的箱数则可以突出主要分布趋势
不适合的场景
例子 1: 不适合展示分类数据的比较
直方图针对的是连续型数值数据的分布,不适合用于非数值型的分类数据比较。对于分类数据的计数统计,应该使用普通柱状图。
例子 2: 不适合展示时间序列的趋势
直方图侧重于展示数据的分布特征,而非随时间变化的趋势。如果需要展示数据随时间的变化趋势,应使用折线图或面积图等时序图表。
直方图的扩展
多分布直方图
多分布直方图可以在同一坐标系中展示多个数据集的分布情况,便于比较不同数据集的分布特征。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://gw.alipayobjects.com/os/antvdemo/assets/data/diamond.json',
transform: [
{
type: 'map',
callback: (d) => ({
...d,
group: d.cut === 'Ideal' ? 'Ideal' : 'Others',
}),
},
],
},
encode: {
x: 'price',
y: 'count',
color: 'group',
},
transform: [
{ type: 'binX', y: 'count', thresholds: 30, groupBy: ['group'] },
],
scale: {
y: { nice: true },
color: { range: ['#1890FF', '#FF6B3B'] },
},
axis: {
x: { title: '价格(美元)' },
y: { title: '频数' },
},
style: {
fillOpacity: 0.7,
},
legend: true,
});
chart.render();
`} />
说明:
- 通过
color: 'group'和groupBy: ['group']实现多分布的对比 - 使用不同颜色和透明度,便于观察不同组别的数据分布差异
直方图与其他图表的对比
直方图和[柱状图](/zh/charts/bar/)
- 直方图用于展示连续型数值数据的分布,强调数据分布形态
- 柱状图用于比较不同类别或时间点的数值大小,强调类别间数值对比
- 直方图的条形间无间隔,柱状图的柱子间有间隔
直方图和[箱型图](/zh/charts/boxplot/)
- 直方图通过频数分布展示数据集中趋势和离散程度
- 箱型图通过四分位数展示数据的集中和离散情况,更便于识别异常值
- 直方图提供更详细的分布形态,箱型图则提供更简洁的统计概括
直方图和[折线图](/zh/charts/line/)、[面积图](/zh/charts/area/)
- 直方图侧重于展示数据的分布状况和形态特征
- 折线图和面积图侧重于展示数据随时间的变化趋势
- 直方图适合单一时间点的数据分析,折线图和面积图适合多时间点的连续数据分析
相似图表
分类
Site Docs Charts K Chart.En (`site/docs/charts/k-chart.en.mdx`)
title: K-Chart sidebar: { icon: 'column' } order: 10 screenshot: 'https://os.alipayobjects.com/rmsportal/UCqFUhWcZgDJsDH.png' category: ['trend', 'time', 'comparison'] similar: ['line', 'area', 'bar', 'boxplot']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to K-Charts
K-Charts, originally known as Candlestick Charts, are commonly used to display stock trading data. A K-line graphically represents the daily, weekly, or monthly changes in a stock's opening price, closing price, highest price, and lowest price.
Through its intuitive visual representation, K-Charts can quickly reflect price trends over a certain period, helping analysts and investors judge market trends. Each K-line contains four key pieces of price information: opening price, closing price, highest price, and lowest price. These four prices constitute complete trading information.
The design concept of K-Charts originated in Japan, initially used for rice futures trading, and later widely adopted in technical analysis across various financial markets.
Other Names: Candlestick Chart (also known as Yin-Yang lines, bar lines, red-black lines, or candle lines).
Components of a K-Chart
Structure of a Single K-Line
A K-line is structured as follows:
- Upper Shadow: The thin line at the top, representing the price difference between the highest price and the closing price (or opening price).
- Real Body: The thick line in the middle, representing the price difference between the opening price and the closing price.
- Lower Shadow: The thin line at the bottom, representing the price difference between the opening price (or closing price) and the lowest price.
When the closing price is higher than the opening price, meaning the stock price is trending upwards, the K-line is called a Yang line (bullish candle). Its real body is usually represented in red or hollow. Conversely, it's called a Yin line (bearish candle), represented by a green or black real body.
| Chart Type | K-Chart |
|---|---|
| Suitable Data | Time series: One time field, four numerical fields (open, close, high, low prices) |
| Function | Observe data trends****Compare price ranges across different periods |
| Data-Graphic Mapping | Time field mapped to the horizontal axisFour price fields mapped to the vertical axis, forming the K-line's body and shadowsUp/down status mapped to color |
| Suitable Data Count | Suitable for medium to long-term data, typically tens to hundreds of trading periods |
Use Cases of K-Charts
Suitable Use Cases
Scenario 1: Stock Price Analysis
The most classic application of K-Charts is in stock market analysis. By observing the patterns of K-lines, one can judge the balance of power between bulls and bears in the market.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
const data = [
{ time: '2015-11-19', start: 8.18, max: 8.33, min: 7.98, end: 8.32 },
{ time: '2015-11-18', start: 8.37, max: 8.6, min: 8.03, end: 8.09 },
{ time: '2015-11-17', start: 8.7, max: 8.78, min: 8.32, end: 8.37 },
{ time: '2015-11-16', start: 8.48, max: 8.85, min: 8.43, end: 8.7 },
{ time: '2015-11-13', start: 8.01, max: 8.75, min: 7.97, end: 8.41 },
{ time: '2015-11-12', start: 7.76, max: 8.18, min: 7.61, end: 8.15 },
{ time: '2015-11-11', start: 7.55, max: 7.81, min: 7.49, end: 7.8 },
{ time: '2015-11-10', start: 7.5, max: 7.68, min: 7.44, end: 7.57 },
];
const tooltip = {
title: 'time',
items: [
{ field: 'start', name: 'Open' },
{ field: 'end', name: 'Close' },
{ field: 'min', name: 'Low' },
{ field: 'max', name: 'High' },
],
};
chart.options({
type: 'view',
data,
encode: {
x: 'time',
color: (d) => {
const trend = Math.sign(d.start - d.end);
// Note: In many Western contexts, red is down and green is up.
// This example uses red for up ('上涨') and green for down ('下跌').
// Translated labels: 'Down', 'Unchanged', 'Up'
// Original colors: Down '#4daf4a' (green), Up '#e41a1c' (red)
return trend > 0 ? 'Down' : trend === 0 ? 'Unchanged' : 'Up';
},
},
scale: {
x: {
compare: (a, b) => new Date(a).getTime() - new Date(b).getTime(),
},
color: {
domain: ['Down', 'Unchanged', 'Up'],
range: ['#4daf4a', '#999999', '#e41a1c'], // Green for Down, Gray for Unchanged, Red for Up
},
},
children: [
{
type: 'link',
encode: { y: ['min', 'max'] },
tooltip,
},
{
type: 'interval',
encode: { y: ['start', 'end'] },
style: {
fillOpacity: 1,
stroke: (d) => {
if (d.start === d.end) return '#999999';
},
},
axis: {
y: {
title: 'Price',
},
},
tooltip,
},
],
});
chart.render();`} />
Scenario 2: Commodity Futures Analysis
K-Charts are also applicable to the price analysis of commodity futures, foreign exchange, and other financial derivatives, helping traders identify price patterns and trends.
Scenario 3: Cryptocurrency Analysis
In cryptocurrency trading, K-Charts are the most commonly used technical analysis tool, clearly displaying price fluctuations.
Scenario 4: Comprehensive Market Analysis with Volume Data
Combining K-Charts with volume indicators provides a more holistic view of market dynamics.
K-Charts with Volume Charts
Pairing K-Charts with volume bar charts allows for a more comprehensive analysis of market behavior.
<Demo height={324} code={`import { Chart } from '@antv/g2';
// Create containers for K-Chart and Volume Chart
document.getElementById('container').innerHTML = `
`;
const data = [
{
time: '2015-11-19',
start: 8.18,
max: 8.33,
min: 7.98,
end: 8.32,
volumn: 1810,
},
{
time: '2015-11-18',
start: 8.37,
max: 8.6,
min: 8.03,
end: 8.09,
volumn: 2790,
},
{
time: '2015-11-17',
start: 8.7,
max: 8.78,
min: 8.32,
end: 8.37,
volumn: 3729,
},
{
time: '2015-11-16',
start: 8.48,
max: 8.85,
min: 8.43,
end: 8.7,
volumn: 2890,
},
];
const KChart = new Chart({
container: 'kChart',
autoFit: true,
});
KChart.options({
type: 'view',
data,
encode: {
x: 'time',
color: (d) => {
const trend = Math.sign(d.start - d.end);
return trend > 0 ? 'Down' : trend === 0 ? 'Unchanged' : 'Up';
},
},
scale: {
color: {
domain: ['Down', 'Unchanged', 'Up'],
range: ['#4daf4a', '#999999', '#e41a1c'],
},
},
children: [
{
type: 'link',
encode: { y: ['min', 'max'] },
},
{
type: 'interval',
encode: { y: ['start', 'end'] },
style: { fillOpacity: 1 },
},
],
axis: {
y: { title: 'Price' },
},
});
// Volume Chart
const VolumeChart = new Chart({
container: 'volumeChart',
autoFit: true,
});
VolumeChart.options({
type: 'interval',
data,
encode: {
x: 'time',
y: 'volumn',
color: (d) => {
const trend = Math.sign(d.start - d.end);
return trend > 0 ? 'Down' : trend === 0 ? 'Unchanged' : 'Up';
},
},
scale: {
color: {
domain: ['Down', 'Unchanged', 'Up'],
range: ['#4daf4a', '#999999', '#e41a1c'],
},
},
axis: {
y: { title: 'Volume' },
},
});
KChart.render();
VolumeChart.render();
`} />
Notes:
The K-Chart section displays the four key price points (open, close, high, low).
The Volume Chart section uses the same color encoding to display trading volume.
Both charts are aligned by the same time axis for easy correlation analysis.
K-Charts with Bar Charts for Volume (Full Data Source)
Using a more complete data source, combine K-Charts and bar charts to show the relationship between stock prices and trading volume, with support for legend interaction.
<Demo height={384} code={`import { Chart } from '@antv/g2';
// Create containers for K-Chart and Column Chart
document.getElementById('container').innerHTML = `
`;
const KChart = new Chart({
container: 'kChart',
autoFit: true,
height: 360,
paddingLeft: 60,
});
KChart.options({
type: 'view',
data: {
type: 'fetch',
value:
'https://gw.alipayobjects.com/os/antvdemo/assets/data/candle-sticks.json',
},
encode: {
x: 'time',
color: (d) => {
const trend = Math.sign(d.start - d.end);
return trend > 0 ? 'Down' : trend === 0 ? 'Unchanged' : 'Up';
},
},
scale: {
x: {
compare: (a, b) => new Date(a).getTime() - new Date(b).getTime(),
},
color: {
domain: ['Down', 'Unchanged', 'Up'],
range: ['#4daf4a', '#999999', '#e41a1c'],
},
},
children: [
{
type: 'link',
encode: { y: ['min', 'max'] },
tooltip: {
title: 'time',
items: [
{ field: 'start', name: 'Open' },
{ field: 'end', name: 'Close' },
{ field: 'min', name: 'Low' },
{ field: 'max', name: 'High' },
],
},
},
{
type: 'interval',
encode: { y: ['start', 'end'] },
style: {
fillOpacity: 1,
stroke: (d) => (d.start === d.end ? '#999999' : undefined),
},
axis: {
x: { title: false },
y: { title: false },
},
tooltip: {
title: 'time',
items: [
{ field: 'start', name: 'Open' },
{ field: 'end', name: 'Close' },
{ field: 'min', name: 'Low' },
{ field: 'max', name: 'High' },
],
},
},
],
});
const ColumnChart = new Chart({
container: 'columnChart',
autoFit: true,
paddingTop: 0,
paddingBottom: 0,
height: 180,
paddingLeft: 60,
});
ColumnChart.options({
type: 'interval',
data: {
type: 'fetch',
value:
'https://gw.alipayobjects.com/os/antvdemo/assets/data/candle-sticks.json',
},
encode: {
x: 'time',
y: 'volumn',
color: (d) => {
const trend = Math.sign(d.start - d.end);
return trend > 0 ? 'Down' : trend === 0 ? 'Unchanged' : 'Up';
},
},
scale: {
x: {
compare: (a, b) => new Date(a).getTime() - new Date(b).getTime(),
},
color: {
domain: ['Down', 'Unchanged', 'Up'],
range: ['#4daf4a', '#999999', '#e41a1c'],
},
},
axis: {
x: false,
y: { title: false },
},
});
// Legend interaction linkage
KChart.on('legend:filter', (e) => {
const { nativeEvent, data } = e;
if (!nativeEvent) return;
ColumnChart.emit('legend:filter', { data });
});
KChart.on('legend:reset', (e) => {
const { nativeEvent, data } = e;
if (!nativeEvent) return;
ColumnChart.emit('legend:reset', { data });
});
KChart.render();
ColumnChart.render();
`} />
Notes:
- The upper K-Chart displays price trends, while the lower bar chart shows trading volume.
- Both charts use the same color encoding and are aligned by the time axis.
- Supports legend interaction: clicking the legend filters data in both charts simultaneously.
- Uses real stock data source to display more complete market information.
Unsuitable Use Cases
Scenario 1: Non-Time Series Data
K-Charts are specifically designed for time series data. For comparing categorical data that does not involve a time dimension, Bar Charts or Column Charts should be used.
Scenario 2: Displaying Single Numerical Trends
If you only need to show simple numerical trends, Line Charts or Area Charts would be more concise and clear.
Comparing K-Charts to Other Charts
K-Charts vs. [Line Charts](/en/charts/line/), [Bar Charts](/en/charts/bar/), and [Box Plots](/en/charts/boxplot/)
K-Charts and Line Charts:
- K-Charts display complete price information (open, close, high, low), suitable for detailed technical analysis.
- Line Charts only show a single price line (usually the closing price), suitable for displaying the overall direction of price trends.
K-Charts and Bar Charts:
- K-Charts are specifically used for analyzing price data in time series, emphasizing price changes over time.
- Bar Charts are mainly used for comparing numerical values between different categories and do not involve time series.
K-Charts and Box Plots:
- K-Charts show the price range at specific time points, focusing on price trend analysis.
- Box Plots display the statistical distribution characteristics of data, focusing on the statistical analysis of data distribution.
Similar Charts
Categories
Site Docs Charts K Chart.Zh (`site/docs/charts/k-chart.zh.mdx`)
title: K线图 sidebar: { icon: 'column' } order: 10 screenshot: 'https://os.alipayobjects.com/rmsportal/UCqFUhWcZgDJsDH.png' category: ['trend', 'time', 'comparison'] similar: ['line', 'area', 'bar', 'boxplot']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
K 线图的简介
K 线图,原名蜡烛图,又称阴阳图、棒线、红黑线或蜡烛线,常用于展示股票交易数据。K 线就是指将各种股票每日、每周、每月的开盘价、收盘价、最高价、最低价等涨跌变化状况,用图形的方式表现出来。
K 线图通过直观的视觉表现方式,能够快速反映某一时期的价格走势,帮助分析师和投资者判断市场趋势。每根 K 线包含四个关键价格信息:开盘价、收盘价、最高价和最低价,这四个价格构成了完整的交易信息。
K 线图的设计理念源于日本,最初用于大米期货交易,后来被广泛应用于各种金融市场的技术分析中。
英文名:Candlestick Chart, K Chart
K 线图的构成
单根 K 线结构
K 线如图所示:
- 上影线:最上方的一条细线,表示最高价和收盘价(或开盘价)之间的价差
- 实体:中间的一条粗线,表示开盘价和收盘价之间的价差
- 下影线:下面的一条细线,表示开盘价(或收盘价)和最低价之间的差距
当收盘价高于开盘价,也就是股价走势呈上升趋势时,我们称这种情况下的 K 线为阳线,中部的实体通常以红色或空白表示。反之称为阴线,用绿色或黑色实体表示。
| 图表类型 | K 线图 |
|---|---|
| 适合的数据 | 时间序列:一个时间字段,四个数值字段(开盘价、收盘价、最高价、最低价) |
| 功能 | 观察数据的趋势变化对比不同时期的价格区间 |
| 数据与图形的映射 | 时间字段映射到横轴四个价格字段映射到纵轴形成 K 线实体和影线涨跌状态映射到颜色 |
| 适合的数据条数 | 适合中长期数据,通常几十到几百个交易周期 |
K 线图的应用场景
适合的场景
场景 1:股票价格分析
K 线图最经典的应用场景就是股票市场分析,通过观察 K 线的形态可以判断市场的多空力量对比。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
const data = [
{
time: '2015-11-19',
start: 8.18,
max: 8.33,
min: 7.98,
end: 8.32,
},
{
time: '2015-11-18',
start: 8.37,
max: 8.6,
min: 8.03,
end: 8.09,
},
{
time: '2015-11-17',
start: 8.7,
max: 8.78,
min: 8.32,
end: 8.37,
},
{
time: '2015-11-16',
start: 8.48,
max: 8.85,
min: 8.43,
end: 8.7,
},
{
time: '2015-11-13',
start: 8.01,
max: 8.75,
min: 7.97,
end: 8.41,
},
{
time: '2015-11-12',
start: 7.76,
max: 8.18,
min: 7.61,
end: 8.15,
},
{
time: '2015-11-11',
start: 7.55,
max: 7.81,
min: 7.49,
end: 7.8,
},
{
time: '2015-11-10',
start: 7.5,
max: 7.68,
min: 7.44,
end: 7.57,
},
];
const tooltip = {
title: 'time',
items: [
{ field: 'start', name: '开盘价' },
{ field: 'end', name: '收盘价' },
{ field: 'min', name: '最低价' },
{ field: 'max', name: '最高价' },
],
};
chart.options({
type: 'view',
data,
encode: {
x: 'time',
color: (d) => {
const trend = Math.sign(d.start - d.end);
return trend > 0 ? '下跌' : trend === 0 ? '不变' : '上涨';
},
},
scale: {
x: {
compare: (a, b) => new Date(a).getTime() - new Date(b).getTime(),
},
color: {
domain: ['下跌', '不变', '上涨'],
range: ['#4daf4a', '#999999', '#e41a1c'],
},
},
children: [
{
type: 'link',
encode: { y: ['min', 'max'] },
tooltip,
},
{
type: 'interval',
encode: { y: ['start', 'end'] },
style: {
fillOpacity: 1,
stroke: (d) => {
if (d.start === d.end) return '#999999';
},
},
axis: {
y: {
title: '价格',
},
},
tooltip,
},
],
});
chart.render();`} />
场景 2:商品期货分析
K 线图同样适用于商品期货、外汇等金融衍生品的价格分析,帮助交易者识别价格模式和趋势。
场景 3:数字货币分析
在数字货币交易中,K 线图是最常用的技术分析工具,可以清楚地展示价格的波动情况。
不适合的场景
场景 1:非时间序列数据
K 线图专门用于时间序列数据,对于不涉及时间维度的分类数据比较,应该使用柱状图或条形图。
场景 2:单一数值展示
如果只需要展示简单的数值变化趋势,折线图或面积图会更加简洁明了。
K 线图的扩展
K 线图与成交量组合
将 K 线图与成交量柱状图结合,可以更全面地分析市场行为。
<Demo height={324} code={`import { Chart } from '@antv/g2';
// 创建K线图容器
document.getElementById('container').innerHTML = `
`;
const data = [
{
time: '2015-11-19',
start: 8.18,
max: 8.33,
min: 7.98,
end: 8.32,
volumn: 1810,
},
{
time: '2015-11-18',
start: 8.37,
max: 8.6,
min: 8.03,
end: 8.09,
volumn: 2790,
},
{
time: '2015-11-17',
start: 8.7,
max: 8.78,
min: 8.32,
end: 8.37,
volumn: 3729,
},
{
time: '2015-11-16',
start: 8.48,
max: 8.85,
min: 8.43,
end: 8.7,
volumn: 2890,
},
];
const KChart = new Chart({
container: 'kChart',
autoFit: true,
});
KChart.options({
type: 'view',
data,
encode: {
x: 'time',
color: (d) => {
const trend = Math.sign(d.start - d.end);
return trend > 0 ? '下跌' : trend === 0 ? '不变' : '上涨';
},
},
scale: {
color: {
domain: ['下跌', '不变', '上涨'],
range: ['#4daf4a', '#999999', '#e41a1c'],
},
},
children: [
{
type: 'link',
encode: { y: ['min', 'max'] },
},
{
type: 'interval',
encode: { y: ['start', 'end'] },
style: { fillOpacity: 1 },
},
],
axis: {
y: { title: '价格' },
},
});
// 成交量图
const VolumeChart = new Chart({
container: 'volumeChart',
autoFit: true,
});
VolumeChart.options({
type: 'interval',
data,
encode: {
x: 'time',
y: 'volumn',
color: (d) => {
const trend = Math.sign(d.start - d.end);
return trend > 0 ? '下跌' : trend === 0 ? '不变' : '上涨';
},
},
scale: {
color: {
domain: ['下跌', '不变', '上涨'],
range: ['#4daf4a', '#999999', '#e41a1c'],
},
},
axis: {
y: { title: '成交量' },
},
});
KChart.render();
VolumeChart.render();
`} />
说明:
- K 线图部分展示价格的四个关键信息(开盘、收盘、最高、最低)
- 成交量图部分使用相同的颜色编码展示交易量
- 两个图表通过相同的时间轴对齐,便于关联分析
K 线图与柱状图组合
使用更完整的数据源,结合 K 线图和柱状图展示股票价格和成交量的关系,并支持图例联动交互。
<Demo height={384} code={`import { Chart } from '@antv/g2';
// 创建K线图和柱状图容器
document.getElementById('container').innerHTML = `
`;
const KChart = new Chart({
container: 'kChart',
autoFit: true,
height: 360,
paddingLeft: 60,
});
KChart.options({
type: 'view',
data: {
type: 'fetch',
value:
'https://gw.alipayobjects.com/os/antvdemo/assets/data/candle-sticks.json',
},
encode: {
x: 'time',
color: (d) => {
const trend = Math.sign(d.start - d.end);
return trend > 0 ? '下跌' : trend === 0 ? '不变' : '上涨';
},
},
scale: {
x: {
compare: (a, b) => new Date(a).getTime() - new Date(b).getTime(),
},
color: {
domain: ['下跌', '不变', '上涨'],
range: ['#4daf4a', '#999999', '#e41a1c'],
},
},
children: [
{
type: 'link',
encode: { y: ['min', 'max'] },
tooltip: {
title: 'time',
items: [
{ field: 'start', name: '开盘价' },
{ field: 'end', name: '收盘价' },
{ field: 'min', name: '最低价' },
{ field: 'max', name: '最高价' },
],
},
},
{
type: 'interval',
encode: { y: ['start', 'end'] },
style: {
fillOpacity: 1,
stroke: (d) => (d.start === d.end ? '#999999' : undefined),
},
axis: {
x: { title: false },
y: { title: false },
},
tooltip: {
title: 'time',
items: [
{ field: 'start', name: '开盘价' },
{ field: 'end', name: '收盘价' },
{ field: 'min', name: '最低价' },
{ field: 'max', name: '最高价' },
],
},
},
],
});
const ColumnChart = new Chart({
container: 'columnChart',
autoFit: true,
paddingTop: 0,
paddingBottom: 0,
height: 180,
paddingLeft: 60,
});
ColumnChart.options({
type: 'interval',
data: {
type: 'fetch',
value:
'https://gw.alipayobjects.com/os/antvdemo/assets/data/candle-sticks.json',
},
encode: {
x: 'time',
y: 'volumn',
color: (d) => {
const trend = Math.sign(d.start - d.end);
return trend > 0 ? '下跌' : trend === 0 ? '不变' : '上涨';
},
},
scale: {
x: {
compare: (a, b) => new Date(a).getTime() - new Date(b).getTime(),
},
color: {
domain: ['下跌', '不变', '上涨'],
range: ['#4daf4a', '#999999', '#e41a1c'],
},
},
axis: {
x: false,
y: { title: false },
},
});
// 图例联动交互
KChart.on('legend:filter', (e) => {
const { nativeEvent, data } = e;
if (!nativeEvent) return;
ColumnChart.emit('legend:filter', { data });
});
KChart.on('legend:reset', (e) => {
const { nativeEvent, data } = e;
if (!nativeEvent) return;
ColumnChart.emit('legend:reset', { data });
});
KChart.render();
ColumnChart.render();
`} />
说明:
- 上方 K 线图展示价格走势,下方柱状图展示成交量
- 两个图表使用相同的颜色编码和时间轴对齐
- 支持图例联动,点击图例可以同时过滤两个图表的数据
- 使用真实的股票数据源,展示更完整的市场信息
K 线图与其他图表的对比
K 线图和[折线图](/zh/charts/line/)
- K 线图展示完整的价格信息(开盘、收盘、最高、最低),适合详细的技术分析
- 折线图只展示单一价格线(通常是收盘价),适合展示价格趋势的整体走向
K 线图和[柱状图](/zh/charts/bar/)
- K 线图专门用于时间序列的价格数据分析,强调时间维度上的价格变化
- 柱状图主要用于不同分类之间的数值大小对比,不涉及时间序列
K 线图和[箱形图](/zh/charts/boxplot/)
- K 线图展示特定时间点的价格区间,侧重于价格走势分析
- 箱形图展示数据的统计分布特征,侧重于数据分布的统计分析
相似图表
分类
Site Docs Charts Kagi.En (`site/docs/charts/kagi.en.mdx`)
title: Kagi Chart sidebar: { icon: 'line' } order: 25 screenshot: 'https://zos.alipayobjects.com/rmsportal/GYxDnAkxCMrLfpB.png' category: ['trend', 'time'] similar: ['line', 'area', ' k-chart']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
Introduction to Kagi Charts
Kagi charts were invented around the 1870s when the Japanese stock market began trading. In the United States, the Kagi chart analysis method became popular after Steven Nison published "Beyond Candlesticks." Due to its ability to clearly and effectively display price movement paths, the Kagi chart is one of the tools investors use to make better decisions about stocks.
A Kagi chart consists of a series of vertical lines connected by short horizontal lines. The horizontal lines serve as connectors, while the thickness and direction of the vertical lines depend on price movements. An upward vertical line indicates a price increase, while a downward vertical line indicates a price decrease. A new vertical line is drawn when the price movement reverses beyond a threshold, connected by a horizontal line at the turning point. Thick lines (Yang lines) are used when the price rises above the previous high, and thin lines (Yin lines) are used when the price falls below the previous low.
Features of Kagi Charts:
- Simulates the relationship between supply and demand forces in securities, making it highly suitable for short-term stock operations.
- Filters out daily price fluctuations through threshold markers, focusing only on significant price changes.
- Independent of time.
:::warning{title=Note}
The lines drawn in a Kagi chart are calculated using the Kagi chart algorithm and differ from the original data curve.
:::
English Name: Kagi Chart
Components of a Kagi Chart
| Chart Type | Kagi Chart |
|---|---|
| Suitable Data | One categorical field, one continuous field |
| Function | Observing data trends |
| Data Mapping | Turning point time categories (auto-calculated) mapped to the x-axis, turning point values mapped to the y-axis |
| Suitable Data Count | More than 10 data points |
Key Elements:
- Yang Line: A thick line drawn when the price rises above the previous high.
- Yin Line: A thin line drawn when the price falls below the previous low.
- Turning Point: Key points where the price movement direction reverses.
- Connecting Line: Horizontal lines connecting vertical segments, marking turning positions.
Use Cases of Kagi Charts
Suitable Use Cases
Use Case 1: Displaying Price or Stock Movement Trends
Kagi charts are most suitable for analyzing trends in price changes for stocks, futures, forex, and other financial markets. By filtering out daily minor fluctuations, they highlight significant turning points in prices, helping investors identify trend changes.
Use Case 2: Technical Analysis and Trend Judgement
Kagi charts are particularly useful in technical analysis because they:
- Filter market noise, focusing on significant price movements.
- Clearly display support and resistance levels.
- Help identify trend continuations and reversal signals.
Unsuitable Use Cases
Use Case 1: Time-Sensitive Data
Kagi charts are independent of time and only represent the upward and downward trends of data. They cannot reflect certain characteristics of data over time, such as cycles. Therefore, Kagi charts are not recommended for time-sensitive data.
For example, website traffic data often has clear time cycles (weekday vs. weekend, day vs. night). Using Kagi charts would lose these important time features. For such data, line charts or area charts are recommended.
Use Case 2: Comparing Multiple Data Groups
The x-axis of Kagi charts is unique (turning point time), making it impossible to plot multiple Kagi charts on the same x-axis for comparative analysis. To compare multiple data series, multi-series line charts are recommended.
Comparing Kagi Charts to Other Charts
Kagi Charts and Candlestick Charts
| Feature | Kagi Chart | Candlestick Chart |
|---|---|---|
| Time Dependency | Independent of time, shows trends | Time-dependent, each period corresponds to a candlestick |
| Data Display | Filters minor fluctuations, highlights key turning points | Displays open, high, low, and close prices for a specific time period |
| Analysis Focus | Trend direction and turning points | Price fluctuations and volume within a time period |
| Suitable Scenarios | Medium- to long-term trend analysis | Short-term trading and time-sensitive analysis |
Kagi Charts and Line Charts
| Feature | Kagi Chart | Line Chart |
|---|---|---|
| Data Processing | Turning point data calculated by algorithm | Strictly plotted based on original data coordinates |
| Axis | X-axis represents calculated turning points | Both axis correspond to original data |
| Line Meaning | Color and thickness represent specific meanings (Yang and Yin lines) | Usually only represents data connection relationships |
| Multi-Series | Cannot plot multiple data groups | Can plot multiple data groups for comparison |
| Noise Filtering | Automatically filters minor fluctuations | Displays all data fluctuations |
Similar Charts
Categories
Site Docs Charts Kagi.Zh (`site/docs/charts/kagi.zh.mdx`)
title: 卡吉图 sidebar: { icon: 'line' } order: 25 screenshot: 'https://zos.alipayobjects.com/rmsportal/GYxDnAkxCMrLfpB.png' category: ['trend', 'time'] similar: ['line', 'area', ' k-chart']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
卡吉图的简介
卡吉图大约发明于 19 世纪 70 年代日本股票市场开始交易的时候。在美国,史蒂文·尼森出版《烛形图之外》后,卡吉图分析法随之流行。由于能够清晰、有效地显示价格走势的路径,卡吉图是投资者用于对股票做出更好决策的图表之一。
卡吉图是一系列由短水平线连接的垂直线,水平线起连接作用,垂直线的厚度和方向取决于价格运动。垂直线方向向上代表价格上升,方向向下代表价格下降,当价格运动方向反转超过阈值时绘制一条新的垂直线,在转折处用水平线相连。当价格上升超过前一个高点转折时采用粗线绘制,称为阳线,当价格下降低于前一个低点转折时采用细线绘制,称为阴线。
卡吉图的特点:
- 卡吉图模拟了证券的供给与需求力量的关系,非常适用于股票短线操作
- 卡吉图通过阈值标记逆转,交易者可以过滤掉日常价格波动,只关注价格的显著变化
- 卡吉图独立于时间
:::warning{title=注意}
卡吉图绘制的折线是经过卡吉图算法计算之后的,与原数据曲线有区别
:::
英文名:Kagi Chart
卡吉图的构成
| 图表类型 | 卡吉图 |
|---|---|
| 适合的数据 | 一个分类数据字段,一个连续字段 |
| 功能 | 观察数据变化趋势 |
| 数据与图形映射 | 转折点的时间分类(自动计算)映射到横轴,转折点的值映射到纵轴 |
| 适合的数据条数 | 大于 10 条 |
构成要素:
- 阳线:价格上升超过前一个高点时的粗线,通常用较粗的线条表示
- 阴线:价格下降低于前一个低点时的细线,通常用较细的线条表示
- 转折点:价格运动方向发生逆转的关键点位
- 连接线:连接垂直线段的水平线,标识转向位置
卡吉图的应用场景
适合的场景
场景 1:展示价格或股票变化走势
卡吉图最适合用于展示金融市场中股票、期货、外汇等价格变化的趋势分析。通过过滤掉日常的小幅波动,突出显示价格的重要转折点,帮助投资者识别趋势的变化。
场景 2:技术分析和趋势判断
卡吉图在技术分析中特别有用,因为它能够:
- 过滤市场噪音,专注于重要的价格变动
- 清晰显示支撑位和阻力位
- 帮助识别趋势的延续和反转信号
不适合的场景
场景 1:对时间敏感的数据
卡吉图与时间无关,只表示数据上升下降的走势,无法体现数据在时间上的一些特性,例如周期等。特别是当数据对时间敏感时不推荐使用卡吉图。
例如网站访问量数据通常具有明显的时间周期性(工作日 vs 周末,白天 vs 夜晚),使用卡吉图会丢失这些重要的时间特征信息。对于此类数据,推荐使用折线图或面积图。
场景 2:多组数据对比
卡吉图的横坐标具有特殊性(转折点时间),无法在同一个横轴上绘制多组卡吉图进行对比分析。如需对比多个数据系列,建议使用多系列折线图。
卡吉图与其他图表的对比
卡吉图与 K 线图
| 特征 | 卡吉图 | K 线图 |
|---|---|---|
| 时间依赖 | 独立于时间,仅表现数据走势 | 与时间相关,每个时间段对应一个 K 线 |
| 数据展示 | 过滤小幅波动,突出重要转折 | 展示指定时间段内的开高低收价格 |
| 分析重点 | 趋势方向和转折点 | 时间段内的价格波动和成交量 |
| 适用场景 | 中长期趋势分析 | 短期交易和时间敏感分析 |
卡吉图与折线图
| 特征 | 卡吉图 | 折线图 |
|---|---|---|
| 数据处理 | 经过算法计算的转折点数据 | 严格按照原数据的坐标绘制 |
| 坐标轴 | 横坐标为计算得出的转折点 | 横纵坐标都对应原始数据 |
| 线条含义 | 颜色和粗细代表特定含义(阳线阴线) | 通常只表示数据连接关系 |
| 多系列 | 无法绘制多组数据 | 可以绘制多组数据进行对比 |
| 噪音过滤 | 自动过滤小幅波动 | 显示所有数据波动 |
卡吉图的扩展
不同阈值设置
卡吉图的核心参数是逆转阈值,不同的阈值设置会产生不同的效果:
- 较小阈值:更敏感,会捕捉到更多的价格转折,但可能包含较多噪音
- 较大阈值:过滤更多噪音,只显示重要的趋势变化,但可能错过一些转折信号
时间加权卡吉图
传统卡吉图完全忽略时间因素,而时间加权卡吉图在计算转折点时会考虑时间间隔,使图表在保持卡吉图特色的同时,部分保留时间信息。
实现说明
:::info{title=开发说明}
G2 目前暂未提供内置的卡吉图标记,但可以通过以下方式实现:
- 数据预处理:使用卡吉图算法对原始数据进行转换,计算出转折点数据
- 自定义标记:结合
path标记和自定义形状实现卡吉图的视觉效果 - 算法实现:需要实现卡吉图的核心算法,包括阈值判断、转折点计算等
详细的实现方式可以参考 自定义标记 文档。
:::
相似图表
分类
Site Docs Charts Line.En (`site/docs/charts/line.en.mdx`)
title: Line Chart sidebar: { icon: 'line' } order: 2 screenshot: 'https://os.alipayobjects.com/rmsportal/VVPAIRTNYwbbZut.jpg' category: ['trend', 'time'] similar: ['area', 'bar', 'scatter', 'stacked-area']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Line Charts
A line chart is a statistical chart that connects data points in chronological or categorical order to form a line, used to display data trends over time or ordered categories. Through the rise or fall of the line, it can intuitively show the speed, amplitude, range, and periodicity of data changes.
Line charts are particularly suitable for displaying continuous time series data changes and can effectively reflect data trends, fluctuations, periodicity, and anomalies. When comparing multiple data series, line charts use lines of different colors or styles to clearly show the comparison and relationships between different data series.
Compared to area charts, line charts focus more on showing trends and trajectories of data changes rather than total quantities. Compared to bar charts, line charts are more suitable for showing continuous trends rather than discrete numerical comparisons.
Other Names: Line Chart
Components of a Line Chart
Basic Line Chart
| Chart Type | Basic Line Chart |
|---|---|
| Suitable Data | Time series data: one ordered/continuous data field (usually time), one continuous data field |
| Function | Display data trends over time or ordered dimensions |
| Data-to-Graphics Mapping | Time field maps to x-axis positionValue field maps to y-axis heightData points are connected by lines to show change trajectory |
| Suitable Scenarios | Single data series change trends over time |
Multi-Series Line Chart
| Chart Type | Multi-Series Line Chart |
|---|---|
| Suitable Data | Multi-series time data: one ordered/continuous data field (usually time), one continuous data field, one categorical data field |
| Function | Display trends of multiple data series over time, facilitating comparison of relationships between different series |
| Data-to-Graphics Mapping | Time field maps to x-axis positionValue field maps to y-axis heightCategory field maps to different colored lines |
| Suitable Scenarios | Comparison of multiple data series trends over time |
Use Cases of Line Charts
Suitable Use Cases
Example 1: Suitable for displaying continuous time series trends
The following chart is a line chart of stock price trends, showing the change trend of a company's stock price over time.
| date | close |
|---|---|
| 2015/1/5 | 121.73 |
| 2015/1/6 | 115.07 |
| 2015/1/7 | 116.75 |
| ... | ... |
Explanation:
- The
datefield maps to the x-axis position, representing chronological order - The
closefield maps to the y-axis height, showing price trends over time - Data points are connected by lines, clearly displaying the trajectory of data changes
Example 2: Suitable for displaying comparative trends of multiple data series
Multi-series line charts can simultaneously display changes of multiple data series over time, facilitating comparative analysis. The following chart shows unemployment rate trends in different regions.
Explanation:
- The
datefield maps to the x-axis, representing the time dimension - The
unemploymentfield maps to the y-axis, representing unemployment rate - The
divisionfield maps to color, distinguishing different regions - Multiple lines facilitate intuitive comparison of unemployment rate trends and differences across regions
Example 3: Displaying subtle data changes and fluctuations
Line charts can clearly display subtle data changes and fluctuations, especially when there are many data points with frequent changes.
Explanation:
- The line chart clearly displays annual temperature change curves for Tokyo and London
- Through different colored lines, temperature differences and change patterns between the two cities can be intuitively compared
Unsuitable Use Cases
Example 1: Not suitable for displaying discrete category comparisons
When the horizontal axis data type is unordered categories or the vertical axis data type is continuous time, line charts are not suitable.
We take a scenario comparing sales of different game types as an example. For data representing categorical comparisons, we should use bar charts instead of line charts.
Wrong approach (using line chart):
<Demo height={274} code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 250,
});
chart.options({
type: 'line',
autoFit: true,
data: [
{ genre: 'Sports', sold: 27500 },
{ genre: 'Strategy', sold: 11500 },
{ genre: 'Action', sold: 6000 },
{ genre: 'Shooter', sold: 3500 },
{ genre: 'Other', sold: 1500 },
],
encode: { x: 'genre', y: 'sold' },
axis: {
x: {
title: 'Game Type',
},
y: {
title: 'Sales',
labelFormatter: (val) => val / 1000 + 'k',
},
},
style: {
lineWidth: 3,
stroke: '#1890ff',
},
});
chart.render();
`} />
Correct approach (using bar chart):
<Demo height={274} code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 250,
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ genre: 'Sports', sold: 27500 },
{ genre: 'Strategy', sold: 11500 },
{ genre: 'Action', sold: 6000 },
{ genre: 'Shooter', sold: 3500 },
{ genre: 'Other', sold: 1500 },
],
encode: { x: 'genre', y: 'sold', color: 'genre' },
axis: {
x: {
title: 'Game Type',
},
y: {
title: 'Sales',
labelFormatter: (val) => val / 1000 + 'k',
},
},
});
chart.render();
`} />
Problem description:
- Game types have no natural order or continuous relationship
- The connecting line implies a trend relationship between categories, but this relationship doesn't actually exist
- The line may mislead readers into thinking there's a trend from "Sports" to "Strategy"
- Bar charts can more accurately represent independent sales comparisons between game types
Example 2: Poor effectiveness when data points are few or changes are insignificant
When there are few data points or changes are insignificant, line charts may not fully leverage their advantage of showing trend changes. In such cases, consider using bar charts or dot plots to emphasize comparisons between individual data points.
Problem description:
- Too few data points (only 4), unable to form a clear trend line
- Very small value changes (99-102), the line appears almost flat
- Difficult to extract meaningful trend information
- Bar charts or dot plots would better emphasize comparisons between individual values
Extensions of Line Charts
Step Line Chart
Step line charts use horizontal and vertical line segments to connect data points, creating a step-like effect, suitable for displaying data that changes abruptly at specific time points.
Explanation:
- Use
encode: { shape: 'hv' }to specify step-like line shape - Suitable for displaying data that changes at specific time points and remains stable until the next change point, such as tiered electricity prices, inventory level changes, etc.
Dashed Line Chart
Dashed line charts use different line styles to distinguish different data series or represent specific meanings, such as predicted values, reference lines, etc.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
data: [
{ year: '1991', value: 3, type: 'Actual' },
{ year: '1992', value: 4, type: 'Actual' },
{ year: '1993', value: 3.5, type: 'Actual' },
{ year: '1994', value: 5, type: 'Actual' },
{ year: '1995', value: 4.9, type: 'Actual' },
{ year: '1996', value: 6, type: 'Actual' },
{ year: '1997', value: 7, type: 'Actual' },
{ year: '1998', value: 9, type: 'Actual' },
{ year: '1999', value: 13, type: 'Actual' },
{ year: '1999', value: 13, type: 'Predicted' },
{ year: '2000', value: 16, type: 'Predicted' },
{ year: '2001', value: 21, type: 'Predicted' },
{ year: '2002', value: 25, type: 'Predicted' },
{ year: '2003', value: 30, type: 'Predicted' },
],
children: [
{
type: 'line',
encode: { x: 'year', y: 'value', color: 'type' },
style: {
lineWidth: 2,
lineDash: (d) => (d[0].type === 'Predicted' ? [4, 4] : null),
},
},
{
type: 'point',
encode: { x: 'year', y: 'value', color: 'type', shape: 'circle' },
},
],
scale: {
color: {
range: ['#1890FF', '#FF6B3B'],
},
},
axis: {
x: { title: null },
y: { title: null },
},
});
chart.render();
`} />
Explanation:
- Use
lineDash: (d) => (d[0].type === 'Predicted' ? [4, 4] : null)to set dashed line style for predicted values - Solid lines represent existing historical data, dashed lines represent predicted or estimated data, enhancing data readability
Comparing Line Charts to Other Charts
Line Charts and [Area Charts](/en/charts/area/)
- Line charts focus on displaying trends and trajectories of data changes, emphasizing direction and speed of change
- Area charts emphasize visual effects of quantities through filled areas, more suitable for displaying total quantity changes
- Choose line charts when highlighting change trends, choose area charts when emphasizing magnitude changes
Line Charts and [Stacked Area Charts](/en/charts/stacked-area/)
- Line charts are suitable for displaying trends of multiple independent data series, allowing direct comparison between series
- Stacked area charts show the contribution of each part to the total, emphasizing cumulative effects and part-to-whole relationships
- Choose line charts when comparing multiple independent trends, choose stacked area charts when showing how parts contribute to total changes
Line Charts and [Bar Charts](/en/charts/bar/)
- Line charts are more suitable for displaying continuous time series change trends, emphasizing data fluidity and continuity
- Bar charts are more suitable for displaying numerical comparisons between discrete categories, emphasizing size comparisons of individual independent values
- Choose line charts when data points are numerous and trend changes are the focus, choose bar charts when data points are fewer and specific value comparisons are the focus
Line Charts and [Scatter Plots](/en/charts/scatter-plot/)
- Line charts show data change trends and continuity through connecting lines, emphasizing relationships between data points
- Scatter plots display distribution of individual independent data points, without emphasizing continuous relationships between data points
- Choose line charts when displaying data trends, choose scatter plots when displaying data distribution or correlation
Similar Charts
Categories
Site Docs Charts Line.Zh (`site/docs/charts/line.zh.mdx`)
title: 折线图 sidebar: { icon: 'line' } order: 2 screenshot: 'https://os.alipayobjects.com/rmsportal/VVPAIRTNYwbbZut.jpg' category: ['trend', 'time'] similar: ['area', 'bar', 'scatter', 'stacked-area']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
折线图的简介
折线图是一种将数据点按时间或类别顺序连接成一条折线,用于显示数据随时间或有序类别变化趋势的统计图表。通过折线的上升或下降,可以直观地表现数据变化的速度、幅度、范围及其周期性。
折线图特别适合展示连续时间序列的数据变化,能够有效地反映数据的趋势、波动、周期性和异常点。在多系列数据比较时,折线图通过不同颜色或样式的线条,清晰地展示各数据系列间的对比和关系。
相比于面积图,折线图更侧重于展示数据变化的趋势和轨迹,而非总量;相比于柱状图,折线图更适合展示连续变化的趋势,而非离散的数值比较。
英文名:Line Chart
折线图的构成
基础折线图
| 图表类型 | 基础折线图 |
|---|---|
| 适合的数据 | 时间序列数据:一个有序/连续数据字段(通常是时间)、一个连续数据字段 |
| 功能 | 展示数据随时间或有序维度的变化趋势 |
| 数据与图形的映射 | 时间字段映射到横轴的位置数值字段映射到纵轴的高度各数据点通过线条连接,展示变化轨迹 |
| 适合的场景 | 单一数据系列随时间的变化趋势 |
多系列折线图
| 图表类型 | 多系列折线图 |
|---|---|
| 适合的数据 | 多序列时间数据:一个有序/连续数据字段(通常是时间)、一个连续数据字段、一个分类数据字段 |
| 功能 | 展示多个数据系列随时间变化的趋势,便于比较不同系列间的关系 |
| 数据与图形的映射 | 时间字段映射到横轴的位置数值字段映射到纵轴的高度分类字段映射到不同颜色的线条 |
| 适合的场景 | 多数据系列随时间的变化趋势对比 |
折线图的应用场景
适合的场景
例子 1: 适合展示连续时间序列的趋势
下图是一个股票价格走势的折线图,展示了某公司股票价格随时间的变化趋势。
| date(日期) | close(收盘价) |
|---|---|
| 2015/1/5 | 121.73 |
| 2015/1/6 | 115.07 |
| 2015/1/7 | 116.75 |
| ... | ... |
说明 :
date字段,映射到横轴的位置,表示时间的先后顺序close字段,映射到纵轴的高度,展示了价格随时间的变化趋势- 通过线条连接各个数据点,清晰地展示数据的变化轨迹
例子 2: 适合展示多个数据系列的对比趋势
多系列折线图可以同时展示多个数据系列随时间的变化,便于进行比较分析。下图展示了不同地区失业率的变化趋势。
说明:
date字段映射到横轴,表示时间维度unemployment字段映射到纵轴,表示失业率division字段映射到颜色,区分不同地区- 多条折线便于直观比较不同地区失业率的变化趋势和差异
例子 3: 展示数据的细微变化和波动
折线图可以清晰地展示数据的细微变化和波动,特别是当数据点较多且变化频繁时。
说明:
- 折线图清晰地展示了东京和伦敦全年温度的变化曲线
- 通过不同颜色的折线,可以直观地比较两个城市温度的差异和变化模式
不适合的场景
例子 1: 不适合展示离散类别的比较
当水平轴的数据类型为无序的分类或者垂直轴的数据类型为连续时间时,不适合使用折线图。
我们以一个不同游戏类型的销量对比的场景为例,对于表示分类对比的数据时,我们更应该使用柱状图,而不是折线图。
错误的做法
<Demo height={274} code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 250,
});
chart.options({
type: 'line',
autoFit: true,
data: [
{ genre: 'Sports', sold: 27500 },
{ genre: 'Strategy', sold: 11500 },
{ genre: 'Action', sold: 6000 },
{ genre: 'Shooter', sold: 3500 },
{ genre: 'Other', sold: 1500 },
],
encode: { x: 'genre', y: 'sold' },
axis: {
x: {
title: '游戏类型',
},
y: {
title: '销售量',
labelFormatter: (val) => val / 1000 + 'k',
},
},
style: {
lineWidth: 3,
stroke: '#1890ff',
},
});
chart.render();
`} />
正确的做法
<Demo height={274} code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
height: 250,
});
chart.options({
type: 'interval',
autoFit: true,
data: [
{ genre: 'Sports', sold: 27500 },
{ genre: 'Strategy', sold: 11500 },
{ genre: 'Action', sold: 6000 },
{ genre: 'Shooter', sold: 3500 },
{ genre: 'Other', sold: 1500 },
],
encode: { x: 'genre', y: 'sold', color: 'genre' },
axis: {
x: {
title: '游戏类型',
},
y: {
title: '销售量',
labelFormatter: (val) => val / 1000 + 'k',
},
},
});
chart.render();
`} />
问题说明:
- 游戏类型之间没有自然的顺序或连续性关系
- 连线暗示了类别间的趋势关系,但实际上不存在这种关系
- 折线可能误导读者认为从"Sports"到"Strategy"存在某种变化趋势
- 柱状图能更准确地表达各游戏类型的独立销量比较
例子 2: 数据点较少或变化不明显时效果不佳
当数据点较少或变化不明显时,折线图可能无法充分发挥其展示趋势变化的优势。这种情况下,可以考虑使用柱状图或点图来强调个别数据点的比较。
问题说明:
- 数据点太少(仅 4 个),无法形成明显的趋势线
- 数值变化很小(99-102),折线看起来几乎是平的
- 难以从中获得有意义的趋势信息
- 柱状图或点图能更好地强调各个独立数值的比较
折线图的扩展
阶梯折线图
阶梯折线图使用水平和垂直线段连接数据点,形成阶梯状的效果,适合展示在特定时间点发生突变的数据。
说明:
- 使用
encode: { shape: 'hv' }指定阶梯状的线条形状 - 适合展示在特定时间点发生变化且保持稳定直到下一变化点的数据,如电费阶梯价格、库存水平变化等
虚线折线图
虚线折线图通过不同的线型来区分不同的数据系列或表示特定含义,如预测值、参考线等。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
theme: 'classic',
});
chart.options({
type: 'view',
autoFit: true,
data: [
{ year: '1991', value: 3, type: '实际值' },
{ year: '1992', value: 4, type: '实际值' },
{ year: '1993', value: 3.5, type: '实际值' },
{ year: '1994', value: 5, type: '实际值' },
{ year: '1995', value: 4.9, type: '实际值' },
{ year: '1996', value: 6, type: '实际值' },
{ year: '1997', value: 7, type: '实际值' },
{ year: '1998', value: 9, type: '实际值' },
{ year: '1999', value: 13, type: '实际值' },
{ year: '1999', value: 13, type: '预测值' },
{ year: '2000', value: 16, type: '预测值' },
{ year: '2001', value: 21, type: '预测值' },
{ year: '2002', value: 25, type: '预测值' },
{ year: '2003', value: 30, type: '预测值' },
],
children: [
{
type: 'line',
encode: { x: 'year', y: 'value', color: 'type' },
style: {
lineWidth: 2,
lineDash: (d) => (d[0].type === '预测值' ? [4, 4] : null),
},
},
{
type: 'point',
encode: { x: 'year', y: 'value', color: 'type', shape: 'circle' },
},
],
scale: {
color: {
range: ['#1890FF', '#FF6B3B'],
},
},
axis: {
x: { title: null },
y: { title: null },
},
});
chart.render();
`} />
说明:
- 使用
lineDash: (d) => (d[0].type === '预测值' ? [4, 4] : null)为预测值设置虚线样式 - 实线表示已有的历史数据,虚线表示预测或估计的数据,增强了数据的可读性
折线图与其他图表的对比
折线图和[面积图](/zh/charts/area/)
- 折线图侧重于展示数据变化的趋势和轨迹,关注变化的方向和速度
- 面积图通过填充区域强调数量的视觉效果,更适合展示总量变化
- 当需要突出变化趋势时选择折线图,当需要强调数量级变化时选择面积图
折线图和[堆叠面积图](/zh/charts/stacked-area/)
- 折线图适合展示多个独立数据系列的变化趋势,各系列间可以直接比较
- 堆叠面积图显示各部分对总体的贡献,强调累积效果和部分与整体的关系
- 当需要比较多个独立趋势时选择折线图,当需要展示部分构成总体的变化时选择堆叠面积图
折线图和[柱状图](/zh/charts/bar/)
- 折线图更适合展示连续时间序列的变化趋势,强调数据的流动性和连续性
- 柱状图更适合展示离散分类之间的数值比较,强调各个独立数值的大小对比
- 当数据点较多且关注变化趋势时选择折线图,当数据点较少且关注具体数值比较时选择柱状图
折线图和[散点图](/zh/charts/scatter-plot/)
- 折线图通过连线展示数据的变化趋势和连续性,强调数据点间的关系
- 散点图展示各个独立数据点的分布,不强调数据点间的连续关系
- 当需要展示数据趋势时选择折线图,当需要展示数据分布或相关性时选择散点图
相似图表
分类
Site Docs Charts Mosaic.En (`site/docs/charts/mosaic.en.mdx`)
title: Mosaic Plot sidebar: { icon: 'heatmap' } order: 1 screenshot: 'https://os.alipayobjects.com/rmsportal/eXoQbOxSvByiNWd.jpg' category: ['comparison', 'proportion'] similar: ['heatmap', 'treemap']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Mosaic Plots
A mosaic plot (also known as a Marimekko Chart) is a chart used to display relationships between categorical data. It represents data proportions and classifications through the area and color of rectangles.
Mosaic plots are divided into two types: uniform and non-uniform. Uniform mosaic plots are more common in daily life, such as subway fare charts, while non-uniform mosaic plots are more frequently used in statistical fields.
Other Names: Mosaic Plot, Marimekko Chart
Components of a Mosaic Plot
Non-uniform Axis Mosaic Plot
| Chart Type | Non-uniform Axis Mosaic Plot |
|---|---|
| Suitable Data | Multi-dimensional categorical data |
| Functionality | Display distribution of multi-dimensional categorical data |
| Data Mapping | Categorical data fields map to non-uniform coordinate axisArea and color represent data proportions and classifications |
| Data Size Limit | More effective with higher dimensional data |
Uniform Axis Mosaic Plot
| Chart Type | Uniform Axis Mosaic Plot |
|---|---|
| Suitable Data | Two-dimensional categorical data |
| Functionality | Display distribution of two-dimensional categorical data |
| Data Mapping | Categorical data fields map to uniform coordinate axisColor represents data classifications |
| Data Size Limit | More effective with lower dimensional data |
Use Cases of Mosaic Plots
Suitable Use Cases
Example 1: Suitable for multi-dimensional categorical data analysis
Example 2: Suitable for two-dimensional categorical data analysis
<Demo height={424} code={`import * as G2 from '@antv/g2';
const chart = new G2.Chart({
container: 'container',
autoFit: true,
height: 400,
});
chart.options({
type: 'cell',
data: [
{ product: 'Phone', region: 'North', sales: 120, category: 'Premium' },
{ product: 'Phone', region: 'East', sales: 180, category: 'Premium' },
{ product: 'Phone', region: 'South', sales: 150, category: 'Premium' },
{ product: 'Computer', region: 'North', sales: 80, category: 'Mid-range' },
{ product: 'Computer', region: 'East', sales: 110, category: 'Mid-range' },
{ product: 'Computer', region: 'South', sales: 95, category: 'Mid-range' },
{ product: 'Tablet', region: 'North', sales: 60, category: 'Mid-range' },
{ product: 'Tablet', region: 'East', sales: 85, category: 'Mid-range' },
{ product: 'Tablet', region: 'South', sales: 70, category: 'Budget' },
{ product: 'Headphone', region: 'North', sales: 40, category: 'Budget' },
{ product: 'Headphone', region: 'East', sales: 55, category: 'Budget' },
{ product: 'Headphone', region: 'South', sales: 45, category: 'Budget' },
],
encode: {
x: 'product',
y: 'region',
color: 'category',
size: 'sales',
},
scale: {
color: {
palette: 'category10',
type: 'ordinal',
},
size: {
type: 'linear',
range: [0.3, 1],
},
},
style: {
stroke: '#fff',
strokeWidth: 2,
inset: 2,
},
legend: {
color: {
title: 'Product Category',
position: 'top',
},
size: {
title: 'Sales Volume',
position: 'right',
},
},
axis: {
x: {
title: 'Product Type',
labelAutoRotate: false,
},
y: {
title: 'Sales Region',
},
},
tooltip: {
title: (d) => `${d.product} - ${d.region}`,
items: [
{ field: 'sales', name: 'Sales', valueFormatter: (v) => `${v}K` },
{ field: 'category', name: 'Category' },
],
},
});
chart.render();
`} />
Example 3: Market Segmentation Analysis (Non-uniform Mosaic Plot)
This example demonstrates how to use a non-uniform mosaic plot to display the distribution of different market segments, where the width of each rectangle represents market size, and the height represents the proportion of each market segment.
<Demo height={824} code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
width: 900,
height: 800,
paddingLeft: 0,
paddingRight: 0,
});
chart.options({
type: 'interval',
data: {
type: 'fetch',
value:
'https://gw.alipayobjects.com/os/bmw-prod/3041da62-1bf4-4849-aac3-01a387544bf4.csv',
},
transform: [
{ type: 'flexX', reducer: 'sum' }, // Flexible X-axis width
{ type: 'stackY' }, // Y-axis stacking
{ type: 'normalizeY' }, // Y-axis normalization
],
encode: {
x: 'market',
y: 'value',
color: 'segment',
},
axis: {
y: false,
},
scale: {
x: { paddingOuter: 0, paddingInner: 0.01 },
},
tooltip: 'value',
labels: [
{
text: 'segment',
x: 5,
y: 5,
textAlign: 'start',
textBaseline: 'top',
fontSize: 10,
fill: '#fff',
},
{
text: 'value',
x: 5,
y: 5,
textAlign: 'start',
dy: 15,
fontSize: 10,
fill: '#fff',
},
],
});
chart.render();
`} />
Example 4: Movie Rating Distribution Analysis (Density Mosaic Plot)
This example demonstrates how to use a density mosaic plot to analyze the relationship between IMDB and Rotten Tomatoes ratings, where the color intensity represents the number of movies.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/movies.json',
},
encode: {
x: 'IMDB Rating',
y: 'Rotten Tomatoes Rating',
},
transform: [
{ type: 'bin', color: 'count', thresholdsX: 30, thresholdsY: 20 },
],
scale: {
color: { palette: 'ylGnBu' },
},
tooltip: {
title: { channel: 'color' },
items: [
(d, i, data, column) => ({
name: 'IMDB Rating',
value: `${column.x.value[i]}, ${column.x1.value[i]}`,
}),
(d, i, data, column) => ({
name: 'Rotten Tomatoes Rating',
value: `${column.y.value[i]}, ${column.y1.value[i]}`,
}),
],
render: () => '1',
},
});
chart.render();
`} />
Example 5: Athletes' Physiological Data Analysis (Grouped Density Mosaic Plot)
This example shows how to use a mosaic plot to display the height and weight distribution of athletes grouped by gender, with opacity representing data point density.
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/athletes.json',
},
encode: {
x: 'weight',
y: 'height',
color: 'sex',
},
transform: [{ type: 'bin', opacity: 'count' }],
legend: {
opacity: false,
},
style: {
inset: 0.5,
},
tooltip: {
title: { channel: 'opacity' },
items: [
(d, i, data, column) => ({
name: 'Weight',
value: `${column.x.value[i]}, ${column.x1.value[i]}`,
}),
(d, i, data, column) => ({
name: 'Height',
value: `${column.y.value[i]}, ${column.y1.value[i]}`,
}),
],
},
});
chart.render();
`} />
Unsuitable Use Cases
Mosaic plots are not suitable for:
- Displaying continuous numerical data trends
- Showing precise numerical comparisons
- Analyzing time series data
- Displaying data with too many categories (which can make the chart cluttered and hard to read)
Comparing Mosaic Plots to Other Charts
Mosaic Plots and [Heatmaps](/en/charts/heatmap/)
- From graphical properties perspective:
- Heatmaps represent the third dimension with linear color changes
- Mosaic plots represent the third dimension with categorical colors
- Standard heatmaps use smoothing algorithms with no clear boundaries
- Mosaic plots have clear boundaries
- From data perspective:
- Uniform mosaic plots and heatmaps have very similar meanings for continuous data
- From analytical needs perspective:
- Heatmaps focus on distribution and can predict data in unknown areas
- Mosaic plots have clearer boundaries and focus more on comparison
Mosaic Plots and [Treemaps](/en/charts/treemap/)
- Mosaic plots are better for showing relationships between multiple categorical variables
- Treemaps are more suitable for displaying hierarchical data structures
- Mosaic plots use position and area to encode data
- Treemaps primarily use area and nesting to represent hierarchical relationships
Similar Charts
Categories
Site Docs Charts Mosaic.Zh (`site/docs/charts/mosaic.zh.mdx`)
title: 马赛克图 sidebar: { icon: 'heatmap' } order: 1 screenshot: 'https://os.alipayobjects.com/rmsportal/eXoQbOxSvByiNWd.jpg' category: ['comparison', 'proportion'] similar: ['heatmap', 'treemap']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
马赛克图的简介
马赛克图(Mosaic Plot,又名 Marimekko Chart)是一种用于显示分类数据之间关系的图表。它通过矩形的面积和颜色来表示数据的比例和分类。
马赛克图分为均匀和非均匀两种类型,均匀马赛克图在生活中更为常见,例如地铁票价图;而非均匀马赛克图多用于统计学领域。
英文名:Mosaic Plot, Marimekko Chart
马赛克图的构成
非均匀坐标轴马赛克图
| 图表类型 | 非均匀坐标轴马赛克图 |
|---|---|
| 适合的数据 | 多维分类数据 |
| 功能 | 显示多维分类数据的分布 |
| 数据与图形的映射 | 分类数据字段映射到非均匀的坐标轴面积和颜色表示数据的比例和分类 |
| 适合的数据条数 | 数据维度较多时效果更佳 |
均匀坐标轴马赛克图
| 图表类型 | 均匀坐标轴马赛克图 |
|---|---|
| 适合的数据 | 二维分类数据 |
| 功能 | 显示二维分类数据的分布 |
| 数据与图形的映射 | 分类数据字段映射到均匀的坐标轴颜色表示数据的分类 |
| 适合的数据条数 | 数据维度较少时效果更佳 |
马赛克图的应用场景
适合的场景
例子 1: 适合应用到多维分类数据分析
例子 2: 适合应用到二维分类数据分析
<Demo height={424} code={`import * as G2 from '@antv/g2';
const chart = new G2.Chart({
container: 'container',
autoFit: true,
height: 400,
});
chart.options({
type: 'cell',
data: [
{ product: '手机', region: '华北', sales: 120, category: '高端' },
{ product: '手机', region: '华东', sales: 180, category: '高端' },
{ product: '手机', region: '华南', sales: 150, category: '高端' },
{ product: '电脑', region: '华北', sales: 80, category: '中端' },
{ product: '电脑', region: '华东', sales: 110, category: '中端' },
{ product: '电脑', region: '华南', sales: 95, category: '中端' },
{ product: '平板', region: '华北', sales: 60, category: '中端' },
{ product: '平板', region: '华东', sales: 85, category: '中端' },
{ product: '平板', region: '华南', sales: 70, category: '低端' },
{ product: '耳机', region: '华北', sales: 40, category: '低端' },
{ product: '耳机', region: '华东', sales: 55, category: '低端' },
{ product: '耳机', region: '华南', sales: 45, category: '低端' },
],
encode: {
x: 'product',
y: 'region',
color: 'category',
size: 'sales',
},
scale: {
color: {
palette: 'category10',
type: 'ordinal',
},
size: {
type: 'linear',
range: [0.3, 1],
},
},
style: {
stroke: '#fff',
strokeWidth: 2,
inset: 2,
},
legend: {
color: {
title: '产品类别',
position: 'top',
},
size: {
title: '销售额',
position: 'right',
},
},
axis: {
x: {
title: '产品类型',
labelAutoRotate: false,
},
y: {
title: '销售区域',
},
},
tooltip: {
title: (d) => `${d.product} - ${d.region}`,
items: [
{ field: 'sales', name: '销售额', valueFormatter: (v) => `${v}万` },
{ field: 'category', name: '类别' },
],
},
});
chart.render();
`} />
例子 3: 市场细分分析(非均匀马赛克图)
这个例子展示了如何使用非均匀马赛克图来展示不同市场细分的分布情况,其中矩形的宽度表示市场规模,高度表示各细分市场的占比。
<Demo height={824} code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
width: 900,
height: 800,
paddingLeft: 0,
paddingRight: 0,
});
chart.options({
type: 'interval',
data: {
type: 'fetch',
value:
'https://gw.alipayobjects.com/os/bmw-prod/3041da62-1bf4-4849-aac3-01a387544bf4.csv',
},
transform: [
{ type: 'flexX', reducer: 'sum' }, // 灵活X轴宽度
{ type: 'stackY' }, // Y轴堆叠
{ type: 'normalizeY' }, // Y轴归一化
],
encode: {
x: 'market',
y: 'value',
color: 'segment',
},
axis: {
y: false,
},
scale: {
x: { paddingOuter: 0, paddingInner: 0.01 },
},
tooltip: 'value',
labels: [
{
text: 'segment',
x: 5,
y: 5,
textAlign: 'start',
textBaseline: 'top',
fontSize: 10,
fill: '#fff',
},
{
text: 'value',
x: 5,
y: 5,
textAlign: 'start',
dy: 15,
fontSize: 10,
fill: '#fff',
},
],
});
chart.render();
`} />
例子 4: 电影评分分布分析(密度马赛克图)
这个例子展示了如何使用密度马赛克图来分析 IMDB 和烂番茄评分的关系分布,颜色深浅表示电影数量的多少。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/movies.json',
},
encode: {
x: 'IMDB Rating',
y: 'Rotten Tomatoes Rating',
},
transform: [
{ type: 'bin', color: 'count', thresholdsX: 30, thresholdsY: 20 },
],
scale: {
color: { palette: 'ylGnBu' },
},
tooltip: {
title: { channel: 'color' },
items: [
(d, i, data, column) => ({
name: 'IMDB评分',
value: `${column.x.value[i]}, ${column.x1.value[i]}`,
}),
(d, i, data, column) => ({
name: '烂番茄评分',
value: `${column.y.value[i]}, ${column.y1.value[i]}`,
}),
],
render: () => '1',
},
});
chart.render();
`} />
例子 5: 运动员生理数据分析(分组密度马赛克图)
这个例子展示了如何使用马赛克图按性别分组展示运动员身高和体重的分布情况,不透明度表示数据点的密度。
<Demo code={`import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'rect',
data: {
type: 'fetch',
value: 'https://assets.antv.antgroup.com/g2/athletes.json',
},
encode: {
x: 'weight',
y: 'height',
color: 'sex',
},
transform: [{ type: 'bin', opacity: 'count' }],
legend: {
opacity: false,
},
style: {
inset: 0.5,
},
tooltip: {
title: { channel: 'opacity' },
items: [
(d, i, data, column) => ({
name: '体重',
value: `${column.x.value[i]}, ${column.x1.value[i]}`,
}),
(d, i, data, column) => ({
name: '身高',
value: `${column.y.value[i]}, ${column.y1.value[i]}`,
}),
],
},
});
chart.render();
`} />
马赛克图与其他图表的对比
马赛克图和热力图
- 从图形属性上:
- 热力图表示第三维度的颜色是线性变化的。
- 马赛克图表示第三维度的颜色是分类的。
- 标准热力图要经过平滑算法,没有明显的边界。
- 马赛克图拥有清晰的边界。
- 从数据上看:
- 均匀的马赛克图和热力图在连续数据上的含义非常相似。
- 从分析需求上看:
- 热力图侧重于分布,可预测未知区域数据。
- 马赛克图拥有更清晰的边界,更侧重于对比。
马赛克图的扩展阅读
- A Brief History of the Mosaic Display
- Are Mosaic Plots Worthwhile
- Marimekko Charts
- Marimekko Charts FusionChart
- Marimekko Charts The Data Visualisation Catalogue
- Marimekko Charts in Microsoft Excel
相似图表
分类
Site Docs Charts Multi Set Bar.En (`site/docs/charts/multi-set-bar.en.mdx`)
title: Multi-set Bar Chart sidebar: { icon: 'column' } order: 4 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*kqGUT4wRYrsAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison'] similar: ['bar', 'stacked-bar', 'histogram']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
Introduction to Multi-set Bar Charts
A multi-set bar chart, also known as a grouped bar chart or clustered bar chart, is used when you need to display different groups within the same categories on a single axis.
Similar to regular bar charts, it uses the height of bars to map and compare data values. Each group contains bars with different colors or varying transparency to distinguish different categories, with spacing maintained between each group.
Multi-set bar charts are frequently used for comparing data between different groups that all contain the same categorical data.
However, it's important to avoid having too many categories within groups, as this can lead to overcrowded and densely packed bars, significantly affecting chart readability.
Other Names: Grouped Bar Chart, Clustered Bar Chart
Components of Multi-set Bar Charts
| Chart Type | Multi-set Bar Chart |
|---|---|
| Suitable Data | A dataset containing two categorical fields and one continuous field |
| Functionality | One categorical field serves as grouping, allowing comparison of data sizes between different categories within the same group, as well as comparison of the same category across different groups |
| Data Mapping | One categorical field maps to axis positions for grouping, another categorical field is offset within the same group and distinguished by different colors, continuous field maps to bar length |
| Data Size Limit | No more than 12 groups, with no more than 6 categories per group |
Use Cases of Multi-set Bar Charts
Suitable Use Cases
Example 1: Comparing data of the same category across different groups, and comparing different categories within the same group
The chart below compares the sales of various game types for "I Am Rich" gaming company across three years: 2001, 2002, and 2003.
The horizontal axis shows different game types, with each game type forming a group in the bar chart, comparing sales numbers for different years within each group.
<Demo height={424} code={`import { Chart } from '@antv/g2';
const data = [
{ year: '2001', genre: 'Sports', sold: 27500 },
{ year: '2001', genre: 'Strategy', sold: 11500 },
{ year: '2001', genre: 'Action', sold: 6000 },
{ year: '2001', genre: 'Shooter', sold: 3500 },
{ year: '2001', genre: 'Other', sold: 1500 },
{ year: '2002', genre: 'Sports', sold: 29500 },
{ year: '2002', genre: 'Strategy', sold: 10500 },
{ year: '2002', genre: 'Action', sold: 8000 },
{ year: '2002', genre: 'Shooter', sold: 4500 },
{ year: '2002', genre: 'Other', sold: 1800 },
{ year: '2003', genre: 'Sports', sold: 30500 },
{ year: '2003', genre: 'Strategy', sold: 12500 },
{ year: '2003', genre: 'Action', sold: 4000 },
{ year: '2003', genre: 'Shooter', sold: 6500 },
{ year: '2003', genre: 'Other', sold: 2000 },
];
const chart = new Chart({
container: 'container',
autoFit: true,
height: 400,
});
chart.options({
type: 'interval',
data,
encode: {
x: 'genre',
y: 'sold',
color: 'year',
},
transform: [{ type: 'dodgeX' }],
axis: {
y: { title: 'Game Sales' },
x: { title: 'Game Genre' },
},
});
chart.render();
`} />
Explanation:
genreuses the horizontal axis position to distinguish different game typesyearuses color and offset positions within the same game type to distinguish sales for different yearssolduses bar length to compare sales across different games and years
Unsuitable Use Cases
Example 1: Too many groups and categories
When there are too many groups and categories, it leads to overcrowded and densely packed bars, resulting in poor readability, as shown in the chart below:
<Demo code={`import { Chart } from '@antv/g2';
// Complete barley dataset - demonstrating the problem of too many groups
const barleyData = [
{ yield: 27, variety: 'Manchuria', year: 1931, site: 'University Farm' },
{ yield: 48.87, variety: 'Manchuria', year: 1931, site: 'Waseca' },
{ yield: 27.43, variety: 'Manchuria', year: 1931, site: 'Morris' },
{ yield: 39.93, variety: 'Manchuria', year: 1931, site: 'Crookston' },
{ yield: 32.97, variety: 'Manchuria', year: 1931, site: 'Grand Rapids' },
{ yield: 28.97, variety: 'Manchuria', year: 1931, site: 'Duluth' },
{ yield: 43.07, variety: 'Glabron', year: 1931, site: 'University Farm' },
{ yield: 55.2, variety: 'Glabron', year: 1931, site: 'Waseca' },
{ yield: 28.77, variety: 'Glabron', year: 1931, site: 'Morris' },
{ yield: 38.13, variety: 'Glabron', year: 1931, site: 'Crookston' },
{ yield: 29.13, variety: 'Glabron', year: 1931, site: 'Grand Rapids' },
{ yield: 29.67, variety: 'Glabron', year: 1931, site: 'Duluth' },
{ yield: 35.13, variety: 'Svansota', year: 1931, site: 'University Farm' },
{ yield: 47.33, variety: 'Svansota', year: 1931, site: 'Waseca' },
{ yield: 25.77, variety: 'Svansota', year: 1931, site: 'Morris' },
{ yield: 40.47, variety: 'Svansota', year: 1931, site: 'Crookston' },
{ yield: 29.67, variety: 'Svansota', year: 1931, site: 'Grand Rapids' },
{ yield: 25.7, variety: 'Svansota', year: 1931, site: 'Duluth' },
{ yield: 39.9, variety: 'Velvet', year: 1931, site: 'University Farm' },
{ yield: 50.23, variety: 'Velvet', year: 1931, site: 'Waseca' },
{ yield: 26.13, variety: 'Velvet', year: 1931, site: 'Morris' },
{ yield: 41.33, variety: 'Velvet', year: 1931, site: 'Crookston' },
{ yield: 23.03, variety: 'Velvet', year: 1931, site: 'Grand Rapids' },
{ yield: 26.3, variety: 'Velvet', year: 1931, site: 'Duluth' },
{ yield: 36.57, variety: 'Trebi', year: 1931, site: 'University Farm' },
{ yield: 63.83, variety: 'Trebi', year: 1931, site: 'Waseca' },
{ yield: 43.77, variety: 'Trebi', year: 1931, site: 'Morris' },
{ yield: 46.93, variety: 'Trebi', year: 1931, site: 'Crookston' },
{ yield: 29.77, variety: 'Trebi', year: 1931, site: 'Grand Rapids' },
{ yield: 33.93, variety: 'Trebi', year: 1931, site: 'Duluth' },
];
const chart = new Chart({
container: 'container',
autoFit: true,
paddingLeft: 50,
});
chart.options({
type: 'interval',
data: barleyData,
encode: {
x: 'site',
y: 'yield',
color: 'variety',
},
transform: [{ type: 'dodgeX' }],
axis: {
x: {
labelAutoHide: true,
labelAutoRotate: true,
},
},
tooltip: {
title: 'site',
},
});
chart.render();
`} />
Optimization Method 1: Show only important data
Filter or aggregate data to show only the top-ranked or most important groups:
<Demo code={`import { Chart } from '@antv/g2';
// Filtered data - showing only top 3 locations to demonstrate optimization effect
const filteredBarleyData = [
{ yield: 27, variety: 'Manchuria', year: 1931, site: 'University Farm' },
{ yield: 48.87, variety: 'Manchuria', year: 1931, site: 'Waseca' },
{ yield: 27.43, variety: 'Manchuria', year: 1931, site: 'Morris' },
{ yield: 43.07, variety: 'Glabron', year: 1931, site: 'University Farm' },
{ yield: 55.2, variety: 'Glabron', year: 1931, site: 'Waseca' },
{ yield: 28.77, variety: 'Glabron', year: 1931, site: 'Morris' },
{ yield: 35.13, variety: 'Svansota', year: 1931, site: 'University Farm' },
{ yield: 47.33, variety: 'Svansota', year: 1931, site: 'Waseca' },
{ yield: 25.77, variety: 'Svansota', year: 1931, site: 'Morris' },
{ yield: 39.9, variety: 'Velvet', year: 1931, site: 'University Farm' },
{ yield: 50.23, variety: 'Velvet', year: 1931, site: 'Waseca' },
{ yield: 26.13, variety: 'Velvet', year: 1931, site: 'Morris' },
{ yield: 36.57, variety: 'Trebi', year: 1931, site: 'University Farm' },
{ yield: 63.83, variety: 'Trebi', year: 1931, site: 'Waseca' },
{ yield: 43.77, variety: 'Trebi', year: 1931, site: 'Morris' },
];
const chart = new Chart({
container: 'container',
autoFit: true,
paddingLeft: 50,
});
chart.options({
type: 'interval',
data: filteredBarleyData,
encode: {
x: 'site',
y: 'yield',
color: 'variety',
},
transform: [{ type: 'dodgeX' }],
axis: {
x: {
labelAutoHide: true,
labelAutoRotate: true,
},
},
tooltip: {
title: 'site',
},
});
chart.render();
`} />
Optimization Method 2: Use stacked bar charts
If you need to display complete data, we recommend using stacked bar charts to reduce chart width and improve readability:
<Demo code={`import { Chart } from '@antv/g2';
// Complete barley dataset - demonstrating stacked bar chart optimization effect
const barleyData = [
{ yield: 27, variety: 'Manchuria', year: 1931, site: 'University Farm' },
{ yield: 48.87, variety: 'Manchuria', year: 1931, site: 'Waseca' },
{ yield: 27.43, variety: 'Manchuria', year: 1931, site: 'Morris' },
{ yield: 39.93, variety: 'Manchuria', year: 1931, site: 'Crookston' },
{ yield: 32.97, variety: 'Manchuria', year: 1931, site: 'Grand Rapids' },
{ yield: 28.97, variety: 'Manchuria', year: 1931, site: 'Duluth' },
{ yield: 43.07, variety: 'Glabron', year: 1931, site: 'University Farm' },
{ yield: 55.2, variety: 'Glabron', year: 1931, site: 'Waseca' },
{ yield: 28.77, variety: 'Glabron', year: 1931, site: 'Morris' },
{ yield: 38.13, variety: 'Glabron', year: 1931, site: 'Crookston' },
{ yield: 29.13, variety: 'Glabron', year: 1931, site: 'Grand Rapids' },
{ yield: 29.67, variety: 'Glabron', year: 1931, site: 'Duluth' },
{ yield: 35.13, variety: 'Svansota', year: 1931, site: 'University Farm' },
{ yield: 47.33, variety: 'Svansota', year: 1931, site: 'Waseca' },
{ yield: 25.77, variety: 'Svansota', year: 1931, site: 'Morris' },
{ yield: 40.47, variety: 'Svansota', year: 1931, site: 'Crookston' },
{ yield: 29.67, variety: 'Svansota', year: 1931, site: 'Grand Rapids' },
{ yield: 25.7, variety: 'Svansota', year: 1931, site: 'Duluth' },
{ yield: 39.9, variety: 'Velvet', year: 1931, site: 'University Farm' },
{ yield: 50.23, variety: 'Velvet', year: 1931, site: 'Waseca' },
{ yield: 26.13, variety: 'Velvet', year: 1931, site: 'Morris' },
{ yield: 41.33, variety: 'Velvet', year: 1931, site: 'Crookston' },
{ yield: 23.03, variety: 'Velvet', year: 1931, site: 'Grand Rapids' },
{ yield: 26.3, variety: 'Velvet', year: 1931, site: 'Duluth' },
{ yield: 36.57, variety: 'Trebi', year: 1931, site: 'University Farm' },
{ yield: 63.83, variety: 'Trebi', year: 1931, site: 'Waseca' },
{ yield: 43.77, variety: 'Trebi', year: 1931, site: 'Morris' },
{ yield: 46.93, variety: 'Trebi', year: 1931, site: 'Crookston' },
{ yield: 29.77, variety: 'Trebi', year: 1931, site: 'Grand Rapids' },
{ yield: 33.93, variety: 'Trebi', year: 1931, site: 'Duluth' },
];
const chart = new Chart({
container: 'container',
autoFit: true,
paddingLeft: 50,
});
chart.options({
type: 'interval',
data: barleyData,
encode: {
x: 'site',
y: 'yield',
color: 'variety',
},
transform: [{ type: 'stackY' }],
axis: {
x: {
labelAutoHide: true,
labelAutoRotate: true,
},
},
tooltip: {
title: 'site',
},
});
chart.render();
`} />
Optimization Method 3: Use horizontal stacked bar charts
For large amounts of data, horizontal stacked bar charts are a better choice, making full use of vertical space to display more categories:
Extensions of Multi-set Bar Charts
Horizontal Multi-set Bar Charts
When group names are long or you need to display more groups, you can use horizontal multi-set bar charts:
<Demo height={424} code={`import { Chart } from '@antv/g2';
const data = [
{ category: 'Sports Games', year: '2001', sold: 27500 },
{ category: 'Strategy Games', year: '2001', sold: 11500 },
{ category: 'Action Games', year: '2001', sold: 6000 },
{ category: 'Shooter Games', year: '2001', sold: 3500 },
{ category: 'Sports Games', year: '2002', sold: 29500 },
{ category: 'Strategy Games', year: '2002', sold: 10500 },
{ category: 'Action Games', year: '2002', sold: 8000 },
{ category: 'Shooter Games', year: '2002', sold: 4500 },
{ category: 'Sports Games', year: '2003', sold: 30500 },
{ category: 'Strategy Games', year: '2003', sold: 12500 },
{ category: 'Action Games', year: '2003', sold: 4000 },
{ category: 'Shooter Games', year: '2003', sold: 6500 },
];
const chart = new Chart({
container: 'container',
autoFit: true,
height: 400,
});
chart.options({
type: 'interval',
data,
coordinate: { transform: [{ type: 'transpose' }] },
encode: {
x: 'sold',
y: 'category',
color: 'year',
},
transform: [{ type: 'dodgeX' }],
axis: {
x: { title: 'Game Sales' },
y: { title: 'Game Type' },
},
});
chart.render();
`} />
Comparing Multi-set Bar Charts to Other Charts
Multi-set Bar Charts and Regular Bar Charts
- Multi-set bar charts can add an additional dimension for comparing data values of different categories within a group, capable of representing 3 data fields (dimensions), while regular bar charts can only represent 2 data fields (dimensions)
- Multi-set bar charts have more bars, so they can display fewer groups
Multi-set Bar Charts and Stacked Bar Charts
- Multi-set bar charts can compare data sizes of different categories within the same group, as well as compare data sizes of the same category across different groups, but cannot compare the total amounts of each group
- Stacked bar charts can compare data sizes or proportions of different categories within the same group and can also compare group totals, but are not suitable for comparing data sizes of the same category across different groups
Similar Charts
Categories
Site Docs Charts Multi Set Bar.Zh (`site/docs/charts/multi-set-bar.zh.mdx`)
title: 分组柱状图 sidebar: { icon: 'column' } order: 2 screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*kqGUT4wRYrsAAAAAAAAAAAAADmJ7AQ/original' category: ['comparison'] similar: ['bar', 'stacked-bar', 'histogram']
import ChartCategories from '../../src/components/ChartCategories.astro';
import ChartGallery from '../../src/components/ChartGallery.astro';
import { Demo } from '@antv/astro-theme-antv/components';
分组柱状图的简介
分组柱状图,又叫聚合柱状图。当使用者需要在同一个轴上显示各个分类下不同的分组时,需要用到分组柱状图。
跟柱状图类似,使用柱子的高度来映射和对比数据值。每个分组中的柱子使用不同的颜色或者相同颜色不同透明的方式区别各个分类,各个分组之间需要保持间隔。
分组柱状图经常用于不同组间数据的比较,这些组都包含了相同分类的数据。
但是仍需要注意,避免分组中分类过多的情况,分类过多会导致分组中柱子过多过密,非常影响图表可读性。
英文名:Multi-set Bar Chart
分组柱状图的构成
| 图表类型 | 分组柱状图 |
|---|---|
| 适合的数据 | 列表:两个分类数据字段、一个连续数据字段 |
| 功能 | 其中一个分类数据字段作为分组,可以对比相同分组下不同分类的数据大小,也可以对比不同分组下,相同分类的数据大小 |
| 数据与图形的映射 | 其中一个分类数据字段映射到坐标轴的位置用于分组,另一个分类数据在同一个分组内错开,并通过不同的颜色来区分连续数据字段映射到矩形的长度 |
| 适合的数据条数 | 分组个数不要超过 12 个,每个分组下的分类不要超过 6 个 |
分组柱状图的应用场景
适合的场景
例子 1:对比不同分组内相同分类的大小,对比相同分组内不同分类的大小
下图对比了『我是土豪』游戏公司在 2001、2002、2003 这三年的各类游戏的销量情况。
水平轴显示的是不同的游戏类型,每种游戏类型作为一个柱状图的分组,在每一个分组内对比不同年份的销售数量。
<Demo height={424} code={`import { Chart } from '@antv/g2';
const data = [
{ year: '2001', genre: 'Sports', sold: 27500 },
{ year: '2001', genre: 'Strategy', sold: 11500 },
{ year: '2001', genre: 'Action', sold: 6000 },
{ year: '2001', genre: 'Shooter', sold: 3500 },
{ year: '2001', genre: 'Other', sold: 1500 },
{ year: '2002', genre: 'Sports', sold: 29500 },
{ year: '2002', genre: 'Strategy', sold: 10500 },
{ year: '2002', genre: 'Action', sold: 8000 },
{ year: '2002', genre: 'Shooter', sold: 4500 },
{ year: '2002', genre: 'Other', sold: 1800 },
{ year: '2003', genre: 'Sports', sold: 30500 },
{ year: '2003', genre: 'Strategy', sold: 12500 },
{ year: '2003', genre: 'Action', sold: 4000 },
{ year: '2003', genre: 'Shooter', sold: 6500 },
{ year: '2003', genre: 'Other', sold: 2000 },
];
const chart = new Chart({
container: 'container',
autoFit: true,
height: 400,
});
chart.options({
type: 'interval',
data,
encode: {
x: 'genre',
y: 'sold',
color: 'year',
},
transform: [{ type: 'dodgeX' }],
axis: {
y: { title: '游戏销售量' },
x: { title: '游戏类型' },
},
});
chart.render();
`} />
说明:
genre,使用横轴的位置来区分不同的游戏类型year,使用颜色和在同一个游戏类型内的错开的位置,来区分不同年份的游戏销售sold,使用矩形的长度对比不同游戏、不同年份的销量
不适合的场景
例子 1:分组过多、分类过多
当分组和分类过多时会导致柱子过多过密,可读性不佳,如下图所示:
<Demo code={`import { Chart } from '@antv/g2';
// 完整的barley数据集 - 演示分组过多的问题
const barleyData = [
{ yield: 27, variety: 'Manchuria', year: 1931, site: 'University Farm' },
{ yield: 48.87, variety: 'Manchuria', year: 1931, site: 'Waseca' },
{ yield: 27.43, variety: 'Manchuria', year: 1931, site: 'Morris' },
{ yield: 39.93, variety: 'Manchuria', year: 1931, site: 'Crookston' },
{ yield: 32.97, variety: 'Manchuria', year: 1931, site: 'Grand Rapids' },
{ yield: 28.97, variety: 'Manchuria', year: 1931, site: 'Duluth' },
{ yield: 43.07, variety: 'Glabron', year: 1931, site: 'University Farm' },
{ yield: 55.2, variety: 'Glabron', year: 1931, site: 'Waseca' },
{ yield: 28.77, variety: 'Glabron', year: 1931, site: 'Morris' },
{ yield: 38.13, variety: 'Glabron', year: 1931, site: 'Crookston' },
{ yield: 29.13, variety: 'Glabron', year: 1931, site: 'Grand Rapids' },
{ yield: 29.67, variety: 'Glabron', year: 1931, site: 'Duluth' },
{ yield: 35.13, variety: 'Svansota', year: 1931, site: 'University Farm' },
{ yield: 47.33, variety: 'Svansota', year: 1931, site: 'Waseca' },
{ yield: 25.77, variety: 'Svansota', year: 1931, site: 'Morris' },
{ yield: 40.47, variety: 'Svansota', year: 1931, site: 'Crookston' },
{ yield: 29.67, variety: 'Svansota', year: 1931, site: 'Grand Rapids' },
{ yield: 25.7, variety: 'Svansota', year: 1931, site: 'Duluth' },
{ yield: 39.9, variety: 'Velvet', year: 1931, site: 'University Farm' },
{ yield: 50.23, variety: 'Velvet', year: 1931, site: 'Waseca' },
{ yield: 26.13, variety: 'Velvet', year: 1931, site: 'Morris' },
{ yield: 41.33, variety: 'Velvet', year: 1931, site: 'Crookston' },
{ yield: 23.03, variety: 'Velvet', year: 1931, site: 'Grand Rapids' },
{ yield: 26.3, variety: 'Velvet', year: 1931, site: 'Duluth' },
{ yield: 36.57, variety: 'Trebi', year: 1931, site: 'University Farm' },
{ yield: 63.83, variety: 'Trebi', year: 1931, site: 'Waseca' },
{ yield: 43.77, variety: 'Trebi', year: 1931, site: 'Morris' },
{ yield: 46.93, variety: 'Trebi', year: 1931, site: 'Crookston' },
{ yield: 29.77, variety: 'Trebi', year: 1931, site: 'Grand Rapids' },
{ yield: 33.93, variety: 'Trebi', year: 1931, site: 'Duluth' },
];
const chart = new Chart({
container: 'container',
autoFit: true,
paddingLeft: 50,
});
chart.options({
type: 'interval',
data: barleyData,
encode: {
x: 'site',
y: 'yield',
color: 'variety',
},
transform: [{ type: 'dodgeX' }],
axis: {
x: {
labelAutoHide: true,
labelAutoRotate: true,
},
},
tooltip: {
title: 'site',
},
});
chart.render();
`} />
优化方式 1:仅显示重要数据
通过筛选或聚合数据,只展示排名靠前或最重要的几个分组:
<Demo code={`import { Chart } from '@antv/g2';
// 筛选后的数据 - 只显示前3个地点,演示优化效果
const filteredBarleyData = [
{ yield: 27, variety: 'Manchuria', year: 1931, site: 'University Farm' },
{ yield: 48.87, variety: 'Manchuria', year: 1931, site: 'Waseca' },
{ yield: 27.43, variety: 'Manchuria', year: 1931, site: 'Morris' },
{ yield: 43.07, variety: 'Glabron', year: 1931, site: 'University Farm' },
{ yield: 55.2, variety: 'Glabron', year: 1931, site: 'Waseca' },
{ yield: 28.77, variety: 'Glabron', year: 1931, site: 'Morris' },
{ yield: 35.13, variety: 'Svansota', year: 1931, site: 'University Farm' },
{ yield: 47.33, variety: 'Svansota', year: 1931, site: 'Waseca' },
{ yield: 25.77, variety: 'Svansota', year: 1931, site: 'Morris' },
{ yield: 39.9, variety: 'Velvet', year: 1931, site: 'University Farm' },
{ yield: 50.23, variety: 'Velvet', year: 1931, site: 'Waseca' },
{ yield: 26.13, variety: 'Velvet', year: 1931, site: 'Morris' },
{ yield: 36.57, variety: 'Trebi', year: 1931, site: 'University Farm' },
{ yield: 63.83, variety: 'Trebi', year: 1931, site: 'Waseca' },
{ yield: 43.77, variety: 'Trebi', year: 1931, site: 'Morris' },
];
const chart = new Chart({
container: 'container',
autoFit: true,
paddingLeft: 50,
});
chart.options({
type: 'interval',
data: filteredBarleyData,
encode: {
x: 'site',
y: 'yield',
color: 'variety',
},
transform: [{ type: 'dodgeX' }],
axis: {
x: {
labelAutoHide: true,
labelAutoRotate: true,
},
},
tooltip: {
title: 'site',
},
});
chart.render();
`} />
优化方式 2:使用堆叠柱状图
如果需要展示完整数据,推荐使用堆叠柱状图来减少图表宽度,提高可读性:
<Demo code={`import { Chart } from '@antv/g2';
// 完整的barley数据集 - 演示堆叠柱状图优化效果
const barleyData = [
{ yield: 27, variety: 'Manchuria', year: 1931, site: 'University Farm' },
{ yield: 48.87, variety: 'Manchuria', year: 1931, site: 'Waseca' },
{ yield: 27.43, variety: 'Manchuria', year: 1931, site: 'Morris' },
{ yield: 39.93, variety: 'Manchuria', year: 1931, site: 'Crookston' },
{ yield: 32.97, variety: 'Manchuria', year: 1931, site: 'Grand Rapids' },
{ yield: 28.97, variety: 'Manchuria', year: 1931, site: 'Duluth' },
{ yield: 43.07, variety: 'Glabron', year: 1931, site: 'University Farm' },
{ yield: 55.2, variety: 'Glabron', year: 1931, site: 'Waseca' },
{ yield: 28.77, variety: 'Glabron', year: 1931, site: 'Morris' },
{ yield: 38.13, variety: 'Glabron', year: 1931, site: 'Crookston' },
{ yield: 29.13, variety: 'Glabron', year: 1931, site: 'Grand Rapids' },
{ yield: 29.67, variety: 'Glabron', year: 1931, site: 'Duluth' },
{ yield: 35.13, variety: 'Svansota', year: 1931, site: 'University Farm' },
{ yield: 47.33, variety: 'Svansota', year: 1931, site: 'Waseca' },
{ yield: 25.77, variety: 'Svansota', year: 1931, site: 'Morris' },
{ yield: 40.47, variety: 'Svansota', year: 1931, site: 'Crookston' },
{ yield: 29.67, variety: 'Svansota', year: 1931, site: 'Grand Rapids' },
{ yield: 25.7, variety: 'Svansota', year: 1931, site: 'Duluth' },
{ yield: 39.9, variety: 'Velvet', year: 1931, site: 'University Farm' },
{ yield: 50.23, variety: 'Velvet', year: 1931, site: 'Waseca' },
{ yield: 26.13, variety: 'Velvet', year: 1931, site: 'Morris' },
{ yield: 41.33, variety: 'Velvet', year: 1931, site: 'Crookston' },
{ yield: 23.03, variety: 'Velvet', year: 1931, site: 'Grand Rapids' },
{ yield: 26.3, variety: 'Velvet', year: 1931, site: 'Duluth' },
{ yield: 36.57, variety: 'Trebi', year: 1931, site: 'University Farm' },
{ yield: 63.83, variety: 'Trebi', year: 1931, site: 'Waseca' },
{ yield: 43.77, variety: 'Trebi', year: 1931, site: 'Morris' },
{ yield: 46.93, variety: 'Trebi', year: 1931, site: 'Crookston' },
{ yield: 29.77, variety: 'Trebi', year: 1931, site: 'Grand Rapids' },
{ yield: 33.93, variety: 'Trebi', year: 1931, site: 'Duluth' },
];
const chart = new Chart({
container: 'container',
autoFit: true,
paddingLeft: 50,
});
chart.options({
type: 'interval',
data: barleyData,
encode: {
x: 'site',
y: 'yield',
color: 'variety',
},
transform: [{ type: 'stackY' }],
axis: {
x: {
labelAutoHide: true,
labelAutoRotate: true,
},
},
tooltip: {
title: 'site',
},
});
chart.render();
`} />
优化方式 3:使用横向堆叠柱状图
对于大量数据的情况,横向堆叠柱状图是更好的选择,可以充分利用垂直空间展示更多分类:
分组柱状图的扩展
横向分组柱状图
当分组名称较长或者需要显示更多分组时,可以使用横向分组柱状图:
<Demo height={424} code={`import { Chart } from '@antv/g2';
const data = [
{ category: '体育游戏', year: '2001', sold: 27500 },
{ category: '策略游戏', year: '2001', sold: 11500 },
{ category: '动作游戏', year: '2001', sold: 6000 },
{ category: '射击游戏', year: '2001', sold: 3500 },
{ category: '体育游戏', year: '2002', sold: 29500 },
{ category: '策略游戏', year: '2002', sold: 10500 },
{ category: '动作游戏', year: '2002', sold: 8000 },
{ category: '射击游戏', year: '2002', sold: 4500 },
{ category: '体育游戏', year: '2003', sold: 30500 },
{ category: '策略游戏', year: '2003', sold: 12500 },
{ category: '动作游戏', year: '2003', sold: 4000 },
{ category: '射击游戏', year: '2003', sold: 6500 },
];
const chart = new Chart({
container: 'container',
autoFit: true,
height: 400,
});
chart.options({
type: 'interval',
data,
coordinate: { transform: [{ type: 'transpose' }] },
encode: {
x: 'sold',
y: 'category',
color: 'year',
},
transform: [{ type: 'dodgeX' }],
axis: {
x: { title: '游戏销售量' },
y: { title: '游戏类型' },
},
});
chart.render();
`} />
分组柱状图和其他图表的对比
分组柱状图和一般柱状图
- 分组柱状图可以增加一个维度,用于对比一组数据内不同分类的数据值大小,可以表示 3 个数据字段(维度)的数据,而一般柱状图只能表示 2 个数据字段(维度)
- 分组柱状图的柱子较多,所以能展示的分组较少
分组柱状图和层叠柱状图
- 分组柱状图,可以对比同一个分组内部不同分类的数据大小,也可以对比不同分组内相同分类的数据大小,但无法对比各分组的总量
- 层叠柱状图,可以对比同一个分组内部不同分类的数据大小或占比,也可以对比分组的总量,但不适合对比不同分组内相同分类的数据大小
相似图表
分类
Site Docs Charts Overview.En (`site/docs/charts/overview.en.mdx`)
title: 📈 Chart Gallery sidebar: { label: 'Chart Gallery', icon: 'other' } order: 0 category: []
import ChartGallery from '../../src/components/ChartGallery.astro';
Site Docs Charts Overview.Zh (`site/docs/charts/overview.zh.mdx`)
title: 📈 图表介绍 sidebar: { label: '图表介绍', icon: 'other' } order: 0 category: []
import ChartGallery from '../../src/components/ChartGallery.astro';
Site Docs Charts Pack.En (`site/docs/charts/pack.en.mdx`)
title: Pack Chart
sidebar: { icon: 'scatter' }
order: 2
screenshot: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*epG0TaxEVTsAAAAAAAAAAAAADmJ7AQ/original'
category: ['r