近日几个高中朋友都上岸研究生,某人提议做一个求学路线图,这种技术活儿当然就交给我了。
python 3.11.2
pyecharts 2.0.3
selenium 4.8.3
pyecharts-snapshot 0.2.0
官方文档
是一个基于Echarts的python工具包,用于数据可视化,可以用来画日历图、饼图、雷达图、词云图、涟漪特效图、热力图、散点图、数图、地图、3D图等
pip install pyecharts
将 pyecharts/echarts.js 的输出呈现为 png、jpeg、gif、eps、svg 图像、原始 base64 编码或 pdf 文件
pip install pyecharts-snapshot
pyecharts-snapshot用来将地图渲染成图片。
要使用pyecharts-snapshot,确保电脑正确安装Phantomjs,否则会报错,Phantomjs官网下载链接,选择符合自己电脑的版本下载。
下载完成之后,将bin加入到系统变量中。
使用pyecharts的过程,会学到链式调用和万物皆可对象化!
第一步,我们要画中国地图,创建一个Geo对象(地理图标)
geo = Geo()
在Geo()
中初始化地图,设置一些基本的参数
一般写法
geo = Geo(
width="1000px",
height="600px",
theme=ThemeType.ESSOS, # 地图主题
)
但是在pyecharts中有一个重要的思想就是
标准的写法是
geo = Geo(
init_opts=opts.InitOpts(
width="1000px", # 画布宽度
height="600px", # 画布高度
theme=ThemeType.ESSOS, # 地图主题
)
)
在这里使用init_opts
进行初始化,init_opts
是一个options
,值由opts.InitOpts
实例化得到,而width="1000px"...
等params
则作为opts.InitOpts
的参数。
个人认为万物皆options有以下几点好处:
比如这个InitOpts
,经查阅文档后共有这么多属性
class InitOpts(
# 图表画布宽度,css 长度单位。
width: str = "900px",
# 图表画布高度,css 长度单位。
height: str = "500px",
# 图表 ID,图表唯一标识,用于在多图表时区分。
chart_id: Optional[str] = None,
# 渲染风格,可选 "canvas", "svg"
# # 参考 `全局变量` 章节
renderer: str = RenderType.CANVAS,
# 网页标题
page_title: str = "Awesome-pyecharts",
# 图表主题
theme: str = "white",
# 图表背景颜色
bg_color: Optional[str] = None,
# 远程 js host,如不设置默认为 https://assets.pyecharts.org/assets/"
# 参考 `全局变量` 章节
js_host: str = "",
# 画图动画初始化配置,参考 `global_options.AnimationOpts`
animation_opts: Union[AnimationOpts, dict] = AnimationOpts(),
)
再加上一些必要的参数,完整版初始化代码如下:
geo = Geo(
init_opts=opts.InitOpts(
width="1000px", # 画布宽度
height="600px", # 画布高度
theme=ThemeType.ESSOS, # 地图主题
),
is_ignore_nonexistent_coord=True
)
调用.add_schema()
方法设置Geo
对象的地图类型、缩放、视角中心点等
.add_schema(
maptype='china' # 设置地图类型为china
zoom=1.5, # 缩放比例为1.5
center=[105.95, 34.27], # 设置视角中心点为[105.95, 34.27]
)
其中zoom
center
都是为后面导出图像设置的,效果如下
调用geo
对象的.add
方法,添加需要显示的点,并设置其样式
这里最坑的是,文档中没有给出点实例,导致调试data废了很大功夫
以北京举例:应该是("北京“, [116.407526, 39.90403])
,数据项为元组类型,第一个元素为坐标点名称,第二个元素为坐标点的经度纬度,如果多个点,则data_pair
为列表形式
这里有个坑,名称和经纬度必须一一对应才能正确显示,如果把北京改成北京市区,就不行了,估摸着他应该内置了一个对应关系
.add(
series_name='研究生', # 这一系列点的名称
symbol_size=18, # 标志(圆圈)的尺寸
data_pair=city_graduate, # 数据项
type_="scatter", # 数据类型
label_opts=opts.LabelOpts( #标签(就是文字)
is_show=True, # 是否显示标签
formatter='{b}', # 标签显示的格式
font_size=20, # 标签的文字大小
font_style="normal", # 标签的样式
))
调用geo.render
参数为渲染后的html文件路径
.render('html/graduate.html')
第一个参数为渲染引擎,这里选择phantomjs
;第二个参数是html文件路径;第三个参数是渲染后的图片文件路径
from snapshot_phantomjs import snapshot
from generate_coordinate import generate_coordinate
make_snapshot(snapshot, 'html/graduate.html', 'image/graduate.png')
这里不得不提python的链式调用,十分直观,简约
geo = (
Geo(
init_opts=opts.InitOpts(
width="1000px", # 画布宽度
height="600px", # 画布高度
theme=ThemeType.ESSOS, # 地图主题
),
is_ignore_nonexistent_coord=True
)
.add_schema(
maptype='china' # 设置地图类型为china
zoom=1.5, # 缩放比例为1.5
center=[105.95, 34.27], # 设置视角中心点为[105.95, 34.27]
)
.add(
series_name='研究生', # 这一系列点的名称
symbol_size=18, # 标志(圆圈)的尺寸
data_pair=city_graduate, # 数据项
type_="scatter", # 数据类型
label_opts=opts.LabelOpts( #标签(就是文字)
is_show=True, # 是否显示标签
formatter='{b}', # 标签显示的格式
font_size=20, # 标签的文字大小
font_style="normal", # 标签的样式
)
)
.render('html/graduate.html')
)
把所有有关这个对象的操作链成一个链条执行,将每个操作的结果组合,返回给geo对象。
“ReferenceError: Can‘t find variable: echarts\n\n undefined:1\nnull\n“
错误,考虑项目目录中是否有中文,将其移动到纯英文目录中,问题就解决了。这还是我google来的,仔细思考一下,
can't find variable
问题出在找不到echarts变量,但是echarts变量是存在的,否则画图就会报错,这样变量存在却找不到的情况,多半是路径出现问题,考虑到中文路径,以后这类Bug都可以往这方面想。
github链接
至此,城市分布图地图画好了!!短短的几行代码花了我六小时琢磨,反思一下: