如果你的电脑里还躺着 pyecharts 0.5.11 这个版本号这篇文章就是为你准备的。我手上有几个数据看板项目代码就是用这套旧版 API 写的一直跑得好好的所以也没急着升级。0.5.11 看起来不够“新”但它在实际业务里非常能打启动快、依赖少、入门曲线短很多毕业设计、报表系统的代码到现在还在线上跑。这篇文章把 pyecharts 0.5.11 的图表生成拆开来讲从安装、数据格式、常用图表到底层渲染原理、常见坑都会说到。不管你是刚接触想快速出图还是接手旧项目需要维护都能从中找到能直接用的东西。需要提醒一句如果你是从 1.x 版本切过来看这篇内容的先放下手里的链式调用习惯。pyecharts 0.5.x 和 1.x 虽然都叫 pyecharts但 API 风格完全是两代人。0.5.11 用的是老式实例化加 add 方法传参的写法1.x 改成 x 轴 y 轴分开配置、统一用 options 管理。只有先把认知切回旧版本的语境下面这些代码才不会让你觉得莫名其妙。1. 为什么还在用 pyecharts 0.5.11以及它的 API 边界1.1 0.5.x 与 1.x 的差异到底有多大很多朋友会问既然 1.x 都出了那么久为什么还守着 0.5.11 不放。答案很简单存量代码太多而且 0.5.11 在简单报表场景里真的是够用。0.5.11 的核心用法一句话就能讲完——初始化一个图表对象然后用 add 方法把数据塞进去最后 render 成 HTML 文件。对比一下 0.5.11 和 1.x 的写法# pyecharts 0.5.11 的经典写法 from pyecharts import Bar bar Bar(近30天销量, 示例数据) bar.add(订单量, [1日, 2日, 3日], [120, 200, 150]) bar.render(bar.html)# pyecharts 1.x 的写法 from pyecharts.charts import Bar from pyecharts import options as opts bar ( Bar() .add_xaxis([1日, 2日, 3日]) .add_yaxis(订单量, [120, 200, 150]) .set_global_opts(title_optsopts.TitleOpts(title近30天销量)) ) bar.render(bar.html)看到区别了吗0.5.11 把标题、数据系列、坐标轴都放在不同的传参位置里1.x 则把配置项收敛成独立的 options 体系。从代码可读性来说1.x 确实更清晰但它引入的链式调用和大量 opts 类会让接手旧项目的人感觉像换了一门语言。我见过不少人因为升级 1.x 时改坏了几十个图表最后又把代码回滚到 0.5.11 继续跑因为老板只关心图表能不能按时出来。1.2 0.5.11 能画什么不能画什么0.5.11 支持的图表类型覆盖了绝大多数业务场景常用的有 Bar 柱状图、Line 折线图、Pie 饼图、Scatter 散点图、KLine 蜡烛图、HeatMap 热力图、Map 地图、Geo 地理坐标图、Radar 雷达图、Funnel 漏斗图、Gauge 仪表盘、WordCloud 词云。这些类都在 pyecharts 包顶层直接 import 就能用。它明显弱于 1.x 的地方主要在两个点。第一0.5.11 没有 1.x 那种统一且严格的 options 校验机制参数名写错了很可能不报错图表只是悄悄少一个功能排查起来非常费劲。第二0.5.11 对响应式布局的支持比较弱移动端看图表经常会出现文字挤压、图例错位的问题。所以如果你的项目是移动端优先我不建议新代码再用 0.5.11但如果是 PC 端后台看板那它完全够用。还有一个容易踩的认知误区0.5.11 虽然会把 echarts 的前端库打包进 HTML但它的模板默认引用的是在线 CDN 地址。换句话说render 出来的 HTML 必须在能访问外网的环境里才能完整渲染。这个问题留到后面“离线运行”部分细说。2. 环境准备装对版本、装对地图包后面才能少踩坑2.1 安装 Python3 环境与 pyecharts 0.5.11如果你用的是虚拟环境直接一条命令pip install pyecharts0.5.11这里强烈建议在虚拟环境里装不要用全局环境。因为很多人的机器上已经装了 1.x 或者其他依赖混装之后 import 的类名可能完全对不上。0.5.11 安装时会自动带上一些运行必需的依赖比如模板渲染需要的那几个包不用额外操心。装完之后验证一下版本pip show pyecharts然后跑一个最简单的例子确认能生成 HTML 文件from pyecharts import Bar bar Bar(验证环境, 示例) bar.add(系列, [A, B], [1, 2]) bar.render(smoke_test.html)如果这一步成功会在当前目录生成一个 smoke_test.html打开后能看到一个带标题的柱状图。看不到就先把浏览器控制台的报错截图留下来后面排查章节会提到最常见的原因。2.2 地图扩展包怎么装才算装对0.5.11 的 Map 和 Geo 图表比较特殊地图的 GeoJSON 数据不在 pyecharts 主包里而是拆成了独立扩展包。画中国地图需要装的是这几个pip install echarts-countries-pypkg pip install echarts-china-provinces-pypkg pip install echarts-china-cities-pypkg pip install echarts-china-misc-pypkg这几个包体积不算小装的时候要耐心等。第一次使用地图时pyecharts 会把对应的地理数据加载进模板所以第一个地图页面渲染可能会明显变慢这是正常现象。有一个容易困惑的点这些包装完之后代码里不需要显式 import 它们。你只要正确传了 maptype 参数比如 maptypechinapyecharts 会自己去注册表里找。如果渲染出来的地图只有轮廓、没有区域颜色十有八九是这些扩展包没装上或者装到了另一个 Python 环境里。2.3 验证一个地图图表from pyecharts import Map data [(北京, 120), (上海, 160), (广东, 200), (浙江, 300)] map_chart Map(各省销量, width800, height400) map_chart.add(销量, data, maptypechina, is_visualmapTrue, visual_range[0, 300]) map_chart.render(map_test.html)这里命名为 map_chart 而不是 map是因为 Python 内置函数 map 很容易被覆盖一旦覆盖了后面再写 list(map(...)) 就会报错。这是旧版 pyecharts 教程里经常会忽略的细节我自己在这上面吃过亏。3. 核心图表实操从柱状图到地图的数据格式与参数3.1 柱状图与折线图先把手感练出来柱状图是所有 pyecharts 项目里出现频率最高的图。0.5.11 的 Bar 初始化参数直接传标题add 方法的第一个参数是系列名第二个是 x 轴数据第三个是 y 轴数据。多个系列就多次调用 add柱状图默认并排显示。from pyecharts import Bar bar Bar( title上半年销售额, subtitle单位万元, width900, height450, ) bar.add(华东, [1月, 2月, 3月, 4月], [12, 19, 28, 32]) bar.add(华南, [1月, 2月, 3月, 4月], [8, 15, 22, 27], is_stackTrue) bar.add(华北, [1月, 2月, 3月, 4月], [5, 10, 14, 18], is_stackTrue) bar.render(bar_demo.html)is_stackTrue 会把同一 x 轴下的多个系列堆叠起来适合展示整体构成。要注意堆叠的细节如果你对第一个系列不传、第二个系列传了 is_stackTrue那么堆叠关系是从第二个系列开始的视觉上会出现一半堆叠一半并排的混乱效果。同类参数里is_label_showTrue 会在柱子上直接显示数值mark_point[max, min] 可以标出最高最低点。折线图和柱状图的套路基本一样只是更值得关注的是曲线平滑和端点符号from pyecharts import Line line Line(访问趋势, 近7日) line.add( UV, [周一, 周二, 周三, 周四, 周五, 周六, 周日], [1200, 1500, 1300, 1800, 2100, 2600, 2400], is_smoothTrue, is_symbol_showFalse, mark_line[average], ) line.render(line_demo.html)is_smoothTrue 会把折线变成曲线is_symbol_showFalse 能去掉数据点的小圆点mark_line[average] 会在图上画一条平均值虚线。这几个参数在多指标趋势图里特别常用。折线图的数据点如果太多可以在 add 里加一句 is_datazoom_showTrue自动出现一个拖拽缩放的滚动条这个在时间序列数据里几乎是标配。3.2 饼图与环形图数据格式是最大的坑饼图在 0.5.11 里的数据格式和其他图完全不一样。柱状图是 x 轴一个列表、y 轴一个列表而饼图要的是成对数据格式是 [(类别, 数值), (类别, 数值)]。很多从 1.x 转过来的人在这里翻车因为 1.x 的 Pie 也是分 x 轴和 y 轴传的。from pyecharts import Pie source [ (直接访问, 32), (搜索引擎, 45), (广告投放, 18), (社交媒体, 5), ] pie Pie(流量来源分析, width800, height400) pie.add( 占比, source, radius[40, 65], # 内径和外径不传就是实心饼 is_label_showTrue, label_posoutside, legend_orientvertical, legend_posleft, ) pie.render(pie_demo.html)radius[40, 65] 是饼图做成环形图的关键。理解也很简单40 是内半径65 是外半径内半径大于 0 时中间就是空的。legend_orient 和 legend_pos 控制图例的位置饼图右侧空间不够时把图例放左边或者下边会舒服很多。饼图数据传入时还有一个小细节pyecharts 在渲染之前会把数据转成 JSON元组会被转成数组所以在业务代码里用字典转列表即可。如果你直接把一个 dict 传进去遍历顺序可能不是你想要的建议显式生成 listdata [{name: k, value: v} for k, v in source]这个格式不是 0.5.11 的饼图要求的它是底层 echarts 的格式。0.5.11 的 add 方法接受的仍是 list of tuple但转成字典列表在排查 JSON 输出时会更直观算是个人经验。3.3 热力图与散点图二维数据场景热力图在业务里常用于时间序列和类目交叉分析比如一周七天、每小时一段的活跃度变化。0.5.11 的 HeatMap 数据格式比较特殊它要求一个由三个元素组成的列表from pyecharts import HeatMap x_labels [周一, 周二, 周三, 周四, 周五] y_labels [8点, 10点, 12点, 14点] data [ [0, 0, 12], # 周一 8 点 [0, 1, 20], # 周一 10 点 [0, 2, 35], # 周一 12 点 [1, 0, 18], [1, 1, 26], # ... ] heatmap HeatMap(时段活跃度) heatmap.add( 活跃度, x_labels, y_labels, data, is_visualmapTrue, visual_text_color#000, ) heatmap.render(heatmap_demo.html)data 里的三个数字分别是 x 轴索引、y 轴索引和数值。x 轴索引从 0 开始对应 x_labels 里的第几个y 轴索引同理。传反了图表不会报错但会画出一个数据完全错位的图排查时特别隐蔽。散点图相对直觉传入两个等长的列表即可from pyecharts import Scatter scatter Scatter(身高体重分布) scatter.add( 样本, [165, 170, 172, 175, 180, 182], # x 轴数据 [55, 60, 68, 72, 80, 85], # y 轴数据 is_visualmapTrue, symbol_size12, ) scatter.render(scatter_demo.html)在 0.5.11 中Scatter 也支持 is_visualmapTrue这会给图表加上渐变色彩条等于同时看到第三维的信息适合展示分布密度。3.4 地图与词云最容易出效果也最容易出问题地图类图表是 0.5.11 的亮点真要做好需要先确认扩展包装好了。Map 的数据格式和饼图一样也是成对列表from pyecharts import Map province_data [ (北京, 120), (上海, 160), (广东, 200), (浙江, 300), (四川, 220), ] map_chart Map(区域指标分布, width900, height500) map_chart.add( 指标, province_data, maptypechina, is_visualmapTrue, visual_range[0, 300], ) map_chart.render(map_demo.html)在绘制具体某个省份的地图时比如 maptype广东需要确认安装的是 echarts-china-provinces-pypkg并且省份名要和扩展包内置名称一致差一个字都可能画不出来。有人会碰到地图上区域颜色全部停留在最低色值这通常不是数据问题而是 visual_range 的范围没设好导致最大值和最小值差距过大视觉上拉不开层次。词云是活动运营和分析报告里的常客。0.5.11 的 WordCloud 用起来也不复杂from pyecharts import WordCloud words [ (数据分析, 100), (Python, 88), (可视化, 76), (报表, 60), (自动化, 52), ] wordcloud WordCloud(关键词分布, width800, height400) wordcloud.add(, words, shapediamond, word_size_range[20, 100]) wordcloud.render(wordcloud_demo.html)shape 参数支持 circle、cardioid、diamond、triangle 等形状。词云不显示的大部分原因是模板里额外引用的 echarts-wordcloud 扩展 JS 没加载成功特别是在离线环境下。这个和普通图表只依赖 echarts.min.js 不一样需要单独处理后面离线运行章节会详细讲。4. 多图组合与页面布局让图表形成一份报告4.1 Grid 多图拼合一页展示多张图单独画一张图不难难的是把多张图组合在一页上形成一份可读的看板。0.5.11 里最常用的组合容器是 Grid它可以把不同图表拼到同一个 HTML 页面里。from pyecharts import Grid, Bar, Line bar Bar(销售与增长趋势) bar.add(销售额, [1月, 2月, 3月], [10, 20, 15]) line Line() line.add(增长率, [1月, 2月, 3月], [5, 12, 8], is_smoothTrue) grid Grid(width900, height450) grid.add(bar, grid_left10%, grid_right55%) grid.add(line, grid_left55%, grid_right10%) grid.render(grid_demo.html)Grid 的 add 方法里grid_left、grid_right 这些参数控制每个子图在页面中的占位。注意 Grid 自身的 title 参数不会直接作用在子图上想让子图带标题必须保证传入的子图对象自己有 title。所以上面代码里 bar 初始化时传了标题而 line 就没有传最终页面上只显示柱状图的标题。这种细节不调几次是不会发现的。4.2 Overlap 双轴图层柱线叠加的看板经典场景柱状图和折线图叠加是销售分析里最经典的双轴图左边柱是销量右边线是增长率。在 0.5.11 里用的是 Overlap 容器from pyecharts import Overlap, Bar, Line bar Bar(销量与增长率) bar.add(销量, [Q1, Q2, Q3, Q4], [320, 480, 620, 780]) line Line() line.add(增长率, [Q1, Q2, Q3, Q4], [8.2, 11.5, 14.8, 17.3]) overlap Overlap() overlap.add(bar) overlap.add(line, is_new_axisTrue) # 关键参数让折线使用新的 y 轴 overlap.render(overlap_demo.html)is_new_axisTrue 是双轴能够实现的核心它会给折线图单独分配一个 y 轴。如果你忘记加这个参数折线会和柱状图共用同一个 y 轴数值范围相差过大时折线会几乎被压成一条直线。4.3 Timeline 时间轴动态看数据变化时间轴容器适合展示同一指标在不同时间段的变化比如各年销售额。它自带一个可以拖拽或自动播放的时间条交互感很强。from pyecharts import Timeline, Bar timeline Timeline(年度销售趋势, width800, height400) for year in range(2020, 2024): bar Bar() bar.add( 销售额, [Q1, Q2, Q3, Q4], [100 year * 10, 120 year * 10, 90 year * 10, 130 year * 10], ) timeline.add(bar, {}年.format(year)) timeline.render(timeline_demo.html)timeline.add 的第二个参数是时间轴上的标签文本格式自己定义。0.5.11 的时间轴默认是纵向排列还是横向排列取决于 echarts 模板的默认行为通常不需要额外配置。如果你希望自动循环播放可以在 Timeline 初始化时透传一些事件参数但我在实际项目里很少开自动播放因为用户一般要自己盯着某个年份看。4.4 Page 多图连续展示五张图从上到下一张报告Page 和 Grid 的区别很好理解Page 是简单的纵向叠加每个图表独占一行适合生成一份长截图式的报告Grid 则是把多个图表放在同一区域适合做一个“总览仪表盘”。from pyecharts import Page page Page(数据看板, width900) page.add(bar) page.add(line) page.add(pie) page.render(page_demo.html)Page 的主要坑在于图表的宽度。如果你不给图表显式设置宽度Page 页面里的图表可能会按各自初始化时的宽度排列导致页面参差不齐。建议每个子图在初始化时就统一 width比如都传 width900。另外 Page 没有 Grid 那么复杂的位置控制所以做简单汇报材料时最省心。4.5 主题切换与全局配置0.5.11 自带几套主题内置的常见主题包括 dark、macaron、shine、roma 等。主题调用方式是在图表对象上调用 use_themebar Bar(深色主题, width800, height400) bar.use_theme(dark) bar.add(数据, [A, B], [10, 20]) bar.render(dark_demo.html)use_theme 必须要在 render 之前调用而且切换主题之后最好看一遍所有图表因为某些主题下的文字颜色会成为浅色如果恰好图表背景也是浅色会出现文字看不见的情况。这个在深色主题下最容易犯我通常会给图表手动加一个深色背景或者干脆只对特定图表使用深色主题。5. 输出与上手HTML、Notebook、图片导出和离线运行5.1 HTML 渲染与 JS 依赖加载原理0.5.11 的 render 方法最终做的是把图表配置转成 JSON塞进 pyecharts 自带的 HTML 模板生成一个独立 HTML 文件。这个文件本质上是 echarts 在前端把 JSON 配置渲染成 SVG 或 Canvas。理解这个原理对排查空白页面特别有帮助。当你打开 HTML 发现整个页面是空白时第一步不是看数据而是按 F12 看浏览器控制台里有没有红色报错。最常见的是 echarts.min.js 加载失败因为默认模板引用的是在线 CDN。解决方向有两个一是让运行环境能访问外网二是把 JS 文件下载到本地并把模板里的引用地址改成相对路径。离线内网环境部署是我踩过最多的坑。做法很简单先在有网环境生成 HTML打开 HTML 源码找到 script 标签里引用的 echarts.min.js 地址下载到本地 static 目录然后替换 HTML 里的引用路径。词云图还要额外找 echarts-wordcloud.min.js地图图表则要把地图数据的 JS 一并下载。0.5.11 还有一个比较实用的方法叫 render_embed它不生成文件而是返回包含图表的 HTML 代码片段。这个在 Flask 后端返回图表时很常用html_code bar.render_embed() # 把 html_code 嵌入自己的页面模板即可5.2 Notebook 中渲染的正确姿势如果你在 Jupyter Notebook 里做数据分析用 render_notebook 会比 render 方便很多from pyecharts import Bar bar Bar(Notebook 内嵌图) bar.add(数据, [A, B], [10, 20]) bar.render_notebook()render_notebook 会把图表以 HTML 片段的形式输出到 cell 里。这里有两个经验第一同一次 kernel 会话中反复执行 render_notebook 不会覆盖之前的输出而是会追加时间久了 Notebook 文件变大第二如果图表无法显示先确认使用了新版 Jupyter 而不是只装了 ipython因为 pyecharts 需要前端支持 HTML 渲染。5.3 图片导出phantomjs 方案与降级方案pyecharts 0.5.11 本身不输出 png它生成的是 HTML。如果业务上必须要图片最正统的方式是用 pyecharts-snapshot 配合 phantomjs。pip install pyecharts-snapshot snapshot bar.html bar.png这条命令会把 bar.html 渲染成 bar.png。phantomjs 的安装是真正的痛点老版本 phantomjs 在新系统上经常缺少依赖。我的建议是如果只是偶尔要图直接用浏览器打开 HTML然后手动截图如果是批量生成图片考虑用 selenium 驱动 Chrome 无头模式稳定度和可维护性都比 phantomjs 好不少。脚本书写量大一点但至少不会因为环境依赖折腾半天。5.4 图表嵌入到 Web 项目时的注意事项把 0.5.11 图表塞进 Django 或 Flask 页面时最省事的方案就是前面提到的 render_embed它返回 HTML 片段直接拼接进模板字符串。这里有一个安全注意点render_embed 输出的内容不经过义如果图表的标题、系列名来自用户输入务必先做 HTML 转义防止脚本注入问题。我自己在做一个内部报表系统时把用户填的标题直接塞进了图表标题结果页面渲染异常排查几小时才发现是特殊字符把属性值截断了。6. 高频问题排查速查与避坑经验6.1 版本错乱pip 列表里出现多个 pyecharts这是最常遇到的环境问题特别是电脑里同时装过 0.5.x 和 1.x 的时候缺的类在 import 时直接报 ModuleNotFoundError。处理方式很直接pip uninstall pyecharts -y pip install pyecharts0.5.11但要注意卸载 1.x 时它不会删掉缓存目录pip 有时会解析出旧版本残留。建议在虚拟环境里操作一旦环境乱了直接删掉重建比排查依赖树快得多。6.2 渲染出来是空白页面或图表不显示空白页面分两种。第一种是整个页面只有标题文字图表区域空荡荡这种通常是 JS 没加载成功。第二种是页面有图表轮廓但坐标轴和柱状条都不显示这种通常是数据没传进去。排查方法打开浏览器开发者工具看 Console 和 Network。Console 里有红色报错先把报错截图绝大多数是 JS 引用失败。Network 里可以看到 HTML 文件本身是否加载了外部资源如果 script 请求失败就按离线部署方案处理。数据问题就在业务代码里用 print 看 add 方法收到的数据确认类型和长度。柱状图两个列表长度不一致时echarts 通常不会报错只会少画几个柱子不要忽略这种静默失败。6.3 图表上中文变成乱码中文乱码一般有三个来源。一是 HTML 文件本身的字符集不是 UTF-8用记事本打开再保存很容易改变编码建议统一用编辑器保存为 UTF-8。二是模板里没有 charset 声明不过 0.5.11 默认模板是有的如果你手动拼接了 HTML 片段就要自己补meta charsetutf-8。三是用 phantomjs 截图时系统缺少中文字体导致图片上的中文全是方块这种情况要在系统里安装中文字体包。在 Linux 服务器上因为缺字体导致报表截图全是方块是很多运维同学会遇到的经典问题。解决后要重新生成图片别用旧缓存。6.4 数据量大导致页面卡顿0.5.11 底层依赖的 echarts 版本比较早数据点超过几千个时交互会明显变卡。我在处理一年多的分钟级监控数据时直接把两万多个点塞进折线图结果浏览器直接掉了两帧。两种处理思路一是后端先聚合比如把分钟级数据聚合成小时级或天级二是在前端开 datazoom让用户自己选择区间减少一次性渲染压力。如果你要展示的是长周期趋势聚合不会损失太多信息反而更好读。6.5 饼图小数据项标签挤成一团当饼图某个分类占比太小它的 label 会和其他标签挤在一起特别丑。常见解法是设置 label_pos 为 outside同时调整 label_line_width或者把占比低于某个阈值的分类合并成“其他”。后者在 0.5.11 里没有现成参数需要自己业务代码合并但这样做出来的图会专业很多。6.6 add 方法参数名写错却不报错因为 0.5.11 的 add 方法参数是通过 kwargs 传给底层图表的写错了不报错只是对应效果不生效。我常用的排查技巧是调用 show_config 方法bar.show_config()它会打印出图表当前保存的配置 JSON逐一核对你要的参数是否真的生效。这个方法在旧版 pyecharts 调试里比看文档还管用。结尾最后讲一个我自己的习惯。接手任何 0.5.11 的旧项目时我会先把里面所有图表对象的 show_config() 输出收集一遍统一看一眼数据格式和参数项这样可以避开很多隐藏的坑点。pyecharts 0.5.11 的 API 虽然旧但只要把数据格式的约定理清楚后面写任何图表都是套模板的事。整理模板的时候我会把柱状图、折线图、饼图、地图这四类最常见图表各存一个函数输入参数只有数据和标题返回一个渲染好的图表对象业务代码瞬间清爽很多。如果你也要长期维护这类项目尽早做封装后面会少加很多班。