日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

用500行纯前端代码在浏览器中构建一个Tableau

發布時間:2024/1/17 HTML 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用500行纯前端代码在浏览器中构建一个Tableau 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

在Gartner最新的對商務智能軟件的專業分析報告中,Tableau持續領跑。Microsoft因為PowerBI表現出色也處于領導者象限。而昔日的領導者像SAP,SAS,IBM,MicroStrategy等逐漸被拉開了差距。

Tableau因為其靈活,出色的數據表現已經成為BI領域里無可爭議的領頭羊。而其數據驅動的可視化和核心思想是來自于Leland Wilkinson的The Grammar Of Graphics?,同樣受到該思想影響的還有R的圖形庫ggplot。

在數據可視化開源領域里,大家對百度開發的echarts可謂耳熟能詳,echarts經過多年的發展,其功能確實非常強大,可用出色來形容。但是螞蟻金服開源的基于The Grammar Of Graphics的語法驅動的可視化庫G2,讓人眼前一亮。那我們就看看如何利用G2和500行左右的純前端代碼來實現一個的類似Tableau的數據分析功能。

  • 演示參見?https://codepen.io/gangtao/full/OZvedx/
  • 代碼參見?https://gist.github.com/gangtao/e053cf9722b64ef8544afa371c2daaee?

數據加載

第一步是加載數據:

數據加載主要用到了三個庫:

  • 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 });});});} };

封裝好后,我們就可以用request.get()方法發送REST請求,獲取csv文件。

let csv = await request.get(url);

這一步可能會遇到跨域請求的問題,github上的文件支持跨域。

把數據存儲在一個SQL數據庫中,這樣做的好處是為了下一步做數據準備的時候,可以方便的利用SQL來進行查詢和分析。

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 arraylet 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}); }

這一步有兩點要注意:

  • 數據中,如果列的名字中有包含點,空格等字符,例如Iris數據集中的Sepal.Length,datatable是無法正常顯示的,這里要調用sanitizeData()方法把列名,也就是JsonArray中Json對象的屬性名中的點和空格去掉。
  • sanitizeData()方法會改變輸入對象,所以在傳入之前做了一個深度拷貝,這里利用JSON的stringfy和parse方法可以對JSON兼容的對象有效的拷貝。
  • 這里要注意,Iris數據集中在datatable中的列名都不顯示點,但實際數據并沒有改變。

    數據準備

    數據加載完畢,我們來到第二步的數據準備階段。數據準備是數據科學項目最花時間的一步,通常需要對數據進行大量的清洗,變形,抽取等工作,使得數據變得可用。

    在這一步我們做了兩件事:

    一是顯示數據的一個摘要,讓我們初步了解數據的概貌,為進一步的數據變形和處理做好準備。

    這個是Iris數據集的摘要:

    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查詢來對數據進行進一步的加工。

    上圖的例子中我們利用限制條件得到一個Iris數據的子集。

    另外G2還提供了Dataset的功能:

    • 源數據的解析,將csv, dsv,geojson 轉成標準的JSON,查看Connector
    • 加工數據,包括 filter,map,fold(補數據) 等操作,查看?Transform
    • 統計函數,匯總統計、百分比、封箱 等統計函數,查看?Transform
    • 特殊數據處理,包括 地理數據、矩形樹圖、桑基圖、文字云 的數據處理,查看?Transform

    數據處理是一個比較大的話題,我們的目標是利用盡可能少的代碼完成一個數據分析的工具,所以這一步僅僅是利用alasql提供的SQL查詢來處理數據。

    數據展示

    數據處理好后就是我們的核心內容,數據展示了。

    這一步主要是利用select2提供的選擇控件構建圖形語法來驅動數據展示。如上圖所示,對應的G2代碼圖形語法為:

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

    圖形語法主要包含以下幾個主要的元素:

    幾何標記?Geometry

    幾何標記定義了使用什么樣的幾何圖形來表征數據。G2現在支持如下這些幾何標記:

    geom 類型描述
    point點,用于繪制各種點圖。
    path路徑,無序的點連接而成的一條線,常用于路徑圖的繪制。
    line線,點按照 x 軸連接成一條線,構成線圖。
    area填充線圖跟坐標系之間構成區域圖,也可以指定上下范圍。
    interval使用矩形或者弧形,用面積來表示大小關系的圖形,一般構成柱狀圖、餅圖等圖表。
    polygon多邊形,可以用于構建色塊圖、地圖等圖表類型。
    edge兩個點之間的鏈接,用于構建樹圖和關系圖中的邊、流程圖中的連接線。
    schema自定義圖形,用于構建箱型圖(或者稱箱須圖)、蠟燭圖(或者稱 K 線圖、股票圖)等圖表。
    heatmap用于熱力圖的繪制。

    這里要注意,intervalstack是官方支持的,但是文檔沒有提到,在閱讀G2的API文檔的時候,我也發現文檔講的不是很清楚,有很多地方沒有講清楚如何使用API。這也是開源軟件值得改進的地方。

    圖形屬性 Attributes

    圖形屬性對應視覺編碼中的不同元素,大家可以參考我的另一博客?數據可視化中的視覺屬性?。

    圖形屬性主要有以下幾種。

  • position:位置,二維坐標系內映射至 x 軸、y 軸;
  • color:顏色,包含了色調、飽和度和亮度;
  • size:大小,不同的幾何標記對大小的定義有差異;
  • shape:形狀,幾何標記的形狀決定了某個具體圖表類型的表現形式,例如點圖,可以使用圓點、三角形、圖片表示;線圖可以有折線、曲線、點線等表現形式;
  • opacity:透明度,圖形的透明度,這個屬性從某種意義上來說可以使用顏色代替,需要使用 'rgba' 的形式,所以在 G2 中我們獨立出來。
  • 在構建語法的時候,我們把圖形屬性綁定一個或者多個數據字段。

    坐標系 Coordinates

    坐標系是將兩種位置標度結合在一起組成的 2 維定位系統,描述了數據是如何映射到圖形所在的平面。

    G2提供了以下幾種坐標系:

    coordType說明
    rect直角坐標系,目前僅支持二維,由 x, y 兩個互相垂直的坐標軸構成。
    polar極坐標系,由角度和半徑 2 個維度構成。
    theta一種特殊的極坐標系,半徑長度固定,僅僅將數據映射到角度,常用于餅圖的繪制。
    helix螺旋坐標系,基于阿基米德螺旋線。

    分面 Facet

    分面,將一份數據按照某個維度分隔成若干子集,然后創建一個圖表的矩陣,將每一個數據子集繪制到圖形矩陣的窗格中。分面其實提供了兩個功能:

  • 按照指定的維度劃分數據集;
  • 對圖表進行排版。
  • 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; }

    這里有幾點要注意:

    • 使用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"); }

    這樣做就是每次選中后,把當前選中的項目移到數據最后的位置。

    一些例子

    好了,下面我們就來看一些例子,了解一下如何使用圖形語法來分析和探索數據。

    Iris數據集散點圖

    圖形語法:

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

    Car數據集折線圖

    圖形語法:

    g2chart.line().position('id*speed');

    切換到極坐標:

    圖形語法:

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

    Berkeley數據柱狀圖

    數據處理:

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

    圖形語法:

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

    Berkeley數據堆疊柱狀圖

    數據處理:

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

    圖形語法:

    g2chart.intervalStack().position('Gender*f').color('Admit')

    Berkeley數據餅圖

    數據處理:

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

    圖形語法:

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

    Berkeley數據分面的應用

    圖形語法:

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

    更多的分析圖形留給大家去嘗試

    總結

    本文分享了一個利用純前端技術構建一個類似Tableau的BI應用的例子,整個代碼統計:

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

    總計474 行,用這么少的代碼就能完成一個看上去還不錯的BI工具,還算不錯吧。當然這里主要是由于開源社區提供了這么多好的前端庫以供應用,我要做的僅僅是讓它們有效的工作在一起。這個只能算是個原型,從功能和質量上來說都不成熟,但是能在瀏覽器中不借助任何的服務器來實現BI的數據分析功能,應該會有很多人想要在自己的應用中嵌一個吧?

    結合我之前分享的TensorflowJS的文章,下面一步可能是加入預測功能,為數據分析加入智能,前端應用的前景,不可限量!

    ?

    參考

    • axios? 基于Promise的HTTP客戶端
    • alasql?基于JS的開源SQL數據庫
    • jquery datatable?JQuery的數據表格插件
    • select2?JQuery的選擇控件插件
    • 相關博客?使用開源軟件快速搭建數據分析平臺?
    • 相關博客?數據可視化中的視覺屬性

    轉載于:https://my.oschina.net/taogang/blog/1811573

    總結

    以上是生活随笔為你收集整理的用500行纯前端代码在浏览器中构建一个Tableau的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 交专区videossex非洲 | 中国免费观看的视频 | 老湿机69福利区午夜x片 | 精品国产av 无码一区二区三区 | 欧美一区二区三区婷婷 | 色综合a| 国产又色又爽无遮挡免费 | 久草视频首页 | 高清在线一区 | 伊人国产女 | 欧美日韩国产电影 | 99热国产在线 | av免费播放网站 | 久久99精品久久久久子伦 | 狠狠操av | 一区二区xxx | 午夜影院免费版 | 午夜资源网 | 欧美激情三级 | 国产成人精品久久久 | 日本www网站 | 久久久亚洲av波多野结衣 | 亚洲 在线 | 久久99精品国产.久久久久久 | 日韩免费电影一区 | 日本wwwwwww | 美女视频黄a视频全免费观看 | 性调教学院高h学校 | 中文字幕av在线免费观看 | 在线中文字日产幕 | 粗大的内捧猛烈进出 | 99久久精品国产一区二区成人 | 三级小说视频 | 九九久久视频 | 男生女生操操操 | 色播视频在线观看 | 日本免费高清一区二区 | 亚洲乱码一区 | 欧美性猛交xxxx黑人交 | 国产精品国产精品 | 精品少妇一区二区三区 | 青青草免费公开视频 | 日日日日操 | 老牛影视少妇在线观看 | 国产亚洲精品久久久久久无几年桃 | 无码人妻一区二区三区在线视频 | 国产一级黄色电影 | 亚洲精品国产精华液 | 国产精品无码在线 | 国产精品日韩一区二区三区 | 国产一级片网站 | 四虎国产精品永久免费观看视频 | 极品一区| 天天干视频在线 | 久久伊人婷婷 | 新天堂av | 一级视频在线播放 | 久久91久久| 奇米网狠狠干 | 超碰最新上传 | 爱情岛论坛永久入址测速 | 福利社午夜| 欧美性猛片aaaaaaa做受 | 少妇不卡视频 | 日本中文字幕影院 | 99爱在线观看| www插插插无码免费视频网站 | 亚洲成人日韩在线 | 精品成在人线av无码免费看 | 国产美女视频一区二区 | 久青草视频 | av在线播放网站 | 欧美人交a欧美精品 | 午夜性刺激免费视频 | 四虎网址大全 | 奇米综合网| 神马午夜电影一区二区三区在线观看 | 日本一级片在线播放 | 欧美日韩一二三四区 | 荒岛淫众女h文小说 | 日韩在线一卡 | 国产一区二区在线视频观看 | mm131丰满少妇人体欣赏图 | 国产亚洲一区二区在线 | 国产精品女人精品久久久天天 | 精品视频一区二区在线观看 | 成人综合色站 | 伊人五月天 | 综合亚洲网 | 亚洲在线a | 国产精品一区二区自拍 | 亚洲国产无线乱码在线观看 | 成年在线观看视频 | 美女午夜视频 | 五月天综合网站 | 亚洲美女av网站 | 中文字幕第一页av | 中国老头同性xxxxx | 精品色哟哟 |