问题现象
想在一张散点图上给每个点标一个编号,编号来自一个与坐标等长的列表。翻遍scatter()的参数,只找到控制标记形状、大小、颜色的marker、s、c,没有任何一个参数接受「每点一段文字」。于是有人开始尝试把文本塞进颜色映射,或者给scatter()传一个自造的关键字,结果要么被忽略,要么抛出unexpected keyword argument。
另一条路是自己写循环加文字,图是标出来了,但每个标签正正压在数据点中心,点和字糊成一团;改成往右上角偏一点,又发现偏移量随时间被数据坐标系拉扁——横轴跨度大时偏得远,跨度小时几乎贴着。
原因分析
关键在于scatter()的定位。它是一个批量绘制接口,一次把整组点交给后端做一次绘制,能从批量中受益的参数只有那些能映射到视觉通道的量:位置、大小、颜色、透明度、标记形状。文本不是视觉通道,每个文本都是一个独立的Text对象,有自己的字体、对齐方式、旋转角,无法用一次批量调用表达。所以逐点文本必须逐点创建,没有捷径。
至于标签压住数据点,根子是锚点与坐标系两件事。annotate()和text()默认把文本的左下角放在给定坐标处,而点的中心也在那个坐标,于是文字直接从点的中心向右上铺开,视觉上盖住了点。要避开,要么改对齐方式,要