Superset 0.28三奏曲——安裝、集成ECharts和漢化


1 環境和版本

操作系統:CentOS Linux release 7.5.1804 (Core)
python版本:3.6.4(直接安裝Anaconda即可)

2 一奏曲——Superset安裝(0.28版本)

Superset 0.22版本的看板中存在很多bug,比如:多個類型一樣的圖表加入到看板中,只有第一個圖可以顯示,其他同類型的圖均顯示不出。在最新版本中不存在,故建議安裝最新版本Superset 0.28。
(1)萬事開頭難。首先咱們得要先安裝Anaconda,因為接下來需要用到pip,去這里下載安裝,最新Superset支持使用python3的版本。
(2)安裝superset

pip install superset

  
  
  
          

划重點!用pip安裝的最新版本Superset的目錄與0.28.1版本源碼有差異,其實是不全,去這里下載源碼,下載好之后,要用源碼中Superset\superset\assets下的src目錄替換自己安裝的superset的assets下的src目錄即可,這個步驟為后續集成ECharts做准備。
(3)初始化

fabmanager create-admin --app superset   //創建管理員賬號

superset db upgrade //初始化數據庫

superset load_examples //載入模板數據

superset init //初始化角色和權限

superset runserver -d -p 8088 //啟動服務,端口號 8088,使用 -p 更改端口號

最后如果瀏覽器進入不了登錄界面,這是因為防火牆的問題,打開就好了。
(4)后台運行superset
使用如下命令,就可以讓superset在后台運行,就不用每一次啟動服務了。

nohup superset runserver -d -p 8088 &

tail -f nohup.out

有圖有真相!
Alt
(5)安裝編譯前端需要的js包
這一步是為接下來的ECharts集成做准備,進入到superset\static\assets下,在命令行中輸入

npm install

  
  
  
          

(6)編譯前端
需要的包全部安裝完之后,進入superset\static\assets下,在命令行中輸入

npm run dev

  
  
  
          

這一步如果報錯,排除語法和權限問題,是包沒有安裝全的原因,一定要把包安裝全才行。
我遇到的是這兩個錯誤:在這里插入圖片描述

ERROR in ./src/visualizations/index.js 86:19
Module parse failed: Unexpected token (86:19)
You may need an appropriate loader to handle this file type.
| var loadNvd3 = function () {
|   function loadNvd3() {
>     return loadVis(import( /* webpackChunkName: "nvd3_vis" */'./nvd3/adaptor.jsx'));
|   }
| 
 @ ./src/modules/AnnotationTypes.js 15:15-30
 @ ./src/chart/chartAction.js
 @ ./src/explore/components/ExploreViewContainer.jsx
 @ ./src/explore/App.jsx
 @ ./src/explore/index.jsx
 @ multi babel-polyfill ./src/explore/index.jsx

  
  
  
          

把包安裝全之后,再執行npm run dev命令,編譯就通過了。之后在ECharts集成時就可以看到實時編譯的網頁效果了。

3 二奏曲——Superset集成ECharts(重點)

Superset集成ECharts其實說來也簡單,主要操作5個地方,分別是:
(1)后端文件
處理傳入前端的數據格式
superset/viz.py
(2)前后端函數匹配文件
superset/static/assets/src/visualizations/index.js
(3)你的新增圖表名稱.js
superset/static/assets/src/visualizations/你的新增圖表名稱.js
(4)前端圖標配置區組件設置
它是Superset左側的GroupBy等組件的開關,需根據你新增的圖表要用的數據格式選擇合適的組件
superset/static/assets/src/explore/visTypes.jsx
(5)縮略圖
superset/static/assets/images/viz_thumbnails
下面來舉兩個集成Echarts圖表的例子

3.1 極坐標柱狀圖

(1)后端文件
進入到superset/viz.py文件中,在BaseViz類的下方和TableViz的上方加入如下代碼(與其他的相似):

class EchartsBarPolar(BaseViz):
    viz_type = 'echarts_bar_polar' #對應前端的名字
    is_timeseries = False
    def should_be_timeseries(self):
        fd = self.form_data
        conditions_met = (
            (fd.get('granularity') and fd.get('granularity') != 'all') or
            (fd.get('granularity_sqla') and fd.get('time_grain_sqla'))
        )
        if fd.get('include_time') and not conditions_met:
            raise Exception(_(
                'Pick a granularity in the Time section or '
                "uncheck 'Include Time'"))
        return fd.get('include_time')
    def query_obj(self):
        d = super(EchartsBarPolar, self).query_obj()
        fd = self.form_data
        if fd.get('all_columns') and (fd.get('groupby') or fd.get('metrics')):
            raise Exception(_(
                'Choose either fields to [Group By] and [Metrics] or '
                '[Columns], not both'))
        sort_by = fd.get('timeseries_limit_metric')
        if fd.get('all_columns'):
            d['columns'] = fd.get('all_columns')
            d['groupby'] = []
            order_by_cols = fd.get('order_by_cols') or []
            d['orderby'] = [json.loads(t) for t in order_by_cols]
        elif sort_by:
            if sort_by not in d['metrics']:
                d['metrics'] += [sort_by]
            d['orderby'] = [(sort_by, not fd.get('order_desc', True))]
        if 'percent_metrics' in fd:
            d['metrics'] = d['metrics'] + list(filter(
                lambda m: m not in d['metrics'],
                fd['percent_metrics'],
            ))
        d['is_timeseries'] = self.should_be_timeseries()
        return d
    def get_data(self, df):
        fd = self.form_data
        if not self.should_be_timeseries() and DTTM_ALIAS in df:
            del df[DTTM_ALIAS]
        return dict(
            records=df.to_dict(orient='records'),
            columns=list(df.columns),
        )

  
  
  
          

(2)前后端函數匹配文件
進入到superset/static/assets/src/visualizations/index.js文件中,
在export const VIZ_TYPES里新增

echarts_bar_polar: 'echarts_bar_polar',

  
  
  
          

在const vizMap里新增

[VIZ_TYPES.echarts_bar_polar]: () => loadVis(import(/*webpackChunkName: 'echarts_bar_polar' */ './echarts_bar_polar.js')),

  
  
  
          

(3)echarts_bar_polar.js
在superset/static/assets/src/visualizations文件夾下,放入echarts_bar_polar.js文件,代碼如下:

import echarts from 'echarts';
import {getColorFromScheme} from '../javascripts/modules/colors';
function EchartsBarPolarVis(slice, payload) {
    var div = d3.select(slice.selector);
	const sliceId = 'e_bar_polar' + slice.formData.slice_id
    var html = '<div id="' + sliceId + '" style="width:' + slice.width() + 'px;' + ''
        + 'px;height:' + slice.height() + 'px;"></div>';
    div.html(html);
    var myChart = echarts.init(document.getElementById(sliceId));
    var option = {
        angleAxis: {
            type: 'category',
            data: [],
            z: 10
        },
        radiusAxis: {},
        polar: {},
        series: []
    };
    myChart.setOption(option);
    const fd = slice.formData;
    const json = payload.data;
    const data = json;
    const records = data['records'];
    const data_column = data.columns;
    const metrics = fd.metrics;
    const group_by = fd.groupby;
    var legend_name = [];
    var axis_name = [];
    var series_data = [];
    for (var i = 0; i < records.length; i++) {
        axis_name.push(records[i][data_column[0]]);
    }
    for (var i = 0; i < metrics.length; i++) {
        legend_name.push(metrics[i]);
        var tmp_data = [];
        for (var j = 0; j < records.length; j++) {
            tmp_data.push(records[j][metrics[i]]);
        }
        series_data.push(
            {
                type: 'bar',
                data: tmp_data,
                coordinateSystem: 'polar',
                name: legend_name[i],
                stack: 'a'
            }
        )
    }
    var option2 = {
        angleAxis: {
            data: axis_name
        },
        series: series_data
    };
    myChart.setOption(option2);
}
module.exports = EchartsBarPolarVis;

  
  
  
          

(4)前端圖標配置區組件設置
進入superset/static/assets/src/explore/visTypes.jsx文件中,在export const visTypes里新增如下代碼:

echarts_bar_polar: {
        label: t('Bar Polar'),
        showOnExplore: true,
        controlPanelSections: [
            {
                label: t('GROUP BY'),
                controlSetRows: [
                    ['groupby'],
                    ['metrics'],
                    ['percent_metrics'],
                    ['include_time'],
                    ['timeseries_limit_metric', 'order_desc'],
                ],
            },
            {
                label: t('NOT GROUPED BY'),
                description: t('Use this section if you want to query atomic rows'),
                controlSetRows: [
                    ['all_columns'],
                    ['order_by_cols'],
                ],
            },
            {
                label: t('Options'),
                controlSetRows: [
                    ['table_timestamp_format'],
                    ['row_limit', 'page_length'],
                    ['include_search', 'table_filter'],
                ],
            },
        ],
        controlOverrides: {
            metrics: {
                validators: [],
            },
            time_grain_sqla: {
                default: null,
            },
        },
    },

  
  
  
          

(5)縮略圖
在superset/static/assets/images/viz_thumbnails文件夾下放入極坐標柱狀圖的縮略圖
在這里插入圖片描述
到此極坐標柱狀圖就集成好啦,快來看看下面的效果吧!

在這里插入圖片描述

3.2 中國地圖(可下鑽至市級)

(1)后端文件
進入到superset/viz.py文件中,在BaseViz類的下方和TableViz的上方加入如下代碼(與其他的相似):

class ChinaMap(BaseViz):
    """ ChinaMap viz """
    viz_type = 'ChinaMap' 
    verbose_name = _('ChinaMap')
    is_timeseries = False
    def get_data(self, df):
        form_data = self.form_data
        df.sort_values(by=df.columns[0], inplace=True)
        print(df.values.tolist())
        ori_data = df.values.tolist()
        data = [{'name' : ori_data[i][0], 'value' : ori_data[i][1]} for i in range(len(ori_data))]
        data_name = [ori_data[i][0] for i in range(len(ori_data))]
        max_data = max([ori_data[i][1] for i in range(len(ori_data))])
        min_data = min([ori_data[i][1] for i in range(len(ori_data))])
        return [data, data_name, max_data, min_data]

  
  
  
          

(2)前后端函數匹配文件
進入到superset/static/assets/src/visualizations/index.js文件中,
在export const VIZ_TYPES里新增

ChinaMap: 'ChinaMap',

  
  
  
          

在const vizMap里新增

[VIZ_TYPES.ChinaMap]: () => loadVis(import(/*webpackChunkName: 'ChinaMap' */ './ChinaMap.js')),

  
  
  
          

(3)ChinaMap.js
在superset/static/assets/src/visualizations文件夾下,放入ChinaMap.js文件,代碼如下:

import echarts from 'echarts';
require('echarts/map/js/china.js');
require('echarts/map/js/province/index.js');
function ChinaMapVis(slice, payload) {
    const div = d3.select(slice.selector);
    const sliceId = 'echarts_slice_' + slice.formData.slice_id;
    const html = '<div id=' + sliceId + ' style="width:' + slice.width() + 'px;height:' + slice.height() + 'px;"></div>';
    div.html(html); // reset
    const myChart = echarts.init(document.getElementById(sliceId));
    const get_data = payload.data;
    const data_value = get_data[0];
    const data_name = get_data[1];
    const max_data = get_data[2];
    const min_data = get_data[3];
    const option = {
        title : {
            subtext:'點擊進入下一級,雙擊返回中國地圖',
            x:'center',
            bottom:'5%'
        },
        tooltip : {
            trigger: 'item',
            formatter:  "{c}"
        },
		toolbox: {
            show: true,
            orient: 'vertical',
            left: 'right',
            top: 'center',
            feature: {
                dataView: {readOnly: false},
                restore: {},
                saveAsImage: {}
            }
        },
        visualMap: {
            //type: 'continuous',
            min: min_data,
            max: max_data,
			text:['高','低'],
			realtime: false,
            calculable: true,
            //right:'-15%',
            inRange:{
                color: ['#d0f4fc',
                    '#a9dbf6',
                    '#9cd3f4',
                    '#93cdf3',
                    '#83c2f0',
                    '#6eb5ed',
                    'yellow']
            }
        },
        series : [
            {
                type : 'map',
                map: 'china',
                selectedMode: 'single',
                roam: 'scale',
                data : data_value,
                label: {
                    normal: {
                        show: true,
                        textStyle:{color:"#b6a38a"}
                    },
                    emphasis: {
                        show: true,
                        textStyle:{color:"#ff6347"}
                    }
                },
                itemStyle: {
                    emphasis: {
                        areaColor:"#2e4783",
                        borderWidth: 0
                    }
                }
            }
        ]
    };
   myChart.setOption(option);
   myChart.on('mouseover', function (params) {
       var dataIndex = params.dataIndex;
       console.log(dataIndex);
   });
   myChart.on('click', function (chinaParam) {
       if (chinaParam.name == chinaParam.name
           &&data_name.indexOf(chinaParam.name)>-1) {
           var option = myChart.getOption();
           option.series[0].map = chinaParam.name;
           myChart.setOption(option);
       }
   });
   myChart.on('dblclick', function (chinaParam) {
       if (myChart.getOption().series[0].map != 'china') {
           var option = myChart.getOption();
           option.series[0].map = 'china';
           myChart.setOption(option);
       }
   });
}
module.exports = ChinaMapVis;

  
  
  
          

(4)前端圖標配置區組件設置
進入superset/static/assets/src/explore/visTypes.jsx文件中,在export const visTypes里新增如下代碼:

ChinaMap: {
        label: t('ChinaMap'),
        showOnExplore: true,
        controlPanelSections: [
            {
                label: t('GROUP BY'),
                controlSetRows: [
                    ['groupby'],
                    ['metrics'],
                    ['percent_metrics'],
                    ['include_time'],
                    ['timeseries_limit_metric', 'order_desc'],
                ],
            },
            {
                label: t('NOT GROUPED BY'),
                description: t('Use this section if you want to query atomic rows'),
                controlSetRows: [
                    ['all_columns'],
                    ['order_by_cols'],
                ],
            },
            {
                label: t('Options'),
                controlSetRows: [
                    ['table_timestamp_format'],
                    ['row_limit', 'page_length'],
                    ['include_search', 'table_filter'],
                ],
            },
        ],
        controlOverrides: {
            metrics: {
                validators: [],
            },
            time_grain_sqla: {
                default: null,
            },
        },
    },

  
  
  
          

(5)縮略圖
在superset/static/assets/images/viz_thumbnails文件夾下放入中國地圖的縮略圖
在這里插入圖片描述
到此中國地圖就集成好啦,快來看看下面的效果吧!點擊中國地圖的省份可以下鑽到市級,雙擊返回中國地圖。
在這里插入圖片描述
在上面的圖中點擊北京市,可進行下鑽,雙擊可返回中國地圖。
在這里插入圖片描述

4 三奏曲——漢化

在superset/translations/zh/LC_MESSAGES安裝目錄下有兩個文件:messages.po文件和messages.json文件,只需要把這兩個文件中的英文對應的中文添上,這可是個費時的工作,然后編譯即可。
(1)messages.po文件
在msgstr字段中添上對應的中文
Alt
(2)messages.json文件
在[""]中添上對應的中文
Alt
(3)設置默認語言為中文
在superset目錄下有一個config.py文件,編輯它,找到BABEL_DEFAULT_LOCALE處,更改為’zh’,如下圖:
Alt
(4)編譯
翻譯完英文之后就可以在superset目錄下進行編譯了 ,命令如下:

pybabel compile -d translations

  
  
  
          

重啟Superset即可看到漢化之后的成果啦!

5 總結

從升級安裝Superset,到Superset集成ECharts,最后在漢化,這個過程總共用了七天的時間,收獲還是很大的,有了些進步,對於前后端也有了些認識。回頭再看看Superset這個BI工具真的太棒了,各種圖非常炫,對於數據的分析也是非常輕松。可視化是數據的一種重要的呈現形式,也是數據分析的“最后一公里”,Superset絕對算得上一名有實力的高富帥,快來使用吧!

原文鏈接:https://blog.csdn.net/qq_33703137/article/details/87874277

在這里插入圖片描述
歡迎關注,本號將持續分享本人在編程路上的各種見聞。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM