开发环境部署:
SupersetBI二次开发环境部署_健胃消食片-的博客-CSDN博客
superset版本:2.0.0
echarts版本:5.3.1
前言:
参考文章:
superset 二次开发 添加新图例 | 出行应用文档中心 (qq.com)
目录
1、\superset-frontend\src\visualizations文件夹下新建Gauge文件夹
2、\superset-frontend\src\visualizations\presets\MainPreset.js修改文件
3、\superset-frontend\src\explore\controlPanels新增文件Gauge.js
4、\superset-frontend\src\explore\controls.jsx新增自定义组件
5、\superset-frontend\src\setup\setupPlugins.ts修改文件
1、superset-frontend/src/explore/controlPanels/controls.jsx添加自定义组件
4、superset-frontend/src/explore/controlPanels/xxx.js
入口文件superset-templates-tail_js_custom_extra.html
一、添加自定义图表:
1、\superset-frontend\src\visualizations文件夹下新建Gauge文件夹
-
新建images文件夹
-
新建GaugeChartPlugin.js
import { t } from '@superset-ui/core';
import { ChartMetadata, ChartPlugin } from '@superset-ui/core';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';
const metadata = new ChartMetadata({
name: t('Mix Line Bar'),
description: '',
credits: ['https://www.echartsjs.com/examples/en/editor.html?c=mix-line-bar'],
thumbnail,
});
export default class MixLineBarChartPlugin extends ChartPlugin {
constructor() {
super({
metadata,
transformProps,
loadChart: () => import('./ReactMixLineBar.js'), // 前端渲染逻辑
});
}
}
-
新建Gauge.jsx前端渲染图表主要逻辑
import React from 'react'
import * as echarts from 'echarts'
import PropTypes from 'prop-types'
const propTypes = {
data: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
width: PropTypes.number,
height: PropTypes.number,
chartId: PropTypes.number,
groupby: PropTypes.arrayOf(PropTypes.string),
}
console.log("propTypes", propTypes)
class Gauge extends React.Component {
constructor(props) {
//
console.log("props", props)
super(props)
// 这里的props为 `superset/assets/src/visualizations/Gauge/transformProps.js` 传递过来的数据
this.state = {
chartIns: null
}
}
setOptions() {
const { data, groupby } = this.props;
if (data && data.length > 0) {
const total = data.reduce((acc, item) => acc + item['SUM(sum__num)'], 0);
// 创建仪表盘配置选项
const option = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
series: data.map((item, index) => {
// 根据groupby的值构建customTitle
const customTitle = groupby.map(field => `${field}: ${item[field]}`).join(', ');
return {
name: customTitle || `Gauge ${index + 1}`,
type: 'gauge',
detail: {
formatter: '{value}%',
offsetCenter: [0, `${15 + index * 20}%`], // 调整每个指针的位置
},
data: [{ value: ((item['SUM(sum__num)'] / total) * 100).toFixed(1), name: customTitle || `Gauge ${index + 1}` }],
axisLabel: {
formatter: '{value}%', // 格式化刻度标签
},
// axisLine: {
// lineStyle: {
// color: [[0.2, 'red'], [0.8, 'orange'], [1, 'green']],
// width: 8, // 调整仪表盘刻度线的宽度
// },
// },
// pointer: {
// width: 4, // 调整指针的宽度
// },
// splitLine: {
// length: 12, // 调整分隔线的长度
// },
};
}),
};
this.state.chartIns.setOption(option,true);
}
}
componentDidMount() {
const { data, chartId = 123, customTitle } = this.props
const myChart = echarts.init(
document.getElementById(`gauge_${chartId}`)
)
this.setState({
chartIns: myChart
}, () => {
this.setOptions()
})
}
componentDidUpdate() {
this.setOptions()
this.state.chartIns.resize()
}
render() {
const { width, height, chartId = 123 } = this.props
const style = {
width,
height
}
return <div id={`gauge_${chartId}`} style={style} />
}
}
Gauge.displayName = 'Gauge'
Gauge.propTypes = propTypes
export default Gauge
-
新建transformProps.js前端后端数据转换
export default function transformProps(chartProps) {
const {
width,
height,
queriesData,
formData,
} = chartProps;
// 需要传递给 `superset/assets/src/visualizations/Gauge/Gauge.jsx` 的属性
return {
data: queriesData[0].data,
chartId: formData.sliceId,
// customTitle: formData.customTitle,
width,
height,
groupby:formData.groupby,
};
}
2、\superset-frontend\src\visualizations\presets\MainPreset.js修改文件
# 开头添加
import Gauge from '../Gauge/GaugeChartPlugin';
# 末尾添加
new Gauge().configure({ key: 'gauge'}),
3、\superset-frontend\src\explore\controlPanels新增文件Gauge.js
import { t } from '@superset-ui/core';
export default {
// label对应的是每个section的标题
// expand对应的是改section是否可以被展开
// controlSetRows 定义的是每一行有几个组件,metric,adhoc_filters对应的是组件的key
// 可以在superset-frontend/src/explore/controls.jsx
// 中通过这些key找到对应的配置
label: t('Gauge Chart'),
// requiresTime: true,
controlPanelSections: [
{
label: t('Time'),
controlSetRows: [
['granularity_sqla'],
['time_range'],
// ['time_grain_sqla'],
],
},
{
label: t('Query'),
expanded: true,
controlSetRows: [
['metrics'],
['adhoc_filters'],
['groupby'],
['columns'],
['row_limit'],
['contribution'],
],
},
{
label: t('Chart Options'),
expanded: true,
controlSetRows: [['color_scheme', 'label_colors']],
},
],
controlOverrides: {
// groupby: {
// label: t('Series'),
// },
// columns: {
// label: t('Breakdowns'),
// description: t('Defines how each series is broken down'),
// },
},
};
4、\superset-frontend\src\explore\controls.jsx新增自定义组件
label_colors: {
type: 'ColorMapControl',
label: t('Color Map'),
default: {},
renderTrigger: true,
mapStateToProps: state => ({
colorNamespace: state.form_data.color_namespace,
colorScheme: state.form_data.color_scheme,
}),
},
5、\superset-frontend\src\setup\setupPlugins.ts修改文件
# 开头导入
import Gauge from '../explore/controlPanels/Gauge'
# 末尾添加
.registerValue('gauge', Gauge)
7、\superset\viz.py修改后端代码
# 在METRIC_KEYS数组中添加新增自定义组件
"label_colors",
class GaugeViz(BaseViz):
viz_type = 'gauge' # 当前图例的类型
verbose_name = 'Gauge' # 当前图例的别名
sort_series = False # 是否排序
is_timeseries = False # 是否查询时间
def query_obj(self):
d = super().query_obj()
metric = self.form_data.get("metric")
if not metric:
raise Exception(_("Pick a metric!"))
d["metrics"] = [self.form_data.get("metric")]
self.form_data["metric"] = metric
d["row_limit"] = None
return d
def get_data(self, df):
# 构造未过滤器数据
d = super().query_obj()
d['filter'] = []
res = self.datasource.query(d)
# df1 为总数 无过滤器过滤 -> 分母
df1 = res.df.to_dict(orient="records")
# df2 为过滤后的数据 -> 分子
df2 = df.to_dict(orient="records")
df1.extend(df2)
return df1
8、终端执行
# 安装echarts
npm install echarts@5.3.1
// superset-frontend目录下执行
npm run dev
// 虚拟环境中conda执行,发布本地服务
set FLASK_APP=superset
superset run -p 8099
// 本机127.0.0.1:8099可进入Superset
最终结果:
添加自定义图表本质是添加一个react页面,添加d3图之类的也和上述步骤一样;
二、添加自定义控件
1、superset-frontend/src/explore/controlPanels/controls.jsx添加自定义组件
lon_column: {
...metrics, // 继承
// multi: true, // 多选
clearable: true, // 是否可调用, true当作sql
// validators: [], // 是否可以为空
label: t('Longitude'),
description: t('Column containing longitude data'),
default: null
},
2、superset-frontend/packages/superset-ui-charts-contrlos/src/shared-controls/index.tsx
const lon_column: SharedControlConfig<'MetricsControl'> = {
...metric,
label: t('Longitude'),
default: null,
description: t('Column containing longitude data'),
};
// sharedControls 中添加自定义组件名称
3、 superset/viz.py注册自定义组件
// METRIC_KEYS 注册自定义组件
4、superset-frontend/src/explore/controlPanels/xxx.js
export default {
label: t('Heatmap_On_Map Chart'),
controlPanelSections: [
{
label: t('Query'),
expanded: true,
controlSetRows: [
['lon_column']
]
}
]
};
// label对应的是每个section的标题
// expanded对应的是改section是否可以被展开
// controlSetRows 定义的是每一行有几个组件,metric,adhoc_filters对应的是组件的key
// 可以在superset-frontend/src/explore/controls.jsx中通过这些key找到对应的配置
三、添加图表所需api脚本
图表入口文件superset-templates-tail_js_custom_extra.html
// 添加百度地图api为例
<script type="text/javascript" src="https://api.map.baidu.com/api?v=2.0&ak=YOUR_KEY"></script>
四、打包Superset
依靠主目录下的setup.py文件进行打包成dist文件
// 安装Pyinstaller
pip install pyinstaller
// 主目录下进行打包
pyinstaller setup.py
五、发布Superset服务-gunicorn
该服务是发布在Liunx系统下,使用gunicorn进行发布,连接同一个局域网下的设备都可进行访问;参考代码中发布端口为9119
- 在superset目录下新建superset.sh脚本
superset_status(){
result=`ps -ef | awk '/gunicorn/ && !/awk/{print $2}' | wc -l`
if [[ $result -eq 0 ]]; then
return 0
else
return 1
fi
}
superset_start(){
# 该段内容取自~/.bashrc,所用是进行conda初始化
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/root/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/root/anaconda3/etc/profile.d/conda.sh" ]; then
. "/root/anaconda3/etc/profile.d/conda.sh"
else
export PATH="/root/anaconda3/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<
superset_status >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
conda activate superset ; gunicorn --workers 5 --timeout 120 --bind 0.0.0.0:9119 --daemon 'superset.app:create_app()'
else
echo "superset正在运行"
fi
}
superset_stop(){
superset_status >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo "superset未在运行"
else
ps -ef | awk '/gunicorn/ && !/awk/{print $2}' | xargs kill -9
fi
}
case $1 in
start )
echo "启动Superset"
superset_start
;;
stop )
echo "停止Superset"
superset_stop
;;
restart )
echo "重启Superset"
superset_stop
superset_start
;;
status )
superset_status >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo "superset未在运行"
else
echo "superset正在运行"
- 启动/暂停脚本
// 启动脚本
/anaconda3/envs/superset/lib/sites-package/superset/superset.sh
// 启动服务
superset.sh start
// 暂停服务
superset.sh stop
六、一些零碎问题的解决
报错:WebGL发生渲染错误,渲染已经停止,请刷新页面。 SecurityError: Failed to construct 'Worker': Script at 'file:///E:/BI/superset-2.0-test/superset-frontend/node_modules/mars3d-cesium/Build/Cesium/Workers/createVerticesFromHeightmap.js' cannot be accessed from origin 'http://127.0.0.1:8099'.
解决: 安装react-dom,不然会报跨域问题的错误
错误:mars3d-cesium中访问资源路径错误
解决:参考Mars3d官网教程(修改配置文件)——在已有项目中集成Mars3D | Mars3D开发教程