做好数据可视化前端除了组件配置可能还需要了解这些

avatar
web 前端工程师 @快手

一、引题

目前在工作中主要是支持各种各样的数据分析类的产品,该类产品主要的特点就是通过可视化的方式直观呈现数据的特征,辅助业务低门槛、低成本的分析数据,数据的可视化则大多数是借助如下的图表来进行展示。

(左:echarts 图表,右:antv g2plot 图表)

面对着几十种的可视化图表,作为数据产品的研发同学,就需要考虑如何能够既通用的支持好各业务(如电商、商业化等)不同场景的数据分析诉求,又尽量易用减少重复开发成本提高开发效率呢。个人认为可以重点关注以下两部分:

  1. 标准的数据协议:以乐高积木类比标准的数据协议就是其中的凸点和凹槽,可以适配到各种场景进行数据的呈现或再加工处理。

  2. 丰富的数据配置:则可以视为不同形状和颜色的乐高积木颗粒,少了这些数据配置加工方法,最终的数据呈现就会大大受限。

下面从这两点具体分享我的看法,大家有兴趣也可以通过评论一起对数据可视化进行探讨和完善。

二、标准的数据协议

首先啥是标准的数据协议呢?

数据平台部有比较标准化的数据接入流程,这些数据大部分是可以以指标和维度的形式表示。

  • 指标:通常指可以量化的数据,用来衡量数据的大小,如平台用户日活。
  • 维度:通常指数据的某一特征,用于在该特征下做数据对比,如用户地域、年龄。

本文提的的标准数据协议就是通过二维数组的形式来表示指标和维度数据,具体的字段下文会提到。

那么这样有啥好处呢?

通过标准的数据协议,既可以让我们灵活的适配各种可视化展示的方式,也可以减少前后端重复的字段约定沟通成本。我们常用的图表库中也到处是指标和维度的影子。

2.1 图表中的维度和指标

以 echarts 和 antv g2plot 的图表配置为例,其数据相关的字段也基本都是与指标和维度相关:

antv g2plot 常见图表字段映射

配置说明指标/维度适用图表
xFieldstring,x 轴字段名称维度Line、Column、Area、Bar、DualAxes、Scatter、Radar、Funnel、WaterFull
yFieldstring,y 轴字段名称string[],双 y 轴图指标Line、Column、Area、Bar、DualAxes、Scatter、Radar、Funnel、WaterFull
seriesFieldstring,拆分字段名称维度Line、Column、Area、Bar、DualAxes、Radar、Funnel
groupFieldstring,拆分字段,拆分优先级高于 seriesField,isGroup: true 时会根据 groupField 进行分组维度Column、Bar
angleFieldstring,扇形切片大小(弧度)所对应的数据字段名。指标Pie
colorFieldstring,扇形颜色映射对应的数据字段名。维度Pie、WordCloud
compareFieldstring,对比字段。声明此字段时会自动渲染为对比漏斗图维度Funnel
sourceFieldstring,桑基图的来源节点数据字段维度Sankey
targetFieldstring,桑基图的目标节点数据字段维度Sankey
wordField单词内容在数据中所对应的字段名。维度WordCloud
weightField权重在数据中所对应的字段名。指标Sankey、WordCloud

echarts 数据集映射

配置说明指标/维度
dimensionsstring[],指标和维度的 id 标识,也决定了指标在图表中的顺序指标 + 维度
sourcestring,字段展示名称指标和维度的值

2.2 数据类型细分

我们的标准协议也就可以基于指标和维度来进行设计,根据指标、维度的数量,可以进行以下细分:

2.3 数据协议

基于以上的数据类型,我们就可以通过二维数组的方式进行实际数据协议的表示:

属性说明
columns指标/维度信息Arrayidstring,指标/维度 id
labelstring,指标/维度显示名称
unitstring,指标/维度单位
dimensionboolean,是否是维度
metricboolean,是否是指标
columnsArray,子指标列表
dataList明细数据列表,对象数组keystring, 对应 columns 中的指标/维度 id
showValue显示值,用于在表格、坐标轴 label、tooltip 中展示
realValue真实值,用于表格排序、维度条件、图表间隔计算等

JSON 示例

{
  "columns": [
    {
      "id": "905",
      "dimension": true,
      "unit": "",
      "label": "年龄"
    },
    {
      "id": "16178",
      "metric": true,
      "unit": "",
      "label": "双端不去重活跃设备数",
    },
    {
      "id": "1617801",
      "metric": true,
      "unit": "",
      "label": "上月双端不去重设备数"
    }
  ],
  "dataList": [
    {
      "905": {
        "showValue": "18-23",
        "realValue": "18-23"
      },
      "16178": {
        "showValue": "9999.99万",
        "realValue": 99999910
      },
      "1617801": {
        "showValue": "9999.99万",
        "realValue": 99999910
      }
    },
    {
      "905": {
        "showValue": "12-17",
        "realValue": "12-17"
      },
      "16178": {
        "showValue": "8888.88万",
        "realValue": 88888810
      },
      "1617801": {
        "showValue": "8888.88万",
        "realValue": 88888810
      }
    }
  ]
}

为了向后兼容,数据明细中的数据项是以 json 对象的格式,区分了真实值 realValue和展示值 showValue。要注意的是维度和指标只是基础数据特征的分类,根据数据的类型还有更多特征维度,如时间格式、百分比、对数、坐标位置等,也可以作为 column 中的属性进行扩展补充。

2.4 基于协议自动适配

有了比较通用的标准数据协议,我们前端也可以根据其中的数据特征指标、维度的数量自动进行图表图例的适配。如:

根据指标数据的量级、指标单位差异,自动适配双 y 轴

image.png 按照数据维度、指标的关系来自动适配图例项、tooltip 展示

image.png

三、丰富的数据配置

标准的协议可以让我们前后端的开发更加灵活,然而要满足多种多样的业务需求场景,还需要依赖丰富的数据加工配置能力。

3.1 数据处理

常见的数据处理方式有以下这些: 数据的主要处理都集中在服务端,但前端也存在着一些数据处理的场景,包括需要将标准的数据协议转换成图表所需的数据格式,以及坐标轴刻度值序列化、表格嵌套迷你图表时数据合并等特殊处理。

分类数据处理说明
字段加工字段重命名 rename字段展示的别名
衍生字段二次计算、复合指标...
格式转换 formatter单位、浮点、大数转换...
数据过滤行过滤 filter根据条件影响行数
列过滤 pick根据条件影响列数,如表格显示/隐藏某些列
数据补全行补全 fill-rows分组数据不全时补充,如时间趋势对本月后续时间数据补全
列补全 impute补全某行缺失字段
数据拆分数据分组 partition根据某一维度对数据进行分组排列
取子集 subset取部分数据
字段展开 fold对象展开拆分
拆分 split数组展开拆分
数据排序排序 sort按某个字段进行升/降排列
数据比例总和百分比 percent占总数的比例
行数百分比 proporton满足条件的数据条目的占比
相对百分比漏斗图,计算相对前一值的占比
数据统计聚合统计 aggregate累计计算
回归曲线 regression计算两个字段的回归拟合曲线
数据遍历遍历 map常见的循环遍历
more ...

数据的主要处理集中在服务端,前端一个图表展示的数据来源可能是多个数据表关联而来,数据处理统一放在后端也可以灵活的调配计算资源,数据的计算更加稳定,当存在着数据推送场景时,也可以保证数据的一致性。

但前端也存在着一些数据处理的场景,包括需要将标准的数据协议转换成图表所需的数据格式、坐标轴刻度值序列化、多份数据嵌套合并等,一些数据展示类的处理放在前端可以更加灵活,能减少查询、数据更新显示也更快,但也会有这监控、排障困难的风险。

对于前端数据的加工处理。可以参考以下业界的前端数据集的方案,作用是将数据配置和图表的其他配置进行分离,来提高数据的复用性。因为在业务中数据是常改变的而组件的配置不常变。

Antv Dataset 一个独立的数据预处理模块,主要包括数据连接 Connector 和数据转换 Transform

  • Connector:负责导入和归一化数据,将导入的数据转成标准的 JSON。
  • Transform:负责进行各种数据转换处理。
    • 加工数据,包括过滤 filter、映射 map、排序 sort、补数 fold 等操作。
    • 统计函数,汇总统计、百分比、分箱等统计函数。
    • 特殊数据处理,包括地图数据、矩形树图、桑基图、文字云等数据处理。
// 二维数组,原始数据明细
const data = [...];

const ds = new DataSet();
// connector,通过指定类型导入数据
const dv = ds.createView()
	.source(data, { type: 'xxx' });

// transform 数据转换
dv.transform({ 
	type: 'filter',
  callback(row) {
  	return row.city === '北京';
  }
});

console.log(dv.rows) // 数据转换结果

Echarts Dataset Echarts 中配置项,用于实现多图表系列数据共享,主要包括数据维度 dimensions、数据源 source、数据转换 transform。

  • dimensions:一维数组,维度标识或者名称。
  • source:二维数组,dimensions 中各维度对应的数据。
  • transform:负责数据转换处理,包括 filter、sort  等。
const option = {
	dataset: [
    // 原始数据 index = 0
    {
      dimensions: [...], // 二维数组
    	source: [...] // 二维数组
    },
		// 过滤后的数据 index = 1
    {
    	transform: {
      	type: 'filter',
        config: {
        	and: [
            { dimension: 'date', '>=': '2023-06', parser: 'timer' },
            { dimension: 'city', '=': '北京' }
          ]
        }
      }
    },
    // 转换后的数据可以再度转换 index = 2
    {
    	fromDatasetIndex: 1,
      transform: {...}
    }
  ],
  series: [
    {
    	type: 'line',
			// 将 1 的数据展示为折线图
      datasetIndex: 1,
    },
    {
    	type: 'bar',
      // 将 2 的数据展示为柱图
      datasetIndex: 2,
    }
  ]
}

3.2 数据可视化配置

在标准协议基础上,我们也可以将一些数据的处理工作变得可视化,可以是如左图的基于单个指标、维度的配置,也可以像右图这样基于数据结果进行配置,相对来说基于结果的配置会更简单些。

四、最后

以上是在支持数据分析产品研发过程中的一些感悟,因为前端已经有丰富的可视化组件,所以本篇文章更多是结合数据产品中的数据特色,就数据可视化中数据处理的部分,分享出来希望和大家一起进行可视化方面的探讨。