一个数据视图(DataSet.View)通过 Transform 来进行数据转换操作,其语法如下:
dv.transform({type: connectorName,...otherOptions});
举个例子:
const testCSV = `Expt,Run,Speed1,1,8501,2,7401,3,9001,4,1070`;const dv = new DataSet.View().source(testCSV, {type: 'csv'});console.log(dv.rows);/** dv.rows:* [* {Expt: " 1", Run: "1", Speed: "850"}* {Expt: " 1", Run: "2", Speed: "740"}* {Expt: " 1", Run: "3", Speed: "900"}* {Expt: " 1", Run: "4", Speed: "1070"}* ]*/dv.transform({type: 'filter',callback(row) {return row.Run !== "1";}});console.log(dv.rows);/** dv.rows:* [* {Expt: " 1", Run: "2", Speed: "740"}* {Expt: " 1", Run: "3", Speed: "900"}* {Expt: " 1", Run: "4", Speed: "1070"}* ]*/
上述代码中,数据视图实例 dv 使用 csv 类型的 Connector 载入了一段 CSV 文本,之后执行 filter Transform,过滤了某些数据。
目前 DataSet 支持以下 Transform:
静态处理相关
filter 数据过滤
具体用法见示例:
dv.transform({type: 'filter',callback(row) { // 判断某一行是否保留,默认返回truereturn row.year > 1998;}});
map 数据加工
具体用法见示例:
dv.transform({type: 'map',callback(row) { // 加工数据后返回新的一行,默认返回行数据本身row.newCol = row.xxx + row.yyy;return row;}});
pick 字段过滤
具体用法见示例:
dv.transform({type: 'pick',fields: [ 'xxx', 'yyy' ] // 决定保留哪些字段,如果不传,则返回所有字段});
rename 字段重命名
alias: rename-fields
具体用法见示例:
dv.transform({type: 'rename',map: {xxx: 'yyy' // row.xxx 会被替换成 row.yyy}});
reverse 逆序排列
具体用法见示例:
dv.transform({ // 把数据行逆序排列type: 'reverse',});
sort 数据排序
具体用法见示例:
dv.transform({type: 'sort',callback(a, b) { // 排序依据,和原生js的排序callback一致return a.year - b.year;}});
sort-by 按字段排序
alias: sortBy
具体用法见示例:
dv.transform({type: 'sort-by',fields: [ 'year' ], // 根据指定的字段集进行排序,与lodash的sortBy行为一致order: 'DESC' // 默认为 ASC,DESC 则为逆序})
subset 获取子集
具体用法见示例:
dv.transform({type: 'subset',startRowIndex: 1, // 保留行的起始索引endRowIndex: 2, // 保留行的结束索引fields: [ 'year' ] // 保留字段集})
partition 数据分组
alias: group | groups
具体用法见示例:
dv.transform({type: 'partition',groupBy: [ 'year' ], // 以year字段进行分组orderBy: [ 'month' ] // 以month字段进行排序});
数据形变/数据补全相关
fill-rows 补全行
alias: fillRows
先按照 groupBy 和 orderBy 进行分组,如果以分组作为补全依据(fillBy: 'group'),那么就对比每个分组,以 orderBy 序列字段值最全的分组为标准补全数据行数不足的分组。如果以序列作为补全依据(fillBy: 'order'),那么就取所有 orderBy 序列字段的组合,为每个分组都补充全量的序列。
注意!如果原始数据有除 groupBy 和 orderBy 指定的字段以外的字段,那么补充的数据行里会缺失这些字段。这时可以结合 impute Transform 来做字段数据补全。
具体用法见示例:
fillBy: group
const data = [{ a: 0, b: 0 },{ a: 0, b: 1 },{ a: 0, b: 2 },{ a: 1, b: 1 },{ a: 1, b: 2 },{ a: 1, b: 3 },{ a: 2, b: 0 }];const dv = new DataSet.View().source(data).transform({type: 'fill-rows',groupBy: [ 'a' ],orderBy: [ 'b' ],fillBy: 'group' // 默认为 group,可选值:order});console.log(dv.rows);/** dv.rows 变为:* [* { a: 0, b: 0 }, // 分组1 作为第一个序列字段最全(b)的组,被选为基准* { a: 0, b: 1 },* { a: 0, b: 2 },* { a: 1, b: 1 }, // 分组2 序列字段个数和基准组一致,所以不补充数据* { a: 1, b: 2 },* { a: 1, b: 3 },* { a: 2, b: 0 }, // 分组3 缺省数据,根据基准组进行数据补全* { a: 2, b: 1 }, // 这行数据被补充* { a: 2, b: 2 }, // 这行数据被补充* ]*/
fillBy: order
// 使用和上例同样的数据const dv = new DataSet.View().source(data).transform({type: 'fill-rows',groupBy: [ 'a' ],orderBy: [ 'b' ],fillBy: 'order' // 默认为 group,可选值:order});console.log(dv.rows);/** dv.rows 变为:* [* { a: 0, b: 0 }, // 分组1* { a: 0, b: 1 },* { a: 0, b: 2 },* { a: 0, b: 3 }, // 分组1 补充了这行数据,因为全量的序列字段(b)有这个值* { a: 1, b: 0 }, // 分组2 补充了这行数据,因为全量的序列字段(b)有这个值* { a: 1, b: 1 },* { a: 1, b: 2 },* { a: 1, b: 3 },* { a: 2, b: 0 }, // 分组3 缺省数据,根据基准组进行数据补全* { a: 2, b: 1 }, // 这行数据被补充* { a: 2, b: 2 }, // 这行数据被补充* { a: 2, b: 3 }, // 这行数据被补充* ]*/
impute 补全列/补全字段
根据配置规则为某个字段补全缺失值。
具体用法见示例:
const data = [{ x: 0, y: 1 },{ x: 0, y: 2 },{ x: 0, y: 3 },{ x: 0 },{ x: 1, y: 5 },{ x: 1, y: 6 },{ x: 1, y: 7 },{ x: 1 },{ x: 1, y: 9 },{ x: 2 }];const dv = new DataSet.View().source(data).transform({type: 'impute',field: 'y', // 待补全字段groupBy: [ 'x' ], // 分组字段集(传空则不分组)method: 'max' // 补全字段值时执行的规则});/*dv.rows 变为[{ x: 0, y: 1 },{ x: 0, y: 2 },{ x: 0, y: 3 },{ x: 0, y: 3 },{ x: 1, y: 5 },{ x: 1, y: 6 },{ x: 1, y: 7 },{ x: 1, y: 7 },{ x: 1, y: 9 },{ x: 2, y: 9 }]*/
补全字段的规则(method)有常见的统计函数:max, min, median, mean
还有补充固定值的写法:method 指定为 value,然后 value 指定为填充的常量,譬如
dv.transform({type: 'impute',field: 'y', // 待补全字段groupBy: [ 'x' ], // 分组字段集(传空则不分组)method: 'value', // 补全常量value: 10 // 补全的常量为10});
fold 字段展开
以指定字段集为key,展开数据。
具体用法见示例:
const data = [{ country: "USA", gold: 10, silver: 20 },{ country: "Canada", gold: 7, silver: 26 }];const dv = ds.createView().source(data).transform({type: 'fold',fields: [ 'gold', 'silver' ], // 展开字段集key: 'key', // key字段value: 'value', // value字段retains: [ 'country' ] // 保留字段集,默认为除 fields 以外的所有字段});/*dv.rows 变为[{ key: gold, value: 10, country: "USA" },{ key: silver, value: 20, country: "USA" },{ key: gold, value: 7, country: "Canada" },{ key: silver, value: 26, country: "Canada" }]*/
数据比例(百分比)相关 Transform
percent 总和百分比
统计某个维度下某个字段的值的和占总和的比例(可以分组)。
field 是统计发生的字段(求和,求百分比),dimension 是统计的维度字段,也就是”每个不同的 dimension 下,field 值占总和的百分比”,groupBy 则是分组字段,每一个分组内部独立求百分比(每一个分组内,最后的 percent 字段相加之和为 1)。
具体用法见示例:
dv.transform({type: 'percent',field: 'sold', // 统计销量dimension: 'year', // 每年的占比groupBy: [ 'category' ], // 以不同产品类别为分组,每个分组内部各自统计占比as: 'percent' // 结果存储在 percent 字段});
proportion 行数百分比
统计某个维度下某个字段的数据条数占总条数的比例(可以分组)。和 percent Transform 类似,但统计的是数据条目的占比,而不是数据总和的占比。
具体用法见示例:
dv.transform({type: 'proportion',dimension: 'year', // 每年的占比groupBy: [ 'category' ], // 以不同产品类别为分组,每个分组内部各自统计占比as: 'proportion' // 结果存储在proportion字段});
数据统计相关
aggregate 聚合统计
统计处理,支持并行的多种统计。
具体用法见示例:
dv.transform({type: 'aggregate', // 别名summaryfields: [], // 统计字段集operations: [], // 统计操作集as: [], // 存储字段集groupBy: [] // 分组字段集})
以上fields/operations/as这三个数组元素一一对应。“对某个字段field进行某种统计操作operation结果存储在某个字段上as”
支持的operations: 详见simple-statistics
count
max
min
mean
median
mode
product
standardDeviation
sum
sumSimple
variance
regression 回归曲线
计算两个字段的回归拟合曲线。
具体用法见示例:
dv.transform({type: 'regression',method: 'linear', // 回归算法类型fields: [ 'x', 'y' ], // 统计字段bandwidth: 0.1, // 步长extent: [ 0, 4 ], // 结果集里,x的数值范围as: [ 'x', 'y' ] // 结果字段});
支持的回归算法类型:
linear
exponential
logarithmic
power
polynomial
数据分箱相关
bin.histogram 直方图分箱
单字段
alias: bin.dot
具体用法见示例:
dv.transform({type: 'bin.histogram',field: 'a', // 对应数轴上的一个点bins: 30, // 分箱个数binWidth: 10, // 分箱步长(会覆盖bins选项)offset: 0, // 分箱偏移量groupBy: [], // 分组(用于层叠直方图)as: [ 'x', 'count' ], // x 为数组,存储了某个分箱的上下限 [x0, x1]});
bin.quantile 分位值分箱
单字段
具体用法见示例:
dv.transform({type: 'bin.quantile',field: 'y', // 计算分为值的字段as: '_bin', // 保存分为值的数组字段groupBy: [], // 分组fraction: 4, // 可选,默认四分位p: [ 0.5, 0.3 ] // 可选,p参数列表,与 fraction 二选一});
bin.hexagon 六边形分箱
双字段
alias: bin.hex | hexbin
具体用法见示例:
dv.transform({type: 'bin.hexagon',fields: [ 'a', 'b' ], // 对应坐标轴上的一个点bins: [ 30, 30 ], // 两个方向上的分箱个数binWidth: [ 10, 1000 ], // 两个方向上的分箱步长(会覆盖bins的配置)offset: [ 0, 0 ], // 两个方向上的分箱偏移量sizeByCount: false, // 是否根据分箱个数调整分箱大小(六边形的半径)as: [ 'x', 'y', 'count' ], // 这个点落在的六边形的顶点坐标集,以及每个分箱内的数据条数// x: [ x0, x1, x2, x3, x4, x5 ], y: [ y0, y1, y2, y3, y4, y5 ]// count: Number});/** 顶点顺序:* 3* 4 2** 5 1* 0*/
bin.rectangle 矩形分箱
双字段
alias: bin.rect
具体用法见示例:
dv.transform({type: 'bin.rectangle',fields: [ 'a', 'b' ], // 对应坐标轴上的一个点bins: [ 30, 30 ], // 两个方向上的分箱个数binsWidth: [ 10, 10 ], // 两个方向上的分箱步长(会覆盖bins配置)offset: [ 0, 0 ], // 两个方向上的分箱偏移量sizeByCount: false, // 是否根据分箱个数调整分箱大小as: [ 'x', 'y', 'count' ], // 这个点落在的六边形的顶点坐标集// x: [ x0, x1, x2, x3 ], y: [ y0, y1, y2, y3 ]// count: Number});/** 顶点顺序:* 3 - 2* | |* 0 - 1*/
核函数相关
kernel-smooth.regression 核函数概率密度回归
用于画核函数概率密度回归曲线,支持单字段或者双字段。
具体用法见示例:
dv.transform({type: 'kernel-smooth.regression',fields: [ 'x', 'y' ], // 必填,1 或 2 字段method: 'gaussian', // 采用的核函数类型。也可以指定为自定义的函数extent: [ min(x), max(x) ], // 数值范围,默认为 x 字段的数值范围bandwidth: 0.4, // 步长,默认采用 silverman 的算法计算as: [ 'x', 'y' ], // 结果字段,单字段时,y 为 x 值对应的概率});
支持的核函数类型:
cosine
epanechnikov
gaussian (default)
quartic
triangular
tricube
triweight
uniform
kernel-smooth.density 核函数概率密度分布
用于画核函数概率密度分布热力图,双字段。
具体用法见示例:
dv.transform({type: 'kernel-smooth.density',fields: [ 'x', 'y' ], // 必填method: 'gaussian', // 采用的核函数类型。也可以指定为自定义的函数extent: [ [ min(x), max(x) ], [ min(y), max(y)] ], // 数值范围,默认为 x 以及 y 字段各自的数值范围bandwidth: 0.4, // 步长,默认采用 silverman 的算法计算as: [ 'x', 'y' ], // 结果字段,单字段时,y 为 x 值对应的概率});
silverman 提出的 bandwidth 计算算法: paper
支持的核函数类型同上
树相关
hierarchy.treemap 树形图
alias: treemap
根据树形数据生成树形图 Treemap 布局。
具体用法见示例:
dv.transform({type: 'hierarchy.treemap',field: 'value',tile: 'treemapSquarify', // 布局类型size: [ 1, 1 ], // width, heightround: false,// ratio: 1.618033988749895, // golden ratiopadding: 0, // 各种 padding 配置paddingInner: 0,paddingOuter: 0,paddingTop: 0,paddingRight: 0,paddingBottom: 0,paddingLeft: 0,as: [ 'x', 'y' ] // 矩形的顶点集// x: [ x0, x1, x2, x3 ], y: [ y0, y1, y2, y3 ]});
支持的布局类型:
treemapBinary
treemapDice
treemapSlice
treemapSliceDice
treemapSquarify
treemapResquarify
hierarchy.partition 相邻层次图
alias: adjacency
根据树形数据生成相邻层次图 Adjacency Diagram 布局,可以通过坐标变换变形为 Sunburst 图。
具体用法见示例:
dv.transform({type: 'hierarchy.partition',field: 'value',size: [ 1, 1 ], // width, heightround: false,// ratio: 1.618033988749895, // golden ratiopadding: 0, // 各种 padding 配置as: [ 'x', 'y' ], // 矩形的顶点集// x: [ x0, x1, x2, x3 ], y: [ y0, y1, y2, y3 ]});
图相关
diagram.arc 弧长链接图
弧长链接图(Arc Diagram)可以变形为和弦图(Chord Diagram)。
alias: arc
具体用法见示例:
dv.transform({type: 'diagram.arc',y: 0,thickness: 0.05, // 节点高度,区间 (0, 1)weight: false, // 是否带权重,无权重为弧长链接图,带权重为和弦图marginRatio: 0.1, // 空隙比例,区间[0, 1)id: node => node.id, // 获取节点idsource: edge => edge.source, // 获取边起始点idtarget: edge => edge.target, // 获取边结束点idsourceWeight: edge => edge.value, // 获取边起始点权重targetWeight: edge => edge.value1, // 获取边结束点权重sortBy: null, // 排序,可以按照id,权重('weight')或者边数量('frequency')排序,也可以自定排序函数});
注意!这个 Transform 做完之后,有两部分数据(顶点和边数据),G2 在使用是不能直接通过 chart.source(dv) 来导入数据,只能分别导入顶点和边集合,例如:
const nodeView = chart.view();nodeView.source(dv.nodes);const edgeView = chart.view();edgeView.source(dv.edges);
diagram.sankey 桑基图
alias: sankey
具体用法见示例:
dv.transform({type: 'diagram.sankey',value: node => node.value, // 权重source: edge => edge.source, // 边起点idtarget: edge => edge.target, // 边终点idnodeAlign: 'sankeyJustify', // sankeyLeft / sankeyRight / sankeyCenternodeWidth: 0.02, // 节点宽,范围:(0, 1)nodePadding: 0.02, // 节点上下间距,范围:(0, 1)});
注意!这个 Transform 做完后同样需要注意上述 arc transform 一样的数据导入问题
diagram.voronoi
voronoi 图
alias: voronoi
具体用法见示例:
dv.transform({type: 'diagram.voronoi',fields: [ 'field0', 'field1' ], // 对应坐标轴上的一个点extend: [ [ x0, y0 ], [ x1, y1 ] ], // 范围size: [ width, height ], // 范围as: [ 'x', 'y' ], // 每个点包围多边形的顶点集// x: [ x0, x1, x2, ... ], y: [ y0, y1, y2, ... ]})
Geo 地理数据相关
geo.projection 地理映射
具体用法见示例:
dv.transform({type: 'geo.projection',projection: 'geoAiry', // 指定映射类型as: [ 'x', 'y', 'centroid_x', 'centroid_y' ], // x,y是对应多边形的顶点集// centroid_x是中心点的x坐标// centroid_y是中心点y坐标});
geo.centroid 由地名获取地理位置点
具体用法见示例:
dv.transform({type: 'geo.centroid',field: 'name', // 标注地名的字段geoDataView: geoDataView, // 使用的geo数据来源,可以是DataView实例,也可以是DataView实例的nameas: [ '_centroid_x', '_centroid_y' ], // _centroid_x是中心点的x坐标// _centroid_y是中心点y坐标});
geo.region 由地名获取地理位置区域
具体用法见示例:
dv.transform({type: 'geo.region',field: 'name', // 标注地名的字段geoDataView: geoDataView, // 使用的geo数据来源,可以是DataView实例,也可以是DataView实例的nameas: [ '_x', '_y' ], // 多边形的顶点集// _x: [ x0, x1, x2, ... ], _y: [ y0, y1, y2, ... ]});
其他
tag-cloud 词云布局
alias: word-cloud
具体用法见示例:
dv.transform({type: 'tag-cloud',fields: [ 'text', 'value' ], // 参与标签云layout的字段集(前者为文本内容,后者为权重值)font: 'serif', // 标签字体size: [ 500, 500 ], // 画布size,[ width, height ]padding: 0,spiral: 'archimedean', // 标签螺旋排布规律函数 'archimedean' || 'rectangular' || {function}fontSize(d) { return d.value }, // 计算标签字体大小的回调函数,d为一行数据timeInterval: Infinity, // 最大迭代时间,默认为无限大imageMask: {Image}, // Image的实例,必须是 loaded 状态})
带图片形状的词云布局实例
const imageMask = new Image()imageMask.crossOrigin = ''imageMask.src = 'https://zos.alipayobjects.com/rmsportal/EEFqYWuloqIHRnh.jpg'imageMask.onload = () => {dv.transform({type: 'tag-cloud',imageMask});};
