用500行纯前端代码在浏览器中营造二个Tableau

Car数据集折线图

图片 1

图片语法:

g2chart.line().position(‘id*speed’);

1
g2chart.line().position(‘id*speed’);

切换来极坐标:

图片 2

图片语法:

g2chart.line().position(‘id*speed’); g2chart.coord(‘polar’);

1
2
g2chart.line().position(‘id*speed’);
g2chart.coord(‘polar’);

 

有的事例

好了,上面大家就来看有些事例,领悟一下什么样行使图形语法来深入分析和商讨数据。

 

伯克利数据柱状图

图片 3

数量管理:

SELECT SUM(Freq) as f , Gender FROM table GROUP BY Gender

1
SELECT SUM(Freq) as f , Gender FROM table GROUP BY Gender

图表语法:

g2chart.interval().position(‘Gender*f’).color(‘Gender’).label(‘f’);

1
g2chart.interval().position(‘Gender*f’).color(‘Gender’).label(‘f’);

 

Iris数据集散点图

图片 4

图形语法:

g2chart.point().position(‘Sepal.Length*Petal.Length’).color(‘Species’).size(‘Sepal.Width’)

1
g2chart.point().position(‘Sepal.Length*Petal.Length’).color(‘Species’).size(‘Sepal.Width’)

 

数码展现

数据管理好后正是大家的主旨内容,数据显示了。

图片 5

这一步关键是选择select2提供的挑选控件创设图形语法来驱动数据显示。如上海体育地方所示,对应的G2代码图形语法为:

g2chart.facet(‘rect’, { fields: [ ‘Admit’, ‘Dept’ ], eachView(view) {
view.interval().position(‘Gender*Freq’).color(‘Gender’).label(‘Freq’);
} });

1
2
3
4
5
6
g2chart.facet(‘rect’, {
  fields: [ ‘Admit’, ‘Dept’ ],
  eachView(view) {
    view.interval().position(‘Gender*Freq’).color(‘Gender’).label(‘Freq’);
  }
});

图片语法首要涵盖以下多少个基本点的元素:

 

图片属性 Attributes

图形属性对应视觉编码中的分裂因素,大家能够参见笔者的另一博客 多少可视化中的视觉属性 。

图片属性主要有以下两种。

  1. position:地点,二维坐标系内映射至 x 轴、y 轴;
  2. color:颜色,富含了颜色、饱和度和亮度;
  3. size:大小,分化的几何标记对大小的定义有差别;
  4. shape:形状,几何标识的样子决定了有个别具体图表类型的表现方式,比方点图,能够使用圆点、三角形、图片表示;线图能够有折线、曲线、点线等表现方式;
  5. opacity:发光度,图形的反射率,这些天性从某种意义上的话能够选拔颜色代表,供给运用
    ‘rgba’ 的款型,所以在 G2 中大家独立出来。

在创设语法的时候,大家把图片属性绑定三个只怕多个数据字段。

 

Beck雷数据饼图

图片 6

数量管理:

SELECT SUM(Freq) as f , Gender FROM table GROUP BY Gender

1
SELECT SUM(Freq) as f , Gender FROM table GROUP BY Gender

图表语法:

g2chart.intervalStack().position(‘f’).color(‘Gender’).label(‘f’);
g2chart.coord(‘theta’)

1
2
g2chart.intervalStack().position(‘f’).color(‘Gender’).label(‘f’);
g2chart.coord(‘theta’)

 

数据加载

率先步是加载数据:

图片 7

数据加载首要利用了多个库:

  • axios  基于Promise的HTTP客户端
  • alasql 基于JS的开源SQL数据库
  • jquery datatable JQuery的数目表格插件

数据通过自身存放在GitHub中的csv格式的公文,以REST央求的艺术来加载。下边包车型客车代码把Axios的Promise产生async/wait形式。

// Ajax async request const request = { get: url => { return new
Promise((resolve, reject) => { axios .get(url) .then(response => {
resolve({ data: response.data }); }) .catch(error => { resolve({
data: error }); }); }); } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Ajax async request
const request = {
  get: url => {
    return new Promise((resolve, reject) => {
      axios
        .get(url)
        .then(response => {
          resolve({ data: response.data });
        })
        .catch(error => {
          resolve({ data: error });
        });
    });
  }
};

包装好后,咱们就足以用request.get()方法发送REST央求,获取csv文件。

let csv = await request.get(url);

1
let csv = await request.get(url);

这一步大概会遭受跨域央求的主题素材,github上的文件协助跨域。

把多少存款和储蓄在三个SQL数据库中,那样做的功利是为了下一步做多少准备的时候,能够方便的行使SQL来展开询问和解析。

JavaScript

class SqlTable { constructor(data) { this.data = data; } async
query(sql) { // following line of code does not run in full page view
due to security concern. // const query_str =
sql.replace(/(?<=FROM\s+)\w+/, “CSV(?)”); const query_str =
sql.replace(“table”, “CSV(?)”); return await alasql.promise(query_str,
[this.data]); } }

1
2
3
4
5
6
7
8
9
10
11
12
class SqlTable {
  constructor(data) {
    this.data = data;
  }
 
  async query(sql) {
    // following line of code does not run in full page view due to security concern.
    // const query_str = sql.replace(/(?<=FROM\s+)\w+/, "CSV(?)");
    const query_str = sql.replace("table", "CSV(?)");
    return await alasql.promise(query_str, [this.data]);
  }
}

SqlTable是贰个对数据表的卷入,把csv数据存在SQL数据库表中,提供三个query()方法。这里要做的是把SQL查询个从 “SELECT
* FROM table” 变成 “SELECT * FROM CSV(?)”
表示查询参数是CSV数据。因为codepen的安全性限制,运维前向找寻的replace语句(这里的regex表示把后面是“FROM
”词的交替为CSV(?)的)在full page
view下是不可能实践的,所以笔者用了一个更轻便的借使,用户的表名便是table,这样做有非常多标题,大家若是在codepen之外的境遇,能够用注释掉的代码。

然后把”SELECT * FROM table”的询问结果(JSON Array)用datatable来展现。

function sanitizeData(jsonArray) { let newKey;
jsonArray.forEach(function(item) { for (key in item) { newKey =
key.replace(/s/g, “”).replace(/./g, “”); if (key != newKey) {
item[newKey] = item[key]; delete item[key]; } } }); return
jsonArray; } function displayData(tableId, data) { // tricky to clone
array let display_data = JSON.parse(JSON.stringify(data));
display_data = sanitizeData(display_data); let columns = []; for
(let item in display_data[0]) { columns.push({ data: item, title:
item }); } $(“#” + tableId).DataTable({ data: display_data, columns:
columns, destroy: true }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function sanitizeData(jsonArray) {
  let newKey;
  jsonArray.forEach(function(item) {
    for (key in item) {
      newKey = key.replace(/s/g, "").replace(/./g, "");
      if (key != newKey) {
        item[newKey] = item[key];
        delete item[key];
      }
    }
  });
  return jsonArray;
}
 
function displayData(tableId, data) {
  // tricky to clone array
  let display_data = JSON.parse(JSON.stringify(data));
  display_data = sanitizeData(display_data);
  let columns = [];
  for (let item in display_data[0]) {
    columns.push({ data: item, title: item });
  }
  $("#" + tableId).DataTable({
    data: display_data,
    columns: columns,
    destroy: true
  });
}

这一步有两点要注意:

  1. 多少中,借使列的名字中有隐含点,空格等字符,举例Iris数据汇总的Sepal.Length,datatable是心余力绌符合规律呈现的,这里要调用sanitizeData()方法把列名,也正是JsonArray中Json对象的属性名中的点和空格去掉。
  2. sanitizeData()方法会退换输入对象,所以在传诵此前做了一个深度拷贝,这里运用JSON的stringfy和parse方法能够对JSON包容的指标有效的正片。

此间要专注,Iris数据汇总在datatable中的列名都不彰显点,但骨子里数目并不曾变动。

 

用500行纯前端代码在浏览器中创设二个Tableau

2018/05/16 · 基础技艺 ·
BI,
Tableau,
数码可视化

初稿出处: 用500行纯前端代码在浏览器中营造二个Tableau。naughty   

在Gartner最新的对商务智能软件的专门的工作深入分析报告中,Tableau持续领跑。Microsoft因为PowerBI表现优良也高居领导者象限。而现在的公司管理者像SAP,SAS,IBM,MicroStrategy等慢慢被拉开了异样。

图片 8

Tableau因为其心灵手巧,特出的数目表现已经成为BI领域里确实的领头羊。而其数据驱动的可视化和大旨绪想是来自于Leland
Wilkinson的The
Grammar Of
Graphics ,
无差异于遭到该思考熏陶的还或者有奥迪Q5的图形库ggplot。

图片 9

用500行纯前端代码在浏览器中营造二个Tableau。在数量可视化开源领域里,大家对百度开采的echarts可谓耳闻则诵,echarts经过日久天长的进化,其成效确实非常壮大,可用非凡来描写。但是蚂蚁金服开源的依附The
Grammar Of
Graphics
的语法驱动的可视化库G2,令人改头换面。这我们就看看哪些行使G2和500行左右的纯前端代码来促成三个的好像Tableau的数码深入分析效益。

  • 演示参见 
  • 代码参见 https://gist.github.com/gangtao/e053cf9722b64ef8544afa371c2daaee用500行纯前端代码在浏览器中营造二个Tableau。 

用500行纯前端代码在浏览器中营造二个Tableau。 

总结

正文分享了一个行使纯前端技艺营造一个临近Tableau的BI应用的例子,整个代码总计:

  • JS 370 行 JS6
  • HTML 69 + 9 + 5 = 83
  • CSS 21

总计474
行,用如此少的代码就能够做到二个看起来尚可的BI工具,还算不错啊。当然这里最主借使由于开源社区提供了这样多好的前端库以供应用,小编要做的独自是让它们有效的劳作在一起。这几个只可以算是个原型,从成效和质感上的话都不成熟,可是能在浏览器中不正视任何的服务器来贯彻BI的数额剖析成效,应该会有许五人想要在协调的选拔中嵌二个吗?

整合本身事先分享的TensorflowJS的文章,下边一步也许是加盟预测效果,为数据深入分析参预智能,前端选择的前景,不可捉摸!

 

几何标识 Geometry

几何标识概念了利用什么的几何图形来表征数据。G2现在帮助如下这一个几何标识:

geom 类型 描述
point 点,用于绘制各种点图。
path 路径,无序的点连接而成的一条线,常用于路径图的绘制。
line 线,点按照 x 轴连接成一条线,构成线图。
area 填充线图跟坐标系之间构成区域图,也可以指定上下范围。
interval 使用矩形或者弧形,用面积来表示大小关系的图形,一般构成柱状图、饼图等图表。
polygon 多边形,可以用于构建色块图、地图等图表类型。
edge 两个点之间的链接,用于构建树图和关系图中的边、流程图中的连接线。
schema 自定义图形,用于构建箱型图(或者称箱须图)、蜡烛图(或者称 K 线图、股票图)等图表。
heatmap 用于热力图的绘制。

此间要留意,intervalstack是合法支持的,然而文书档案未有提到,在读书G2的API文书档案的时候,小编也意识文书档案讲的不是很掌握,有广大地点没有讲领会哪些运用API。那也是开源软件值得立异的地点。

 

数据图谋

多少加载完结,大家来到第二步的数据计划阶段。数据策动是数码正确项目最花时间的一步,平常要求对数码实行多量的涤荡,变形,收取等专门的学业,使得数据变得可用。

在这一步我们做了两件事:

一是体现数据的二个摘要,让大家初始询问多少的轮廓,为更为的多寡变形和拍卖做好计划。

本条是Iris数据集的摘要:

图片 10

function isString(o) { return typeof o == “string” || (typeof o ==
“object” && o.constructor === String); } function summaryData(data) {
let summary = {}; summary.count = data.length; summary.fields = [];
for (let p in data[0]) { let field = {}; field.name = p; if (
isString(data[0][用500行纯前端代码在浏览器中营造二个Tableau。p]) ) { field.type = “string”; } else { field.type
= “number”; } summary.fields.push(field); } for (let f of
summary.fields) { if ( f.type == “number” ) { f.max = d3.max(data, x
=> x[f.name]); f.min = d3.min(data, x => x[f.name]); f.mean =
d3.mean(data, x => x[f.name]); f.median = d3.median(data, x =>
x[f.name]); f.deviation = d3.deviation(data, x => x[f.name]); }
else { f.values = Array.from(new Set(data.map(x => x[f.name]))); }
} return summary; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function isString(o) {
    return typeof o == "string" || (typeof o == "object" && o.constructor === String);
}
 
function summaryData(data) {
  let summary = {};
  summary.count = data.length;
  summary.fields = [];
  for (let p in data[0]) {
    let field = {};
    field.name = p;
    if ( isString(data[0][p]) ) {
      field.type = "string";
    } else {
      field.type = "number";
    }
    summary.fields.push(field);
  }
  
  for (let f of summary.fields) {
      if ( f.type == "number" ) {
        f.max = d3.max(data, x => x[f.name]);
        f.min = d3.min(data, x => x[f.name]);
        f.mean = d3.mean(data, x => x[f.name]);
        f.median = d3.median(data, x => x[f.name]);
        f.deviation = d3.deviation(data, x => x[f.name]);
      } else {
        f.values = Array.from(new Set(data.map(x => x[f.name])));
      }
  }
  return summary;
}

这里我们选用多少的种类判别出每一个字段是数值型依然字符型。对于字符型的字段,我们应用JS6的Set来获得全部的Unique数据。对于数值型,大家选拔d3的max,min,mean,median,deviation方法总计出相应的最大值,最小值,平平均数量,中位数和偏差。

另三个正是使用SQL查询来对数据开始展览进一步的加工。

图片 11

上海体育场所的事例中大家使用限制条件获得七个Iris数据的子集。

其它G2还提供了Dataset的功能:

  • 源数据的深入分析,将csv, dsv,geojson
    转成规范的JSON,查看Connector
  • 加工数据,包涵 filter,map,fold(补多少)
    等操作,查看 Transform
  • 总结函数,汇总计算、百分比、封箱
    等计算函数,查看 Transform
  • 新鲜数据管理,包罗 地理数据、矩形树图、桑基图、文字云
    的数目管理,查看 Transform

数码处理是一个十分大的话题,我们的靶子是选用尽或许少的代码完结贰个数量分析的工具,所以这一步仅仅是应用alasql提供的SQL查询来处理多少。

 

分面 Facet

分面,将一份数据依照有些维度分隔成多少子集,然后创立三个图片的矩阵,将每三个数据子集绘制到图片矩阵的窗格中。分面其实提供了三个作用:

  1. 服从钦赐的维度划分数据集;
  2. 对图片举办排版。

G2协理以下的分面类型:

分面类型 说明
rect 默认类型,指定 2 个维度作为行列,形成图表的矩阵。
list 指定一个维度,可以指定一行有几列,超出自动换行。
circle 指定一个维度,沿着圆分布。
tree 指定多个维度,每个维度作为树的一级,展开多层图表。
mirror 指定一个维度,形成镜像图表。
matrix 指定一个维度,形成矩阵分面。

小心,在自家的代码中,为了简化使用,只协理list和rect,当绑定一个字段的时候用list,绑定三个字段的时候用rect。

除却上面提到的要素,当然还会有众多别样的成分我们从没包蕴和支撑,举个例子:坐标轴,图例,提醒等等。

有关图形的语法的越多内容,请参见这里。

变动图形语法的为主代码如下:

function getFacet(faced, grammarScript) { let facedType = “list”; let
facedScript = “” grammarScript =
grammarScript.replace(chartScriptName,”view”); if ( faced.length == 2 )
{ facedType = “rect”; } let facedFields = faced.join(“‘, ‘”) facedScript
= facedScript + `${ chartScriptName }.facet(‘${ facedType }’, {n`;
facedScript = facedScript + ` fields: [ ‘${ facedFields }’ ],n`;
facedScript = facedScript + ` eachView(view) {n`; facedScript =
facedScript + ` ${ grammarScript };n`; facedScript = facedScript + `
}n`; facedScript = facedScript + `});n`; return facedScript }
function getGrammar() { let grammar = {}, grammarScript =
chartScriptName + “.”; grammar.geom = $(‘#geomSelect’).val();
grammar.coord = $(‘#coordSelect’).val(); grammar.faced =
$(‘#facetSelect’).val(); geom_attributes.map(function(attr){
grammar[attr] = $(‘#’ + attr + “attr”).val(); }); grammarScript =
grammarScript + grammar.geom + “()”;
geom_attributes.map(function(attr){ if (grammar[attr].length > 0)
{ grammarScript = grammarScript + “.” + attr + “(‘” +
grammar[attr].join(“*”) + “‘)”; } }); if (grammar.coord) {
grammarScript = grammarScript + “;n ” + chartScriptName + “.” +
“coord(‘” + grammar.coord + “‘);”; } else { rammarScript = grammarScript

  • “;”; } if ( grammar.faced ) { if ( grammar.faced.length == 1 ||
    grammar.faced.length == 2 ) { grammarScript = getFacet(grammar.faced,
    grammarScript); } } console.log(grammarScript) return grammarScript; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function getFacet(faced, grammarScript) {
  let facedType = "list";
  let facedScript = ""
  grammarScript = grammarScript.replace(chartScriptName,"view");
  if ( faced.length == 2 ) {
      facedType = "rect";
  }
  let facedFields = faced.join("’, ‘")
  facedScript = facedScript + `${ chartScriptName }.facet(‘${ facedType }’, {n`;
  facedScript = facedScript + `  fields: [ ‘${ facedFields }’ ],n`;
  facedScript = facedScript + `  eachView(view) {n`;
  facedScript = facedScript + `    ${ grammarScript };n`;
  facedScript = facedScript + `  }n`;
  facedScript = facedScript + `});n`;
  return facedScript
}
 
function getGrammar() {
  let grammar = {}, grammarScript = chartScriptName + ".";
  grammar.geom = $(‘#geomSelect’).val();
  grammar.coord = $(‘#coordSelect’).val();
  grammar.faced = $(‘#facetSelect’).val();
  geom_attributes.map(function(attr){
    grammar[attr] = $(‘#’ + attr + "attr").val();
  });
  
  grammarScript = grammarScript + grammar.geom + "()";
  geom_attributes.map(function(attr){
    if (grammar[attr].length > 0) {
      grammarScript = grammarScript + "." + attr + "(‘" + grammar[attr].join("*") + "’)";
    }
  });
  
  if (grammar.coord) {
    grammarScript = grammarScript + ";n " + chartScriptName + "." + "coord(‘" + grammar.coord + "’);";
  } else {
    rammarScript = grammarScript + ";";
  }
  
  if ( grammar.faced ) {
    if ( grammar.faced.length == 1 ||
        grammar.faced.length == 2 ) {
      grammarScript = getFacet(grammar.faced, grammarScript);
    }
  }
  
  console.log(grammarScript)
  return grammarScript;
}

此处有几点要专注:

  • 选用JS的模板字符串能够使得的结构代码片段
  • 运用eval实践组织好的语法驱动的代码来响应select的change事件,以赢得可观的交互性。在生养条件,要专注该方式的安全性隐患,因为纯前端,eval能拉动的勒迫极小,生产中,可以把这几个实践放在安全的沙箱中运维
  • 你须要掌握图形语法,并不是随便的组合都能使得出可行的图形。

此地对于select2的多选,有叁个小的提示,在缺省气象下,多选的一一是定点的各样,并不借助选择的逐一,然则相当多图形语法和字段的依次有关,所以我们运用如下的法子来对号入座select的选用事件。

function updateSelect2Order(evt) { let element =
evt.params.data.element; let $element = $(element); $element.detach();
$(this).append($element); $(this).trigger(“change”); }

1
2
3
4
5
6
7
function updateSelect2Order(evt) {
  let element = evt.params.data.element;
  let $element = $(element);
  $element.detach();
  $(this).append($element);
  $(this).trigger("change");
}

如此那般做就是历次选中后,把这段时间选中的花色移到数码最后的岗位。

 

Beck雷数据分面的应用

图片 12

图形语法:

g2chart.facet(‘rect’, { fields: [ ‘Dept’, ‘Admit’ ], eachView(view) {
view.coord(‘theta’);
view.intervalStack().position(‘Freq’).color(‘Gender’); } });

1
2
3
4
5
6
7
g2chart.facet(‘rect’, {
  fields: [ ‘Dept’, ‘Admit’ ],
  eachView(view) {
    view.coord(‘theta’);
    view.intervalStack().position(‘Freq’).color(‘Gender’);
  }
});

更加多的辨析图形留给大家去尝试

 

参考

  • axios  基于Promise的HTTP客户端
  • alasql 基于JS的开源SQL数据库
  • jquery datatable JQuery的数额表格插件
  • select2 JQuery的精选控件插件
  • 连锁博客 行使开源软件连忙搭建数据深入分析平台 
  • 连锁博客 数码可视化中的视觉属性

    2 赞 1 收藏
    评论

图片 13

坐标系 Coordinates

坐标系是将二种职位标度结合在一块儿组成的
2 维定位系统,描述了数码是何许映射到图片所在的平面。

G2提供了以下二种坐标系:

coordType 说明
rect 直角坐标系,目前仅支持二维,由 x, y 两个互相垂直的坐标轴构成。
polar 极坐标系,由角度和半径 2 个维度构成。
theta 一种特殊的极坐标系,半径长度固定,仅仅将数据映射到角度,常用于饼图的绘制。
helix 螺旋坐标系,基于阿基米德螺旋线。

 

Beck雷数据堆成堆柱状图

图片 14

数码管理:

SELECT SUM(Freq) as f , Gender , Admit FROM table GROUP BY Gender, Admit

1
SELECT SUM(Freq) as f , Gender , Admit FROM table GROUP BY Gender, Admit

图片语法:

g2chart.intervalStack().position(‘Gender*f’).color(‘Admit’)

1
g2chart.intervalStack().position(‘Gender*f’).color(‘Admit’)

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注