superset安装与集成echarts

一、安装环境要求:

1、win7_64或win10_64,
2、python3.7,
3、superset0.27.0(因0.28.0目录发生变更,暂不适用)
4、.net framework4.6,
5、vc++14.0(http://go.microsoft.com/fwlink/?LinkId=691126,注意vc2015需卸载)

二、修改pip源,在用户目录下新建pip文件夹,新建pip.ini:

    [global]
    index-url=https://pypi.tuna.tsinghua.edu.cn/simple 
    [install]
    trusted-host=pypi.tuna.tsinghua.edu.cn
    disable-pip-version-check = true  
    timeout = 6000

三、安装:

1、安装

    c: 
    cd/ 
    md superset
    cd superset
	
    pip install virtualenv #安装python虚拟环境库,py3.7自带,py -3 -m venv venvname
    virtualenv venv #新建虚拟环境env文件夹
	
    cd env\scripts
    activate #激活虚拟环境 
	
    pip install --upgrade setuptools pip #更新pip,setuptools
    pip install sasl(http://www.lfd.uci.edu/~gohlke/pythonlibs/#sasl) cryptography #安装库
    pip install click==6.7 colorama==0.3.9 markdown==2.6.11 flask-sqlalchemy==2.1 (numpy)
    pip install superset==0.27.0 
    pip install -r c:\requirements.txt  (-r requirements-dev.txt) #安装依赖库,从github下载

python3.66不用修改,python3.7中async为关键字,修改3处:
在site-packages\superset\views\cores.js文件内: 修改变量async为async_in
2、启动服务,安装完成后执行以下命令可以使用:

    cd env\lib\site-packages\superset\bin
    fabmanager create-admin --app superset #创建用户
    python superset db upgrade  #升级数据库
    python superset load_examples #加载例子
    python superset init #初始化
    python superset runserver -d #启动服务

四、集成echarts环境搭建:

    npm config set registry http://registry.npm.taobao.org/ #设置npm源
	npm install yarn -g #安装yarn依赖包管理工具

	yarn config set registry http://registry.npm.taobao.org/ #设置yarn源
	yarn add [email protected] #添加库
	yarn add [email protected]
	yarn add cross-env

修改site-packages\superset\package.json: NODE_ENV前加cross-env,4处

    yarn install #初始化
    npm run dev | more # | 管道命令,方便查看错误,如无错误,可进行在线编译添加echarts

npm run dev 生成目录site-packages\superset\static\assets\dist,在python3.66下集成echarts生成dist目录后,覆盖到python3.7环境的dist,重启服务可以使用。

五、漏斗示例(修改时需启动服务和在线编译窗口同时运行):

1、下载echarts,存储site-packages\superset\static\assests\src\exploer\echarts.js
2、site-packages\superset\templates\supersetbase.html: 增加一行:

    <script src="/static/assests/src/exploer/controlPanels/echarts.js">script>

3、site-packages\superset\package.json:

    "dependencies": {,"echarts": "^4.1.0",}   # 注意','

4、site-packages\superset\static\assets\src\visualizations\index.js,增加:

    VIZ_TYPES = { echarts_funnel:'echarts_funnel',}
    vizMap = { [VIZ_TYPES.echarts_funnel]:require('./echarts_funnel.js'),}

5、site-packages\superset\viz.py: 增加类class EchartsFunnelViz(BaseViz):{},如下:

	class EchartsFunnelViz(BaseViz):
		# Funnel Chart
		viz_type = 'echarts_funnel'
		verbose_name = _('echarts_funnel')
		is_timeseries = False

		def get_data(self, df):
			metric = self.metric_labels[0] 
			df = df.pivot_table(
				index=self.groupby,
				values=[metric])
			df.sort_values(by=metric, ascending=False,inplace=True)
			df = df.reset_index()
			df.columns = ['name','value']
			# mydata = [{'name':'p1','value':40},{'name':'p2','value':30},{'name':'p3','value':20}] #测试数据
			return df.to_dict(orient='records')

6、site-packages\superset\static\assets\src\explore\vistypes.js:
在export const visTypes:{}增加新类型{ echarts_funnel: {}},如下:

    echarts_funnel: {
    label: t('echarts_funnel'),
    showOnExplore: true,
    controlPanelSections: [
      {
        label: t('Query'),
        expanded: true,
        controlSetRows: [
          ['metric'],
          ['adhoc_filters'],
          ['groupby'],
          ['limit'],
        ],
      },
      {
        label: t('Chart Options'), // 这个是额外控制选项
        expanded: true,
        controlSetRows: [
            ['pie_label_type'],
            ['donut', 'show_legend'],
            ['labels_outside'],
            ['color_scheme'],
        ],
      },
    ],
    },

7、site-packages\superset\static\assets\src\visualizations: 新增加EchartsFunnel.js,如下:

    import echarts from 'echarts';
    function EchartsFunnel(slice, payload) { //两个参数payload就是 viz.py返回来的数据 slice不不知道从哪⾥里里来的似乎除了了编号没什什么⽤用
        const div = d3.select(slice.selector); //这4⾏行行是创建⼀一个div⽤用来绑定给echats做显示的基础画板,并制定slice的id号
        const sliceId = 'echarts_slice_' + slice.formData.slice_id;
        const html = '
+ slice.width() + 'px;height:' + slice.height() + 'px;">
'
; div.html(html); // reset const myChart = echarts.init(document.getElementById(sliceId)); const mydata = payload.data; // const mydata = [{'name': 'RDAA201851940000000001', 'value': 1},{'name': 'RDAA201851940000000002', 'value': 1}]; var option = { title: { text: '漏漏⽃斗图', subtext: '图例例' }, tooltip: { trigger: 'item', formatter: "{a}
{b} : {c}%"
}, toolbox: { feature: { dataView: {readOnly: false}, restore: {}, saveAsImage: {} } }, legend: { data: mydata.name }, calculable: true, series: [ { name:'漏漏⽃斗图', type:'funnel', left: '10%', top: 60, bottom: 60, width: '80%', min: 0, max: 100, minSize: '0%', maxSize: '100%', sort: 'descending', gap: 2, label: { normal: { show: true, position: 'inside' }, emphasis: { textStyle: { fontSize: 20 } } }, labelLine: { normal: { length: 10, lineStyle: { width: 1, type: 'solid' } } }, itemStyle: { normal: { borderColor: '#fff', borderWidth: 1 } }, data:mydata } ] }; // 使⽤用刚指定的配置项和数据显示图表。 myChart.setOption(option); } // module.exports = EchartsFunnel;

8、增加图片到superset/static/assets/images/viz_thumbnails:
添加名字(echarts_funnel.png)要和vistypes.js中的名字一致

六、superset0.29rc7

1. 离线安装superset(复制的均为下载的包文件)

虚拟环境安装pip install --upgrade pip setuptools, pip install sasl(下载sasl文件),

	删除C:\incubator-superset-0.29.0rc7\superset\static下的assets
	复制C:\incubator-superset-0.29.0rc7\superset\assets到C:\incubator-superset-0.29.0rc7\superset\static下
	修改 requirements.txt, 删除cryptography, 并单独安装cryptography和docs\requirements和requirements.txt
	修改 requirements-dev.txt, 删除mysqlclient并单独安装, 并单独安装requirements-dev.txt
	修改setup.py第18行with io.open('C:\incubator-superset-0.29.0rc7\README.md',
	复制C:\incubator-superset-0.29.0rc7\superset文件夹到C:\venv\Lib\site-packages下,
	并到C:\venv\Lib\site-packages下执行python c:\incubator-superset-0.29rc7\setup.py
	复制.flaskenv到superset目录,并修改为:FLASK_APP=:app  FLASK_ENV=development
	复制src目录到asset
	其它同上.
	
	yarn add python.dotenv , # 加载flask环境变量(.flaskenv),或使用npm命令,下同
	yarn install ,# 初始化依赖库
	yarn run build ,  # 可不执行,重新使用webpack打包
	npm run dev , # 可实时webpack打包, 在线修改时使用

flask1.0.2:
命令python superset runserver -d 修改为:
在superset目录下执行:

    flask run -h 0.0.0.0 -p 8080 --with-threads --reload --debugger

因windows与linux不同,sqllab编辑器执行错误,需修改superset\utils\core.py:

    def __enter__(self):
        try:
            #signal.signal(signal.SIGALRM, self.handle_timeout)
            #signal.alarm(self.seconds)
            pass
        except ValueError as e:
            logging.warning("timeout can't be used in the current context")
            logging.exception(e)

    def __exit__(self, type, value, traceback):
        try:
            #signal.alarm(0)
            pass
        except ValueError as e:
            logging.warning("timeout can't be used in the current context")
            logging.exception(e)

2.1 仿写已存在的CountryMap(修改后需重新编译)

引导界面

A、 在superset\viz.py增加

    class EchartsCountryMapViz(BaseViz):

		"""A country centric"""

		viz_type = 'echarts_country_map'
		verbose_name = _('Echarts Country Map')
		is_timeseries = False
		credits = 'From bl.ocks.org By john-guerra'

		def query_obj(self):
			qry = super(EchartsCountryMapViz, self).query_obj()
			qry['metrics'] = [
				self.form_data['metric']]
			qry['groupby'] = [self.form_data['entity']]
			return qry

		def get_data(self, df):
			fd = self.form_data
			cols = [fd.get('entity')]
			metric = self.metric_labels[0]
			cols += [metric]
			ndf = df[cols]
			df = ndf
			df.columns = ['country_id', 'metric']
			d = df.to_dict(orient='records')
			return d

控制面板

B、 在superset/assets/src/explore/controlPanels/index.js引入

	import EchartsCountryMap from './EchartsCountryMap';
	export const controlPanelConfigs = {  echarts_country_map: EchartsCountryMap, }

C、 在superset/assets/src/explore/controlPanels/下新建EchartsCountryMap.js(左侧选项)

    import { t } from '@superset-ui/translation';
	export default {
		controlPanelSections: [
			{
				label: t('Query'),
				expanded: true,
				controlSetRows: [
					['entity'],
					['metric'],
				],
			},
			{
				label: t('Options'),
				controlSetRows: [
					['select_country'],
					['number_format'],
					['linear_color_scheme'],
				],
			},
		],
		controlOverrides: {
			entity: {
				label: t('ISO 3166-2 codes of region/province/department'),
				description: t('It\'s ISO 3166-2 of your region/province/department in your table. (see documentation for list of ISO 3166-2)'),
			},
			metric: {
				label: t('Metric'),
				description: 'Metric to display bottom title',
			},
			linear_color_scheme: {
				renderTrigger: false,
			},
		},
	};

对应适当的切片,及图表文件

D、 修改superset\static\assets\src\visualizations\presets\MapChartPreset.js,
(一般为CommonChartPreset.js)

    import { Preset } from '@superset-ui/core';
	import CountryMapChartPlugin from '../CountryMap/CountryMapChartPlugin';
	import MapBoxChartPlugin from '../MapBox/MapBoxChartPlugin';
	import WorldMapChartPlugin from '../WorldMap/WorldMapChartPlugin';
	import EchartsCountryMapChartPlugin from '../EchartsCountryMap/EchartsCountryMapChartPlugin';

	export default class MapChartPreset extends Preset {
	  constructor() {
		super({
		  name: 'Maps',
		  plugins: [
			new CountryMapChartPlugin().configure({ key: 'country_map' }),
			new MapBoxChartPlugin().configure({ key: 'mapbox' }),
			new WorldMapChartPlugin().configure({ key: 'world_map' }),
			new EchartsCountryMapChartPlugin().configure({ key: 'echarts_country_map' }),
		  ],
		});
	  }
	}

E、 复制countryMap,并改名为EchartsCountryMap
⑴修改transformProps.js: 在const {}和return {}新增字段:‘sliceId,’
⑵参照countryMap修改EchartsCountryMap.css文件和EchartsCountryMapChartPlugin.js和EchartsReactCountryMap.js文件(改名).
⑶修改EchartsCountryMap.js: 或使用countryMap.js文件,如:

	import echarts from 'echarts';
	import PropTypes from 'prop-types';
	import d3 from 'd3';
	import { format as d3Format } from 'd3-format';
	import './EchartsCountryMap.css';
	import { getSequentialSchemeRegistry } from '@superset-ui/color';
	const propTypes = {
		data: PropTypes.arrayOf(PropTypes.shape({
			country_id: PropTypes.string,
			metric: PropTypes.number,
		})),
		width: PropTypes.number,
		height: PropTypes.number,
		country: PropTypes.string,
		linearColorScheme: PropTypes.string,
		mapBaseUrl: PropTypes.string,
		numberFormat: PropTypes.string,
		sliceId: PropTypes.number,
	};

	function EchartsCountryMap(element, props) {
		const {
			data,
			width,
			height,
			 country,
			linearColorScheme,
			mapBaseUrl = '/static/assets/src/visualizations/EchartsCountryMap/countries',
			numberFormat,
			sliceId,
		} = props;

		const div = d3.select(element);
		const sliceID = 'echarts_slice_' + sliceId;
		const html = '
+ width + 'px;height:' + height + 'px;">
'
; div.html(html); // reset const myChart = echarts.init(document.getElementById(sliceID)); const json = data; let oldFeatures = {}; const features = []; const resultFeatures = {}; const colorScale = getSequentialSchemeRegistry().get(linearColorScheme); const colors=colorScale.getColors(); const format = d3Format(numberFormat); let formatter; if (format === 'none') { formatter = ''; } else if (format === 'province') { formatter = '{b}'; } else if (format === 'province+number') { formatter = '{b}:{c}'; } else if (format === 'number') { formatter = '{c}'; } let max = null; let min = null; // const dataAll = []; $.each(json, function (i, item) { const d = {}; d.name = item.country_id; d.value = item.metric; if (max == null || d.value > max) { max = d.value; } if (min == null || d.value < min) { min = d.value; } dataAll.push(d); }); const countryKey = country.toLowerCase(); const url = `${mapBaseUrl}/${countryKey}.geojson`; d3.json(url, function (datas) { oldFeatures = datas.features; // domecharts // var name; $.each(oldFeatures, function (i, oldFeature) { const feature = {}; feature.type = oldFeature.type; feature.id = oldFeature.properties.ID_0; feature.properties = {}; feature.properties.name = oldFeature.properties.NL_NAME_1; if (oldFeature.properties.NL_NAME_1 == null) { feature.properties.name = oldFeature.properties.NAME_1; } else { feature.properties.name = oldFeature.properties.NL_NAME_1; } feature.geometry = oldFeature.geometry; features.push(feature); }); resultFeatures.type = datas.type; resultFeatures.features = features; echarts.registerMap('USA', resultFeatures, { Alaska: { // left: -131, top: 25, width: 15, }, Hawaii: { left: -110, // top: 28, width: 5, }, 'Puerto Rico': { // left: -76, top: 26, width: 2, }, }); const option = { // tooltip: { trigger: 'item', showDelay: 0, transitionDuration: 0.2, formatter(params) { let value = (params.value + '').split('.'); value = value[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,'); return params.seriesName + '
'
+ params.name + ': ' + value; }, }, // visualMap: { left: 'right', min, max, inRange: { color: colors, }, text: ['High', 'Low'], // calculable: true, }, // toolbox: { show: true, // orient: 'Horizontal', left: 'left', top: 'top', feature: { restore: {}, dataView: { readOnly: false }, saveAsImage: {}, }, }, // series: [ { name: '', type: 'map', roam: true, map: 'USA', // map: fd.select_country.toUpperCase(), label: { normal: { show: true, // textStyle: { color: '#238e23' }, // formatter, }, emphasis: {// show: true, textStyle: { color: '#800080' }, }, }, // itemStyle: { // normal: { // show: true,// // textStyle: {color: "#c71585"},// // formatter: '{c}' // }, // emphasis: {label: {show: true},formatter:'{c}'} // }, // textFixed: { Alaska: [20, -20], }, data: dataAll, }, ], }; // myChart.dispatchAction({ // type:'mapunselected', // seriesId:string, // name:'a', // selected:a // }); myChart.setOption(option); }); } EchartsCountryMap.displayName = 'EchartsCountryMap'; EchartsCountryMap.propTypes = propTypes; export default EchartsCountryMap;

2.2 集成echarts的仪表盘gauge,

文件位置均在site-packages\superset,修改后需重新编译
A、从后台获取数据 修改viz.py, 增加:

	class Gauge(BaseViz):
		"""Gauge"""
		viz_type = 'gauge'
		verbose_name = _('Gauge')
		is_timeseries = False
		def get_data(self, df):
			metric = self.metric_labels[0]
			df = df.pivot_table(
				index = 1,#self.groupby,
				values=[metric])
			return df.to_dict(orient='records')

B、控制面板引导文件 修改 \static\assets\src\explore\controlPanels\index.js,增加:

	import Gauge from './Gauge';
	export const controlPanelConfigs = {
		...
		gauge: Gauge,
	};

C、控制面板 在\static\assets\src\explore\controlPanels\下增加文件gauge.js:

	import { t } from '@superset-ui/translation';
	export default {
	  controlPanelSections: [
		{
		  label: t('Query'),
		  expanded: true,
		  controlSetRows: [
			['metric'],
		  ],
		},
		{
		  label: t('Chart Options'),
		  expanded: true,
		  controlSetRows: [
		  ],
		},
	  ],
	  controlOverrides: {
		row_limit: {
		  default: 25,
		},
	  },
	};

D可视化文件配置 在static\assets\src\visualizations\下新建gauge文件夹:
1、新建images文件夹,并存放thumbnail.png图片
2、新建css文件:(图表使用)

	.partition {
	  position: relative;
	}
	.partition .chart {
	  display: block;
	  margin: auto;
	  font-size: 11px;
	}
	.partition rect {
	  stroke: #eee;
	  fill: #aaa;
	  fill-opacity: .8;
	  transition: fill-opacity 180ms linear;
	  cursor: pointer;
	}
	.partition rect:hover {
	  fill-opacity: 1;
	}
	.partition g text {
	  font-weight: bold;
	  fill: rgba(0, 0, 0, 0.8);
	}
	.partition g:hover text {
	  fill: rgba(0, 0, 0, 1);
	}
	.partition .partition-tooltip {
	  position: absolute;
	  top: 0;
	  left: 0;
	  opacity: 0;
	  padding: 5px;
	  pointer-events: none;
	  background-color: rgba(255,255,255, 0.75);
	  border-radius: 5px;
	}
	.partition-tooltip td {
	  padding-left: 5px;
	  font-size: 11px;
	}

3、新建GaugeChartPlugin.js, 通过index.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('Gauge'),
	  description: '',
	  thumbnail,
	});
	export default class GaugeChartPlugin extends ChartPlugin {
	  constructor() {
		super({
		  metadata,
		  transformProps,
		  loadChart: () => import('./ReactGauge.js'),
		});
	  }
	}

4、新建ReactGauge.js, react引用

	import reactify from '../../utils/reactify';
	import Component from './Gauge';
	export default reactify(Component);

5、新建transformProps.js, 整理可提供的变量参数

	export default function transformProps(chartProps) {
	  const { width, height, datasource, formData, payload } = chartProps;
	  const {
		metrics,
		dateTimeFormat,
	  } = formData;
	  const { verboseMap } = datasource;
	  return {
		width,
		height,
		data: payload.data,
		metrics,
		dateTimeFormat,
	  };
	}

6、新建Gauge.js, 生成图表文件

	import echarts from 'echarts';
	import d3 from 'd3';
	import PropTypes from 'prop-types';
	import { hierarchy } from 'd3-hierarchy';
	import { CategoricalColorNamespace } from '@superset-ui/color';
	import { d3TimeFormatPreset } from '../../modules/utils';
	import './Gauge.css';
	const propTypes = {
		width: PropTypes.number,
		height: PropTypes.number,
		data: PropTypes.arrayOf(PropTypes.shape({
			count: PropTypes.number,
		}))
	};
	function Gauge(element, props){
		// 建立chart图表的容器
		const div = d3.select(element);
		const divId = 'echarts_guage' + "_guage_ID";
		var html = `
${divId}" style="width: ${props.width}px;height: ${props.height}px;">
`
; div.html(html); // 重新加载 // 初始化 var myChart = echarts.init(document.getElementById(divId)); // 图表参数配置 var option = { tooltip : { formatter: "{a}
{c} {b}"
}, toolbox: { show: true, feature: { restore: {show: true}, saveAsImage: {show: true} } }, series : [ { name: '速度', type: 'gauge', z: 1, min: 0, max: 50000, splitNumber: 10, radius: '100%', axisLine: { // 坐标轴线 lineStyle: { // 属性lineStyle控制线条样式 width: 25 } }, axisTick: { // 坐标轴小标记 length: 35, // 属性length控制线长 lineStyle: { // 属性lineStyle控制线条样式 color: 'auto' } }, splitLine: { // 分隔线 length: 40, // 属性length控制线长 lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式 color: 'auto' } }, axisLabel: { backgroundColor: 'auto', borderRadius: 2, color: '#eee', padding: 10, textShadowBlur: 2, textShadowOffsetX: 1, textShadowOffsetY: 1, textShadowColor: '#222' }, title : { // 其余属性默认使用全局文本样式,详见TEXTSTYLE fontWeight: 'bolder', fontSize: 40, fontStyle: 'italic', }, detail : { // 其余属性默认使用全局文本样式,详见TEXTSTYLE formatter: function (value) { value = (value + '').split('.'); value.length < 2 && (value.push('00')); return ('00' + value[0]).slice(-2) + '.' + (value[1] + '00').slice(0, 2);}, fontWeight: 'bolder', borderRadius: 3, backgroundColor: '#444', borderColor: '#aaa', shadowBlur: 5, shadowColor: '#333', shadowOffsetX: 0, shadowOffsetY: 3, borderWidth: 2, textBorderColor: '#000', textBorderWidth: 2, textShadowBlur: 2, textShadowColor: '#fff', textShadowOffsetX: 0, textShadowOffsetY: 0, fontFamily: 'Arial', width: 100, color: '#eee', rich: {} }, data:[{value: props.data[0].count, name: 'km/h'}] } ] }; // 参数加载 myChart.setOption(option); }; Gauge.displayName = 'Gauge'; Gauge.propTypes = propTypes; export default Gauge;

八、匿名登录和默认语言

1,修改config.py: PUBLIC_ROLE_LIKE_GAMMA = True
2, 网页admin登录superset,安全>用户列表>修改public,增加
	all datasource access on all_datasource_access
	all database access on all_database_access
3, superset\bin下,执行python superset init,初始化用户角色和权限
4,到看板页面,分享相应看板的链接。
5,修改config.py:BABEL_DEFAULT_LOCALE = 'zh'

你可能感兴趣的:(superset)