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

在这里插入图片描述
欢迎关注,本号将持续分享本人在编程路上的各种见闻。

猜你喜欢

转载自www.cnblogs.com/Alex458/p/12227960.html