☰
Python中文词云7案例:从能出图到能控图
2026/11/2 7:43:11 网站建设 项目流程

简介:这是一份面向初学者与中级Python用户的词云实践教程PDF,聚焦文本挖掘与数据可视化场景,帮助读者把零散文本转化为直观图形。教程围绕wordcloud与matplotlib展开,先说明词云的概念、作用与生成原理,再系统梳理文本预处理、停用词与标点清理、词频或TF-IDF权重计算、词云绘制与保存等环节。7个由浅入深的案例覆盖最简调用、中文不分词与分词处理、蒙版形状、自定义配色、关键词及权重提取等做法,并附环境版本、代码示例和运行结果,便于对照复现、理解参数与排查问题。压缩包共1个PDF文件,大小约2.07MB,适合作为Python课程配套资料,也可用于项目报告、社交媒体分析、教学演示等场景。已有109人学习,读者可借此掌握词云生成流程和常用扩展技巧,提升文本分析与可视化落地能力。

1. 七个案例把词云从「能出图」推到「能控图」:这套 python 词云教程适合谁

上周朋友拿着一批商品评论文本来找我,要一张「一眼看出大家在夸什么、骂什么」的图。她先在几个在线词云站里把文本粘进去,结果很难看:中文整段糊成一个巨大的色块,剩下能看清的只有「的」「了」「是」。不是工具不行,是中文词云本来就有两道坎——不分词、不带中文字体。这套 python 词云教程用 7 个案例把这两道坎连同形状蒙版、配色、关键词权重一次走完:案例01 是十几行最简调用,案例07 已经用 jieba.analyse 提出关键词权重喂给generate_from_frequencies。做数据分析的、要出报告封面的、想把词云塞进自己小工具的,都能直接拿去改。下面按环境、案例拆解、避坑、二次开发四段说。

2. 环境与依赖:wordcloud 1.9.3 在 Python 3.7 下的可复现搭法

2.1 版本锁定与虚拟环境

教程给的环境是 PyCharm + Python 3.7 + wordcloud 1.9.3 + matplotlib 3.5.3。这个组合看着旧,对词云来说反而省事:wordcloud 是带 C 扩展的包,这几个版本在包索引上都有完整的预编译轮子,装的时候不用本地编译。我见过太多人直接pip install wordcloud装到最新版,然后在 Windows 上卡在「error: Microsoft Visual C++ 14.0 or greater is required」这一步,一卡就是半小时。锁版本不是保守,是省掉一次无意义的排障。

# 建一个独立环境,避免和机器上其他项目的 numpy 版本打架 python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate # 四个包要一起装:wordcloud 是主角,jieba 管中文分词, # Pillow 和 numpy 是案例04 之后处理蒙版必须自己 import 的 pip install wordcloud==1.9.3 matplotlib==3.5.3 jieba pillow numpy

命令本身没什么花样,关键是最后一行把 Pillow 和 numpy 显式写出来。很多人以为装了 wordcloud 就自带,确实带了,但那是它内部的依赖,你自己import numpy as np、from PIL import Image的时候,虚拟环境里如果版本被顶掉,报错信息会指向你的代码,排查方向就歪了。

装完先别急着跑案例,验证一下导入链路:

# check_env.py 确认四个包能同时 import,且版本对得上 import wordcloud, matplotlib, jieba, PIL, numpy print('wordcloud ', wordcloud.__version__) print('matplotlib', matplotlib.__version__) print('jieba ', jieba.__version__) print('numpy ', numpy.__version__)

这三个 print 是给自己留证据。后面出问题的时候,第一反应应该是版本,而不是先怀疑代码。PyCharm 里记得把解释器指到venv里的那个 python,而不是系统 python,这是新手最常忽略的一步——终端里pip install成功、编辑器里import报红,八成就是解释器没换。

2.2 目录布局与素材文件约定

教程里的代码有个细节很容易被忽略:打开文本用的是open('../xyj.txt'),字体是font_path='../xxx.ttf',都带一个..。这说明 7 个案例脚本是放在某个子目录里的(比如code/),而素材文件统一放在上一层。你如果把这些代码原样贴到一个新目录里直接跑,第一行的 open 就会抛 FileNotFoundError。

按教程的用法,配套素材大概是这么几类:

文件用途出现在
constitution.txt一份英文长文本,用于演示默认英文分词案例01
xyj.txt一部古典章回体小说的中文全文,UTF-8 编码案例02~07
一个中文.ttf字体文件给中文词提供字形,不配就是方块案例02~07
black_mask.png纯形状蒙版,只有轮廓没有颜色案例04
color_mask.png带颜色的蒙版,既定形状又定配色案例05~07
main_*.png各案例的输出图全部

字体这一项单独说一句。教程自带的是一个 ttf 文件,代码里直接写了文件名。你在自己机器上找不到这个文件时,去系统字体目录里挑一个中文字体就行(Windows 在C:\Windows\Fonts,macOS 在/System/Library/Fonts,Linux 一般在/usr/share/fonts),拷到素材目录或者写绝对路径都可以。我习惯把路径全部收敛到一个常量文件里,七个案例共用,改一次全生效:

# paths.py 七个案例共享的素材路径,换机器只改这一个文件 from pathlib import Path BASE = Path(__file__).resolve().parent.parent # 指到素材根目录 TXT_EN = BASE / 'constitution.txt' TXT_CN = BASE / 'xyj.txt' FONT = BASE / 'CN_FONT.ttf' # 换成本机可用的中文字体 MASK_SHAPE = BASE / 'black_mask.png' MASK_COLOR = BASE / 'color_mask.png' # wordcloud 对 Path 对象的兼容性不稳,统一转成字符串再传 FONT_PATH = str(FONT)

用常量而不是到处写'../xxx',最大的好处是迁移成本。素材目录一挪,只改BASE一行,剩下的案例脚本一个字都不用动。这个习惯在单个 demo 里看不出价值,等你把七个案例合到一个工程里就有了。

2.3 冒烟测试:三行代码确认字体真的被加载了

环境装完、路径配好,还有一件事必须先做:确认中文字体真的生效。因为字体没加载成功的时候,wordcloud 不会报错,它会安安静静地画一堆方块,或者干脆画一张白图。等你跑到案例03 才发现,前面几步的排查全白做了。

我的做法是造一个最小的词云,不看图,直接看像素:

# smoke.py 只验证字体,不关心好不好看 from wordcloud import WordCloud import numpy as np wc = WordCloud( font_path=FONT_PATH, # 关键:不传这行,中文必出方块 width=200, height=100, background_color='white' ) img = wc.generate('测试 中文 词云 字体').to_array() # 全白图的均值接近 255;有字画上去就会明显变小 print(img.shape, img.mean())

期望输出是(100, 200, 3)和一个明显小于 255 的均值。如果均值是 255 或者非常接近,说明字一个都没画上去,问题一定出在font_path——路径不存在、文件不是 ttf、或者字体里压根没有这些汉字。这个检查只要三秒,比后面盯着空白图发呆强得多。

3. 从英文到中文:案例01~03 的核心链路拆解

3.1 案例01 最简调用:generate 内部其实做了四件事

# -*- coding: utf-8 -*- from wordcloud import WordCloud import matplotlib.pyplot as plt # 1. 读文本:英文文本默认编码即可 text = open('constitution.txt').read() # 2. 生成对象并出词:generate 一步完成分词、计数、布局 wc = WordCloud().generate(text) # 3. 显示:bilinear 插值让放大后的字边缘不发毛 plt.imshow(wc, interpolation='bilinear') plt.axis('off') # 关掉坐标轴,不然图上会有刻度 plt.show() # 4. 落盘 wc.to_file('wordcloud.png')

这段代码短,但generate(text)这一行做的事不少。它内部大致有四个动作:用正则把文本切成词、滤掉内置的英文停用词、统计词频、再按词频给每个词分配字号并做碰撞检测布局。官方默认参数里几个值得记住的是:画布width=400, height=200、max_words=200、background_color='black'、prefer_horizontal=0.9(九成词横排)、min_font_size=4、collocations=True。

collocations=True这个默认值容易被忽略:它会额外把经常相邻出现的两个词当成一个词组塞进词云,英文里能出「data science」这种效果,中文里如果没做好分词,就会冒出一些奇怪的双词组合。做中文时我一般直接关掉。

另一个参数是relative_scaling,它控制「词频差距到底反映成多大的字号差距」。默认值让字号主要看排名不看绝对频次,好处是长尾词不会小到看不见,坏处是真正的头部大词不够突出。做汇报图的时候我会调到 0.8 左右,让第一名和第二名拉开差距。

3.2 案例02 中文不分词:你得到的是一个大色块

# -*- coding: utf-8 -*- # 中文不分词,看看会发生什么 from wordcloud import WordCloud import matplotlib.pyplot as plt from paths import TXT_CN, FONT_PATH # 显式 utf-8,Windows 默认编码不是 utf-8,很容易在这里翻车 with open(TXT_CN, 'r', encoding='utf-8') as f: text = f.read() wc = WordCloud( font_path=FONT_PATH, # 中文字形,不给就是方块 width=800, height=600, mode='RGBA', # 出四通道图,才有透明背景 background_color=None # 背景透明 ).generate(text) plt.imshow(wc, interpolation='bilinear') plt.axis('off') plt.show() wc.to_file('main_2.png')

这段代码的价值不在结果好看,在于让你亲眼看到「不分词」的后果。wordcloud 切词靠的是空白和标点,中文句子中间没有空格,一整段会被当作少数几个超长「词」,词频统计出来每个都只出现一次。于是图上只有两三坨一样大的巨型文字,缩到画布放不下还得继续缩,观感非常糟糕。

这也就解释了一个常见误解:有人在案例02 的代码外面套一句' '.join(list(text)),把每个汉字用空格隔开,结果图是出来了,但全是「的」「一」「不」这种单字,没有任何语义。分词和拆字是两件事,中间的差别就是 jieba 存在的理由。

顺带说mode='RGBA'和background_color=None这一对。前者决定输出图带 alpha 通道,后者告诉 wordcloud 不要填底色。两个必须同时给,只给一个的话要么背景还是黑的,要么 PNG 存下来是 RGB 三通道。

3.3 案例03 jieba 分词:' '.join这一行的分量

# -*- coding: utf-8 -*- # 中文 + 分词 from wordcloud import WordCloud import matplotlib.pyplot as plt import jieba from paths import TXT_CN, FONT_PATH with open(TXT_CN, 'r', encoding='utf-8') as f: text = f.read() # 核心就这一行:jieba 切完,用空格重新拼回字符串交给 wordcloud text = ' '.join(jieba.cut(text)) print(text[:100]) # 打印前 100 字,肉眼确认切得对不对 wc = WordCloud( font_path=FONT_PATH, width=800, height=600, mode='RGBA', background_color=None ).generate(text) plt.imshow(wc, interpolation='bilinear') plt.axis('off') plt.show() wc.to_file('wordcloud.png')

jieba.cut返回的是生成器,不是列表,所以不能直接丢给 wordcloud,必须 join 成空格分隔的字符串。这一步是整个中文词云的分水岭:切得好,图上就是人名、地名、动作词;切得差,图上全是「一个」「这个」「说道」。

三种模式的选择:

模式写法特点什么时候用
精确模式jieba.cut(text)切分最准,不重叠绝大多数词云场景的默认选择
全模式jieba.cut(text, cut_all=True)所有可能的词都扫出来,有大量重叠做关键词召回、不怕噪音的时候
搜索引擎模式jieba.cut_for_search(text)精确模式基础上把长词再切短想让长专有名词也贡献一份词频

做词云我基本只用精确模式。全模式出来的结果重叠太严重,同一个位置会出现「北京大学」「北京」「大学」三个词,词频被重复计数,图上的字号分布就失真了。

print(text[:100])这行看着像调试残留,实际上是我反复强调的习惯。分词出问题的时候,看图片是看不出来的——你只会觉得「这图怎么这么丑」,而看前 100 个字符,一眼就知道是切成词了还是切碎了。

3.4 分词之后的清洗:停用词表与正则过滤

原教程的案例在分词之后就直奔出图了,实际项目里还得加一步清洗,否则图上一半面积都是虚词。

# clean.py 分词 + 清洗,输出干净的词串 import re import jieba # 停用词表一行一个词,网上现成的很多,也可以自己攒 STOP = set(open('stopwords.txt', encoding='utf-8').read().split()) def clean_text(text: str) -> str: # 只保留汉字,标点、数字、英文一律转成空格 text = re.sub(r'[^\u4e00-\u9fa5]', ' ', text) words = [] for w in jieba.cut(text): w = w.strip() if len(w) < 2: # 丢掉单字,噪音能少一大半 continue if w in STOP: # 丢掉「我们」「他们」这类高频虚词 continue words.append(w) return ' '.join(words)

三个参数值得掰开说。[^\u4e00-\u9fa5]是汉字区间的反向匹配,把非汉字全部替换成空格,对中文小说、评论这类纯中文语料特别有效,能顺手干掉引号、破折号和夹杂的英文。len(w) < 2过滤单字,代价是会误伤「家」「国」「雪」这种本身有意义的单字词,如果你的语料主题正好靠单字表达(比如古诗词),就得把这行去掉。停用词表建议从通用表起步,跑一遍看结果,再把这批语料特有的高频废话(比如电商评论里的「宝贝」「收到」)手工加进去。

清洗前后各跑一次案例03,图上的信息密度差别很明显。这一步没有捷径,就是看结果调表。

4. 蒙版与着色:案例04~06 的形状和颜色控制

4.1 案例04 形状蒙版:白色区域是不画字的地方

# -*- coding: utf-8 -*- from wordcloud import WordCloud from PIL import Image import numpy as np import matplotlib.pyplot as plt import jieba from paths import TXT_CN, FONT_PATH, MASK_SHAPE with open(TXT_CN, 'r', encoding='utf-8') as f: text = f.read() text = ' '.join(jieba.cut(text)) # 蒙版读成 numpy 数组,wordcloud 靠它判断哪里能落词 mask = np.array(Image.open(MASK_SHAPE)) wc = WordCloud( mask=mask, # 形状来源 font_path=FONT_PATH, mode='RGBA', background_color=None ).generate(text) plt.imshow(wc, interpolation='bilinear') plt.axis('off') plt.show() wc.to_file('main_4.png')

mask的规则是反直觉的:值为 255(纯白)的像素被当作「不绘制区域」,其余像素才允许放词。所以蒙版图的白色部分最终是空的,有色部分才是词云本体。如果你的蒙版做反了,出来会是一个矩形中间挖个洞。

这个参数对数组的形状有要求:至少要二维,最好是从Image.open()直接转出来的单通道图。如果原图是带透明通道的 PNG,用np.array()转出来是四维的(h, w, 4),某些版本会直接抛IndexError: tuple index out of range。稳妥写法是先转 L 模式:

# 强制转灰度,规避 RGBA 蒙版导致的索引错误 mask = np.array(Image.open(MASK_SHAPE).convert('L'))

用了 mask 之后,width和height就不再是画布尺寸了,画布尺寸由蒙版的像素尺寸决定。这一点改动代码时容易漏,导致你调了半天宽高发现没反应。

4.2 案例05 ImageColorGenerator:颜色从原图对应位置采样

# -*- coding: utf-8 -*- from wordcloud import WordCloud, ImageColorGenerator from PIL import Image import numpy as np import matplotlib.pyplot as plt import jieba from paths import TXT_CN, FONT_PATH, MASK_COLOR with open(TXT_CN, 'r', encoding='utf-8') as f: text = f.read() text = ' '.join(jieba.cut(text)) mask = np.array(Image.open(MASK_COLOR)) wc = WordCloud( mask=mask, font_path=FONT_PATH, mode='RGBA', background_color=None ).generate(text) # 关键两步:先由图片构造取色器,再把颜色回填到词上 image_colors = ImageColorGenerator(mask) wc.recolor(color_func=image_colors) plt.imshow(wc, interpolation='bilinear') plt.axis('off') plt.show() wc.to_file('main_5.png')

recolor必须在generate之后调用,顺序反了没有效果。ImageColorGenerator的工作原理是:对每个词所在的矩形区域,取蒙版图上对应位置的平均颜色,赋给这个词。所以蒙版图里橙色的区域,落在那里的词就是橙色的,整个词云看上去和原图色调一致。

这里有一个隐藏条件:ImageColorGenerator要的是三维数组(RGB),传单通道灰度图会报错。所以 4.1 里那个convert('L')的技巧在案例05 不能用,必须保留彩色通道。这两个案例对蒙版的处理方式正好相反,我第一次做的时候就在这里来回改了好几遍。

4.3 案例06 自定义颜色函数:回调签名和 HSL 拼色

# -*- coding: utf-8 -*- from wordcloud import WordCloud from PIL import Image import numpy as np import matplotlib.pyplot as plt import random import jieba from paths import TXT_CN, FONT_PATH, MASK_COLOR with open(TXT_CN, 'r', encoding='utf-8') as f: text = f.read() text = ' '.join(jieba.cut(text)) # 颜色回调:每个词画之前都会调一次,返回什么颜色就用什么颜色 # 签名要写成 random_state=None, **kwargs 兜住版本差异 def random_color(word, font_size, position, orientation, random_state=None, **kwargs): h = random.randint(0, 360) # 色相随机,全彩 s = random.randint(60, 80) # 饱和度控制在中间段 l = random.randint(40, 70) # 亮度别太浅,白底会看不清 return 'hsl(%d, %d%%, %d%%)' % (h, s, l) mask = np.array(Image.open(MASK_COLOR)) wc = WordCloud( color_func=random_color, # 优先级高于 colormap mask=mask, font_path=FONT_PATH, mode='RGBA', background_color=None ).generate(text) plt.imshow(wc, interpolation='bilinear') plt.axis('off') plt.show() wc.to_file('main_06.png')

回调的五个参数里,前四个是位置参数:当前词、这个词的字号、它在画布上的坐标、它是横排还是竖排。剩下的random_state是关键字参数,不同版本传参方式有差别,所以一定要用**kwargs兜底,否则一加 color_func 就 TypeError。

原教程的例子把色相固定成 0(红色系),只随机饱和度和亮度,出来是一片红粉色系的图,风格统一但单调。我把色相也随机了,代价是整张图容易花。实际做品牌图的时候更好用的做法是按词频分档:高频词固定用主色,低频词用灰度,图的层次感立刻就出来了:

def brand_color(word, font_size, position, orientation, random_state=None, **kwargs): # 字号大于 30 的词认为是核心词,统一给深色 if font_size > 30: return 'hsl(210, 70%, 35%)' return 'hsl(210, 15%%, %d%%)' % random.randint(55, 75)

font_size这个入参在这里就派上用场了,它让颜色可以跟着权重走,比纯随机可控得多。

4.4 案例07 权重直供:extract_tags 加 generate_from_frequencies

# -*- coding: utf-8 -*- from wordcloud import WordCloud, ImageColorGenerator from PIL import Image import numpy as np import matplotlib.pyplot as plt import jieba.analyse from paths import TXT_CN, FONT_PATH, MASK_COLOR with open(TXT_CN, 'r', encoding='utf-8') as f: text = f.read() # topK 控制取多少个词,withWeight=True 才会带回权重 freq = jieba.analyse.extract_tags(text, topK=200, withWeight=True) print(freq[:20]) # 先看看前 20 个是不是你要的词 # 从 [(词, 权重), ...] 转成 {词: 权重},这是 generate_from_frequencies 要的格式 freq = {i[0]: i[1] for i in freq} mask = np.array(Image.open(MASK_COLOR)) wc = WordCloud( mask=mask, font_path=FONT_PATH, mode='RGBA', background_color=None ).generate_from_frequencies(freq) # 注意不是 generate image_colors = ImageColorGenerator(mask) wc.recolor(color_func=image_colors) plt.imshow(wc, interpolation='bilinear') plt.axis('off') plt.show() wc.to_file('main_07.png')

这个案例把整个流程的控制权拿了回来。generate_from_frequencies跳过了内部的分词和停用词处理,直接按你给的字典排字号,所以前面清洗做得好不好,这里会立刻反映出来。

extract_tags默认用的是 TF-IDF 思路:一个词在这篇文本里出现得多、在通用语料里出现得少,权重就高。这比单纯词频聪明,能自动压掉「我们」「时候」这类到处都有的词,所以很多人到这一步反而不需要停用词表了。

topK=200是个经验值。取太小(比如 50),图上会很稀疏,蒙版尺寸大的时候大片空白;取太大,长尾词的字号会小到看不见,还拖慢布局计算。800×600 的画布上,200 到 300 之间比较合适。

还有一个细节:generate_from_frequencies会先把权重归一化再映射字号,所以你的权重是 0.001 还是 1000,出来的图是一样的。想让某个词特别大,靠调绝对值没用,得拉开它和第二名之间的相对差距。

5. 避坑与排查:七个案例里最容易翻车的五处

5.1 字体与路径:两类最像「环境坏了」的假故障

现象一:图上全是方块,或者干脆一张白图,代码一行没报错。

原因是font_path没给或者给错了。wordcloud 默认字体只有拉丁字形,遇到汉字要么画成方框,要么直接跳过不画。而且它不会抛异常,静默失败。解决办法是把路径打印出来确认文件存在,再按 2.3 那个冒烟脚本看像素均值,均值接近 255 就说明字没画上去。注意传参时最好str(Path)转一下,Path 对象在部分版本里传给 font_path 会出问题。

现象二:FileNotFoundError,但文件明明就在那个目录里。

两种情况。一是相对路径的基准不是脚本所在目录,而是你执行命令时的工作目录,PyCharm 里跑和终端里跑结果可能不一样。二是路径里有中文或空格,某些版本的底层库处理不了。解决办法是把路径统一成Path(__file__).resolve().parent起头的绝对路径,一行解决所有相对位置问题,这也是我在 2.2 里坚持用paths.py的原因。

5.2 参数与回调:看着像 API 变了,其实是签名对不上

现象三:加上color_func之后立刻 TypeError,提示参数数量不对。

原因是回调函数的签名和库内部调用时传的参数不匹配。教程里的写法是(word, font_size, position, orientation, font_path, random_state),把font_path当第五个位置参数,但库内部是按关键字传random_state的,位置一对不上就炸。解决办法是把签名固定成(word, font_size, position, orientation, random_state=None, **kwargs),**kwargs兜住所有版本差异,写完这一版,后面换版本也不用再改。

现象四:蒙版形状完全没生效,出来还是矩形。

原因多半是蒙版读进来是四通道 RGBA 数组,形状不对,库要么忽略要么报索引错误。解决办法是先convert('L')转灰度再np.array(),如果这个案例还需要取色(像案例05),那就保留彩色,但在传之前确认mask.ndim == 3。两个需求冲突的时候,我的做法是准备两张蒙版:一张灰度图给 case04,一张彩图给 case05~07,各管各的。

5.3 出图结果不对:背景、词量和视觉层次

现象五:说要透明背景,导出的 PNG 打开一看黑底。

原因是mode='RGBA'和background_color=None只给了一个。只给后者,图还是 RGB 三通道,透明信息直接丢了,很多看图软件就渲染成黑底。解决办法是两个参数成对出现。另外注意保存的时候用wc.to_file()而不是plt.savefig(),后者存的是 matplotlib 的画布,会把坐标轴的留白也带进去,透明度还不一定保得住。

顺带一个不算 bug 但很影响观感的点:词太少。max_words默认 200,如果你的topK只取了 50,图上就是几十个大字飘在空白里。改法是把 topK 提到 200 以上,或者调小max_font_size让字号整体收敛,视觉密度立刻就上来了。

排查这类问题,我固定走三步:先print(text[:100])看分词结果对不对,再print(wc.words_)看最终的词和权重字典是不是预期的那些词,最后wc.to_array().mean()看像素均值判断到底画没画上东西。三步走完,问题基本就定位到具体某一环了,比反复改参数瞎试快得多。

6. 二次开发:把七个案例收成一个可复用的词云生成器

七个案例跑通之后,真正的浪费是把它们当成七段互不相干的代码。我第二次做词云项目时,把它们收敛成了一个类,后面所有需求都是改参数,不再复制粘贴。

# builder.py 把七个案例的差异点抽成参数 class WordCloudBuilder: def __init__(self, font_path, stopwords=None): self.font_path = font_path self.stopwords = stopwords or set() def fit_text(self, text, topk=200, use_idf=True): """案例03 + 07 的合并:要么走 TF-IDF,要么走清洗后词频""" import jieba.analyse self.freq = dict( jieba.analyse.extract_tags(text, topK=topk, withWeight=True) ) return self def render(self, mask_path=None, colorize=False, out='out.png'): """案例04/05 的合并:有彩图蒙版才取色,否则纯色""" from wordcloud import WordCloud, ImageColorGenerator from PIL import Image import numpy as np kwargs = dict(font_path=self.font_path, mode='RGBA', background_color=None) mask = None if mask_path: mask = np.array(Image.open(mask_path)) kwargs['mask'] = mask wc = WordCloud(**kwargs).generate_from_frequencies(self.freq) if colorize and mask is not None and mask.ndim == 3: wc.recolor(color_func=ImageColorGenerator(mask)) wc.to_file(out) return out

这个类把变化点收得很干净,实际改起来只看几个地方:

想改什么动哪里经验值
词太多太挤fit_text的 topk800×600 画布用 200~300
词语全是废话stopwords或改用 TF-IDF中文小说类语料先上停用词
图上只有几个大字max_font_size调小 + topk 调大配合蒙版尺寸一起看
颜色和品牌不符render里换 color_func按 font_size 分档比纯随机稳
空白处不透明kwargs 里两个参数成对给mode 和 background_color 缺一不可

验证方式也很直接:拿同一份语料分别跑一遍原案例03 和这个 builder,把两张图放在一起比词和字号分布,如果wc.words_里的键值对基本一致,说明抽象没有改变行为,可以放心往下加功能。我通常还会留一个debug=True的开关,打开就把text[:100]、wc.words_前 20 项、图片像素均值一起打出来,出问题的时候不用重新加 print。

从那以后我每次做词云,都强制先把font_path和stopwords在命令行里打印一遍再 generate。这两个东西一旦出错,图还是能出,只是错得非常安静,等到交付前才发现就晚了。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询