VTable 多维数据的表格展示原理揭秘——基于HTML5 Canvas

多维表格介绍

多维表格又名透视表、交叉表、Pivot Table,指的是可以在行维度和列维度放入一个或多个维度,显示维度之间相互关系的一种表格。用户可以一目了然地分析出各种场景指标以及对比,旨在帮助业务分析推动决策。

假设需要分析如下表格所示的销售数据:

在对这样的表数据进行分析时,不同的数据分析师或者不同角色都会基于自己感兴趣的业务角度提出相关的问题,比如:有人关心各个地区的销售额,希望找出销售情况较低的地区;有人需要了解近期内不同产品类别的销售额对比,便于做后期的产品研发······

这些问题中的业务角度,比如地区、类别、时间年份就是维度,"销售额"就是指标。

多维表格概念

理解 BI 多维分析中的几个核心概念:

  • 维度:用来对数据进行分类和人们观察业务情况的角度;
  • 维度的层次 :根据维度细节程度不同,划分出来的一类属性,是维度预先定义的不同级别。例如,日期维度的层次包括年、月、日;地区维度的层次包括:国家、省份、城市;维度层次各级别也都属于维度,但维度成员之间具有一定的关系,一般在分析中常作为钻取的方向。
  • 维度成员:是各维度上数据项的取值,即维度值。例如,日期维度的层次月的维度成员有:1月、2月、3月等,地区的成员有:东北,华北,华中等;
  • 指标:用来描述业务情况的数据,例如,销售额、成本、利润等度量值。

在多维分析表中如何展示维度 的呢?下图中一共有四个业务维度:地区省份年份季度,看数指标:销售额利润

针对图中销售数据,位置在单元格[5, 5],即列5行5的数据:代表了2016年Q2季度下东北地区黑龙江省的销售利润值。也就是对应到行维度值:['东北', '黑龙江'],列维度:['2016', '2016-Q2'],指标:'利润'。接下来将介绍如何用VTable实现这种多维表格。

VTable实现多维表格

概念映射到配置项

上图透视表的配置如下:

less 复制代码
const option={
  rows:['region','province'], //行维度
  columns:['year','quarter'], //列维度
  indicators:['sales','profit'], //指标
  records:[ //数据源
    {
      region:'东北',
      province:'黑龙江',
      year:'2016',
      quarter:'2016-Q1',
      sales:1243,
      profit:546
    },
    ...
  ]
}

该配置是多维表格最简配置。随着对功能要求的复杂性可以针对各功能点来添加各项配置来满足需求。

数据分析相关配置:

| 配置项 | 类型 | 描述 |
|----------------------------------|----------------------|----------------|----------------------|
| rows | string[] | IDimension[] | 行维度字段数组,用于解析出对应的维度成员 |
| columns | string[] | IDimension[] | 列维度字段数组,用于解析出对应的维度成员 |
| indicators | string[] | IIndicator[] | 具体展示指标 |
| dataConfig.aggregationRules | aggregationRule[] | 按照行列维度聚合值计算规则 |
| dataConfig.derivedFieldRules | DerivedFieldRule[] | 派生字段 |
| dataConfig.sortRules | sortRule[] | 排序规则 |
| dataConfig.filterRules | filterRule[] | 过滤规则 |
| dataConfig.totals | totalRule[] | 小计或总计 |

dataConfig配置定义:

arduino 复制代码
/**
 * 数据处理配置
 */
export interface IDataConfig {
  aggregationRules?: AggregationRules; //按照行列维度聚合值计算规则;
  sortRules?: SortRules; //排序规则;
  filterRules?: FilterRules; //过滤规则;
  totals?: Totals; //小计或总计;
  derivedFieldRules?: DerivedFieldRules; //派生字段定义
  ...
}

dataConfig 应用举例:

数据汇总规则

具体示例:visactor.io/vtable/demo...

yaml 复制代码
dataConfig: {
      totals: {
        row: {
          showGrandTotals: true,
          showSubTotals: true,
          subTotalsDimensions: ['province'],
          grandTotalLabel: '行总计',
          subTotalLabel: '小计'
        },
        column: {
          showGrandTotals: true,
          showSubTotals: true,
          subTotalsDimensions: ['quarter'],
          grandTotalLabel: '列总计',
          subTotalLabel: '小计'
        }
      }
    },

排序规则

具体示例:visactor.io/vtable/demo...

css 复制代码
      sortRules: [
        {
          sortField: 'city',
          sortByIndicator: 'sales',
          sortType: VTable.TYPES.SortType.DESC,
          query: ['办公用品', '笔']
        } as VTable.TYPES.SortByIndicatorRule
      ]
   

过滤数据

具体示例:visactor.io/vtable/demo...

csharp 复制代码
filterRules: [
        {
          filterFunc: (record: Record<string, any>) => {
            return record.province !== '四川省' || record.category !== '家具';
          }
        }
      ]

聚合方式

具体示例:visactor.io/vtable/demo...

arduino 复制代码
    aggregationRules: [
        //做聚合计算的依据,如销售额如果没有配置则默认按聚合sum计算结果显示单元格内容
        {
          indicatorKey: 'TotalSales', //指标名称
          field: 'Sales', //指标依据字段
          aggregationType: VTable.TYPES.AggregationType.SUM, //计算类型
          formatFun: sumNumberFormat
        },
        {
          indicatorKey: 'OrderCount', //指标名称
          field: 'Sales', //指标依据字段
          aggregationType: VTable.TYPES.AggregationType.COUNT, //计算类型
          formatFun: countNumberFormat
        },
        {
          indicatorKey: 'AverageOrderSales', //指标名称
          field: 'Sales', //指标依据字段
          aggregationType: VTable.TYPES.AggregationType.AVG, //计算类型
          formatFun: sumNumberFormat
        }
      ]

派生字段

具体示例:visactor.io/vtable/demo...

css 复制代码
  derivedFieldRules: [
      {
        fieldName: 'Year',
        derivedFunc: VTable.DataStatistics.dateFormat('Order Date', '%y', true),
      },
      {
        fieldName: 'Month',
        derivedFunc: VTable.DataStatistics.dateFormat('Order Date', '%n', true),
      }
    ]

数据分析过程

依赖配置:维度,指标及dataConfig。

遍历数据的流程:

遍历一遍records,解析出行列表头维度值用于展示表头单元格,将records中所有数据分配到对应的行列路径集合中并计算出body部分指标单元格的聚合值。

数据维度tree

根据上述遍历的结构,将产生一棵维度树,从这棵树可以查找到单元格的值及值的原始数据条目。

经过对record分组聚合的分析计算,最终呈现到表格中单元格数据和records数据源的对应关系:

自定义维度树

虽然具有分析能力的多维表格可以自动分析各个维度的维度值组成行列表头的树形结构,并且可以根据dataConfig.sortRules进行排序,但具有复杂业务逻辑的场景还是期望可以能够自定义行列表头维度值及其顺序。那么可以通过rowTree和columnTree来实现这些业务需求场景。

自定义树的配置详情:

yaml 复制代码
const option = {
    rowTree: [{
        dimensionKey: 'region',
        value: '中南',
        children: [
            {
                dimensionKey: 'province',
                value: '广东',
            },
            {
                dimensionKey: 'province',
                value: '广西',
            }
        ]
    },
    {
        dimensionKey: 'region',
        value: '华东',
        children: [
            {
                dimensionKey: 'province',
                value: '上海',
            },
            {
                dimensionKey: 'province',
                value: '山东',
            }
        ]
    }],
    columnTree: [{
        dimensionKey: 'year',
        value: '2016',
        children: [
            {
                dimensionKey: 'quarter',
                value: '2016-Q1',
                children: [
                    {
                        indicatorKey: 'sales',
                        value: 'sales'
                    },
                    {
                        indicatorKey: 'profit',
                        value: 'profit'
                    }
                ]
            },
            {
                dimensionKey: 'quarter',
                value: '2016-Q2',
                children: [
                    {
                        indicatorKey: 'sales',
                        value: 'sales'
                    },
                    {
                        indicatorKey: 'profit',
                        value: 'profit'
                    }
                ]
            }
        ]
    }],
    indicators: ['sales', 'profit'],
    //enableDataAnalysis:true,
    corner: {
        titleOnDimension: 'none'
    },
    records: [
        {
            region: '中南',
            province: '广东',
            year: '2016',
            quarter: '2016-Q1',
            sales: 1243,
            profit: 546
        },
        {
            region: '中南',
            province: '广东',
            year: '2016',
            quarter: '2016-Q2',
            sales: 2243,
            profit: 169
        }, {
            region: '中南',
            province: '广西',
            year: '2016',
            quarter: '2016-Q1',
            sales: 3043,
            profit: 1546
        },
        {
            region: '中南',
            province: '广西',
            year: '2016',
            quarter: '2016-Q2',
            sales: 1463,
            profit: 609
        },
        {
            region: '华东',
            province: '上海',
            year: '2016',
            quarter: '2016-Q1',
            sales: 4003,
            profit: 1045
        },
        {
            region: '华东',
            province: '上海',
            year: '2016',
            quarter: '2016-Q2',
            sales: 5243,
            profit: 3169
        }, {
            region: '华东',
            province: '山东',
            year: '2016',
            quarter: '2016-Q1',
            sales: 4543,
            profit: 3456
        },
        {
            region: '华东',
            province: '山东',
            year: '2016',
            quarter: '2016-Q2',
            sales: 6563,
            profit: 3409
        }
    ]
};

最终效果如:

VTable官网示例:visactor.io/vtable/demo...

自定义树的复杂在于组建行列维度树,可酌情根据业务场景来选择使用,如果具有复杂的排序、汇总或分页规则可选择使用自定义方式。

注意选择自定义树的配置方式将没有数据聚合能力,即匹配到的数据条目中的某一条即作为单元格指标值。

业务场景配置示例

下面介绍几个常见需求配置内容:

  1. 需求: 不同指标设置不同格式

配置方式: 为指标设置不同的cellType。具体示例代码:codesandbox.io/s/vtable-pi...

  1. 需求: 不同维度设置不同字号,行维度的region维度值设置字号为20,province维度值设置字号为16。

配置方式: 可以通过在对应维度的headerStyle中配置样式来实现。

  1. 需求: 角头配置显示行维度名称。

配置方式: 默认角头会显示列维度columns中的维度名,如果想以行维度的维度名显示在角头,配置titleOnDimension为row。

  1. 需求: 趋势分析表------展示不同时间段的销售情况和同环比及趋势图

配置方式: 将其中某一个指标cellType设置为'sparkline',对于图表趋势可以使用icon进行配置

示例地址: visactor.io/vtable/demo...

  1. 需求: 表格中集成图表来更形象的表达数据

    1. 配置方式: indicator指标的cellType设置为'chart'
    2. 示例地址: visactor.io/vtable/demo...
  1. 需求: 透视组合图,分维度分指标综合看数据分布和趋势

    1. 配置方式: 使用表格类型PivotChart,indicator指标的cellType设置为'chart'
    2. 示例地址: visactor.io/vtable/demo...

VTable 可以无缝集成VChart,将 VChart的图表类型作为单元格的元素类型进行渲染,极大的提升 了表格的可视化表现力。同时,也为解决单页面多图表渲染的性能问题提供了新的解决方案。

欢迎交流

联系方式

项目官网:www.visactor.io/vtable

微信公众号(通过公众号菜单可以加入微信群和飞书群):

今夜无月,期待你点亮星空,感谢Star:

githubgithub.com/VisActor/VT...

更多参考:

  1. VTable------不只是高性能的多维数据分析表格,开源,免费,百万数据秒级渲染
  2. VisActor------面向叙事的智能可视化解决方案 - 掘金
  3. 火山引擎DataWind产品可视化能力揭秘 - 掘金
  4. 更多 VTable 示例
相关推荐
AntDreamer9 小时前
在实际开发中,如何根据项目需求调整 RecyclerView 的缓存策略?
android·java·缓存·面试·性能优化·kotlin
B站计算机毕业设计超人14 小时前
计算机毕业设计Python+Flask微博情感分析 微博舆情预测 微博爬虫 微博大数据 舆情分析系统 大数据毕业设计 NLP文本分类 机器学习 深度学习 AI
爬虫·python·深度学习·算法·机器学习·自然语言处理·数据可视化
Book_熬夜!1 天前
Python基础(六)——PyEcharts数据可视化初级版
开发语言·python·信息可视化·echarts·数据可视化
黑狼传说1 天前
前端项目优化:极致最优 vs 相对最优 —— 深入探索与实践
前端·性能优化
Lill_bin1 天前
Lua编程语言简介与应用
开发语言·数据库·缓存·设计模式·性能优化·lua
字节跳动数据平台2 天前
火山引擎数智平台:高性能ChatBI的技术解读和落地实践
大数据·大模型·数据可视化·bi
人工智能培训咨询叶梓2 天前
MobiLlama,面向资源受限设备的轻量级全透明GPT模型
人工智能·gpt·语言模型·自然语言处理·性能优化·多模态·轻量级
William数据分析2 天前
[Python数据可视化] Plotly:交互式数据可视化的强大工具
python·数据分析·数据可视化
Flying_Fish_roe3 天前
JVM 性能优化与调优-ZGC(Z Garbage Collector)
jvm·性能优化
Flying_Fish_roe3 天前
JVM 性能优化与调优-GraalVM
jvm·性能优化