本人最近在离线情况下绘制使用pyecharts图表遇到了一些坑,通过查阅相关资料解决了问题,现在分享出来。
pyecharts:2.0.4
python:3.8,windows11
pyecharts绘制的图表,通过渲染成html文件,打开该文件,会发现script指向了一个网址,在联网环境下,该图就可以成功加载并显示,但在离线情况下,就无法正常加载,现在分享离线绘制图表的4种方法。我比较推荐最后1种。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Awesome-pyecharts</title>
<script type="text/javascript" src="https://assets.pyecharts.org/assets/v5/echarts.min.js"></script>
开始之前,必须要准备好静态资源文件,从官方地址下载,我们绘图需要的资源文件都在assets/v5文件夹里面,把assets文件夹放在我们的项目目录里面。v5文件夹下面的echarts.min.js是最新的,所以我们用这个版本的。
方法一,这也是大多数网络搜索结果及官方分享的方法,pyecharts 提供了更改全局 HOST 的快捷方式,下面以开发者启动本地 FILE SERVER 为例
步骤1:设置host地址,路径指向v5文件夹
from pyecharts.globals import CurrentConfig
CurrentConfig.ONLINE_HOST = "http://127.0.0.1:8000/assets/v5/"#请注意,这里的文件夹路径要指向echarts.min.js所在文件夹
步骤2:开启本地http服务
$ cd D:\python\离线绘制#项目地址
$ python -m http.server
# Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
# 默认会在本地 8000 端口启动一个文件服务器
这个代码也可以写进python里面,使用thread+os.system(command)实现
def start_http():
path=str(Path.cwd())
command=f"python -m http.server -d {path}"
os.system(command)
thread=threading.Thread(target=start_http)
thread.start()#开启线程
thread.join()#等待线程结束
步骤3:开始绘制图形
line = Line()
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [random.random() * i for i in range(10)]
line.add_xaxis(x).add_yaxis("示例", y)
line.render("示例.html")
os.startfile("示例.html")#打开html
此时打开绘制的html文件,可以看到script指向了本机刚刚设置的地址的echarts.min.js文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Awesome-pyecharts</title>
<script type="text/javascript" src="http://127.0.0.1:8000/assets/v5/echarts.min.js"></script>
总结:该方法代码简单,实现需要开启http服务,但生成的html文件依赖于本机echarts.min.js文件,无法转发分享。
方法二,更改全局 HOST 直接指向本地静态资源文件地址
步骤1:更改全局HOST
from pyecharts.globals import CurrentConfig
CurrentConfig.ONLINE_HOST = str(Path.cwd())+"/assets/v5/"
步骤2:开始绘图,绘图完成后打开html文件,可以看到script指向了设置路径下的echarts.min.js文件。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Awesome-pyecharts</title>
<script type="text/javascript" src="D:\python\离线绘制/assets/v5/echarts.min.js"></script>
总结:该方法代码更简单,不需要开启http服务,但生成的html文件依赖于本机echarts.min.js文件,无法转发分享。
方法三:使用pyecharts的class pyecharts.options.RenderOpts配置项,设置is_embed_js:bool=False实现在渲染 HTML 时嵌入 JS 文件
步骤1:同方法一的步骤1
步骤2:同方法一的步骤2
步骤3:创建绘图对象时,设置render_opts配置项
line = Line(render_opts=opts.RenderOpts(is_embed_js=True))
步骤4:开始绘图,会提示错误,此时需要修改库源文件
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1131)
打开site-packages\pyecharts\render\display.py文件,第77行,修改HTTPSConnection为HTTPConnection
try:
conn = http.client.HTTPConnection(host, port)
conn.request("GET", path)
resp = conn.getresponse()
if resp.status != 200:
raise RuntimeError("Cannot load JavaScript lib: %s" % lib)
self.javascript_contents[lib] = resp.read().decode("utf-8")
finally:
ok,成功绘制图形,打开html文件,会发现js文件的内容已经内嵌入html文件了。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Awesome-pyecharts</title>
<script type="text/javascript">
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
总结:该方法略显复杂,而且需要修改库文件,优点是将js文件内容内嵌入html文件中,不再依赖本机echarts.min.js文件,可以转发分享。
方法四:该方法对方法三略作修改,不修改库文件。通过Monkey patching方法实现,修改库文件中的Javascript.load_javascript_contents方法
步骤1:Monkey patching修改Javascript.load_javascript_contents方法
from pyecharts.render.display import Javascript
#定义新的load_javascript_contents函数,该函数实现程序请求js文件时,从磁盘读取该文件,并将内容直接赋值
def new_js(self):
for lib in self.lib:
work_path = str(Path.cwd()) + "/assets/v5/"
new_lib = lib.replace("https://assets.pyecharts.org/assets/v5/", f"{work_path}")
with open(new_lib, "r", encoding="utf-8") as f:
self.javascript_contents[lib] = f.read()
f.close()
continue
return self
Javascript.load_javascript_contents = new_js
步骤2:开始绘图,打开html文件,会发现js文件的内容已经内嵌入html文件了。
全部代码如下:
import os
import random
from pathlib import Path
from pyecharts import options as opts
from pyecharts.charts import Line
from pyecharts.render.display import Javascript
# 定义新的load_javascript_contents函数
def new_js(self):
for lib in self.lib:
work_path = str(Path.cwd()) + "/assets/v5/"
new_lib = lib.replace("https://assets.pyecharts.org/assets/v5/", f"{work_path}")
with open(new_lib, "r", encoding="utf-8") as f:
self.javascript_contents[lib] = f.read()
f.close()
continue
return self
Javascript.load_javascript_contents = new_js
line = Line(render_opts=opts.RenderOpts(is_embed_js=True))
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [random.random() * i for i in range(10)]
line.add_xaxis(x).add_yaxis("示例", y)
line.render("示例.html")
os.startfile("示例.html")
总结,该方法代码复杂一点,但不修改源文件的情况下实现了内嵌js文件,html可转发分享。