前面也说过,度量Scale是数据空间到图形空间的转换桥梁,负责原始数据到[0,1]区间数值的相互转换工作,也叫归一化。不清楚为什么要做归一化操作的同学可以看options属性这篇文章。那scale又是如何实现这个归一化操作的呢?这个得从原始数据类型开始讲起。

原始数据类型

在G2中,我们按照数据是否连续将数据划分为以下几类:

  • 分类(定性)数据,又分为有序的分类和无序的分类;
  • 连续(定量)数据,连续不间断的数值,时间也是一种连续的数据类型。

例子说明:

  1. [
  2. { month: '一月', temperature: 7, city: 'tokyo' },
  3. { month: '二月', temperature: 6.9, city: 'newYork' },
  4. { month: '三月', temperature: 9.5, city: 'tokyo' },
  5. { month: '四月', temperature: 14.5, city: 'tokyo' },
  6. { month: '五月', temperature: 18.2, city: 'berlin' }
  7. ]

其中:month 代表月份,temperature 代表温度,city 代表城市。

  • 上面数据中 monthcity 都是离散的分类,但是又有所差异。month 是有序的分类类型,而 city 是无序的分类类型。
  • temperature 是连续的数字。

因为原始数据具有许多不同类型,因此scale也需要对应的类型去处理原始数据,下面就介绍一下scale的类型及其用法。

度量scale类型

G2中scale类型如下表:



连续
linear(连续数据基类) 连续的数字 [1, 2, 3, 4, 5]
time 连续的时间类型
log 连续非线性的 Log 数据 将 [1, 10, 100, 1000] 转换成 [0, 1, 2, 3]
pow 连续非线性的 pow 数据 将 [2, 4, 8, 16, 32] 转换成 [1, 2, 3, 4, 5]
固定 identity 常量类型的数值,也就是说数据的某个字段是不变的常量
分类(非连续) timeCat 非连续的时间,比如股票的时间不包括周末或者未开盘的日期
cat(分类数据基类) 分类, [‘男’, ‘女’]

注意点

连续数据度量类型和timeCat在显示时会默认对数据进行排序。

知道了scale的类型,那究竟不同类型的scale是怎么将不同的数据进行归一化的呢?

归一化操作(重要)

首先说一下归一化操作主要做的三件事:

  1. 将数据转换到 0-1 范围内,方便将数据映射到位置、颜色、大小等图形属性;
  2. 将转换过的数据从 0-1 的范围内反转到原始值。例如 分类a 转换成 0.2,那此时 0.2 反转回来的值就是 分类a
  3. 将数据划分,用于在坐标轴上、图例上显示数值的范围、分类等信息;

转换过程:
例子:
当原始数据类型为连续数据时,scale类型选择连续类型里的一种,

  1. const data=[
  2. {name:1,value:5},
  3. {name:2,value:10},
  4. {name:2,value:15}
  5. ];

scale配置:

默认配置机制

  • 查看用户有没有配置了对应字段的scale
  • 如果有,则按照配置的scale进行操作
  • 如果没有,判断字段的第一条数据的字段类型
    • 如果数据中不存在对应的字段,则为 ‘identity’
    • 如果是数字则为 ‘linear’;
    • 如果是字符串,判定是否是时间格式,如果是时间格式则为时间类型 ‘time’,
    • 否则是分类类型 ‘cat’

例子:

  1. const data=[
  2. {name:1,value:5},
  3. {name:2,value:10},
  4. {name:2,value:15}
  5. //{name:"1",value:5},
  6. // {name:"2",value:10},
  7. // {name:"3",value:15}
  8. ];
  9. const chart=new G2.Chart({
  10. container:"root",
  11. width:400,
  12. height:400,
  13. });
  14. chart.source(data);
  15. chart.interval().position("name*value");
  16. chart.render();

Day7 Scale用法解析 - 图4Day7 Scale用法解析 - 图5

data中name字段为数字 data中name字段为字符串

总结

从上图可以看出:当name为数字时,度量类型默认采用linear;当name为字符串时,因为不是时间格式,所以默认为cat

共同属性

不同类型的配置参数可能会有所差别,但是也有以下共同属性:

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

下面针对每种类型scale的用法进行说明:

linear

连续数据类型的基类,除了以上共有属性,还包括以下特殊属性:

属性名 说明
min 定义域的最小值,默认取数据中的最小值(即坐标起点)
max 定义域的最大值,默认取数据中的最大值(即坐标终点)
tickCount 连续类型的度量,默认生成坐标点的个数是5
tickInterval 用于指定坐标轴各个标度点的间距,是原始数据之间的间距差值,tickCount 和 tickInterval 同时声明时以 tickCount 为准
nice 是否根据人对数字识别的友好度,来调整min和max。例如 min:3,max: 97,如果nice: true,那么会自动调整为:min: 0,max: 100

linear和cat的区别

举例:
代码:

  1. const data=[
  2. {name:"3",value:5},
  3. {name:"4",value:10},
  4. {name:"5",value:15}
  5. ];
  6. const chart=new G2.Chart({
  7. container:"root",
  8. width:400,
  9. height:400,
  10. options:{
  11. scales:{
  12. name:{
  13. type:"linear"
  14. //type:"cat"
  15. }
  16. }
  17. }
  18. });
  19. chart.source(data);
  20. chart.interval().position("name*value");
  21. chart.render();

图片.png图片.png
type为linear type为cat

总结

当type为linear时,因为min和max及tickCount都没有设置,所以min默认取数据中的最小值3,max默认取数据中的最大值5,又因为tickCount默认分成5个坐标点,所以tickInterval被设置成了0.5,但是这样的图表显然不是我们想要的,所以我们可以通过设置min和max让图表的位置更加合理。

当type为cat时,为什么图表的位置就正常了呢?

因为当type为cat时,scale的转换方式就变了,它会将3,4,5分成3类,每一类的所占比例都是均分的,这是和linear时的scale转换最大的不同,linear是按照数值大小来取比例的,并不是均分的,所以最后的图表才会出现这种差异化。

cat

分类类型度量的独有属性:

属性名 说明
values 当前字段的分类值(其实就是个排序操作,按数组中的分类值进行排序)

values属性说明

将linear实例代码中的scales改为:

  1. name:{
  2. type:"cat",
  3. //values:["5","4","1"]
  4. }

图片.png图片.png
values设置之前 values设置之后
可以发现,当values设置之后,最后图表分类字段的显示顺序变成了数组中的分类字段排列顺序了。
注意:values中的值必须和数据中的字段一一对应,即不能采用数据中不存在的字段。

time

time类型的值是一种特殊的连续类型,是linear的子类,其特殊的属性:

属性名 说明
mask 数据的格式化格式 默认:’YYYY-MM-DD’

目前支持两种time类型:

  • 时间戳的数字形式, 1436237115500 // new Date().getTime()
  • 时间字符串: ‘2015-03-01’, ‘2015-03-01 12:01:40’, ‘2015/01/05’,’2015-03-01T16:00:00.000Z’

    time与linear的区别

    因为用linear无法直接表示数据类型为时间的数据,所以增加了time度量类型来专门处理数据类型为时间的数据。

    log

log类型度量可以将数据[2,4,8,16,32]转换成[1,2,3,4,5]再进行归一化处理,所以能将非常大范围的数据映射到一个均匀的范围内,这种度量是linear的子类,支持所有通用的属性和linear度量的属性,特有的属性:

属性名 说明
base Log 的基数,默认是2

以下情形下建议使用log度量

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

    linear和log的区别:

    例子:
    代码:
  1. const data=[
  2. {name:1,value:1},
  3. {name:2,value:2},
  4. {name:3,value:3},
  5. {name:4,value:4},
  6. {name:5,value:5},
  7. {name:6,value:6},
  8. {name:1024,value:15}
  9. ];
  10. const chart=new G2.Chart({
  11. container:"root",
  12. width:400,
  13. height:400,
  14. options:{
  15. scales:{
  16. name:{
  17. type:"log"
  18. //type:"linear"
  19. }
  20. }
  21. }
  22. });
  23. chart.source(data);
  24. chart.point().position("name*value");
  25. chart.render();

图片.png图片.png
type为linear type为log
由以上两图可以看出,当数据分布不均匀时,此处低值数值比较密集,如果用linea类型r,则低数值范围基本排为一列,看不出差异;但是如果用log类型,则低数值范围也能很好的展示。

pow

pow类型的度量能将数据[1,2,3,4,5]转换成[2,4,8,16,32]然后进行归一化处理,它也是linear类型的一个子类,除了支持所有通用的属性和linear度量的属性外也有自己的属性:

属性名 说明
exponent 指数,默认是2

使用场景:

  • 最小值和最大值悬殊非常大时可以用 pow 平滑一下数据。

    linear和pow的区别:

    分析原理同linear和log 的区别

    timeCat

timeCat类型的数据,是一种日期数据,但是不是连续的日期。例如代表存在股票交易的日期,此时如果使用time类型,那么节假日没有数据,折线图、k线图会断裂,所以此时使用timeCat的度量表示分类的日期,默认会对数据做排序。

属性名 说明
tickCount 此时需要设置坐标点的个数
mask 数据的格式化格式

timeCat、time、cat的区别

举例:
代码:

  1. const data=[
  2. {name:2,value:2,time:"1996-05-01"},
  3. {name:3,value:3,time:"1996-05-02"},
  4. {name:4,value:4,time:"1996-05-03"},
  5. {name:5,value:5,time:"1996-08-01"},
  6. {name:6,value:16,time:"1996-09-03"},
  7. {name:1024,value:15,time:"1996-08-02"}
  8. ];
  9. const chart=new G2.Chart({
  10. container:"root",
  11. width:400,
  12. height:400,
  13. options:{
  14. scales:{
  15. time:{
  16. type:"timeCat"
  17. //type:"time"
  18. //type:"cat"
  19. }
  20. }
  21. }
  22. });
  23. chart.source(data);
  24. chart.interval().position("time*value");
  25. chart.render();

图片.png图片.png
type为timeCat type为cat
图片.png
type为time
从以上三幅图的对比中我们可以看出:
timeCat与cat的区别:timeCat会对分类的时间进行排序,而cat只是简单的分类,并不会对分类进行排序,
可以把timeCat理解成time和cat的子类,所以既有time对日期排序的特性,也有cat分类的特性。
timeCat与time的区别:timeCat是分类度量,对时间进行分类,然后再进行归一化出处理,而time是连续度量,会对时间直接进行归一化处理。