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
有图有真相!
(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.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.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字段中添上对应的中文
(2)messages.json文件
在[""]中添上对应的中文
(3)设置默认语言为中文
在superset目录下有一个config.py文件,编辑它,找到BABEL_DEFAULT_LOCALE处,更改为’zh’,如下图:
(4)编译
翻译完英文之后就可以在superset目录下进行编译了 ,命令如下:
pybabel compile -d translations
重启Superset即可看到汉化之后的成果啦!
5 总结
从升级安装Superset,到Superset集成ECharts,最后在汉化,这个过程总共用了七天的时间,收获还是很大的,有了些进步,对于前后端也有了些认识。回头再看看Superset这个BI工具真的太棒了,各种图非常炫,对于数据的分析也是非常轻松。可视化是数据的一种重要的呈现形式,也是数据分析的“最后一公里”,Superset绝对算得上一名有实力的高富帅,快来使用吧!
原文链接:https://blog.csdn.net/qq_33703137/article/details/87874277