数字唐诗数据可视化实战:从清洗到答辩展示 📅 发布时间:2026/9/16 18:10:19 👁 浏览次数: 简介面向需要完成Python数据可视化课程设计、期末大作业或毕业设计的同学这是一套基于数字唐诗主题的完整项目资料。项目以唐诗数据为分析对象借助Python完成数据采集、清洗与可视化展示难度适中既有综合性又不至于过难适合本科阶段课程项目参考与二次开发。压缩包大小42.39MB整体资料包含可直接运行的源码、项目文档说明以及答辩PPT目录结构清晰便于按模块查看、调试与扩展。目前已有493人学习下载。源码均经过本地编译验证可正常启动运行评审分达到98分内容经过助教老师审定可信度和完整度都比较高。入手后既能直接部署运行展示成果也可以对照文档梳理分析流程理解从数据预处理到图表呈现的全过程对完成课程汇报、毕业设计答辩都有实际帮助。1. 数字唐诗可视化大作业从数据清洗到答辩PPT一次走通“数字唐诗可视化”经常被误当成“用 Python 画几张诗词语云”的简单任务。实际上评审看重的是两个点第一是否能把《全唐诗》这类非结构化文本里的诗人和句子提取成可比较的数字指标第二这些指标最终能否落到一张说得清的图上而不是只会调用官方示例。本文以常见的开源全唐诗 JSON 数据为输入从加载、清洗、统计、出图到答辩文件归档演示一套可以直接交付的作业框架。适合准备数据可视化课程设计、答辩前需要补齐实现细节的同学即使时间紧张也能按这条线把源码、图表和 PPT 材料同步完成避免做完图才发现数据口径对不上。2. 数字唐诗数据清洗与词频画像把《全唐诗》变成二维DataFrame做数字唐诗可视化第一件事不是选图表而是先把原文转成能统计的 DataFrame。全唐诗原始文件通常是 JSON 数组每首诗包含标题、作者、诗句列表几个字段。直接用文件里的字符串做图会遇到三个问题标题和作者有空值诗句里有换行和全角空格大量重复条目会干扰统计。所以需要先建立一套稳定的清洗流程并顺手算出“诗长、联数、平均句长”这三个最基础的量化字段。2.1 数字唐诗数据集选型结构化JSON优先于临时爬虫很多同学拿到题目第一反应是写爬虫去唐诗网站抓文本但反爬、编码、页面结构变化都会让项目不可复现。常见做法是直接找开源的全唐诗 JSON 数据一首诗对应一个对象字段如下import json import pandas as pd def load_tang_poems(json_pathpoet.tang.json): with open(json_path, r, encodingutf-8) as f: raw_poems json.load(f) rows [] for poem in raw_poems: rows.append({ title: poem.get(title, ), author: poem.get(author, ), paragraphs: \n.join(poem.get(paragraphs, [])) }) return pd.DataFrame(rows) df load_tang_poems() print(df.shape) print(df.head(3).to_string())paragraphs原本是数组这里用\n.join合并既保留每联的边界又便于后续按行切分。读取时强制指定utf-8可以避免 Windows 默认 GBK 编码带来的乱码。注意poem.get(title, )使用了默认值防止个别记录缺少字段导致整个程序中断。2.2 清洗并抽取“诗长、联数、平均句长”三个可统计字段拿到原始 DataFrame 后需要做四步清洗去除空文本、去除完全重复记录、过滤残句、生成统计字段。这里我会同时创建char_len、line_num和avg_line_len三列。df df.dropna(subset[paragraphs]) df df.drop_duplicates(subset[title, author]) df[char_len] df[paragraphs].apply( lambda s: len(.join(s.split())) ) df[line_num] df[paragraphs].apply( lambda s: len([line for line in s.split(\n) if line.strip()]) ) df[avg_line_len] df.apply( lambda row: row[char_len] / max(row[line_num], 1), axis1 ) # 过滤掉过短的残句 df df[df[char_len] 20]char_len先去掉所有空白再统计总字数使五言、七言诗的长度可以横向比较。line_num表示诗句行数不适合作者因为每联可能很长。avg_line_len是平均句长数值接近 5 或 7说明这首诗大概率是五言或七言。用max(row[line_num], 1)是防止除数为 0。清洗后的字段可以整理成一张字段说明表放进项目文档字段名数据类型清洗后用途titlestr页面展示、去重依据authorstr作者排行、相似度分组paragraphsstr分词、词频统计char_lenint诗篇长度分布line_numint绝句、律诗、长诗判断avg_line_lenfloat五言、七言风格推断2.3 用jieba和高频词表给唐诗建立风格画像对全唐诗全文直接做词频统计结果会被“之乎者也”这类虚词淹没。数字唐诗可视化要展示的是意象比如“月、风、山、花”所以必须先做停用词过滤。我一般会用 jieba 分词再补一个针对文言文的停用词集合。import jieba from collections import Counter stop_words set( 之 乎 者 也 兮 矣 哉 而 与 及 乃 其 以 于 然 则 若 何 如 但 更.split() ) word_counter Counter() for paragraph in df[paragraphs].head(2000): for word in jieba.cut(paragraph): w word.strip() if w and w not in stop_words and not w.isdigit(): word_counter[w] 1 top_words word_counter.most_common(30) print(top_words)先用head(2000)采样目的是快速验证参数不用每次都遍历全部四万多首。停用词里的单字要慎重像“月、云、风”都不能删它们恰恰是唐诗意象最高的词。word_counter统计的是 jieba 切分后的词不限制词长所以词云里既能出现单字意象也能出现“相思、故人”这样的双字词组。提示分词参数不是越复杂越好。停用词表控制在 20 个左右词云效果最接近人们对唐诗的直觉加入太多停用词会让结果只剩地名和人名。3. 用pyecharts实现数字唐诗核心可视化排行榜、诗体占比和词云数据准备完成后就到了可视化主体部分。pyecharts 是这类大作业里最顺手的库输出 HTML交互缩放开箱即用不需要额外搭前端框架。下面三张图是答辩 PPT 中最常被评审注意到的诗人作品榜、诗体占比饼图和唐诗意象词云。3.1 诗人作品Top20柱状图先做名次轴再做细节轴诗人作品数量是最直观的对比方向。李白、杜甫、白居易必然排在前列但真正决定图是否好看的是横轴标签作者名一旦过长就会相互遮挡。from pyecharts.charts import Bar from pyecharts import options as opts author_stats ( df.groupby(author) .size() .reset_index(name作品数) .sort_values(作品数, ascendingFalse) ) top_authors author_stats.head(20) bar ( Bar() .add_xaxis(top_authors[author].tolist()) .add_yaxis(诗作数, top_authors[作品数].tolist()) .set_global_opts( title_optsopts.TitleOpts(title数字唐诗诗人作品Top20), xaxis_optsopts.AxisOpts( axislabel_optsopts.LabelOpts(rotate45, interval0) ), yaxis_optsopts.AxisOpts(name作品数), ) ) bar.render(output/poet_rank.html)rotate45让唐诗作者名斜排避免“白居易”这类三个字的标签叠在一起。interval0表示强制显示全部标签如果作者名超过 30 个建议改成intervalauto。这里先按ascendingFalse排序直接用 DataFrame 结果传入 pyecharts避免手动构造列表时出现顺序错乱。3.2 按句子数量划分绝句、律诗、长诗饼图说清体裁分布诗体维度用饼图展示最直观。依据之前算出的line_num字段四句归为绝句八句归为律诗其余归为长诗。规则不完全精确但作为课程设计足够说明问题。from pyecharts.charts import Pie def classify_form(line_num): if line_num 4: return 绝句四句 elif line_num 8: return 律诗八句 return 长诗/排律 df[form] df[line_num].apply(classify_form) form_stats df[form].value_counts() pie ( Pie() .add( 诗体, [list(item) for item in zip(form_stats.index, form_stats.values)], radius[35%, 65%], ) .set_global_opts( title_optsopts.TitleOpts(title数字唐诗诗体结构分布), legend_optsopts.LegendOpts(orientvertical, pos_leftleft), ) .set_series_opts(label_optsopts.LabelOpts(formatter{b}: {c} ({d}%))) ) pie.render(output/form_pie.html)radius[35%, 65%]生成环形图比实心饼图更适合展示占比。{d}%是 pyecharts 内置的百分比格式化语法用于在标签里同时显示数量和比例。这里要注意value_counts()返回的索引顺序可能不固定所以演示时最好先固定form_stats的索引顺序。3.3 高频意象词云word_size_range与单字词的处理词云几乎是唐诗可视化大作业的标配也是最容易翻车的图。如果直接使用原生 wordcloud 库还要处理中文字体路径pyecharts 的 WordCloud 在浏览器端渲染字体问题会少很多。from pyecharts.charts import WordCloud wc ( WordCloud() .add( 唐诗意象, top_words, word_size_range[16, 90], shapediamond, ) .set_global_opts(title_optsopts.TitleOpts(title数字唐诗高频意象词云)) ) wc.render(output/wordcloud.html)word_size_range[16, 90]控制字体最小和最大像素范围太大时低频词看不清范围太小时重点不突出。top_words来自第 2.3 节的Counter.most_common(30)传入的格式是[(“月”, 1843), (“风”, 1506), ...]pyecharts 要求的就是这种二元组列表。三张图完成后建议统一输出到output/目录方便后续文档和 PPT 引用也方便写成脚本一键重跑。4. 数字唐诗进阶可视化作者相似度网络与Streamlit仪表板基础图表能保证作业合格但如果想拿高分需要增加一个“关系维度”。唐诗没有社交网络数据但可以从词频特征计算作者之间的风格相似度生成一张“唐诗作者相似度网络图”。同时用 Streamlit 把几张图并成一个展示页面答辩现场可以当场切换效果远比一张静态截图好。4.1 用词频向量计算诗人相似度网络将每个作者的所有诗合并成语料用 TF-IDF 向量表示作者风格然后计算两两余弦相似度。相似度高于阈值就在网络图中连一条边。这里的边不是人物交游关系而是“用词风格接近”。import networkx as nx from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity top_authors author_stats.head(50)[author].tolist() corpus ( df[df[author].isin(top_authors)] .groupby(author)[paragraphs] .apply(lambda s: \n.join(s)) ) vectorizer TfidfVectorizer( tokenizerlambda text: [ w for w in jieba.cut(text) if w.strip() and w not in stop_words ], max_features2000, ) tfidf_matrix vectorizer.fit_transform(corpus) similarity cosine_similarity(tfidf_matrix) graph nx.Graph() for name in top_authors: graph.add_node(name) threshold 0.15 for i in range(len(top_authors)): for j in range(i 1, len(top_authors)): if similarity[i, j] threshold: graph.add_edge(top_authors[i], top_authors[j], weightround(float(similarity[i, j]), 3)) nx.write_graphml(graph, output/author_network.graphml) print(graph.number_of_nodes(), graph.number_of_edges())max_features2000限制特征数量避免向量维度爆炸。网络图阈值不能拍脑袋取不同值会影响边数阈值边数趋势画面效果0.08边数过多所有作者连成团看不清结构0.15边数适中能分辨风格聚团适合提交0.22边数较少只剩高相似组适合快速讲结论写进文档时顺便提供一个“阈值-边数”小表能够有效应对答辩时“这个 0.15 怎么来的”这类问题。4.2 用Streamlit把多个HTML打包成一个可视化作坊pyecharts默认生成独立的 HTML 文件。如果只放在output/目录答辩要逐个打开效率很低。常见做法是在 Streamlit 页面中直接把多个图拼起来用选项卡切换。import streamlit as st import streamlit.components.v1 as components st.set_page_config(page_title数字唐诗可视化, layoutwide) st.title(数字唐诗可视化工作台) bar ( Bar() .add_xaxis(top_authors[author].tolist()) .add_yaxis(作品数, top_authors[作品数].tolist()) ) html bar.render_embed() components.html(html, height500, scrollingTrue)render_embed()是关键它把图表连同 JS 依赖一起内嵌到 HTML 字符串中不需要依赖外部资源。scrollingTrue允许图表容器内滚动保证页面整体布局不被打乱。这份页面跑起来后可以直接用浏览器全屏模式演示效果比 PPT 内嵌视频更稳定。4.3 用GraphML文件给PPT补充网络图素材author_network.graphml是标准图数据格式可以用 Gephi 导入后重新布局也可以直接用 Python 输出节点和边的表格。答辩 PPT 里放一张“局部放大图”再放一段计算逻辑比整页导出整个网络图更清楚。网络图的意义在于李白、杜甫这类作者不会因为“单字重复”被错误聚类聚合体多由时代或题材相近的作者形成。提示用 TF-IDF 得到的是风格距离不是社交关系。在文档说明里写清这一点反而比硬解释成“文学流派”更严谨。5. 数字唐诗项目的答辩PPT自检图档目录、指标断言与讲稿准备最后一个环节最容易被忽略代码能跑但交上去的 PPT 里缺关键说明。应对方法是把项目目录固定成三类输出并在答辩前跑一遍断言脚本。5.1 把答辩PPT内容映射到源码输出这页结构可以直接作为 PPT 大纲页面位置展示内容对应文件背景页数字唐诗项目数据源与处理流程文档说明.md数据页数据量、字段表、清洗逻辑上方清洗代码图表页诗人Top20、诗体分布、词云output/ 下的HTML技术亮点Streamlit多图联动dashboard.py结果页结论、局限与后续改进答辩PPT最后一页用一个目录状态表把未生成的图暴露出来比口头说“图表已经跑通了”更有说服力。5.2 答辩前五分钟左右跑一个数字唐诗项目断言脚本import os import sys required_files [ output/poet_rank.html, output/form_pie.html, output/wordcloud.html, output/author_network.graphml, ] for path in required_files: if not os.path.exists(path): sys.exit(f[失败] 缺少 {path}) if len(df) 40000: sys.exit([失败] 唐诗数据量不足) assert graph.number_of_edges() 10, 相似度网络边数过少 print([OK] 数字唐诗可视化项目文件完整)这里的len(df) 40000只作为粗略规模校验不必纠结是否覆盖全量《全唐诗》。校验脚本是给答辩现场准备的所有检查结果直接输出到终端也能写进运行日志。5.3 准备一个“词云参数对比”备用页答辩常被追问“为什么词云字号是 16 到 90”。不要回答“好看”而是准备一个参数对比word_size_range[8, 50]会让词频差异不明显[16, 120]会让低频词几乎不可见。把三张参数截图放进 PPT 附页既展示调试过程也体现你对渲染参数有控制力。这个技巧比临时改代码有效得多。本文还有配套的精品资源点击获取