
简介这份PDF教程面向对文本挖掘与数据可视化感兴趣的初学者和中级Python用户围绕wordcloud与matplotlib两个库系统讲解从文本预处理、权重计算到词云生成、展示与保存的完整流程可用于项目报告、数据分析、社交媒体监控或教学演示等场景。压缩包内为1个PDF文件大小约2.07MB内容以图文教程和代码示例为主便于按章节阅读与实践。教程包含7个递进案例从最简调用起步逐步覆盖中文不分词、中文分词、蒙版形状、自定义配色以及关键词与权重提取等做法并给出运行结果与环境版本说明读者可据此理解参数设置、排查常见问题并改造出个性化词云。目前已有109人学习适合希望快速上手词云制作并补充文本可视化实践的Python学习者。1. 从一张没人看的表格说起Python 词云能替你压掉多少解释成本前年做过一次内部复盘我把两万多条用户反馈归类统计成一张大表会上翻页翻到那一页几乎没人抬头。第二版我把同一批文本丢进 Python 词云字号一大一小谁在抱怨、谁在夸一眼就看出来后面十分钟的讨论全围着这张图展开。这套七案例教程干的就是这件事从三行代码出第一张图一路做到蒙版形状、按图片取色、用 jieba 提关键词权重再画。它面向的是手里已经有文本、想快速出一张能塞进报告或幻灯片的人——文本挖掘入门、运营复盘、课程作业、数据探索都合适。整套东西就靠 wordcloud 加 matplotlib 两个库撑起来上手门槛很低但想让图能见人中间有几处必须踩过去。2. 环境与目录七个案例跑起来前必须先定死的三件事在动手之前讲清楚一件事这七个案例的所有报错八成不是代码逻辑写错而是环境、路径、素材这三样没对齐。代码本身短得可怜最长的案例也就三十来行真正让人卡住的是「字体在哪」「蒙版放哪」「为什么我这边一片豆腐块」。所以先把这三件事定死后面七个案例几乎是复制粘贴。2.1 依赖与版本这套 python3.7 wordcloud 1.9.3 matplotlib 3.5.3 组合为什么能跑教程给的版本是 Python 3.7、wordcloud 1.9.3、matplotlib 3.5.3编辑器用 PyCharm。这个组合不是随便报的wordcloud 1.9.x 要求 Python 3.7 及以上matplotlib 3.5.x 是最后一批完整支持 3.7 的版本线两边不打架。真正被依赖的还有两个隐性包numpy 负责把蒙版图变成数组Pillow 负责读写图片wordcloud 内部就是靠 Pillow 出图的。我一般会写一个 requirements.txt 把版本钉死避免过两个月同事拉下来装出一堆新版本跑出来的图跟文档里对不上。# requirements.txt wordcloud1.9.3 matplotlib3.5.3 jieba0.42.1 numpy pillow# 一次装完建议先升级 pip老版本 pip 对 wheel 的兼容性差 python -m pip install --upgrade pip pip install -r requirements.txt第一段是版本清单jieba 只在案例 03 之后用到但一起装上省事numpy 和 pillow 不写版本让 pip 自己挑兼容当前 Python 的。第二段是安装命令--upgrade pip这一步别省我在 Windows 上见过 pip 版本太老导致 wordcloud 去下源码包而不是预编译 wheel然后卡在编译环节。提示如果你在 Windows 上装 wordcloud 时报出跟 C 编译相关的错误基本就是没拿到 wheel 在本地编译。先确认 Python 位数python -c import platform;print(platform.architecture())和 pip 位数一致再重试实在不行换 conda 装conda 的二进制包省掉编译这一步。2.2 目录结构代码里的../到底是相对谁这是我看别人跑这套代码时见得最多的坑。原文的代码里到处是../novel.txt、../Hiragino.ttf看着像是「上一级目录」但它相对的是当前工作目录不是脚本文件所在目录。PyCharm 里右键 Run工作目录默认是脚本所在目录所以能跑你一旦打开终端先cd到别处再python 案例02.py路径立刻失效报 FileNotFoundError。我习惯把素材和代码分开摆路径写清楚wordcloud-demo/ ├── code/ │ ├── case01_minimal.py │ ├── case02_no_cut.py │ ├── case03_jieba.py │ ├── case04_mask.py │ ├── case05_mask_color.py │ ├── case06_custom_color.py │ └── case07_keywords.py ├── data/ │ └── novel.txt # 中文语料一行一段就行 ├── fonts/ │ └── simhei.ttf # 中文字体必须有 ├── assets/ │ ├── mask_black.png # 形状蒙版白底黑图 │ └── mask_color.png # 取色蒙版彩色图 └── out/ # 所有生成的图统一落这里这样摆的好处是路径只有一种写法脚本里统一用相对项目根目录的路径跑的时候在项目根目录执行python code/case03_jieba.py就行。原文之所以用../是因为它的代码放在code/子目录、素材放在上一级本质上是同一套思路只是它把「工作目录」这件事隐含掉了。2.3 素材准备一份语料、一个字体、两张蒙版语料没什么讲究一份几万字的纯文本最好太长会让布局阶段变慢。字体是硬要求wordcloud 默认字体不带中文字形中文会全部渲染成方框这不是编码问题是字体缺字形。字体路径各平台差别很大我给个对照表照着抄就行平台常见中文字体路径说明WindowsC:/Windows/Fonts/simhei.ttf黑体最稳字形全WindowsC:/Windows/Fonts/msyh.ttc微软雅黑ttc 格式部分版本识别不稳macOS/System/Library/Fonts/PingFang.ttc苹方系统自带Linux/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc需自行安装 Noto CJK路径里的反斜杠要改成正斜杠或者写成原始字符串否则\n、\t会被当转义符吃掉这个错我见过不止一次。蒙版图有两张职责不同。形状蒙版必须是白底、黑色或深色图形——wordcloud 会把像素值接近白色的位置判定为「不画字」深色位置才落词。很多人拿一张黑底白字的图当蒙版跑出来一张空白就是因为判反了。取色蒙版则是彩色图颜色越丰富ImageColorGenerator采出来的字色层次越多。2.4 跑通验证先出一张图再谈好不好看在写第一个案例之前先跑一段十行的自检脚本把字体和中文两件事一次性验证掉能省掉后面一半的困惑。# -*- coding: utf-8 -*- from wordcloud import WordCloud import matplotlib.pyplot as plt FONT fonts/simhei.ttf # 用最短的中文串验证字体能不能渲染中文 wc WordCloud(font_pathFONT, width400, height200, background_colorwhite).generate(测试 中文 词云 字体) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.show() wc.to_file(out/selftest.png)这段代码干了三件事把字体路径固定成常量后面所有脚本直接复用用一组中文词直接喂给generate这里已经手动加过空格等价于分好词出图并落盘到out/。width和height控制画布尺寸background_color指定底色这两参数在案例里会反复出现。如果出来的图是方框说明字体路径写错了或者字体文件本身不带中文字形如果plt.show()弹不出窗口说明当前环境没有图形界面服务器、Docker 里很常见换成plt.savefig()或者设置后端为 Agg 就行。这两条先过掉后面七个案例才有意义。3. 案例骨架七个脚本从「三行出图」到「蒙版取色」的递进这七个案例不是并列的七份代码而是一条递进线先证明能出图再解决中文再解决形状再解决颜色最后解决「画什么词」。每一层只加一个新变量其余代码基本不动这种写法特别适合拿来当模板——你以后改自己的项目只需要替换其中一两行。3.1 案例 01 最简调用真正有用的其实只有三句第一个案例是整条链路的基线英文语料、默认字体、默认画布把 wordcloud 和 matplotlib 的最小闭环跑通。# -*- coding: utf-8 -*- from wordcloud import WordCloud import matplotlib.pyplot as plt # 读入一份英文语料换成你自己的 txt 同样可以 with open(data/english_demo.txt, r, encodingutf-8) as f: text f.read() # 生成词云对象默认参数400x200 画布、黑色背景、内置英文停用词 wc WordCloud().generate(text) # 显示wc 内部会自动转成 ndarray等价于 plt.imshow(wc.to_array()) plt.imshow(wc, interpolationbilinear) plt.axis(off) # 关掉坐标轴否则图上会出现刻度 plt.show() # 落盘png 格式最稳 wc.to_file(out/01_minimal.png)逐句看。WordCloud()不带参数时用的是默认配置画布 400×200、背景黑色、字体是库自带的那款、自动加载内置英文停用词。generate(text)做的是完整流程——按空格切词、统计词频、剔除停用词、按词频分配字号、做矩形布局碰撞检测。imshow的interpolationbilinear是插值方式词云本身是位图双线性插值让边缘不那么硬plt.axis(off)必须加否则坐标刻度会印在图上导出后特别难看。这里有个容易被忽略的点wc是 WordCloud 对象不是数组imshow能直接吃是因为它实现了数组协议内部转成了 ndarray。你想拿原始像素做后处理就显式调wc.to_array()返回的是 H×W×3 或 H×W×4 的 uint8 数组。3.2 案例 02 与案例 03不分词和分词差的不只是多一个 jieba案例 02 是最短的「中文能出不乱码」验证案例 03 才真正把中文当回事。# -*- coding: utf-8 -*- # 案例 02中文不分词只解决字体 from wordcloud import WordCloud import matplotlib.pyplot as plt FONT fonts/simhei.ttf with open(data/novel.txt, r, encodingutf-8) as f: text f.read() wc WordCloud( font_pathFONT, # 关键指定中文字体 width800, # 画布宽度字多了要放大 height600, modeRGBA, # 带 alpha 通道 background_colorNone, # 配 RGBA 才是真透明 ).generate(text) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.show() wc.to_file(out/02_no_cut.png)这段代码没有分词generate会按空格切中文整段没有空格结果就是「整段开头一句话被当成一个超大词」——图能出来但信息量几乎为零。它的价值只在于验证字体路径有效、透明底配置有效。modeRGBA和background_colorNone必须成对出现只设background_colorNone而不开 RGBA库会退回黑色底。案例 03 加了一行 jieba本质是把「切词」这一步从 wordcloud 手里拿回来自己做# -*- coding: utf-8 -*- # 案例 03中文分词后再生成 from wordcloud import WordCloud import matplotlib.pyplot as plt import jieba FONT fonts/simhei.ttf with open(data/novel.txt, r, encodingutf-8) as f: text f.read() # 精确模式切词再用空格拼回去让 generate 按空格切 words jieba.cut(text) # 返回生成器不占内存 text .join(words) print(text[:100]) # 打印前 100 字符肉眼确认切词效果 wc WordCloud(font_pathFONT, width800, height600, modeRGBA, background_colorNone).generate(text) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.show() wc.to_file(out/03_jieba.png)jieba.cut有四种模式值得记默认精确模式尽量切得准cut_allTrue全模式把能成词的都扫出来快但歧义多cut_for_search搜索引擎模式在精确模式基础上对长词再切一刀召回率高适合做索引还有jieba.cut(text, HMMFalse)关掉新词发现纯词典匹配。词云场景我一般用默认精确模式专有名词多的时候才开 HMM。 .join(words)这步别省。wordcloud 的generate只认空格分隔的 token 序列jieba 返回的是生成器直接传进去会报错。先 join 再传等价于把切词结果序列化成一个字符串代价是多占一份内存几万字的文本完全无所谓。3.3 案例 04 与案例 05蒙版形状和蒙版取色是两件事案例 04 把矩形画布换成任意形状核心是把蒙版图读成 numpy 数组塞进mask参数。# -*- coding: utf-8 -*- # 案例 04用蒙版控制词云的形状 from wordcloud import WordCloud from PIL import Image import numpy as np import matplotlib.pyplot as plt import jieba FONT fonts/simhei.ttf with open(data/novel.txt, r, encodingutf-8) as f: text f.read() text .join(jieba.cut(text)) # 白底黑图的蒙版白色区域不落词深色区域落词 mask np.array(Image.open(assets/mask_black.png)) wc WordCloud( maskmask, font_pathFONT, modeRGBA, background_colorNone, contour_width0, # 想要轮廓线就调大配合 contour_color ).generate(text) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.show() wc.to_file(out/04_mask.png)三个点。第一mask传进去的数组形状直接决定输出画布尺寸你设的width、height会被忽略很多人以为参数没生效其实是被蒙版接管了。第二蒙版必须是二维或三通道如果原图是带 alpha 的四通道 PNG转数组后是 H×W×4部分版本会取错通道导致形状错乱稳妥做法是先Image.open(...).convert(RGB)。第三判色逻辑是「越白越不画」所以蒙版图要做成白底加深色图形颠倒过来就是一张空白图。案例 05 在形状之上再加颜色靠ImageColorGenerator从蒙版图里采样# -*- coding: utf-8 -*- # 案例 05从彩色蒙版里取颜色 from wordcloud import WordCloud, ImageColorGenerator from PIL import Image import numpy as np import matplotlib.pyplot as plt import jieba FONT fonts/simhei.ttf with open(data/novel.txt, r, encodingutf-8) as f: text f.read() text .join(jieba.cut(text)) mask np.array(Image.open(assets/mask_color.png).convert(RGB)) wc WordCloud(maskmask, font_pathFONT, modeRGBA, background_colorNone).generate(text) # 从同一张蒙版生成配色器再回填到已生成的词云上 image_colors ImageColorGenerator(mask) wc.recolor(color_funcimage_colors) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.show() wc.to_file(out/05_mask_color.png)顺序很关键必须先生成generate再染色recolor。反过来调recolor拿不到任何词的位置信息。ImageColorGenerator的逻辑是对每个词所在的矩形区域取蒙版对应位置的平均色。所以蒙版颜色分布越均匀、色块越明确出来的字色越干净蒙版如果大面积是白色词就会偏白在浅色背景上看不清。3.4 案例 06 与案例 07自定义颜色函数和关键词权重解决「画什么」案例 06 把配色从「采样」换成「自己算」暴露了color_func这个回调接口。# -*- coding: utf-8 -*- # 案例 06自定义颜色函数 from wordcloud import WordCloud from PIL import Image import numpy as np import matplotlib.pyplot as plt import random import jieba FONT fonts/simhei.ttf with open(data/novel.txt, r, encodingutf-8) as f: text f.read() text .join(jieba.cut(text)) def random_color(word, font_size, position, orientation, font_path, random_state): 对每个词调用一次返回一个颜色字符串 h random.randint(0, 360) # 色相全开才是彩色 s random.randint(60, 80) # 饱和度 l random.randint(60, 80) # 亮度 return hsl({}, {}%, {}%).format(h, s, l) mask np.array(Image.open(assets/mask_color.png).convert(RGB)) wc WordCloud(color_funcrandom_color, maskmask, font_pathFONT, modeRGBA, background_colorNone).generate(text) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.show() wc.to_file(out/06_custom_color.png)color_func的词云库约定签名就是这六个参数一个都不能少顺序也不能换。word是当前词font_size是算出来的字号position是 (x, y)orientation是 0 或 90font_path是当前字体random_state是内部随机状态。最值得注意的是颜色的写法原文用的是hsl(0, %d%%, %d%%)色相固定在 0结果所有词都是红色系把第一个参数换成随机 0360才真正是彩色词云。这是调参时最容易看走眼的地方。案例 06 里还有一行print(s)原意是调试实际上每个词打印一次两三百个词刷满终端。自己改的时候删掉不然日志里什么都看不清。案例 07 是七个案例里思路最不一样的一个不再靠词频改用 jieba 的 TF-IDF 提关键词和权重。# -*- coding: utf-8 -*- # 案例 07提取关键词和权重按权重画 from wordcloud import WordCloud, ImageColorGenerator from PIL import Image import numpy as np import matplotlib.pyplot as plt import jieba.analyse FONT fonts/simhei.ttf with open(data/novel.txt, r, encodingutf-8) as f: text f.read() # topK 控制词数withWeightTrue 才会返回 (词, 权重) 元组 freq jieba.analyse.extract_tags(text, topK200, withWeightTrue) print(freq[:20]) # 先看前 20 个确认提词质量 # 转成 {词: 权重} 字典generate_from_frequencies 只认这个格式 freq {i[0]: i[1] for i in freq} mask np.array(Image.open(assets/mask_color.png).convert(RGB)) wc WordCloud(maskmask, font_pathFONT, modeRGBA, background_colorNone).generate_from_frequencies(freq) image_colors ImageColorGenerator(mask) wc.recolor(color_funcimage_colors) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.show() wc.to_file(out/07_keywords.png)extract_tags的topK200决定最多出 200 个词withWeightTrue返回带权重的元组列表不带就只返回词。这里没有走jieba.cut所以不需要分词再拼接extract_tags内部自己会切。转成 dict 是因为generate_from_frequencies的入参就是{word: weight}权重是浮点字号按权重线性映射。这一步的收益是低频但高区分度的词能被拉出来而纯词频画法只能靠数量堆。4. 核心拆解generate 与 generate_from_frequencies 两条入口背后的生成链路七个案例翻下来其实只调用了 wordcloud 的两个入口方法。把这两个入口的差别搞清楚剩下的参数都是在这一条链路上拧螺丝。4.1 两个入口的分工一个帮你分词一个让你自己定权重generate(text)内部走的是完整流水线先process_text做清洗去 HTML 实体、去标点、按空格切成 token 列表再统计collections.Counter词频再剔除停用词、剔除collocations生成的二元组最后按词频从大到小排逐个尝试放置。你传进去的字符串有多少个空格分隔的 token就按多少个词统计中文不分词就会退化成一整段。generate_from_frequencies(frequencies)直接跳过前面所有步骤拿你给的字典当最终权重表。所以它有两个隐含要求键必须是已经切好的词不能带空格值必须是能比大小的数值。案例 07 用它的好处是能把 TF-IDF、TextRank、甚至外部模型算出来的分数直接灌进去画出来的图反映的是「重要性」而不是「数量」。两条路都能出图选哪条看场景语料干净、只想看高频词用generate省事要做搜索词分析、要接自己的打分模型用generate_from_frequencies。4.2 布局阶段字号从哪来词为什么排不进去字号不是随机的。默认max_font_sizeNone库会把画布里最大的词定成一个跟画布高度相关的值其余词按权重比例缩放最小不低于min_font_size4。权重差距悬殊时图会变成「一个大词 一堆小到看不见的词」这时候把max_font_size手动压到画布高度的 1/4 左右min_font_size提到 8视觉上会均衡很多。布局阶段是纯碰撞检测词按权重从大到小依次尝试随机位置放不下就换个位置试够次数还放不下就丢弃。所以max_words200的控制很直接数字越大能塞的词越多但塞不下的也会越多。想减少丢弃就加大画布、减少词数、或者调小min_font_size。random_state这个参数看着不起眼但非常有用。布局里用了随机数同一份文本两次跑出来的排布完全不同设一个固定值比如random_state42就能稳定复现出图对稿、写文档、做回归测试都靠它。4.3 停用词与 collocations决定「哪些词不该出现」WordCloud有个内置的STOPWORDS集合但那是英文的中文一个都没有。中文场景必须自己传# -*- coding: utf-8 -*- from wordcloud import WordCloud, STOPWORDS import jieba # 自定义停用词语气词、代词、无意义高频词 my_stop {的, 了, 是, 在, 和, 也, 就, 不, 我, 他, 她} with open(data/novel.txt, r, encodingutf-8) as f: text .join(jieba.cut(f.read())) wc WordCloud( font_pathfonts/simhei.ttf, stopwordsmy_stop | STOPWORDS, # 合并内置英文停用词避免英文语料漏网 collocationsFalse, # 关掉二元组中文词云建议关 max_words150, random_state42, width1200, height900, ).generate(text)stopwords传什么就完全覆盖什么不做合并所以想保留英文停用词就得自己并上STOPWORDS。collocations默认是True库会自动把相邻出现的两个词拼成一个二元组也参与统计英文里能出「machine learning」这种短语中文里常常拼出「的的」「他他」这类垃圾关掉更干净。max_words150配合更大的画布是让图不至于糊成一团的关键。4.4 透明底、保存格式和 matplotlib 后端modeRGBA加background_colorNone这套组合最终效果是词云以外的区域完全透明能直接叠在 PPT 的深色母版上不用再抠图。但有两个前提保存必须是 PNGJPG 不支持 alpha 通道存出来会变成黑底或白底to_file的扩展名要写对库是按扩展名选编码器的。还有 matplotlib 那一侧。plt.show()在没有图形界面的环境里会直接报错或者卡死常见于服务器、容器、SSH 会话。稳妥做法是脚本里只savefig不show或者进文件前先切后端。import matplotlib matplotlib.use(Agg) # 必须在 import pyplot 之前 import matplotlib.pyplot as pltAgg是纯光栅后端不依赖任何窗口系统。这行要放在import pyplot之前放后面不生效这个顺序错误我踩过一次报错信息完全不指向根因。5. 避坑与排查中文词云最容易翻车的五个位置这一节的东西基本都来自实际跑图时踩到的坑每条按「现象、原因、解决」写对上了直接抄。5.1 现象图里全是方框一个字都不认得原因几乎百分百是字体没指定或者指定的字体文件不带中文字形。wordcloud 默认用库自带的那款 Droid Sans只有拉丁字符遇到中文就渲染成豆腐块。解决显式传font_path并且用绝对路径先确认文件真的存在。Windows 上还要注意反斜杠转义C:\Windows\Fonts\simhei.ttf里的\n、\f会被当成转义符写成C:/Windows/Fonts/simhei.ttf或者加r前缀。另外.ttc字体集合在部分版本上识别不稳能换成.ttf就换。5.2 现象中文能显示了但整句开头的话变成一个巨大的词原因是没做分词。generate按空格切 token中文没空格整段就被当成一个 token词频为 1字号按默认逻辑给到最大。解决先用 jieba 切再用 .join()拼回字符串。判断有没有切成功最简单的办法是在generate之前print(text[:100])看输出里有没有空格分隔——案例 03 里那行打印就是干这个的别当成调试残留删了。还有个小概率情况切了但仍然出怪词那是 jieba 词典没有该领域词汇加载自定义词典或者改用cut_for_search。5.3 现象传了蒙版出来的图还是矩形形状完全没生效原因有几个。一是蒙版图本身是纯白或者纯黑没有明暗对比库判定所有区域都该画或者都不该画结果退化成整块画布。二是蒙版读进来是四通道通道取错导致形状错乱。三是路径写错Image.open直接抛异常但如果外面套了 try 就静默过去了。解决先把蒙版用图片查看器打开确认「白底、深色图形」再convert(RGB)强制三通道最后打印一下mask.shape看是不是预期的 (H, W, 3)。蒙版生效之后width和height参数就不起作用了画布尺寸完全由蒙版决定这点不要误判成参数失效。5.4 现象设置了透明背景导出来的图还是黑底原因八成是只设了background_colorNone但没开modeRGBA库在这种情况下会退回默认的黑色。还有一种情况是存成了 JPGJPG 没有 alpha 通道透明区域被填成黑色。解决两个参数成对写保存时扩展名必须是.png。另外plt.imshow显示的时候matplotlib 默认底色是白的透明区域看不出来别以为没生效用图片查看器打开文件确认最准。5.5 现象关键词权重那版一跑就报错或者出来的词特别少报错的常见形态是TypeError原因是直接把extract_tags返回的列表塞给了generate_from_frequencies它要的是字典必须先做{i[0]: i[1] for i in freq}这一步转换。词特别少的常见原因是topK设得太小或者画布太小装不下权重差距大的时候小权重词全被丢弃。解决先打印freq[:20]看提词质量确认里面没有大量无意义的词再检查字典转换最后把画布放大、max_font_size手动压小让权重分布摊开。如果发现提出来一堆人名就在extract_tags之前用jieba.analyse.set_stop_words(stopwords.txt)挂一个自定义停用词表。6. 二次开发把词云塞进自己的数据管道并保证可复现七个案例是七份独立脚本真要用起来第一步就是合成一个函数。我的习惯是只保留三组参数数据文本或权重字典、外观字体、蒙版、画布、行为词数、复现种子其余全部走默认。6.1 一个可复用的封装# -*- coding: utf-8 -*- from wordcloud import WordCloud, ImageColorGenerator from PIL import Image import numpy as np import jieba import jieba.analyse FONT fonts/simhei.ttf def make_cloud(textNone, freqNone, mask_pathNone, outout/cloud.png, topk200, max_words150, seed42, by_weightFalse): text 和 freq 二选一by_weightTrue 走 TF-IDF 提词 if by_weight and freq is None: pairs jieba.analyse.extract_tags(text, topKtopk, withWeightTrue) freq {w: v for w, v in pairs} mask None if mask_path: mask np.array(Image.open(mask_path).convert(RGB)) wc WordCloud(font_pathFONT, maskmask, modeRGBA, background_colorNone, max_wordsmax_words, collocationsFalse, random_stateseed) if freq is not None: wc.generate_from_frequencies(freq) else: wc.generate( .join(jieba.cut(text))) if mask is not None: wc.recolor(color_funcImageColorGenerator(mask)) wc.to_file(out) return out逻辑上分三段先决定权重来源自己给还是 TF-IDF 提再决定画布形态有无蒙版最后统一染色并落盘。seed一定要透传这是批量出图能对比的前提。by_weight这个开关把案例 03 和案例 07 两条路合成一个入口调用方不用关心内部走哪条。6.2 接管道时的三个改造点第一个是数据源。真实场景里文本很少是现成 txt多数是从数据库或接口拉的一批字段拼接。我的做法是先落一个中间层统一清洗成「一行一段」的纯文本再进make_cloud这样换数据源不影响画图逻辑。第二个是批量。一次要出十几张图的时候别在脚本里循环plt.show()全部走to_file文件名带上分组标识和日期跑完一次性打包。第三个是可复现。出图给不定的人看之前我会固定seed再跑两遍确认两次的 md5 一致。有一次给外部做材料前一天出的图和第二天出的图排布完全不同被追问是不是换了数据那之后我每次批量出图前都强制走一遍 seed 复现校验宁可多花两分钟也不想在会议上解释这种问题。这套东西不大但把版本钉死、路径统一、入口收敛这三件事做完它就不只是一个教程里的七个 demo而是你手上一个能反复用的出图工具。希望帮到你。本文还有配套的精品资源点击获取