资讯动态

从选型到实战:用Python Pyecharts打造交互式图表与HTML报告

发布时间:2026/9/30 1:30:30 来源:尧图企业网站定制
很多人问我“现在做Python图表到底该学Matplotlib还是Pyecharts”我一般不会直接回答学哪个而是反问一句你要的是论文用的静态配图还是要一份能点、能缩放、能交出去的HTML报告如果是后者Pyecharts目前在我这儿的性价比最高。它本质上是ECharts的Python封装让我这种不太想写前端JS的人也能在几行代码内得到带tooltip、dataZoom、地域颜色映射的交互图表。这篇文章不是把官方示例抄一遍而是把从选型、版本坑、第一张图到地图空白、导出图片踩过的坑按我自己使用的顺序完整讲一遍。想快速上手Pyecharts的或者已经被网上新旧版本资料搞晕的人都可以按着这篇走。1. 从Matplotlib叛逃过来的人Pyecharts带给我什么1.1 静态图表没问题互动和交付才要命我用Matplotlib做过几年图表说实话如果是给论文做插图、给技术文档做示意图它依然是稳妥的选择。但业务汇报里负责人要看的往往不是一个静态图片而是希望用鼠标滑过柱状图时能看到具体数值、能拖动时间轴看某一段趋势、能一键切换不同维度。Matplotlib在Jupyter里虽然也有交互扩展但跨浏览器、跨设备的体验并不统一。每次把PNG丢进PPT领导说“这个数字再细看一下”我就得回头重画一遍。Pyecharts给我的第一印象是它把ECharts的交互能力完整保留但写起来仍然是Python。比如要做一页带标题、图例、悬停提示、缩放条的柱状图十几行代码足够了。输出的是独立HTML文件浏览器直接打开就能用不需要启动服务不需要前端编译丢给同事、放进系统后台都很方便。日常数据分析之外我做内部报表和运营周报也逐步换成了这套流程因为交付物从“一张图”变成了“一个页面”信息量完全不一样。这里放一张我做选型时的对比仅供参考维度MatplotlibPlotlyPyecharts上手难度平缓平缓平缓交互图表较弱强强HTML交付较麻烦可以但资料偏分散直接输出独立HTML中文生态很丰富一般中文资料多贴近ECharts当然这几套工具没有绝对的“谁替代谁”。Pyecharts更适合需要交互、需要HTML交付、需要快速做的场景如果要发表高质量的印刷图片Matplotlib的矢量导出仍然是好选择。关键是先明确用途再选工具而不是盲目追求“新”。1.2 我看重的是“对象化配置项”这套设计Pyecharts的内核我概括成两句话一切皆对象配置靠options。Bar、Line、Pie、Map这些图形本质上都是一个Chart对象。创建之后通过链式调用往里面添加X轴、Y轴、系列数据再通过set_global_opts、set_series_opts设置外观和交互。这个设计让我可以把配置代码封装成一个函数批量生成几十张同款图表数据每次从DataFrame里取出来填进去就行。对比Matplotlib的pyplot这种全局状态模式Pyecharts的对象化方式更可控尤其在多层循环画图的时候不需要担心上一个图的状态污染下一个图。后面我会详细讲options的体系这里先记住一个关键全局选项管图表外围比如标题、图例、提示框、坐标轴、缩放条系列选项管每一组数据自己比如颜色、线型、标签、堆积方式。一旦理解了这个分工换图表类型不过就是换一个类名的事。当然也要直面它的边界。Pyecharts本身不负责数据处理数据清洗、聚合、计算都在pandas或numpy里完成它只做最终呈现。数据量非常大、需要在前端实时拉取百万级数据的场景直接生成一个巨大HTML也不是最优解这时候得考虑后端接口配合前端ECharts。我在后续性能一节会再展开。2. 动手前先处理挡路的版本和依赖细节2.1 网上资料大量停留在v0.x先分版本再抄代码我踩过最狠的坑就是照着旧教程抄代码。Pyecharts在1.0版本前后经历过一次大规模重构网上不少教程还停留在0.5.x时代。旧写法是代码像ECharts配置那样塞进一个字典新写法则是面向对象的链式调用。比如旧版这样from pyecharts import Bar bar Bar(标题, 副标题)新版这样from pyecharts.charts import Bar from pyecharts import options as opts bar ( Bar() .add_xaxis([A, B, C]) .add_yaxis(销量, [10, 20, 30]) )如果你拿旧教程在1.x以上版本运行很可能第一行就报错cannot import name Bar from pyecharts。所以看到任何Pyecharts资料第一步先看对方代码里的import语句。新版标准导入是from pyecharts.charts import Bar选项是from pyecharts import options as opts。这也是判断教程是否过时的最快方法。2.2 安装与运行环境安装其实很简单常规做法是在虚拟环境里执行pip install pyecharts如果只是想画图这一个包就够。它的依赖里有jinja2负责把图表配置渲染成HTML模板有simplejson负责数据序列化。这些依赖装的时候会一起处理一般不会出幺蛾子。输出HTML的时候建议确认当前用户对目录有写权限否则render时会报权限错误。如果你希望在Jupyter Notebook里直接看交互图表不需要额外装依赖调用chart.render_notebook()就行。VS Code的Python Interactive窗口里同样适用日常写分析脚本时用这种方式最舒服。需要说明的是Pyecharts本身不依赖数据库也没有“后端服务”这种概念它就是一个把Python数据变成浏览器图表的渲染工具所以部署到Linux服务器也完全没有问题。2.3 用notebook还是脚本我的建议很简单探索阶段用render_notebook()交付阶段用render(xxx.html)。在Notebook里图表对象会以HTML框架的形式直接嵌在单元格下方鼠标悬停、缩放这些交互都在。但要注意Notebook里每次运行单元格都会重新渲染一次如果图表很复杂、数据量很大会明显卡顿这时候就该改成脚本方式一次性生成HTML文件再打开。生成HTML文件后如果是在本地开发机上跑Windows下可以直接os.startfile(bar.html)macOS可以用os.system(open bar.html)Linux服务器上一般不需要自动打开直接把文件路径交给上层系统即可。很多初学者以为render()会在当前程序里弹出一个窗口其实不会它只是落盘一个文件想看图得主动用浏览器打开。3. 第一张图从图表对象到HTML需要一个什么流程3.1 Chart对象与链式调用先给一段最常规的柱状图代码这是Pyecharts最典型的写法from pyecharts.charts import Bar from pyecharts import options as opts bar ( Bar() .add_xaxis([一季度, 二季度, 三季度, 四季度]) .add_yaxis(销售额, [320, 420, 510, 680]) .set_global_opts( title_optsopts.TitleOpts(title全年销售趋势), tooltip_optsopts.TooltipOpts(triggeraxis), ) ) bar.render(bar.html)这段代码做的事情拆开看先创建一个Bar对象add_xaxis填入X轴分类add_yaxis添加一个叫“销售额”的系列数据。set_global_opts设置标题和提示框触发方式最后render(bar.html)生成文件。运行后打开bar.html一张带标题、坐标轴、鼠标悬停提示的柱状图就出来了。可能有人会问为什么add_yaxis叫“添加系列”因为同一张图可以放多个序列比如除了“销售额”还可以再来一个“利润”序列bar.add_yaxis(利润, [120, 130, 140, 150])两个柱子就会并排出现。这是ECharts“系列”概念的延续理解了这个词后面看文档会顺畅很多。3.2 render()不是弹图是生成HTML文件我见过不少人卡在这一步以为bar.render()会像Matplotlib的plt.show()一样弹出窗口结果什么动静都没有。Pyecharts的render()默认不弹窗它只是把图表配置序列化成JSON再塞进一个HTML模板里最后写成本地文件。所以“看到图”这个动作其实是浏览器打开的。如果你打开生成的HTML源码会发现里面有大量JS代码图表数据也被序列化成一段JavaScript对象嵌在页面里。这个设计有一个隐藏好处图表数据和页面是绑定的文件单独拷贝到任何电脑上打开都能正常显示不需要联网、不需要Python环境。这一点在写业务报告、做交付件时非常实用我经常把一个周报目录下的十几个HTML直接压缩发给别人对方解压后双击就能看。如果不想生成文件在Notebook里就用bar.render_notebook()这个方法只适用于已经启动了Jupyter服务的环境。它会直接在当前输出单元里渲染图表框架操作上最省事。3.3 全局选项和系列选项的分工当你开始给图表加更多细节会发现配置项集中在两类方法里。set_global_opts管的是标题、副标题、图例、工具提示、方位、颜色条、缩放组件、坐标轴名称这些外围元素。set_series_opts管的是每个系列自己的标签、颜色、线条样式、面积渐变、标记点之类。举个具体例子我想让柱状图每个柱子顶部显示数值同时把线条粗细和颜色调一下代码是这样bar ( Bar() .add_xaxis([一季度, 二季度, 三季度, 四季度]) .add_yaxis(销售额, [320, 420, 510, 680]) .set_series_opts( label_optsopts.LabelOpts(is_showTrue, positiontop), itemstyle_optsopts.ItemStyleOpts(color#4b85f7) ) )这种“全局一套系列各自一套”的思路和前端CSS里的全局样式与类名样式有点类似。刚开始不用全记住只需要知道当你想调标题、图例、坐标轴、提示框时去set_global_opts里找当你想调某一组数据的颜色、标签、标记点时去set_series_opts里找。遇到不熟悉的需求优先打开官方文档的options目录按关键字搜索比翻整篇教程高效得多。4. 不止柱状图把折线、饼图、地图放进一份报告4.1 折线、饼图换汤不换药柱状图跑通之后其他图表基本是换类名的问题。比如折线图from pyecharts.charts import Line line ( Line() .add_xaxis([1月, 2月, 3月, 4月, 5月]) .add_yaxis(访问量, [120, 150, 190, 240, 310]) .set_global_opts( title_optsopts.TitleOpts(title访问趋势), tooltip_optsopts.TooltipOpts(triggeraxis), ) ) line.render(line.html)饼图也类似只是数据用二元组列表来表示“名称数值”from pyecharts.charts import Pie pie_data [(直接访问, 335), (搜索引擎, 650), (联盟广告, 250)] pie ( Pie() .add(来源, pie_data) .set_global_opts(title_optsopts.TitleOpts(title访问来源)) .set_series_opts(label_optsopts.LabelOpts(formatter{b}: {c})) ) pie.render(pie.html)Pyecharts官方支持的图表类型非常多散点图、雷达图、热力图、漏斗图、词云图都有对应类。我的经验是先用官方示例抄一个最接近自己需求的图跑通后再改数据。直接从空白开始写容易漏配置而官方示例已经把大多数坑填平了。4.2 地图的“地图数据去哪了”问题地图是Pyecharts里比较特殊的一类因为地图需要额外的地理边界数据。以前地图数据在包里内置但后来因为维护成本和包体积新版把地图数据拆开了。所以很多人第一次用Map画中国地图会得到一片空白控制台报错类似“china地图不存在”。常规做法是安装地图数据包pip install echarts-countries-pypkg pip install echarts-china-provinces-pypkg pip install echarts-china-cities-pypkg装完之后再运行from pyecharts.charts import Map data [(北京, 152), (上海, 210), (广东, 300)] map_chart ( Map() .add(销售额, data, china) .set_global_opts( title_optsopts.TitleOpts(title分省销售额), visualmap_optsopts.VisualMapOpts(max_300), ) ) map_chart.render(map.html)关于地图版本的处理不同版本细节有差异稳妥的办法是装完后先跑一个最小示例确认能显示再继续做样式。如果还是空白检查安装的地图包版本是否与Pyecharts版本匹配或者直接查看生成的HTML里JS报错通常能在控制台看到“map not found”这类提示。地图类图表涉及行政区域边界数据使用时要格外注意数据合规只使用官方认可的数据源和标准边界文件。4.3 用Page把多张图拼成一份报告单张图会画以后自然想把它做成“一页多个图”的报告。Pyecharts提供Page组件可以把多个图表对象按顺序拼在同一个HTML文件里from pyecharts.charts import Page page Page() page.add(bar, line, pie, map_chart) page.render(report.html)Page适合做简单的上下拼接每张图之间还有一定间距打开页面滚动即可查看。如果想让几个图表共享一个坐标轴的联动效果可以用Grid想做成带标签页切换的形式可以用Tab。但日常报表我觉得Page最实用代码量最少而且每张图还是独立的不容易出现联动逻辑把数据搞乱的情况。我自己的习惯是先分别调试每张图确认数据、颜色、提示框都满意后再塞进Page统一生成报告。这样排查问题时只需要单独跑某一张图而不需要重新渲染整个报告出错成本低很多。5. 交互不是装饰tooltip、dataZoom与主题才是灵魂5.1 tooltip触发方式和格式化如果做的图表只是静态看那和图片有什么区别所以交互配置才是Pyecharts比较值钱的地方。工具提示框是最常见的交互鼠标悬停时显示当前点位数据默认是“浮现在鼠标位置”的简洁框。在多序列图里建议把触发方式设为triggeraxis这样纵向坐标轴范围内所有系列的值会一起展示tooltip_optsopts.TooltipOpts(triggeraxis, axis_pointer_typecross)axis_pointer_typecross会让鼠标所在位置出现一条十字辅助线看时间序列趋势时非常直观。如果你对提示框内容不满意还可以用formatter回调函数格式化文本。注意这个回调里的参数本质是JS层面处理的所以用字符串模板比较多如果要用Python函数需要先序列化成JSON再传给前端执行复杂度会上升一般场景不建议强行这么做。5.2 dataZoom让数据可读数据量上来以后图表密密麻麻挤在一起没法看这时候dataZoom缩放组件就要登场了。它给图表加一个可拖动的缩放条用户可以自己框选查看区间。配置方式是在set_global_opts里加一个DataZoomOpts列表bar ( Bar() .add_xaxis(date_list) .add_yaxis(成交量, values) .set_global_opts( datazoom_opts[ opts.DataZoomOpts(type_inside, range_start0, range_end50), opts.DataZoomOpts(range_start0, range_end50), ] ) )这里我加了两个缩放组件一个inside类型可以直接用鼠标滚轮缩放一个外部滑条方便用户看到当前查看范围。range_start和range_end表示初始显示的数据区间百分比比如0到50就是默认显示前半段数据。时间跨度很长的图表我通常设置默认显示最近30%的数据让重点更突出。5.3 主题、换色与整体质感默认主题不差但交出去的报告最好和品牌色统一。Pyecharts内置了主题列表最省事的是用InitOpts指定from pyecharts.globals import ThemeType bar Bar( init_optsopts.InitOpts( themeThemeType.DARK, width900px, height500px, ) )内置主题包括LIGHT、DARK、CHALK、ESSOS等不同风格差异还是挺大的深色配大屏场景、浅色配打印场景都能找到合适选择。如果内置主题都不满足可以自定义主题JSON文件加载方式文档里有但一般业务项目用不上。我更常用的做法是自定义单个系列的颜色比如itemstyle_opts里指定color或者用ColorOpts做渐变。整体风格上保持每张图颜色一致不要一张图彩虹色、一张图黑白灰读起来会舒服很多。6. 数据一多就卡性能调优和截图导出实战6.1 卡顿来自标签和动画优先关掉它们Pyecharts生成的HTML本质上是一个完整的ECharts页面浏览器渲染时如果点上万个点还要每个点都显示标签、逐个播放入场动画那卡顿几乎是必然的。我最开始做日访问量趋势图X轴放了365天每个柱子顶上都带数值标签打开页面拖动时明显掉帧。应对手段按优先级排列第一关闭标签显示或者只在特殊点位显示标签用LabelOpts(is_showFalse)第二关闭入场动画特别是大数据量时动画意义不大还会拖慢页面加载第三增加dataZoom让用户按需查看区间而不是一次性渲染全部数据第四如果图表类型合适可以考虑对数据做抽样或聚合比如按周聚合后再画柱状图视觉效果往往比直接绘逐日噪音更好。6.2 交付静态图时用make_snapshot虽然HTML交互很好但有时客户或领导就是要在Word、PPT里放一张PNG。Pyecharts官方没有内置纯Python的图片导出能力因为它本质是渲染到浏览器的所以社区提供了snapshot-selenium方案用无头浏览器打开HTML页面再对页面截图保存为PNG。实际使用方式如下先安装依赖pip install snapshot-selenium还需要本机有Chrome或Chromium浏览器并且selenium能找到对应的Driver。然后这样调用from pyecharts.render import make_snapshot from snapshot_selenium import snapshot bar.render(bar.html) make_snapshot(snapshot, bar.html, bar.png)这里make_snapshot的第二个参数是要截图的HTML文件路径第三个是输出图片路径。遇到图片导不出来的情况多半是Driver版本和浏览器版本不匹配。我的习惯是先直接用selenium打开一个最简单的HTML测试确认环境没问题再让Pyecharts参与进来不要一上来就怀疑图表代码。6.3 导出遇到白图时检查哪些点白图是很常见的导出失败现象页面打开了但截图像素是空的。我遇到一次是浏览器还在加载远程资源时截图太早HTML里引用的ECharts核心JS是从公共CDN加载的网络慢的时候页面还没渲染完就触发了截图。解决办法是把需要的JS下载到本地或者让页面渲染完成后增加等待时间。另一个常见问题是路径里有中文或特殊字符。Windows下无头浏览器处理中文路径偶尔会异常为了省事我会把导出用的临时HTML和图片都放到纯英文目录下成功后再改名。还有个容易被忽略的点如果HTML里嵌入了动态加载的数据截图前要确保数据已经加载完否则截到的就是空壳页面。总之导出图片这一步本质是“模拟浏览器渲染后再截图”所有前端页面会遇到的问题它都会遇到。7. 常见报错与排查地图空白、Jupyter不显示、图片导不出7.1 地图空白的根因排查链地图空白这个问题值得单独写一下排查链路因为不是只有第一次用才遇到。我的排查顺序是固定的先看控制台有没有“map not found”之类报错然后确认地图包是否成功安装再用一个最简示例测试最后看版本是否匹配。如果控制台报错明确说某个地图名找不到那要么是数据包没装要么是地图名写错了。比如“china”和“china-cities”是两个不同的地图前者是省级边界后者是城市边界地图名和你要展示的数据粒度要对上。装了包还是空白就检查安装的是不是适用于当前Pyecharts版本的包。版本不匹配时数据包虽然装在Python环境里但生成HTML时并不会被正确加载。7.2 Jupyter里不显示的典型原因在Jupyter里用Pyecharts最常见的错误是用了render()而不是render_notebook()。render()只是生成了HTML文件不会嵌入当前Notebook输出。所以代码虽然运行成功但单元格下方看不到任何图。解决就是改成bar.render_notebook()另外使用Notebook时如果页面开启了严格CSP策略或者浏览器插件拦截了页面里的JS也可能出现白框或加载不出来。排查方法也简单直接看浏览器开发者工具的Console报错一般都能定位到是被CSP拦截还是资源没加载。最后如果你的Notebook跑在远程服务器上通过SSH端口转发访问部分浏览器对本地HTML框架渲染有额外限制此时可以直接生成HTML文件再通过文件服务访问反而更稳。7.3 让Pyecharts项目少踩坑的几个小习惯项目落地时我给自己定了几个习惯分享出来也供参考。第一每个图表单独一个函数函数返回Chart对象统一在最后组装页面方便复用和测试。第二所有数据在进入图表前先做完清洗和类型转换确保没有NaN、没有对象类型的字符串Pyecharts虽然对数据容错还可以但混入不良数据后生成的JS模板很容易崩溃。第三生成HTML时用相对路径引用的资源尽量都做成本地资源避免打开文件时依赖外网这在内网环境尤其重要。最后关于版本锁定。项目里的requirements.txt固定住pyecharts你使用的版本同时在地图包上也锁定版本。数据可视化代码不是特别需要频繁升级的模块稳定压倒一切我在生产环境中吃过一次“升级后地图包不匹配”的亏从那以后再也不在部署前随手升级Pyecharts版本了。如果你刚开始接触建议先在一个独立虚拟环境里玩把所有坑踩一遍后再用熟悉到闭眼能写的版本去跑正式项目。对我来说Pyecharts就是那个让我用Python几行代码得到专业级交互图表的工具值得你花一个下午好好研究。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑