Author: arcsin1
time: 2020.07.04
info: 这个系列主要结合D3(v4和v5)
开篇认识柱状图
- 柱状图也是最基本最常见的可视化图形,我们用D3一步步绘制
- 柱状图,是一种使用矩形条,对不同类别进行数值比较的统计图表。最基础的柱形图,需要一个分类变量和一个数值变量。在柱状图上,分类变量的每个实体都被表示为一个矩形(通俗讲即为“柱子”),而数值则决定了柱子的高度
- 与“柱状图”相近的概念还有“条形图”,二者在实际使用中可能产生不同理解。例如,在AntV的分类中,条形图是柱状图的子集,专指“横向的柱状图”。而在Excel的图表功能中,柱状图专指纵向、条形图专指横向。
- 柱状图也衍生出多种多样的图表形式:“分组柱状图”,“簇状柱形图”,“堆叠柱状图”
更多具体请参考:antv的对于柱状图的介绍
注意: 在使用柱状图时,务必要使原点位于0,不要篡改y轴。此外,注意对柱状图进行排序。依据可视化的目的、以及想突出的重点信息,确定合理的排序标准,避免柱状图看起来杂乱无章。
适用场景
- 柱状图最适合对分类的数据进行比较。尤其是当数值比较接近时,由于人眼对于高度的感知优于其他视觉元素(如面积、角度等),因此,使用柱状图更加合适。
- 当然最好进行排序也很nice
不适用场景
- 柱状图要求至少一个分类变量,它们之间是离散的(如一班、二班、三班)(柱子之间有间距)
- 如何分类是连续的(比如40,50,60,70)请用直方图(柱子之间没有间距)
- 柱状图最核心的功能是比较,比较的核心是高度。如果人为的改变高度,那么数据间的比例关系会失常;因此,在使用柱状图时,要注意y轴的取值,从0开始。
那么如何用D3绘制柱状图呢?
先看看柱状图的样子:
我分为5个部分:(目前只介绍svg篇,后续再介绍canvas篇)
1. 画出x轴
2. 画出y轴
3. 画出柱子
4. 画出数据值
5. 动画(后面专题补上)
### 开始
准备好数据
const data = [
{ year: '1954', sales: 38 },
{ year: '1955', sales: 52 },
{ year: '1956', sales: 61 },
{ year: '1957', sales: 100 },
{ year: '1958', sales: 48 },
{ year: '1959', sales: 38 },
]
我们开始创建一个svg
注意点: svg的元素基本在g里面绘制,当做group
const width = 600;
const height = 400;
const svg = d3
.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
// 创建一个g 当后面元素的group容器,移到(30,30)的位置
// 定义上下左右边距给坐标轴文字距离
const m = { top: 30, right: 30, bottom: 30, left: 30 };
const g = svg.append("g").attr("transform", "translate(30, 30)");
// 实际我们图的高度宽度
const gW = width - m.left;
const gH = height - m.top - m.bottom;
定义坐标轴的比例尺,gW为x轴的宽度,gH为y轴的高度:
const x = d3
.scaleBand()
.range([0, gW])
.padding(0.1); // 柱状图的间距
const y = d3.scaleLinear().range([gH, 0]);
定义好x轴与y轴的定义域:
x.domain(data.map(item => item.year))
y.domain([0, d3.max(data, item => item.sales)])
然后就能把x轴,y轴绘制出来了:
g.append("g")
.attr("transform", `translate(0, ${gH})`)
.call(d3.axisBottom(x))
.attr("stroke", "red");
g.append("g").call(d3.axisLeft(y));
我们来绘制柱子吧:
// 然后,再把柱状图的一根根柱子绘制上去,一根柱子就是一个`rect`,
// 所以要指定它的位置以及长宽:
const barGroup = g
.selectAll(".bar-gruop")
.data(data)
.join("g")
.attr("class", "bar-gruop");
// 注释是v4写法
// .selectAll(".bar-gruop")
// .data(data)
// .enter()
// .append("g")
// .attr("class", "bar-gruop");
barGroup
.append("rect")
.attr("class", "bar")
.attr("x", item => x(item.year))
.attr("y", item => y(item.sales))
.attr("width", x.bandwidth())
.attr("height", item => gH - y(item.sales))
.attr("fill", "steelblue");
画出数据值(当然可以放任意位置)
barGroup
.append("text")
.attr("class", "barText")
.attr("x", item => x(item.year))
.attr("y", item => y(item.sales))
.attr("dx", x.bandwidth() / 2)
.attr("dy", 20)
.attr("text-anchor", "middle")
.text(item => item.sales);
结尾
看到这里,其实发现绘制一个基本柱状图也就是一个个积木搭建起来的,是不是很有趣,希望你也学会了,去定制更好的。
下一章我们来讲讲饼图的基本绘制。
周末愉快!