当前pyecharts
版本为1.9.0
概述
render
包结构
render
包位于pyecharts
包顶级目录中,用于渲染图表。render
包结构如下:
├─render # 渲染设置包
│ │ display.py # 定义HTML、JavaScript显示类,用于支持在notebook中嵌入输出结果
│ │ engine.py # 定义渲染相关类、函数
│ │ snapshot.py # 定义渲染图片函数
│ │ __init__.py # 暴露渲染图片函数
│ │
│ ├─templates # 定义渲染模板
│ │ components.html
│ │ macro
│ │ nb_components.html
│ │ nb_jupyter_globe.html
│ │ nb_jupyter_lab.html
│ │ nb_jupyter_lab_tab.html
│ │ nb_jupyter_notebook.html
│ │ nb_jupyter_notebook_tab.html
│ │ nb_nteract.html
│ │ simple_chart.html
│ │ simple_globe.html
│ │ simple_page.html
│ │ simple_tab.html
snapshot
模块
snapshot
模块,路径为pyecharts/render/snapshot.py
,作用为提供渲染图片的接口。原理就是将HTML渲染为图片。
注意!单纯依靠该模块还不能直接渲染图片,还需要安装snapshot-selenium
、snapshot-phantomjs
、snapshot-pyppeteer
等包,利用selenium
、phantomjs
、pypeteer
等第三方库生成图片。具体方法参见pyecharts
文档https://pyecharts.org/#/zh-cn/render_images
。
snapshot
模块的结构如下图所示。
make_snapshot
函数,模块最重要的函数,集成模块其他函数对外提供接口。decode_base64(data: str) -> bytes
函数:解码base64字符串为字节数据。save_as_png(image_data: bytes, output_name: str)
函数:根据字节数据生成图片。save_as(image_data: bytes, output_name: str, file_type: str)
函数:依靠PIL
库根据字节数据生成图片。save_as_text(image_data: str, output_name: str)
函数:根据字符串生成文本文件。
make_snapshot
函数
render
包通过from .snapshot import make_snapshot
向外暴露make_snapshot
函数。
make_snapshot
函数的签名为:
def make_snapshot( engine: Any, file_name: str, output_name: str, delay: float = 2, pixel_ratio: int = 2, is_remove_html: bool = False, **kwargs, )
make_snapshot
函数的参数如下:
engine
:渲染引擎,第三方库接口。file_name
:传入的HTML文件名称。字符串。output_name
:输出图片路径。字符串。delay
:延迟时间,避免图还没渲染完成就生成了图片,造成图片不完整。浮点数,默认值为2,单位秒。pixel_ratio
:像素比例,用于调节图片质量。整数,默认值为2。is_remove_html
:渲染完图片是否删除原 HTML 文件。布尔值,默认值为False
。browser
:浏览器类型,目前仅支持 Chrome, Safari,使用snapshot-selenium
时有效。字符串,默认值为"Chrome"
。
make_snapshot
函数的处理要点大致如下:
如果生成图片路径中文件的扩展名为SVG
或base64
,调用save_as_text(image_data: str, output_name: str)
函数生成文件。
如果生成图片路径中文件的扩展名为pdf, gif, png, jpeg,eps
,则利用decode_base64(data: str) -> bytes
构造图像数组。
如果文件扩展名为png
, jpeg
调用save_as_png(image_data: bytes, output_name: str)
函数生成文件。
如果文件扩展名为pdf
, gif
,eps
则调用save_as(image_data: bytes, output_name: str, file_type: str)
函数生成文件。
pyecharts/render/snapshot.py
模块源码
import base64
import codecs
import logging
import os
from io import BytesIO
from ..types import Any
logger = logging.getLogger(__name__)
PNG_FORMAT = "png"
JPG_FORMAT = "jpeg"
GIF_FORMAT = "gif"
PDF_FORMAT = "pdf"
SVG_FORMAT = "svg"
EPS_FORMAT = "eps"
B64_FORMAT = "base64"
def make_snapshot(
engine: Any,
file_name: str,
output_name: str,
delay: float = 2,
pixel_ratio: int = 2,
is_remove_html: bool = False,
**kwargs,
):
logger.info("Generating file ...")
file_type = output_name.split(".")[-1]
content = engine.make_snapshot(
html_path=file_name,
file_type=file_type,
delay=delay,
pixel_ratio=pixel_ratio,
**kwargs,
)
if file_type in [SVG_FORMAT, B64_FORMAT]:
save_as_text(content, output_name)
else:
# pdf, gif, png, jpeg
content_array = content.split(",")
if len(content_array) != 2:
raise OSError(content_array)
image_data = decode_base64(content_array[1])
if file_type in [PDF_FORMAT, GIF_FORMAT, EPS_FORMAT]:
save_as(image_data, output_name, file_type)
elif file_type in [PNG_FORMAT, JPG_FORMAT]:
save_as_png(image_data, output_name)
else:
raise TypeError(f"Not supported file type '{file_type}'")
if "/" not in output_name:
output_name = os.path.join(os.getcwd(), output_name)
if is_remove_html and not file_name.startswith("http"):
os.unlink(file_name)
logger.info(f"File saved in {output_name}")
def decode_base64(data: str) -> bytes:
"""Decode base64, padding being optional.
:param data: Base64 data as an ASCII byte string
:returns: The decoded byte string.
"""
missing_padding = len(data) % 4
if missing_padding != 0:
data += "=" * (4 - missing_padding)
return base64.decodebytes(data.encode("utf-8"))
def save_as_png(image_data: bytes, output_name: str):
with open(output_name, "wb") as f:
f.write(image_data)
def save_as_text(image_data: str, output_name: str):
with codecs.open(output_name, "w", encoding="utf-8") as f:
f.write(image_data)
def save_as(image_data: bytes, output_name: str, file_type: str):
try:
from PIL import Image
m = Image.open(BytesIO(image_data))
m.load()
color = (255, 255, 255)
b = Image.new("RGB", m.size, color)
b.paste(m, mask=m.split()[3])
b.save(output_name, file_type, quality=100)
except ModuleNotFoundError:
raise Exception(f"Please install PIL for {file_type} image type")