大明首辅观察录
前言
终于把 大明首辅观察录 写完啦!一直计划着做完后得写篇文章好好回顾一下。对于这个数据可视化课程结课作业,我将主要的精力花在了 数据的处理 和 展现形式的选择 以及 图表的细节优化 上。其他部分有所欠缺确实也是力有不逮,无法面面俱到
可以说,数据收集的过程大大满足了我的“考据癖”。也不知道这个毛病是什么时候养成的。还记得读上彊村民的《宋词三百首》那会儿,我就爱一个一个注释抠过去……
本篇博文将会从技术实现和设计思路两个角度逐步剖析我制作 大明首辅观察录 的全过程
灵感总在深夜出现
灵感的来源在之前的博文中已经简单提到了。其实那晚原本已经躺上床,准备读会儿《美的历程》陶冶一下情操(简称催眠)。恰巧舍友W回寝谈到兰陵笑笑生原作者云云,勾起了我读《明朝那些事儿》的回忆。加入聊天后发现和舍友F兴趣相投,于是乎多聊了几句,当然,谈话涉及到了某几位著名的首辅。之后我便看不进书了,一直在想换结课作业主题的事儿,阅读进度也就此停留在了“陶器几何纹饰……”😅
结构设计
确定主题后就得设计表现形式。我想改变惯用的从上而下线性表达,看了一些作品后觉得 story-teller 式的滚动说明风格挺符合我的预期。于是找了一篇参考教程 So You Want to Build A Scroller,准备着手试试
在阅读了源码之后,我大致预估了一下绘图代码,觉得似乎并不能原样照搬:该教程作者的绘图参考了 D3js 作者 Mike Bostock 提出的 Towards Reusable Charts,将所有的图表预先绘制在同一张 SVG 上。这意味着随着图片增多,为了代码的可维护性必须进行解耦;而且,绘制在同一张 SVG 上图片交互将会产生冲突……
在综合考虑了各主要矛盾之后,我决定舍弃绘制在同 SVG 中可以带来的滚动动态表现,首先保证代码的可维护性和图表的交互功能。经过一晚上的调整,将原先基于 js 的滚动激活效果整个迁移到 Vue3 上(利用了 Vue 提供的动态组件)。这也是代码设计的主要逻辑:通过监听页面滚动事件切换对应的组件
之后就是一个一个组件往下写了,可维护性至此也得到了保证
试画散点图
在确定“首辅”资格的时候,我主要参考了《明史·宰辅年表》。首辅其实是一个相对模糊的概念,不像别的职务那样有明确的定义。这份年表算是提供了一个相对权威的参考吧。对于年表中记载模糊的地方,还特意去查了《明实录》,尤其是《明世宗实录》
考虑到需要表现出“个体”,我认为散点图会是个不错的选择。通过颜色、坐标轴,我将尽可能多的信息编码进散点图中。横纵两轴其实都有时间的概念,不过这张图最直观的信息应该是首辅疏密程度与时间点间的关系
这里给出我个人发现的几个有意思的时间点。从上图可以看出多个密集区域:天顺元年、嘉靖朝前半时期、天启崇祯一路到明朝灭亡……
- 天顺元年:朱祁镇发动夺门之变成功复辟,几个有从龙之功的投机分子开始“分猪肉”,人来人往好不热闹(背景图选择青花质感也是想牵强附会一下景泰蓝以纪念景泰帝,我私人还是挺同情他的……
- 嘉靖朝前半段:可以看出嘉靖还是很爱玩平衡朝政这一手的。例如图上嘉靖刚即位时,“大礼议”事件一连换了多位首辅。但嘉靖二十一年之后就太平了许多,也不知道是不是和壬寅宫变有关(从此性情大变,安心修仙😇
- 天启崇祯:这密集程度看得我密集恐惧症都要犯了,果然就是快完蛋瞎搞呗
这里加些题外话:虽然每张图表都看上去挺朴实无华的,但大都前后改了好几版才呈现出现在的样子,也就是我前言中所提及的 图表的细节优化。例如这张散点图的坐标轴设计、网格密度调整以及提示框边缘点特判等等
对于创作,我始终相信这是一个发现的过程,你所创作的作品最终会引导你到它该有的状态。当然前提是你投入了足够多的时间使它变得重要,重要到可以引导你,“正因为你为你的玫瑰花费了时间,才使你的玫瑰变得如此重要”(已经开始胡言乱语了,别管我👋
考据起步 —— 地图
统计一下首辅的籍贯当然也是非常重要的,毕竟这也属于主要个人信息嘛。为了画出按朝代绘制的地图,大约是花了个把小时考量和给源数据分层。此外还有把地名对应到古地名的工作,期间参考了《明史》列传和古地图集,被迫学习到了很多地理知识:南通州与北通州分别在京杭大运河的两端,因连接南北直隶而得名……
使用定时器来给地图动态上色,因为实在是不想再按年代细分首辅名字了!好累!所以就定时器一波到底再交互(这也导致切换组件时定时器会错乱的bug,没想好怎么解决=。=)
江西吉安府,repeat it again!庐陵文化真的强👍
考据进阶 —— 桑基图
以前读《明朝那些事儿》有关科举制度一段时,下意识就留下了“同进士不如进士”的印象(为如夫人洗足,赐同进士出身😏),进而想当然认为三甲出身当首辅是极小概率事件。但是……细细查了数据之后(这里强烈致谢 《明朝、清朝各科殿试金榜(进士)名录》 的制作者,数据详实,帮助巨大!),三甲首辅其实还是有不少。不过从人数上看三甲人数还是少于一甲的,顶尖人才还是顶尖啊(战术后仰)
当初想着要表现各名次占比关系,考虑到平面饼图直方图过于简单且不直观,而且一旦数据方差较大时会很难看,没有必要为单一离群点做对数处理……好在让我看到了桑基图。看到它的一瞬间,比例√ 直观√ 多关联√,是我的梦中情图了!
桑基图在 D3v4 版时还只是插件,到 v6 已经被正式加入官方 API 。由于我对使用 chart 的掌握不是很好,出于工期考虑还是稳妥一些选择了 v4 版本的插件实现。比较坑的一点是屏幕宽度不适宜时桑基图是无法显示的(这个bug卡了我好久才发现)
之后还企图想让最后一列年号按时间顺序排列,细看插件的布局算法后立马就放弃了这个念头……人家这么写肯定是有道理的,哪能你说定序就定序(原算法大致表现为先按流入值的一定顺序放置,放不下的往顶上放,才能让最后的布局大体上呈现均衡不错乱)
得益于桑基图的直观性,结论几乎是呼之欲出:
- 不考科举基本是不可能当首辅的,你以为你是杨士奇?
- 我们二甲才是首辅中间力量!
- 崇祯朝对三甲出身宽容度最高,不怕死就来吧!
怎么处理谥号呢?Circle Packing!
从上任到卸任,逻辑很自然会过渡到人物评价上。做人物评价却是不太容易,尤其是这些早已作古的老家伙们。无法从列传中收集足够多权威的评价语制作词云,只能寄希望于谥号,谥号总是不会变且易于考据吧
原本打算做泡泡图,把所有谥号按人数画圈,当然交互是会差一些。正巧课上学到层次图,翻看官网demo的时候一眼相中 Circle Packing,固定的小圈适合长度相近的文本,这简直是为谥号们量身定制的表现形式!感谢官网demo的极高套用性🙏,我几乎只是整理好数据就做完了图
层次图起初想以谥号优劣区分,但是看了相关资料后发现基本都是上谥,分!不!出!区!别!那就简单点,还是按人头数数咯
PS:唯独夏言的“愍”字是个中谥,当然这也与他蒙冤被斩,死后昭雪等遭遇有关
从平面到立体
连谥号都讲过了,再想从群体角度发挥是没辙儿了。想着抓几个有共性的典型吧,就从那些没有谥号的“问题首辅”出发。先 pass 没啥代表性的 ,例如大贪官严嵩、被人诬陷谋逆的陈循、因为老板挂了自己也不可能好过的一群明末首辅……哈,这有几只东林党!来来来,东林党争马上安排(反正东林党在我这也没什么面子🙂
东林党和阉党在天启前后那是你方唱罢我登场。原计划是做力导向图,舍友F提议可以做棋盘图,我一听深以为然,觉得这主意妙极了!力导向美则美矣,在表现关系上却有局限。倒不如拿中国象棋盘做背景,顺道还能把关系与传统文化背景联系在一块儿,不错
先画了 2D 版并做了人物简介的交互,学了 threejs 后打算翻制成 3D 版。但由于 threejs 的选择器通常通过射线选中对应物体,在画面可转动且物体较多的情况下,准度不好控制。多次尝试效果不佳,受工期限制,干脆同时保留 2D 和 3D 两版,一版专攻视觉效果,一版留作交互说明
多提一嘴《东林党点将录》,是真的蛮有趣的hhh
雷达图
终于来到了最后一张图,我以人物介绍作为总结。在带有提示的输入框中输入首辅姓名,可以查询对应首辅的详细生平。雷达图将以较为直观的方式表现这位首辅的可量化参数与平均值的差异(雷达图使用的是 D3 插件)
在实现这部分的时候,还是遇到了一些问题,我很少会在总结性文字中提到“问题”这样的字眼,如果提到,说明这真的很是一个问题(绕吗?绕就对了XD)
大致表现为我需要在两个子组件之间进行数据传输,最后通过A子组件调用父组件调用B子组件的方法实现了在输入框组件搜索→雷达图组件展示结果的功能
总结
看到这已经可以划走了,我自己想再讲两句
做着做着我也不知道这该算个什么作业了,因为我花了大量,哦不,巨量的时间在信息收集与整理考据上、在设计表现形式上……还有,在感叹我发现的小故事上
小时候我最喜欢的就是中国古代史了,那些发生在过去的人和事总能让我兴致盎然。也许也幻想过长大成为一个历史学家或者考古学家什么的,但高考既没选历史,大学也读了完全与之无关的专业……随意感慨几句,可能我真学了历史学会发现全然不是这样,现在的距离就很好
知道这些故事有什么用呢,或许就是无用之用