目前发现有两种方法可以完成一个简单的Echart.
一种是使用%%html
,在一个cell中写完HTML+JS代码。例如,
%%html
<div id="main" style="width:700px;height:400px">div>
<script src="js/echarts.min.js">script>
<script>
<!-- do something -->
<!-- inital echart -->
script>
另一种,%%javascript
和%%html
结合使用,各司其职。
Jupyter Notebook自带requirejs,可以使用requirejs来引入外部js文件.
%%javascript
//配置js源地址,也可以使用本地的js文件
requirejs.config({
paths:{
'echarts': ["http://echarts.baidu.com/dist/echarts.min"], //末尾会自动添加.js, 这里一定要去掉,否则引用失败
'jquery': ["https://code.jquery.com/jquery-3.3.1.min"],
}
});
require(["ecahrts", "jquery"], function(echarts, jquery){
// do something
// initial echart
});
使用Notebook画图时,变量大多是之前用python脚本算好的。那么,要使Notebook中画echart实用,要解决的关键问题就是,如何使用python定义的变量
画图.
Notebook javascript自带的IPython模块,让我们可以在js脚本中执行python的代码。
如图:
Ipython.notebook.kernel.execute允许设置callbacks, 在callbacks中可以对代码执行的output进行相关处理。
var code = "print ('Hello World')";
var callbacks = {
iopub : {
output: function(data){
var res = data.content.text;
// `res` is 'Hello World'
// do something
}
}
};
execute(code, callbacks);
由此,我的基本思路就是通过处理output获取Python定义的变量。
单纯的print出来,当变量是list时,格式会有问题。所以通过json.dumps对数据进行了转换
var code = "print(json.dumps(["+ paramNames.join() +"]))";
//paraNames是变量名组成的list
var callbacks = {
iopub : {
output: function(data){
var res = JSON.parse(data.content.text.trim());
// do something
}
}
整理前面的思路, 将引用js,传递变量等部分,整理为一个js文件. 以后只需要引用这个js文件即可。
这是一个简陋且高度定制化的方法,目前基本满足我的日常工作,如果你有更好的意见或是建议,欢迎指出
// my-echart.js
requirejs.config({
paths:{
'echarts': ["http://echarts.baidu.com/dist/echarts.min"],
'jquery': ["https://code.jquery.com/jquery-3.3.1.min"],
}
});
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function execute(code, callbacks) {
var kernel = IPython.notebook.kernel;
// notebook分享给其他人时,为避免kernel未启动js报错,会等待kernel ready再画图
while(!kernel){
console.log('Taking a break...');
await sleep(2000);
console.log('Two seconds later');
var kernel = IPython.notebook.kernel;
}
console.log("kernel has ready");
IPython.notebook.kernel.execute("import json");
IPython.notebook.kernel.execute(code,callbacks);
}
// 按顺序将echart option中的变量替换为callbacks获取的变量
function formatOption(option) {
var string = JSON.stringify(option)
var args = arguments[1];
var pattern = new RegExp('([", \'])\%([1-'+ args.length +'])([",\'])', "g");
var str_with_data = String(string).replace(pattern,
function(match,p1,index) {
return JSON.stringify(args[index-1]);
});
return JSON.parse(str_with_data)
};
function loadChart(option,chartId){
require(["jquery","echarts"],function(jquery,echarts){
var myChart = echarts.init(document.getElementById(chartId));
myChart.clear();
myChart.setOption(option);
});
};
// MAIN-FUNCTION
async function newEChart(chartId, option, paramNames){
var code = "print(json.dumps(["+ paramNames.join() +"]))";
var callbacks = {
iopub : {
output: function(data){
var res = JSON.parse(data.content.text.trim());
var optionWithData = formatOption(option,res);
loadChart(optionWithData, chartId);
}
}
};
execute(code, callbacks);
};
x = ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
data = [5, 20, 36, 10, 10, 20]
%%html
<div id="main" style="width:700px;height:400px">div>
<script src="js/my-echarts.js">script>
%%javascript
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: "%1" // 会被替换为 x
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: "%2" // 会被替换为 data
}]
};
newEChart("main",option,["x","data"]);
// params: ID, option, parameter names list