教程
简介
图形属性对应视觉编码中的视觉通道,是 G2 语法元素非常重要和灵活的一部分,不同的几何标记都拥有自己的图形属性。G2 中支持的视觉通道有下面几种:
- position,位置,而且坐标系内映射至 x、y,三维坐标系可以映射到 x、y、z;
- color,颜色,包含了色调、饱和度和亮度;
- size,大小,不同的几何标记对大小的定义有差异;
- shape,形状,几何标记的形状决定了某个具体图表类型的表现形式,例如点图,可以使用圆点、三角形、图片表示;线图可以有折线、曲线、点线等表现形式;
- opacity,透明度,图形的透明度,这个属性从某种意义上来说可以使用颜色代替,需要使用 'rgba' 的形式,所以在 G2 中我们独立出来。
语法
在 G2 中,我们这样定义图形属性的映射语法,因为图形属性是属于每一个几何标记的,所以我们先要声明几何标记,然后再再该几何标记上进行图形属性的映射:
chart.<geomType>().<attrType>(dims, [callback]);
其中:
- geomType,几何标记类型,详见;
- attrType,图形属性类型,对应视觉通道;
- dims,参与单个视觉通道映射的字段;
- callback,回调函数,如何解析视觉通道,可以不提供,G2提供了默认的视觉通道解析方式。 除了 attr(dims, callback) 的函数原型外,G2 为了用户的便利性,结合各个视觉通道的特点,也提供了更为便捷的使用方式,在本章后面有详细的介绍。
语法示例:
chart.point().position('a*b').color('c');
chart.interval().position('a*b').color('c', function(cValue) {
if (cvalue === 'fail') {
return 'red';
} else {
return 'green';
}
});
G2 对于每个图形属性的参数 dims 的解析规则如下:
- 如果是单个单词,如
color('a')
会判断该属性是否是输入数据源的字段属性,如果不是则会将其解析为一个常量; - 多个属性的映射,需要使用
*
进行连接,G2 会依次对这些字段进行解析和映射,如position('cut*price')
; - 图形属性在设置属性的时候,支持统计函数嵌套,如
position(Stat.summary.sum('cut*price'))
;
position
position 位置,是唯一一个可以编码分类又可用于编码定序或者定量的数据属性。
位置属性的映射,用于确定由数据中的哪几个字段来确定在平面坐标系的位置。
以下面的语句为例,在 position 属性上,映射了两个属性: cut 和 price,分别表示将 cut 数据值映射至 x 轴坐标点,price 数据值映射至 y 轴坐标点。
chart.point().position('cut*price');
在 position 中,除了支持 * 的属性连接方式,还支持 + 的连接方式,下面就对这两种连接方式进行解释:
position(x*y)
以 chart.point().position('xy') 为例,point 代表图形,即最后需要生成点图,而 position 代表位置,position('xy') 代表数据在图形中的位置由 x 和 y 这两个维度的变量决定,x * y 的数据处理结果可以理解为:
position((x+y)*z)
以此句语法 chart.interval().position((a + b + c + d)*d)
为例,(a + b + c + d) 代表了数据的一个区间,从 a 到 b 到 c 到 d。G2 会默认按照声明的字段顺序将参与加法运算的属性进行合并,生成一列属性名为 'a+b+c+d' 的数据,其中的数据值为数组: [a1, b1, c1, d1],然后将新生成的字段参与图形的绘制和映射。如下,展示的瀑布图,每一个柱子表示了一个数值区间,股票的涨跌范围,这个时候就可以使用 +。
完整代码如下:
var data = [
{"time":1428163200000,"start":469,"end":480},
{"time":1428163203600,"start":480,"end":430},
{"time":1428163207200,"start":430,"end":410},
{"time":1428163210800,"start":410,"end":420},
{"time":1428163214400,"start":420,"end":440},
{"time":1428163218000,"start":440,"end":460},
{"time":1428163221600,"start":460,"end":410},
{"time":1428163225200,"start":410,"end":440},
{"time":1428163228800,"start":440,"end":490}
];
var frame = new G2.Frame(data); // 创建数据源
frame.addCol('trend', function(obj) {
return (obj.start <= obj.end) ? 0 : 1;
});
var chart = new G2.Chart({
id: 'c1',
forceFit: true,
height: 400
});
var defs = {
'time': { // 设置日期类型
type: 'timeCat',
nice: false,
mask: 'HH:MM:ss'
},
'trend': {
type: 'cat',
alias: '趋势',
values: ['上涨','下跌']
}
};
chart.source(frame, defs);
chart.interval()
.position('time*(start+end)')
.color('trend',['#1bbd19','#fa513a'])
.size(25);
chart.render();
嵌套统计函数
每个图形属性都支持统计函数的嵌套,如:
chart.interval().position(Stat.summary.max('cut*price')).color('cut');
这个语句首先经过统计函数计算出每个 cut 分类的 price 最大值,然后进行图形属性的映射,即这个时候横轴为 cut,纵轴为 price 的最大值,如下图所示:
完整代码如下:
$.getJSON('../static/data/diamond.json',function (data) {
var Stat = G2.Stat;
var chart = new G2.Chart({
id: 'c2',
width: 800,
height: 400,
plotCfg: {
margin: [20, 90, 60, 80]
}
});
chart.source(data);
chart.interval().position(Stat.summary.median('cut*price')).color('cut');
chart.render();
});
color
从可视化编码的角度对颜色进行分析,可以将颜色分为亮度、饱和度和色调三个视觉通道,其中前两个可以认为是用于编码定量和定序数据的视觉通道,而色调属于编码定性数据的视觉通道。而在 G2 中我并不区分,统一使用 color 类型。
color 支持的映射语法如下:
color('dim')
,dim 为数据属性,这时候 G2 会在内部调用默认的回调函数,读取默认提供的颜色进行数据值到颜色值的映射;color('dim', colors)
,将数据值映射至指定的颜色值 colors(可以是字符串也可以是数组),此时用于通常映射分类数据;color('dim', 'color1-color2-colorn')
,指定颜色的渐变路径,用于映射定量(连续)的数据;color('dim', callback)
,使用回调函数进行颜色值的自定义;color('red')
, 直接指定颜色常量,不进行数据映射。
分类数据的颜色映射
将 city
属性的数据值映射至制定的颜色来区分不同的城市。
.color('city', ['#1f77b4', '#ff7f0e', '#2ca02c'])
完整的代码如下:
$.getJSON('../static/data/avg-temp.json',function(data){
var Frame = G2.Frame;
var frame = new Frame(data);
frame = Frame.combinColumns(frame, ['New York', 'San Francisco','Austin'], 'value', 'city', 'date');
var chart = new G2.Chart({
id: 'c3',
forceFit: true,
height : 500,
plotCfg: {
margin: [20, 120, 80, 80]
}
});
chart.source(frame, {
date: {
type: 'time',
mask: 'yyyy.mm',
tickCount: 12
},
value: {
alias: 'Temperature, ºF'
}
});
chart.axis('date', {
line: null,
tickLine: {
stroke: '#000',
value: 6 // 刻度线长度
},
title: null
});
chart.axis('value', {
tickLine: {
stroke: '#000',
value: 6 // 刻度线长度
},
labels: {
label: {
fill: '#000'
}
},
line: {
stroke: '#000'
},
grid: null
});
chart.line().position('date*value').color('city', ['#1f77b4', '#ff7f0e', '#2ca02c']).shape('spline').size(2);
chart.render();
});
连续数据的颜色映射
对于连续的数据,我们可以为 color 指定颜色渐变的路径,以可视化数据在某一范围的变化趋势。
.color('Population','#e5f5e0-#31a354')
完整代码如下:
var Stat = G2.Stat;
$.getJSON('../static/data/USA.geo.json', function(mapData) {
var map = [];
var features = mapData.features;
for(var i=0; i<features.length; i++) {
var name = features[i].properties.name;
map.push({
"name": name
});
}
var chart = new G2.Chart({
id: 'c4',
width: 800,
height: 400,
plotCfg: {
margin: [40, 140]
}
});
chart.source(map);
chart.legend(false);
chart.polygon().position(Stat.map.region('name', mapData)).color('#e6e6e6').style({
stroke: '#999',
lineWidth: 1
});
$.getJSON('../static/data/2014-usa-population.json', function(data) {
var view = chart.createView();
view.source(data);
view.polygon().position(Stat.map.region('State', mapData)).color('Population','#e5f5e0-#31a354');
view.point().position(Stat.map.center('State', mapData)).size(0).label('code', {offset: 0});
chart.render();
});
});
shape
不同的几何标记有不同的 shape(图形形状)。shape 这个视觉通道受其他几个视觉通道影响,比如:interval 几何标记的 shape 可以是填充的矩形 rect 也可是空心的边框矩形,这个就决定了是将 color 映射到填充色上还是映射到边框颜色上。shape 方法的使用方式比较简单,常用于映射分类数据:
- shape('dim'),将指定的字段映射到内置的 shapes 数组中;
- shape('dim', shapes),用户自己提供 shapes 数据,来进行数据映射;
- shape('dim', callback),使用回调函数获取shape,用于个性化的 shape 定制;
- shape('circle'),指定常量,将所有数据值映射到固定的shape。
另外 G2 2.0.0 版本开始提供了自定义 shape 的功能,详见如何快速得自定义 shape。
geom 和 shape
使用几何标记实现各种图表类型时,对于每一种几何标记来说,图形在绘制的时候有不同的形状(shape):
- 点图,可以使用圆点、三角形、正方形、十字符号等表示点;
- 线图,可以有折线、曲线、点线等;
- 多边形,可以是实心的多边形,也可以是空心的仅有边框的多边形;
图形形状 shape 决定了各个视觉通道和图形属性的映射,使用边框颜色还是填充颜色、使用点线还是实线,使用平滑线还是折线,都是由图形形状(shape)决定的。
可是说图形形状(shape)是G2中最灵活、内容最丰富的模块,下表列出了目前 G2 内置的对各个几何标记 geom 的图形形状(shape)实现:
geom 类型 | shape 类型 | 解释 |
---|---|---|
point | 'circle', 'square', 'bowtie', 'diamond', 'hexagon', 'triangle', 'triangle-down' 'hollowCircle', 'hollowSquare', 'hollowBowtie', 'hollowDiamond', 'hollowHexagon', 'hollowTriangle', 'hollowTriangle-down', 'cross', 'tick', 'plus', 'hyphen', 'line', 'pointerLine', 'pointerArrow' |
hollow 开头的图形都是空心的。 |
line | 'line', 'smooth', 'fill', 'dot', 'dash', 'dotSmooth', 'spline', 'hv', 'vh', 'hvh', 'vhv' | 'hv', 'vh', 'hvh', 'vhv' 用于 step-line 的绘制。 |
area | 'area', 'smooth', 'line', 'dotLine', 'smoothLine', 'dotSmoothLine' | area 和smooth 是填充内容的区域图,其他图表是空心的封闭线图。 |
interval | 'rect', 'hollowRect', 'line', 'tick', 'funnel', 'pyramid' | [hollowRect]是空心的矩形, [line]和 [tick] 都是线段。 |
polygon | 'polygon', 'hollow' | 'polygon':多边形,'hollow':空心多边形。 |
schema | 'box', 'candle' | 目前仅支持箱须图、K线图,'box' 用于绘制箱须图,'candle'用于绘制股票图。 |
edge | 'smooth', 'line', 'vhv' | 边的几种形状,smooth是平滑的链接线, ’vhv'是常见的折线 |
示例:划分区域的多形状散点图
.shape('type', ['circle', 'triangle-down', 'square', 'diamond'])
完整代码:
G2.Global.setTheme('cheery'); // 切换默认主题
var data = [{"type":"series1","x":1732.8871544450521,"y":-80.75603982433677}, {"type":"series2","x":1546.589955687523,"y":282.97513956204057},{"type":"series3","x":742.7253536880016,"y":479.4877045787871},{"type":"series4","x":772.9451237246394,"y":-407.76275377720594},{"type":"series1","x":1359.810951165855,"y":297.2723776474595},{"type":"series2","x":650.068512186408,"y":-129.5293727889657},{"type":"series3","x":1730.0641294568777,"y":-240.9555669873953},{"type":"series4","x":502.4238293990493,"y":-342.1307345852256},{"type":"series1","x":1582.250035367906,"y":-45.05145130679011},{"type":"series2","x":1829.3536202982068,"y":-113.36682550609112},{"type":"series3","x":1572.7724805474281,"y":115.85489613935351},{"type":"series4","x":1887.0485508814454,"y":6.104619242250919},{"type":"series1","x":882.0341778919101,"y":401.86547581106424},{"type":"series2","x":1620.0402630493045,"y":267.45478762313724},{"type":"series3","x":1925.4421964287758,"y":369.47823595255613},{"type":"series4","x":1611.9598066434264,"y":-234.8197065293789},{"type":"series1","x":1720.9005448967218,"y":-115.85958395153284},{"type":"series2","x":1862.451889552176,"y":-248.42322198674083},{"type":"series3","x":1283.97127520293,"y":325.95419557765126},{"type":"series4","x":1869.39731054008,"y":383.6600771173835},{"type":"series1","x":1988.1872748956084,"y":-216.48837719112635},{"type":"series2","x":1187.2317604720592,"y":404.27824622020125},{"type":"series3","x":1571.8251904472709,"y":-96.22862562537193},{"type":"series4","x":1826.7804672941566,"y":-477.26183850318193},{"type":"series1","x":1177.1034905686975,"y":-112.32297029346228},{"type":"series2","x":1195.6303780898452,"y":448.2225668616593},{"type":"series3","x":1955.4035440087318,"y":21.227966528385878},{"type":"series4","x":1732.739924453199,"y":368.81575733423233},{"type":"series1","x":806.2865408137441,"y":385.1917199790478},{"type":"series2","x":1556.4921544864774,"y":-420.2395495958626},{"type":"series3","x":1181.5953878685832,"y":-277.57429890334606},{"type":"series4","x":1269.245852716267,"y":242.08716116845608},{"type":"series1","x":1219.9176428839564,"y":346.6071574948728},{"type":"series2","x":746.3413281366229,"y":-89.49963096529245},{"type":"series3","x":432.45446030050516,"y":441.71203626319766},{"type":"series4","x":777.959868311882,"y":66.79431581869721},{"type":"series1","x":918.3598393574357,"y":448.46232794225216},{"type":"series2","x":1436.13195233047,"y":184.53770177438855},{"type":"series3","x":1119.1939394921064,"y":-312.59450083598495},{"type":"series4","x":1998.3739340677857,"y":5.358115769922733},{"type":"series1","x":1069.4813169538975,"y":-106.57294746488333},{"type":"series2","x":275.5963373929262,"y":205.64519427716732},{"type":"series3","x":801.038783043623,"y":7.43780517950654},{"type":"series4","x":213.5445298627019,"y":288.95508078858256},{"type":"series1","x":1697.732014581561,"y":-495.7758020609617},{"type":"series2","x":1940.3524557128549,"y":57.93372122570872},{"type":"series3","x":1365.2942385524511,"y":246.1609710007906},{"type":"series4","x":986.5696644410491,"y":248.502679169178},{"type":"series1","x":1991.1393811926246,"y":-269.05048871412873},{"type":"series2","x":1244.1082932054996,"y":378.08641185984015},{"type":"series3","x":958.6482960730791,"y":-222.58463921025395},{"type":"series4","x":1939.0085907652974,"y":-415.7125297933817},{"type":"series1","x":1097.460888326168,"y":298.815727699548},{"type":"series2","x":1132.0891315117478,"y":-409.8006417043507},{"type":"series3","x":934.7271472215652,"y":78.89576349407434},{"type":"series4","x":632.7374717220664,"y":240.34222541376948},{"type":"series1","x":25.66775120794773,"y":386.65700424462557},{"type":"series2","x":1791.440169326961,"y":-98.93955988809466},{"type":"series3","x":1391.1143569275737,"y":46.02528735995293},{"type":"series4","x":538.8829139992595,"y":-428.8868750445545},{"type":"series1","x":933.5943283513188,"y":327.7888190932572},{"type":"series2","x":1381.4812870696187,"y":-36.58548276871443},{"type":"series3","x":152.31592673808336,"y":-233.14770916476846},{"type":"series4","x":90.16109630465508,"y":-45.90578889474273},{"type":"series1","x":1855.3984118625522,"y":234.1356431134045},{"type":"series2","x":889.7370044142008,"y":-261.737990193069},{"type":"series3","x":344.61341612040997,"y":-13.636548072099686},{"type":"series4","x":588.4585017338395,"y":-5.226874258369207},{"type":"series1","x":1714.1733933240175,"y":-204.88095516338944},{"type":"series2","x":905.8979945257306,"y":-326.66328828781843},{"type":"series3","x":179.5906499028206,"y":-468.77168817445636},{"type":"series4","x":472.5130721926689,"y":-1.9495864398777485},{"type":"series1","x":1275.0087166205049,"y":29.06017890200019},{"type":"series2","x":262.88699731230736,"y":496.59054493531585},{"type":"series3","x":44.90217100828886,"y":-441.4119469001889},{"type":"series4","x":1782.4337324127555,"y":-269.77423299103975},{"type":"series1","x":748.8169632852077,"y":336.41374530270696},{"type":"series2","x":1684.0793499723077,"y":-123.5110298730433},{"type":"series3","x":1109.3289218842983,"y":423.3962232246995},{"type":"series4","x":354.1235653683543,"y":-307.66808334738016},{"type":"series1","x":1329.577681608498,"y":470.3424177132547},{"type":"series2","x":273.0302046984434,"y":-147.08185475319624},{"type":"series3","x":1873.354759067297,"y":415.8988082781434},{"type":"series4","x":1152.5639267638326,"y":-228.8104579783976},{"type":"series1","x":480.6276988238096,"y":-168.55818405747414},{"type":"series2","x":724.2633355781436,"y":-137.24337238818407},{"type":"series3","x":879.4547133147717,"y":-114.34462806209922},{"type":"series4","x":988.7294666841626,"y":-206.20282599702477},{"type":"series1","x":1954.3535728007555,"y":214.61118385195732},{"type":"series2","x":851.2419117614627,"y":420.7796682603657},{"type":"series3","x":953.703748062253,"y":89.70340387895703},{"type":"series4","x":61.40255834907293,"y":-160.9144126996398},{"type":"series1","x":1207.9351842403412,"y":386.9934994727373},{"type":"series2","x":1142.1515522524714,"y":279.29873764514923},{"type":"series3","x":1069.3543190136552,"y":239.56217663362622},{"type":"series4","x":1898.9934483543038,"y":341.7890924029052},{"type":"series1","x":736.7067560553551,"y":-414.1982044093311},{"type":"series2","x":1718.982090242207,"y":83.44200439751148},{"type":"series3","x":814.3314002081752,"y":-484.1634132899344},{"type":"series4","x":346.93830739706755,"y":150.88692586869}];
var chart = new G2.Chart({
id: 'c5',
forceFit: true,
height: 400
});
chart.source(data, {
x: {
tickCount: 8
}
});
chart.point().position('x*y').color('type').shape('type', ['circle', 'triangle-down', 'square', 'diamond']).size(7);
// 添加辅助元素
chart.guide().text([250, 550], '0 - 500', {
fontSize: '15px'
});
chart.guide().text([1000, 550], '500 - 1500', {
fontSize: '15px'
});
chart.guide().text([1700, 550], '1500 - 2000', {
fontSize: '15px'
});
chart.guide().rect([0, -600], [500, 600]);
chart.guide().rect([500, -600], [1500, 600], {
fillOpacity: 0.2
});
chart.guide().rect([1500, -600], [2000, 600], {
fillOpacity: 0.3
});
chart.render();
size
对于不同的几何标记含义不完全一致:
- 对于 point 点来说,size 对应着点的半径;
- 对于 line 线来说,size 对应着先的粗细;
- 对于 interval 柱状图来说,size 对应着柱子的宽度。
所以从可视化的角度分析,大小(size)是一个复杂的视觉通道。
在 G2 中,支持如下几种方式的映射语法:
- size('dim'),指定映射到 size 的字段,使用内置的默认大小范围为 [1, 10];
- size('dim', max, min),指定映射到 size 字段外,还提供了 size 的最大值和最小值范围;
- size('dim', callback),使用回调函数映射 size,用于个性化的 size 定制;
- size(10) 直接指定像素大小。
在气泡图中,常常使用 size 图形属性映射,用于编码更多维度的数据。如下例,使用气泡图来可视化每个国家人均国内生产总值同人均寿命之间的相关关系,同时将各个国家人口数据映射至气泡的大小。
.size('Population', 35, 5)
完整代码:
$.getJSON('../static/data/bubble.json',function(data){
var chart = new G2.Chart({
id: 'c6',
width: 800,
height: 400
});
chart.source(data, {
'LifeExpectancy': {
alias: '人均寿命(年)'
},
'Population': {
type: 'pow',
alias: '人口总数'
},
'GDP': {
alias: '人均国内生产总值($)',
tickCount: 10
},
'Country': {
alias: '国家/地区'
}
});
chart.axis('GDP', {
// 格式化坐标轴的显示
formatter: function (value) {
return (value / 1000).toFixed(0) + 'k';
}
});
chart.tooltip({
title: null // 不显示默认标题
});
chart.legend('Population', false);
chart.legend('Country', false);
chart.point().position('GDP*LifeExpectancy')
.size('Population', 35, 5)
.color('continent')
.opacity(0.65)
.shape('circle')
.tooltip('Country*Population*GDP*LifeExpectancy');
chart.render();
});
opacity
透明度在视觉编码过程中,只能进行定量(连续)数据的映射,作为颜色的一个补充使用,所以提供以下快捷方式:
- opacity('dim'),指定透明度映射的字段,透明度默认的范围为 [0, 1];
- opacity(0.5),直接指定透明度常量;
- opacity('dim', callback),使用回调函数获取透明度。
Geom 支持的图形属性
前面提到过,每种几何标记支持的视觉通道有所差异,数据和视觉通道的映射关系也不完全相同。 下表列出了各个 geom 几何标记上支持的图形属性映射:
几何标记 | position |
color |
size |
shape |
opacity |
---|---|---|---|---|---|
point | 支持 | 支持 | 支持 | 支持 | 支持 |
path、line | 支持 | 支持 | 支持 | 支持 | 支持 |
area | 支持 | 支持 | 不支持 | 支持 | 支持 |
interval | 支持 | 支持 | 支持 | 支持 | 支持 |
polygon | 支持 | 支持 | 不支持 | 支持 | 支持 |
edge | 支持 | 支持 | 支持 | 支持 | 支持 |
schema | 支持 | 支持 | 支持 | 支持 | 支持 |
contour | 支持 | 支持 | 支持 | 不支持 | 支持 |
heatmap | 支持 | 支持 | 支持 | 不支持 | 不支持 |