柱图教程
手把手教你制作一个带有Tooltip提示的框的柱图!
1. 准备数据
柱图需要两个信息,维度和每个维度的柱子,在数据视图中制作一个包含一个维度一个数值的结果,如下图表示每日这个渠道的用户访问量,可提供三个在图表视图引用的变量:
- $DATA_VIEWS[0],代表“访问数据集”
- $X_FIELDS[0][0].id,代表“发送时间”维度中的值
- $Y_FIELDS[0][0].id,代表“会话量”数值中的值
2. 画图数据
有了数据,但是画图不能直接用数值结果,比如收入10亿,在图中怎么画?换个角度,需要将数据转换为图中的位置,如用20个像素代表10亿。展示柱图确定柱子的宽度和高度,这就用到了scale
,坐标比例尺,将原始数据转换为画图可用的数据。
- 宽度——现在有6个维度,也就是6个柱子,每个宽度一样,所以每个珠子的宽度应该是"图表的宽度"/6
- 高度——每个柱子的高度由数字决定,应当在图表高度中按照数值大小分布,分布方式有很多种,如线性分布,按照数值比例获取占高度的大小
"scales": [
{
"name": "xscale",
"type": "band",
"domain": {"data": "ds0", "field": "x0"},
"range": "width"
},
{
"name": "yscale",
"domain": {"data": "ds0", "field": "y0"},
"nice": true,
"range": "height"
}
],
定义两个scale
分别代表宽度坐标(xscale)和高度坐标(yscale),每个scale需要有个唯一的名字name
,之后使用时会调用这个名字。
其中宽度坐标需要均分图表宽度,转换类型设置为等分组band
,代表按照维度个数平分图表的宽度;如宽度为600时,第一个维度的坐标将为[0-100]
。domain
为转换坐标的数据来源,上图中使用第一个数据集和其第一个维度字段。range
为目标范围,如上图代表将“width”
图表宽度设为目标值,分组将等分这个值。
高度坐标没有设置type
,默认为linear
,线性分布,可理解为按原值占比获取其在高度目标值的占比,。目标范围设为“height“
图表高度。数据使用数据集的第一个数值“会话量”。这里用的nice
属性为Vega提供的美化语法,可将转换结果进行一定程度处理,使结果更易理解,达到更好的展示效果,如[0, 94.345]
自动转换为[0, 100]
。
range
中使用的“width”
和“height“
为Vega的预置的内部变量,可直接引用图表的宽度和高度;用户也可以手动指定值域数组,如[0, 400]
and [200, 0]
。当type
为band
时,range
可以指定每个柱子的步长,步长=柱子宽度+边距,如设定步长为60,最终柱图总长=60*6=360。当type
为ordinal
时,range
还可以指定一个长数组,指定自定义的颜色序列(如RGB十进制"#ffa804")。
domain
可使用数据视图中数据集结果或数组及各种外部JSON数据,如CSV等。数据转换默认支持处理数值为零的数据,可以通过设置"zero": false
,取消该特性。
比例尺转出的图表数据与原始数据结构对应,使用时需要按照原始数据结构对应,如在画图数据中使用y0
代表使用第一个数值字段转换出的画图坐标。
3. 图形
图形是Vega中最主要的元素,将可视化都拆解为图形的组合,如上面的柱图,每个柱子是一个矩形,共6个矩形,用到了marks
属性:
"marks": [
{
"type": "rect",
"from": {"data":"ds0"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "x0", "offset": 1},
"width": {"scale": "xscale", "band": 1, "offset": -1},
"y": {"scale": "yscale", "field": "y0"},
"y2": {"scale": "yscale", "value": 0}
},
"update": {
"fill": {"value": "steelblue"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
marks
中可以有多个图形,每个图形可以设置自己的类型type
,rect
代表使用矩形(rectangles)。有了图形,还要描述6个柱子根据什么数据画,使用from
属性,说明数据来自第一个数据集,在BDP中通常使用数据视图中的数据集作为数据来源。如果不指定from
会默认画一个图形。
图形的可视化属性在encode
中设置,如颜色、大小,分为几个状态:
enter
,图形第一次绘制,设置了柱图的位置和大小;exit
,图形被删除或移除时,本次没用到;update
,图形设置更新或改变,设置了柱图的颜色,创建后会首次进入更新状态;hover
,鼠标移动至图形上,设置了鼠标移动到柱子上需要改变的颜色;
这里看到颜色没在enter
中设置而是在update
中设置,这是因为hover
设置了颜色改变,如果不设置在update
中,鼠标经过柱子后将出现一个永久红色的柱子。
重点说明创建时如何画出基础图形:
"x": {"scale": "xscale", "field": "x0", "offset": 1},
"width": {"scale": "xscale", "band": 1, "offset": -1},
"y": {"scale": "yscale", "field": "y0"},
"y2": {"scale": "yscale", "value": 0}
画图形四要素,描述图形水平、垂直方向的起始和结束值,x
、width
确定水平位置和每个柱子宽度,y
、y2
决定了垂直位置和柱子高度:
x
,每个图形起始位置,如柱图中每个柱子的的左侧坐标,画图数据使用定过的水平坐标"xscale"
中的第一个维度x0
;"offset": 1
第一个柱子前的偏移量,与其他柱子间隔1像素的样式保持一致;width
,每个维度所占的宽度,即柱子的宽度,使用已经计算好的"xscale"
中的等宽长度。"band": 1
代表使用比例尺计算的大小,可以设置0-1的小数代表使用比例尺结果的百分比结果,如"band": 0.5
代表使用比例尺结果的一半;y
、y2
,柱子顶部的高度,类似x
、width
,每个柱子垂直方向的起始位置和结束位置,也可以使用类似的height
,这里由于每个柱子都是从水平线开始,使用y2
将起始值固定为0
。实际上Vega也不区分y
、y2
哪个是起始值,只要设置了两个值系统会自动按照坐标大小调整位置。
除了标准的图形,Vega支持将图形嵌套分组,通过group
属性,可以包含其他图形,如制作BDP中的对比拆分图。分组中可以自定义比例尺和坐标轴。
PS:坐标系起始值[0.0]在预览区域的的左上角。预览时发现图形并不是从预览区域的左下角开始,这是因为自定义图表默认启用了自动缩放大小,Vega默认为四周留了边距,可以使用"autosize": "none"
取消自动缩放,注意关闭后在BDP仪表盘中调整图表大小将不影响可视化效果。
4. 坐标轴
柱图还有坐标轴,分为X轴和Y轴,包含刻度和值。
"axes": [
{ "orient": "bottom", "scale": "xscale" },
{ "orient": "left", "scale": "yscale", "tickCount": 5,"offset": 6 }
],
简单的坐标轴只需要设置轴的方向和使用的图表数据,系统会自动生成坐标轴。这里指定X轴在底部使用通过日期维度转换出的画图数据;Y轴在左侧使用数值的画图数据,同时设置了"tickCount": 7
默认分为7组刻度,并设置"offset": 6
向右移动6个像素的偏移量。
5. 变量
变量是Vega中一种非常实用的属性,可以在发生事件或其他变量变化时,重新计算结果,柱图中的Tooltip提示框就需要用到变量实现。每个变量需要一个唯一的名称name
和一个初始值,其他属性用于定义变量如何计算。
Tooltip内容通常为所在图形的值,位置在图形上方,所以为了在鼠标移动在某个柱子时需要根据这个柱子展示,需要一个记录当前柱子的变量,并根据这个属性绘制出提示文本框。
创建变量,先设置一个变量为“tooltip”,初始值为空,变动实际在两个事件,矩形rect
的鼠标移入mouseover
和移出mouseout
事件;在鼠标移入时将变量赋值为鼠标所在矩形的数值对象"datum"
,鼠标移出时将变量值设回空值。这是一个Vega特殊的内置变量,代表当前的数据对象,在当前的事件中代表的数据包含这个柱子的日期和会话量,在Data
中使用时可代表所在的完整数据集。
"signals": [
{
"name": "tooltip",
"value": {},
"on": [
{"events": "rect:mouseover", "update": "datum"},
{"events": "rect:mouseout", "update": "{}"}
]
}
],
创建文本框,文本框也是一种图形,由于只在鼠标移动到某个柱子时展示,初始状态"enter"
只设置基础属性,这些设置均相对之后确定的某个坐标点,对齐方式"align"
设为居中,基准线"baseline"
设为底部对齐,颜色为黑色。
确定位置,Tooltip应动态展示在柱子顶部的中间,使用"update"
每次根据当前柱子的坐标,将文本框绘制在正上方,"x"
、"y"
坐标均使用处理好的水平和垂直的画图数据,从画图数据中获取某个柱子坐标时,需要通过原始数据的内容找到对应的转换结果,当移动至某个柱子时变量tooltip值为其的原始数据对象,"tooltip."+x0
即引用了这个柱子的日期维度。为了能坐标点在每个柱子中间,获取水平画图数据时,缩放50%"band": 0.5
;在垂直方向保留了-2
的偏移量,与柱子分隔。
{
"marks": [
...,
{
"type": "text",
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "bottom"},
"fill": {"value": "#333"}
},
"update": {
"x": {"scale": "xscale", "signal": "tooltip."+x0, "band": 0.5},
"y": {"scale": "yscale", "signal": "tooltip."+y0, "offset": -2},
"text": {"signal": "tooltip."+y0},
}
}
}
]
6. 完整代码
尝试用你的数据创建柱图,练习引用其他数据集。
{
"signals": [
{
"name": "tooltip",
"value": {},
"on": [
{"events": "rect:mouseover", "update": "datum"},
{"events": "rect:mouseout", "update": "{}"}
]
}
],
"scales": [
{
"name": "xscale",
"type": "band",
"domain": {"data": "ds0", "field": "x0"},
"range": "width"
},
{
"name": "yscale",
"domain": {"data": "ds0", "field": "y0"},
"nice": true,
"range": "height"
}
],
"axes": [
{ "orient": "bottom", "scale": "xscale" },
{ "orient": "left", "scale": "yscale", "tickCount": 7,"offset": 6 }
],
"marks": [
{
"type": "rect",
"from": {"data":"ds0"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "x0", "offset": 1},
"width": {"scale": "xscale", "band": 1, "offset": -1},
"y": {"scale": "yscale", "field": "y0"},
"y2": {"scale": "yscale", "value": 0}
},
"update": {
"fill": {"value": "steelblue"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
{
"type": "text",
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "bottom"},
"fill": {"value": "#333"}
},
"update": {
"x": {"scale": "xscale", "signal": "tooltip."+"x0", "band": 0.5},
"y": {"scale": "yscale", "signal": "tooltip."+"y0", "offset": -2},
"text": {"signal": "tooltip."+"y0"},
}
}
}
]
}
7. 更多用法
已经有了第一个自定义图表,Vega还有很多强大的可视化能力,下面简要介绍,点击查看官方文档,大家可以尝试做出有意思的效果:
支持的其他Mark
- arc - 圆弧
- area - 区域
- image - 图片
- group - 分组,包含其他图表
- line - 线
- path - 路径或多边形,使用SVG路径
- rect - 矩形
- rule - 简易的一根线,只需要起点和终点
- shape - 任意图形,类似path
- symbol - 预置图形,圆、方形等.
- text - 文本框.
- trail - 粗细可调整的线
支持的其他Scale
定量转化:
离散转化:
更多详细文档正在编写中,使用中遇到问题联系客服,或查看官方文档。