superset 圖表種類擴展

           superset目前發佈的版本是0.28,由於其存在多處已知bug,本文我選用的是最新的0.33版本。0.33版本和0.28版本的目錄結構已經產生了很多區別,而且多數文件夾名稱也被修改,網上的資源多數是基於0.28版本或者更舊的版本,並沒有太大借鑑意義。以下流程以添加一個echarts的散點圖爲例,簡述superset擴展圖表的開發流程,希望能起到一定的幫助。

目錄

一、爲superset配置echarts

二、修改viz.py文件

三、在\superset\assets\src\visualizations下修改文件

四、在\superset\assets\src\explore\controlPanels下修改文件

五、npm重編譯 & 重啓superset服務


 

一、爲superset配置echarts

在superset\assets\packages.json中的“dependencies”中添加"echarts": "^4.2.0-rc.2",版本號就用自己的echarts版本號

 

由於echarts散點圖需要使用到reactify,所以在這裏我們順手也加上reactify的修改

 

然後打開命令行終端,執行以下命令:

cd superset/assets
npm install -d
npm run dev

 

二、修改viz.py文件

viz.py 這個文件起到一個類似於視圖的功能,從前端接受請求後進行一系列處理。我們可以看到,一個圖例就是一個類。經過分析已有的這些類,發現這些類大部分是繼承了BaseViz這個基類,並且主要重寫了query_obj和get_data這兩個方法。其中query_obj,顧名思義,是用來構造查詢條件的。而查詢條件來源於頁面左側的組件,這些組件的信息存儲在form_data的一個字典中,query_obj方法中將會處理form_data,構造除自己需要的查詢條件並返回,在BaseViz這個基類中,會根據這個查詢條件來查詢出數據。然後是get_data方法,get_data接收一個參數df(pandas的DataFrame類型),也就是query_obj之後查詢出來的數據,也可以結合你自己構造的form_data中的一些條件對df進行處理。處理之後的數據以dict格式返回,這個dict會交給js進行下一步處理,也就是展示了。

除了兩個比較重要的方法之外,我們自定義的類還應該有兩個重要的類屬性viz_type和verbose_name。其中viz_type是標識當前類,也就是我們自定義圖例的名稱,注意這個名稱應該與後面的js也結合起來。verbose_name則是相當於別名,展示在前端的。

因爲我們添加的是一個時間序列的散點圖,這裏我們把類命名爲TimeSeriesScatterViz

class TimeSeriesScatterViz(BaseViz):
    viz_type = 'time_series_scatter'
    verbose_name = "Time Series Scatter"
    sort_series = False
    is_timeseries = True
 
    def query_obj(self):
        d = super(TimeSeriesScatterViz, self).query_obj()
        fd = self.form_data #form_data中包含界面左側組件內容
 
        if not fd.get('all_columns'): #這個字段對應×××組件,不爲空
            raise Exception('Choose Columns')
 
        if fd.get('all_columns'):
            d['columns'] = fd.get('all_columns') # all_columns是左側組件名,後面會提到
            # 這裏的例子非常簡單,其實可以做很多事
        return d
 
    def get_data(self, df):
        # df是pandas的DataFrame類型
        # 這裏的例子非常簡單,其實可以做很多事
        data = np.array(df).tolist() #假設數據很簡單,不需要做別的處理
        # 如果除了繪圖用的數據還有別的信息,可以構造一個字典來返回
        # data = {'plot_data':plot_data,'other_info':other_info}
        return data


三、在\superset\assets\src\visualizations下修改文件

按照已有的方式,我們將會爲自己的圖例增加一個文件夾,名字跟前面的類名一樣就叫TimeSeriesScatter。文件夾之下還應該有一個文件夾,叫images,這個文件夾下面存放兩個圖片文件,分別是thumbnail.png和thumbnailLager.png(自己去echarts官網截個散點圖,文件名和格式寫對就行 https://www.echartsjs.com/examples/zh/index.html)展示在選圖例的界面中,區別在尺寸大小不一樣。

然後還應該有transformProps.js、TimeSeriesScatterChartPlugin.js、TimeSeriesScatter.js、ReactTimeSeriesScatter.js這四個文件

 

這裏一定注意文件名不能錯,要跟文件內部對象名對應,否則superset會找不到對應文件。比如你的類名叫ClassName。那麼你應該有ClassName.js、ClassNameChartPlugin.js、RectClassName.js、transformProps.js這四個文件。我們示例的文件內容如下:

// ReactTimeSeriesScatter.js
import reactify from '@superset-ui/chart/esm/components/reactify';
import Component from './TimeSeriesScatter';

export default reactify(Component);

 

// TimeSeriesScatter.js
import echarts from 'echarts';
import d3 from 'd3';
import PropTypes from 'prop-types';

const propTypes = {
  data: PropTypes.array,
  width: PropTypes.number,
  height: PropTypes.number,
}; //檢查類型,其中data包含viz.py中返回的數據,width和height爲圖表寬高

function TimeSeriesScatter(element, props){
    const {
        width,
        height,
        data,
    } = props;
    // console.log(data) 可以檢查一下data內容
    const div = d3.select(element, props);
    var html = '<div id="time_series_scatter" style="height:' + height + 'px; width:' + width + 'px;"></div>';
    div.html(html); //給echarts添加div
    var myChart = echarts.init(document.getElementById('time_series_scatter')); //初始化echarts,接下來的就是echarts內容了
    var option = {
    tooltip: {
        formatter: '{b}: {c}'
    },
    xAxis: {
        type: 'time',
        scale: true
    },
    yAxis: {
        type: 'value',
        scale: true
    },
    series: [{
        type: 'scatter',
        symbolSize: 20,
    }, {
        type: 'scatter',
        data: data,
    }]
    };

    myChart.setOption(option);
}

TimeSeriesScatter.displayName = 'Time Series Scatter';
TimeSeriesScatter.propTypes = propTypes;

export default TimeSeriesScatter;

 

// TimeSeriesScatterChartPlugin.js
import { t } from '@superset-ui/translation';
import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';


const metadata = new ChartMetadata({
  name: t('Time Series Scatter'),
  description: '',
  credits: ['http://echarts.baidu.com/examples/editor.html?c=scatter-effect'],
  thumbnail,
});

export default class TimeSeriesScatterChartPlugin extends ChartPlugin {
  constructor() {
    super({
      metadata,
      transformProps,
      loadChart: () => import('./ReactTimeSeriesScatter.js'),
    });
  }
}

 

// transformProps.js
export default function transformProps(chartProps) {
  const { width, height, payload } = chartProps;
  //console.log(chartProps); 可以用來驗證數據是否正確
  return {
    data: payload.data,
    width,
    height,
  };
}

 

四、在\superset\assets\src\explore\controlPanels下修改文件

這個文件夾下放的文件主要是來配置左側的一些組件。對於新圖例來說,需要添加一個新的文件來配置圖例所需組件

//superset\assets\src\explore\controlPanels\TimeSeriesScatter.js
import { t } from '@superset-ui/translation';
 
export default {
  controlPanelSections: [
      {
          label: t('NOT GROUPED BY'),  //控制塊標題,可以有多個控制塊,一塊包含多個組件
          description: t('Use this section if you want to query atomic rows'), //描述
          expanded: true,
          controlSetRows: [
              ['all_columns'],  //使用的組件名
              ['row_limit', null],
          ],
      },
  ],
};

其中\superset\assets\src\explore\controls.jsx文件(注意路徑)定義了組件的形式與功能,如果需要自定義組件,可以在這個文件下開發,具體可以參考已有的部分。選取對自己的圖例合適的組件也需要多看這個文件。比如在此例子中直接使用了controls.jsx裏的Columns組件all_columns:

 

做完以上工作,需要使配置組件的js生效,還要修改superset\assets\src\explore\controlPanels\index.js、superset\assets\src\visualizations\presets\LegacyChartPreset.js

 

 

五、npm重編譯 & 重啓superset服務

//重新編譯
npm run dev
//重啓服務
gunicorn -w 2 --timeout 120 -b  0.0.0.0:8000 --limit-request-line 0 --limit-request-field_size 0 --reload superset:app

 

注意:如果在測試環境不想每次修改完js文件都手動重新編譯可以選擇熱更新 packages.json->scripts->dev->命令行裏添加“ --hot”

 

實測效果如下,其他圖表也可以按照此流程進行添加

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章