Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 国产片一区二区三区,亚洲国产成人久久综合一区77,亚洲精品午夜视频

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          JavaFX中TableView的CSS相關設置

          、特殊的table設置

          • TableView的單元之間去掉行橫線
          .table-view .table-row-cell {  
              -fx-background-insets: 0;  
          }  
          • TableView的單元之間去掉沒有數據的豎線
          table-row-cell:empty .table-cell {  
              -fx-border-width: 0px;  
          }  
          • TableView的單元之間去掉豎線
          table-row-cell .table-cell {  
              -fx-border-width: 0px;  
          }  
          • TableView的TableColumn的列頭設置
          .table-view .column-header{
              -fx-border-color:white lightgray white white;  
          }
          • table的空閑的列頭設置
          .table-view .filler{
               -fx-background-color: white;    
          }
          • table的列首背景設置,其中包括column-header,filler,MenuButton
          .table-view .column-header-background{   
             -fx-background-color: white;    
          }
          • table的垂直滾動條設置
          .table-view > .virtual-flow > .scroll-bar:vertical{
              -fx-background-insets: 0, 0 0 0 1;
              -fx-padding: -1 -1 -1 0;
          }
          • table的水平滾動條設置
          .table-view > .virtual-flow > .scroll-bar:horizontal{
              -fx-background-insets: 0, 1 0 0 0;
              -fx-padding: 0 -1 -1 -1;
          }
          • table的邊角設置
          .table-view > .virtual-flow > .corner {
              -fx-background-color: derive(-fx-base,-1%); /*-fx-base 是modena 預先定義的顏色*/
          }
          • 選擇一行
          .table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:selected{
              -fx-background: -fx-selection-bar;
              -fx-table-cell-border-color: derive(-fx-selection-bar, 20%);
          }
          • 當控件沒有聚焦時選擇
          .table-row-cell:filled > .table-cell:selected{
              -fx-background: -fx-selection-bar-non-focused;
              -fx-table-cell-border-color: derive(-fx-selection-bar-non-focused, 20%);
          }
          • 聚焦的單元 (鍵盤導航)
          .table-view:focused:cell-selection > .virtual-flow > .clipped-container > .sheet > .table-row-cell > .table-cell:focused{
              -fx-background-color: -fx-background, -fx-cell-focus-inner-border, -fx-background;
              -fx-background-insets: 0, 1, 2;
          }
          .table-view{
              /* Constants used throughout the tableview. */
              -fx-table-header-border-color: -fx-box-border;
              -fx-table-cell-border-color: derive(-fx-color,5%);
          }

          二、TableView tableRow編輯

          • tableRow
          /* Each row in the table is a table-row-cell. Inside a table-row-cell is any number of table-cell. */
          .table-row-cell {
              -fx-background: -fx-control-inner-background;
              -fx-background-color: -fx-table-cell-border-color, -fx-background;
              -fx-background-insets: 0, 0 0 1 0;
              -fx-padding: 0;
              -fx-text-fill: -fx-text-background-color;
          }
          • tableRow單元單數tableCell
          .table-row-cell:odd {
              -fx-background: -fx-control-inner-background-alt;
          }

          三、TableView 單元tableCell編輯

          • tableCell
          .table-cell {
              -fx-padding: 0.166667em; /* 2px, plus border adds 1px */
              -fx-background-color: null;
              -fx-border-color: transparent -fx-table-cell-border-color transparent transparent;
              -fx-cell-size: 2.0em; /* 24 */
              -fx-text-fill: -fx-text-background-color;
          }
          • tableCell選擇單元
          .table-view > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell:selected {
              -fx-background-color: -fx-table-cell-border-color, -fx-background;
              -fx-background-insets: 0, 0 0 1 0;
          }
          • tableCell最右可視單元
          /* When in constrained resize mode, the right-most visible cell should not have
             a right-border, as it is not possible to get this cleanly out of view without
             introducing horizontal scrollbars (see RT-14886). */
          .table-view:constrained-resize > .virtual-flow > .clipped-container > .sheet > .table-row-cell > .table-cell:last-visible {
              -fx-border-color: transparent;
          }

          四、TableView列頭編輯

          • TableView列大小重新調整線
          /* The column-resize-line is shown when the user is attempting to resize a column. */
          .table-view .column-resize-line {
              -fx-background: -fx-accent;
              -fx-background-color: -fx-background;
              -fx-padding: 0.0em 0.0416667em 0.0em 0.0416667em; /* 0 0.571429 0 0.571429 */
          }
          • TableView列頭背景
          /* This is the area behind the column headers. An ideal place to specify background
             and border colors for the whole area (not individual column-header's). */
          .table-view .column-header-background{
              -fx-background-color: -fx-inner-border, -fx-body-color;
              -fx-background-insets: 0, 1;
          }
          • TableView列頭行設置背景
          /* The column header row is made up of a number of column-header, one for each
             TableColumn, and a 'filler' area that extends from the right-most column
             to the edge of the tableview, or up to the 'column control' button. */
          .table-view .column-header,
          .table-view .filler,
          .table-view > .column-header-background > .show-hide-columns-button,
          .table-view:constrained-resize .filler{
              -fx-background-color: -fx-box-border, -fx-inner-border, -fx-body-color;
              -fx-background-insets: 0, 0 1 1 0, 1 2 2 1;
              -fx-font-weight: bold;
              -fx-size: 2em;
              -fx-text-fill: -fx-selection-bar-text;
              -fx-padding: 0.166667em;
          }
          • TableView空閑列
          .table-view .filler,
          .table-view:constrained-resize .filler{
              -fx-background-insets: 0, 0 0 1 0, 1 1 2 1;
          }
          • TableView列頭展示隱藏列按鈕
          .table-view > .column-header-background > .show-hide-columns-button {
              -fx-background-insets: 0, 0 0 1 1, 1 1 2 2;
          }
          • TableView列頭排序順序點容器
          .table-view .column-header .sort-order-dots-container{
              -fx-padding: 2 0 2 0;
          }
          • TableView列頭排序順序
          .table-view .column-header .sort-order{
              -fx-font-size: 0.916667em; /* 11pt - 1 less than the default font */
          }
          • TableView列頭排序順序點
          .table-view .column-header .sort-order-dot {
              -fx-background-color: -fx-mark-color;
              -fx-padding: 0.115em;
              -fx-background-radius: 0.115em;
          }
          • TableView列頭文本標簽
          .table-view .column-header .label{
              -fx-alignment: center;
          }
          /* Plus Symbol */
          .table-view .show-hide-column-image,
           {
              -fx-background-color: -fx-mark-color;
              -fx-padding: 0.25em; /* 3px */
              -fx-shape: "M398.902,298.045c0.667,0,1.333,0,2,0c0,0.667,0,1.333,0,2c0.667,0,1.333,0,2,0c0,0.667,0,1.333,0,2c-0.667,0-1.333,0-2,0c0,0.666,0,1.332,0,1.999c-0.667,0-1.333,0-2,0c0-0.667,0-1.333,0-1.999c-0.666,0-1.333,0-1.999,0c0-0.667,0-1.334,0-2c0.666,0,1.333,0,1.999,0C398.902,299.378,398.902,298.711,398.902,298.045z"; 
          }
          • TableView列拖拽頭留下的空閑區
          /* When a column is being 'dragged' to be placed in a different position, there
             is a region that follows along the column header area to indicate where the
             column will be dropped. This region can be styled using the .column-drag-header
             name. */
          .table-view .column-drag-header {
              -fx-background: -fx-accent;
              -fx-background-color: -fx-selection-bar;
              -fx-border-color: transparent;
              -fx-opacity: 0.6;
          }
          • TableView當前正在移動且半透明覆蓋的列
          /* Semi-transparent overlay to indicate the column that is currently being moved */
          .table-view .column-overlay{
              -fx-background-color: darkgray;
              -fx-opacity: 0.3;
          }
          • TableView列頭排序箭頭
          /* Header Sort Arrows */
          .table-view /*> column-header-background > nested-column-header >*/ .arrow{
              -fx-background-color: -fx-mark-color;
              -fx-padding: 0.25em 0.3125em 0.25em 0.3125em; /* 3 3.75 3 3.75 */
              -fx-shape: "M 0 0 h 7 l -3.5 4 z";
          }
          • TableView沒有行列

          TableView簡介

          QTableView是模型-視圖(Model-View)框架類之一,是Qt模型-視圖框架的組成部分,它實現了一個表格視圖。在一個應用需要和一批數據進行交互,需要以表格形式輸出這些信息的時候,QTableView是最合適的選擇。

          QTableView實現了QAbstractItemView類定義的接口,因此它能夠顯示從QAbstractItemModel類派生的模型提供的數據。

          我們可以通過使用鼠標單擊某個單元格或者使用箭頭來導航表格視圖中的單元格。QTableView擁有一個水平表頭和垂直標表頭。表格視圖中顯示的條目與其他視圖中的條目一樣,使用標準委托類來渲染和編輯。

          QTableView常用方法:

          • setModel(): 設置視圖的Model類;
          • horizontalHeader(): 獲得水平表頭;
          • verticalHeader(): 獲得垂直表頭;
          • rowHeight(): 獲得每一行的高度;
          • columnWidth(): 獲得列的寬度;
          • hideRow(): 隱藏指定行;
          • showRow(): 顯示指定行;
          • hideColumn(): 隱藏指定列;
          • showColumn(): 顯示指定列;
          • selectRow(): 選擇指定行;
          • selectColumn(): 選擇指定列。

          QTableView類繼承關系:

          測試QTableView

          在測試代碼中,我們使用QStandardItemModel作為QTableView的模型類, 對視圖的屬性做了一些限制(只能選中一行,只允許行選中模式,不可編輯等等)。當我們選中某一行是,在狀態條上添加信息顯示,在菜單欄實現了添加行和刪除行的功能。完整代碼如下:

          import sys
          from PyQt5 import QtCore, QtGui, QtWidgets
          from PyQt5.QtCore import Qt,QItemSelection, QItemSelectionModel, QModelIndex
          from PyQt5.QtGui import QStandardItemModel, QStandardItem
          from PyQt5.QtWidgets import (QApplication, QMainWindow, QTableView,
                                       QAbstractItemView, QHeaderView, QMenu, QMenuBar, QAction)
           
          class DemoTableView(QMainWindow):
              def __init__(self, parent=None):
                  super(DemoTableView, self).__init__(parent)   
                  
                   # 設置窗口標題
                  self.setWindowTitle('實戰PyQt5: QTableView 演示')      
                  # 設置窗口大小
                  self.resize(520, 360)
                
                  self.initUi()
                  
              def initUi(self):
                  
                  #行數和列數
                  self.rows = 8
                  self.cols = 4
                  
                  #設置水平表頭信息
                  model = QStandardItemModel(self.rows, self.cols, self)
                  hTitle=[]
                  for col in range(self.cols):
                      hTitle.append('第{}列'.format(col+1))
                  model.setHorizontalHeaderLabels(hTitle)
                  #設置垂直表頭信息
                  vTitle=[]
                  for row in range(self.rows):
                      vTitle.append('第{}行'.format(row+1))
                  model.setVerticalHeaderLabels(vTitle)
                  
                  #設置Item里的內容
                  for row in range (self.rows):
                      for column in range (self.cols):
                          item = QStandardItem('(row %s, column %s)'%(row, column))
                          model.setItem(row, column, item)
                  
                  tableView = QTableView(self)
                  tableView.setModel(model)
                  #設置只能選中一行
                  tableView.setSelectionMode(QAbstractItemView.SingleSelection)
                  #不可編輯
                  tableView.setEditTriggers(QTableView.NoEditTriggers)
                  #設置只有行選中
                  tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
                  #所有列自動拉伸,充滿界面
                  tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
                  
                  #顯示選中行的信息
                  tableView.selectionModel().currentChanged.connect(self.onCurrentChanged)
                          
                  self.model = model
                  self.tableView = tableView
                  self.setCentralWidget(tableView)
              
                  #添加菜單項
                  menuBar = self.menuBar()
                  fileMenu = menuBar.addMenu('文件')
                  editMenu = menuBar.addMenu('編輯')
                  
                  #退出應用
                  appExit = QAction('退出', self)
                  appExit.triggered.connect(self.close)
                  fileMenu.addAction(appExit)
                  
                  #添加一行
                  editAppend = QAction('添加', self)
                  editAppend.triggered.connect(self.appendRow)
                  #刪除一行
                  editRemove = QAction('刪除', self)
                  editRemove.triggered.connect(self.removeRow)
                  editMenu.addAction(editAppend)
                  editMenu.addAction(editRemove)
                  
              def appendRow(self):
                  row = self.model.rowCount()
                  items = list()
                  for col in range (self.cols):
                      items.append(QStandardItem('(row %s, column %s)'%(row, col)))
                  #添加一行
                  self.model.appendRow(items)
                  #更新頭信息
                  self.model.setVerticalHeaderItem(row, QStandardItem('第{}行'.format(row+1)))
              
              def removeRow(self):
                  #獲取選中的行
                  sel = self.tableView.selectionModel().selectedRows()
                  print(sel)
                  if sel:
                      #下面刪除時,選中多行中的最后一行,會被刪掉;不選中,則默認第一行刪掉
                      index=self.tableView.currentIndex()
                      print(index.row())
                      self.model.removeRow(index.row())
                      
              def onCurrentChanged(self,current, previous):
                  #初始化時,previous.row() = -1,不顯示信息
                  if int(previous.row() < 0):
                       return
                  self.statusBar().showMessage('選中第{}行'.format(current.row()+1))
              
          if __name__ == '__main__':
              app = QApplication(sys.argv)
              window = DemoTableView()
              window.show()
              sys.exit(app.exec()) 

          運行結果如下圖:

          測試QTableView

          本文知識點

          • QTableView的行和列的屬性設置;
          • QTableView的選擇屬性的設置;
          • QTableView水平和垂直表頭信息設置;
          • 在QTableView中添加或者刪除一行。

          喜歡本文內容就關注, 收藏,點贊,評論和轉發。

          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 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中的列名都不顯示點,但實際數據并沒有改變。

          數據準備

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

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

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

          這個是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

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

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

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

          在構建語法的時候,我們把圖形屬性綁定一個或者多個數據字段。

          坐標系 Coordinates

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

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



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

          分面 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;
          }

          這里有幾點要注意:

          • 使用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的選擇控件插件
          • 相關文章 再談使用開源軟件搭建數據分析平臺
          • 相關文章 使用開源軟件快速搭建數據分析平臺
          • 相關文章 高維數據可視化圖形語法指南

          主站蜘蛛池模板: 国产在线一区观看| 国产精品一区二区毛卡片| 一区二区三区杨幂在线观看| 熟妇人妻一区二区三区四区| 亚洲日本一区二区三区在线| 无码人妻精品一区二区三区夜夜嗨| 久久婷婷色一区二区三区| 亚洲一区中文字幕| 精品福利一区二区三| 麻豆一区二区三区蜜桃免费| 中文字幕精品亚洲无线码一区| 熟妇人妻AV无码一区二区三区| 一区二区三区视频在线观看| 伊人无码精品久久一区二区| 怡红院AV一区二区三区| 精品国产福利第一区二区三区| 加勒比精品久久一区二区三区| 中文字幕AV一区二区三区| 国产一区二区不卡在线播放| 色狠狠AV一区二区三区| 色综合视频一区二区三区| 精品无码成人片一区二区98| 爆乳熟妇一区二区三区| 一区二区三区高清| 中文字幕精品一区| 亚洲AV日韩综合一区| 中文字幕精品一区影音先锋| 日本免费一区尤物| 一区二区视频在线播放| 一区二区三区免费电影| 国产激情一区二区三区在线观看| 在线观看日本亚洲一区| 国产福利电影一区二区三区久久久久成人精品综合 | 蜜桃传媒一区二区亚洲AV| 极品人妻少妇一区二区三区| 一区二区免费视频| 麻豆天美国产一区在线播放| 麻豆一区二区免费播放网站| 精品无人乱码一区二区三区| 无码日韩人妻AV一区二区三区| 国产精品 一区 在线|