赞
踩
windows11 python-3.10.5 pyecharts-2.0.3,其他版本没试过。
之前用0.5版本的pyecharts倒是没遇到离线使用的问题。换了v2版本后遇到了。
网上查到的大多数方法是开个http服务器,让浏览器访问生成图表的html时下载js脚本改为从本地服务器下载,从而解决pyecharts离线使用问题。但我的需求是:
1、不需要开服务器也能生成html图表。
2、生成的html不用再另外下载js脚本,换台电脑也能直接打开显示图表。
3、不在源码上改动,换台电脑使用一样的pyecharts也可以运行使用。
改动前,生成一份非嵌入js的图表html,找到js脚本链接,下载到本地。
浏览器访问https://assets.pyecharts.org/assets/v5/echarts.min.js,保存下js文件。
需求2很好解决,把js代码嵌入html即可。在pyecharts手册里有提到一个渲染配置项RenderOpts,提供是否在渲染HTML时嵌入JS文件,默认False不嵌入。若想要“换台电脑也能直接打开显示图表”这个效果,则把此配置项设为True即可。
创建图表时候,初始化时候指定下render_opts参数,如下柱状图代码:
bar = Bar(init_opts=opts.InitOpts(), render_opts=opts.RenderOpts(is_embed_js=True))
其实到本步骤,使用本地开服务器方式+嵌入js到html方法,也能勉强满足我原始的需求,但是运行时候发现了个问题,我是用http方式开的服务,但是嵌入js脚本代码却是用https请求访问js资源后才去嵌入html的,导致了异常报错。修改源码把HTTPSConnection改为HTTPConnection发现可以,进一步可以取scheme进行http/https判断走不同逻辑请求。但是我并不想在源码做改动,这样我换台电脑还要改,显然挺麻烦的。
这里我想到了猴子补丁的方法,将源码里的load_javascript_contents方法替换为自己编写的方法。load_javascript_contents的逻辑延用源码的逻辑,然后补充2个点。1个是如果请求的js是echarts.min.js(别的同理),则读取本地echarts.min.js文件内容赋值,达成离线使用效果。1个是判断请求是http还是https,走不同的连接,后续如果扩展可能需要。替换方法的代码如下:
- import http.client
- from typing import Optional
- from urllib.parse import urlparse
-
- from pyecharts import options as opts
- from pyecharts.charts import Bar
- from pyecharts.render.display import Javascript
-
-
- class ChartsLib(object):
-
- def __init__(self):
- Javascript.load_javascript_contents = self.load_javascript_contents
-
- @staticmethod
- def read_echarts_min_js():
- with open("echarts.min.js", "r", encoding="utf-8") as f:
- text = f.read()
- f.close()
- return text
-
- @staticmethod
- def load_javascript_contents(self):
- for lib in self.lib:
- if "echarts.min.js" in lib:
- self.javascript_contents[lib] = ChartsLib.read_echarts_min_js()
- continue
- parsed_url = urlparse(lib)
- scheme: str = parsed_url.scheme
- host: str = str(parsed_url.hostname)
- port: int = parsed_url.port
- path: str = parsed_url.path
- resp: Optional[http.client.HTTPResponse] = None
- try:
- if scheme == "https":
- conn = http.client.HTTPSConnection(host, port)
- else:
- 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:
- if resp is not None:
- resp.close()
- return self
-
- @staticmethod
- def demo_bar(infos, interactions, html_name="bar_interactions.html"):
- bar = Bar(init_opts=opts.InitOpts(height="1000px"), render_opts=opts.RenderOpts(is_embed_js=True))
- bar.add_xaxis(infos)
- bar.add_yaxis("xx数据", interactions)
- bar.reversal_axis()
- bar.set_series_opts(label_opts=opts.LabelOpts(position="right"))
- bar.set_global_opts(title_opts=opts.TitleOpts(title="示例表"),
- toolbox_opts=opts.ToolboxOpts(),
- datazoom_opts=[
- opts.DataZoomOpts(orient="horizontal", range_start=0, range_end=100),
- opts.DataZoomOpts(orient='vertical', range_start=0, range_end=100)
- ])
- bar.render(html_name)
- return bar
这样就达到了3个需求点要求了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。