什么是度量

度量 Scale,是数据空间到图形空间的转换桥梁,负责原始数据到 [0, 1] 区间数值的相互转换工作,从原始数据到 [0, 1] 区间的转换我们称之为归一化操作。

不同的数据类型对应不同的度量,如

  1. 连续数据类型,如 0,1,2,3,4,5,6,7,8,9,10 一组数据,在其原始数值范围 [0, 10] 内通过度量转换至 [0, 1] 范围的数据,变成 0,0.1,0.2....0.9,1,同时通过 invert 反转,还需要度量后的数值恢复至原始值;

  2. 分类数据类型,如 ['男','女'] 这一组数据,通过度量转换后变成 [0, 1],同样时通过 invert 反转可恢复至原始值。

度量的功能

在 G2 中度量用于完成以下功能:

  1. 将数据转换到 [0, 1] 范围内,方便将数据映射到位置、颜色、大小等图形属性;

  2. 将归一化后的数据反转回原始值。例如 分类a 转换成 0.2,那么对应 0.2 需要反转回 分类a

  3. 划分数据,用于在坐标轴、图例显示数值的范围、分类等信息。

Scale 的功能非常简单易理解,但是在 G2 的数据处理流程中起着非常重要的承接作用,通过阅读 G2 数据处理流程章节,可以更好得理解度量 Scale。

度量的类型

度量的类型是由原始数据的类型所决定的,所以在介绍度量的类型之前,需要了解下 G2 对数据的分类方式。

在 G2 中我们按照数值是否连续对数据进行分类:

  1. 分类(非连续)数据,又分为有序分类和无序分类;
  2. 连续数据,时间也是一种连续数据类型。

Example:

[
  {"month":"一月","temperature":7,"city":"tokyo"},
  {"month":"二月","temperature":6.9,"city":"newYork"},
  {"month":"三月","temperature":9.5,"city":"tokyo"},
  {"month":"四月","temperature":14.5,"city":"tokyo"},
  {"month":"五月","temperature":18.2,"city":"berlin"}
]

在上述数据中,month 代表月份,temperature 代表温度,city 代表城市,其中 monthcity 都是分类类型数据,但是不同的是 month 作为月份是有序的分类类型,而 city 是无序的分类类型,而 temperature 是连续的数值类型。

根据上述的数据分类方式,G2 提供了不同的度量类型:

数据类型 度量类型
连续 linear、log、pow、time
分类(非连续) cat、timeCat

另外 G2 还提供了 identity 类型的度量用于数据源中常量数据的操作。

对于 G2 生成的所有度量对象,均拥有以下属性,这些属性均可以由用户进行配置。

{
  type: string, // 度量的类型
  range: array, // 数值范围区间,即度量转换的范围,默认为 [0, 1]
  alias: string, // 为数据属性定义别名,用于图例、坐标轴、tooltip 的个性化显示
  ticks: array, // 存储坐标轴上的刻度点文本信息
  tickCount: number, // 坐标轴上刻度点的个数,不同的度量类型对应不同的默认值
  formatter: function, // 回调函数,用于格式化坐标轴刻度点的文本显示,会影响数据在坐标轴、图例、tooltip 上的显示
}

下面就让我们来详细了解下各个度量的类型:

linear

连续的数据值,如这一组数据:[1, 2, 3, 4, 5],除了通用的属性外,还包含以下自有属性:

{
  nice: boolean, // 默认为 true,用于优化数值范围,使绘制的坐标轴刻度线均匀分布。例如原始数据的范围为 [3, 97],如果 nice 为 true,那么就会将数值范围调整为 [0, 100]
  min: number, // 定义数值范围的最小值
  max: number, // 定义数值范围的最大值
  tickCount: number, // 定义坐标轴刻度线的条数,默认为 5
  tickInterval: number, // 用于指定坐标轴各个刻度点的间距,为原始数据值的差值,tickCount 和 tickInterval 不可以同时声明
}

log

连续非线性的 log 类型度量,该度量会将 [1, 10, 100, 1000] 先转换成 [0, 1, 2, 3] 然后再进行归一化操作。log 类型的数据可以将非常大范围的数据映射到一个均匀的范围内。

log 度量是 linear 的子类,支持所有通用的属性和 linear 度量的属性,特有的属性如下:

{
  base: number, // log 的基数,默认是 2
}

log 度量的使用场景

对于以下场景,建议将数据的度量类型指定为 log 类型:

  1. 散点图中数据的分布非常广,同时数据分散在几个区间内是,例如分布在 0 - 100, 10000 - 100000,1千万 - 1亿内,这时候适合使用 log 度量;
  2. 热力图中数据分布不均匀时也会出现只有非常高的数据点附近才有颜色,此时需要使用 log 度量,对数据进行 log 处理。

pow

连续非线性的 pow 类型度量,该度量将 [2, 4, 8, 16, 32] 先转换成 [1, 2, 3, 4, 5] 然后再进行归一化操作。

pow 类型的度量也是 linear 类型的一个子类,除了支持所有通用的属性和 linear 度量的属性外也有自己的属性:

{
  exponent: number, // 指数,默认是 2
}

time

连续的时间类型,是一种特殊的连续性数据。time 类型的度量也是 linear 的子类,除了支持所有通用的属性和 linear 度量的属性外,还有自己特殊的属性:

{
  mask: string, // 指定时间的显示格式,默认:'yyyy-mm-dd'
}

mask 的占位符有:

  • y: year
  • m: month
  • d: date
  • H: hour
  • M: minute
  • s: second

目前 G2 支持如下两种形式的时间格式,当用户需要生成 time 类型的度量时,需要将原始时间数据转换为如下两种形式:

  1. 时间戳,如 1436237115500;
  2. 时间字符串: '2015-03-01','2015-03-01 12:01:40','2015/01/05','2015-03-01T16:00:00.000Z'。

cat

分类类型数据的度量。除了拥有通用的度量属性外,用户还可以设置 values 属性:

{
  values: array, // 指定当前字段的分类值
}

G2 在生成 cat 类型的度量时,values 属性的值一般都会从原始数据源中直接获取,但对于下面两种场景,需要用户手动指定 values 值:

  1. 需要指定分类的顺序时,例如:type 字段原始值为 ['最大', '最小', '适中'],我们想指定这些分类在坐标轴或者图例上的顺序为 ['最小','适中','最大']。这时候 cat 度量的配置如下:
[
  {a: 'a1', b:'b1', type: '最小'},
  {a: 'a2', b:'b2', type: '最大'},
  {a: 'a3', b:'b3', type: '适中'}
]
var defs = {
  'type': {
    type: 'cat',
    values: ['最小', '适中', '最大']
  }
};

如果不声明度量的values字段,那么默认的顺序是:‘最小’,‘最大’,‘适中’。

  1. 如果数据中的分类类型使用枚举的方式表示,那么也需要指定 values。

Example:

[
  {a: 'a1', b:'b1', type: 0},
  {a: 'a2', b:'b2', type: 2},
  {a: 'a3', b:'b3', type: 1}
]
var defs = {
  'type': {
    type: 'cat',
    values: ['最小', '适中', '最大']
  }
};

此处必须指定 'cat' 类型,values 的值必须按照索引跟枚举类型一一对应。

timeCat

timeCat 度量对应时间数据,但是不是连续的时间类型,而是有序的分类数据。例如股票交易的日期,此时如果使用 time 类型,那么由于节假日没有数据,折线图、k 线图就会发生断裂,所以此时需要使用 timeCat 类型度量将日期转换为有序的分类数据,该度量默认会对数据做排序。

timeCat 是 cat 度量的子类,除了支持所有通用的属性和 cat 度量的属性外也有自己的属性:

{
  mask: string, // 指定时间的显示格式,默认:'yyyy-mm-dd'
}

度量的操作(列定义)

G2 默认提供了一套生成度量的机制,我们会根据每个数据属性的第一个数值类型生成对应类型的度量。但是这套机制并不能满足全部的需求,因此我们为用户提供了手动指定度量类型的使用方式,以满足多样的可视化需求,这种使用方式我们称之为列定义

我们介绍了度量的类型以及各个度量支持的可配置属性,下面我们就来实际操作下,了解如何在 G2 中进行度量的配置,目前提供两种操作方式:

  1. chart.source(data, defs);

  2. chart.col('dim', defs);

chart.source(data, defs)

这种方式可以一次性为所有的数据列进行度量类型的定义。

Example:

var defs = {
  'a': {
    type: 'time', // 指定 time 类型
    mask: 'yyyy-mm-dd HH:MM:ss' // 指定时间的输出格式
  },
  'b': {
    type: 'linear', // 指定 linear 连续类型
    min: 0 // 指定度量的最小值
  },
  'c': {
    type: 'cat', // 指定 cat 分类类型
    values: ['一月','二月','三月'] // 重新指定 c 属性每一个的值
  }
};
chart.source(data, defs);

chart.col('dim', def)

为某一特定的数据列进行度量类型的配置。

Example:

var data = [
  {type: 0, value: 1},
  {type: 1, value: 2},
  {type: 2, value: 3},
];
chart.col('type', {
  type: 'cat', // 声明 type 字段为分类类型
  values: ['A', 'B', 'C'] // 重新显示的值
  alias: '类型' // 设置属性的别名
});

示例

完整代码:

var data = [
  {"value":10,"time":"2015-03-01T16:00:00.000Z"},
  {"value":15,"time":"2015-03-01T16:10:00.000Z"},
  {"value":26,"time":"2015-03-01T16:20:00.000Z"},
  {"value":9,"time":"2015-03-01T16:30:00.000Z"},
  {"value":12,"time":"2015-03-01T16:40:00.000Z"},
  {"value":23,"time":"2015-03-01T16:50:00.000Z"},
  {"value":18,"time":"2015-03-01T17:00:00.000Z"},
  {"value":21,"time":"2015-03-01T17:10:00.000Z"},
  {"value":22,"time":"2015-03-01T17:20:00.000Z"}
];
var chart = new G2.Chart({
  id : 'c1',
  forceFit: true,
  height : 300
});
var defs = {
  'time': {
    type: 'time',
    nice: false,
    mask: 'HH:MM'
  }
};
chart.source(data,defs);
chart.line().position('time*value').color('red');
chart.render();