用 Python 复现了一个偶然看到的 ”藏在Pi里的艺术“ 的数据可视化作品。
复现结果
有些数据可视化项目,结果看起来好像挺丰富、挺炫酷的,其实只是用了几条简单的规则,把一个抽象的事物转化为图像、视频这类具象的视觉形式来表现而已。
借用烹饪来比喻,就是对于珍贵的食材,只需要最简单的处理,最终菜肴的奇妙味道完全源自食材的神秘特性。
π 就是今天的食材,处理只有一个步骤:把360度等分,π 的每位数字相应指向不同的方向,并赋予不同的颜色。然后就没有然后了,任由这个无限不循环小数就这么无休止的走下去。
先用小数点后1000位尝了个鲜,结果大概就是下面这个样子了。

原作信息
这个想法是在一本叫做 Playful Data: Graphic Design And Illustration For Infographics 的书上看到的(豆瓣链接),很有趣的一本书,好像后来又出了续集 New Playful Data 。”藏在Pi里的艺术“是我翻译的名字,英文原名为 The Art in Pi ,是 Nadieh Bremer 的个人项目,原始用 R 和 Illustrator 实现,在1000位之后,作者又完成了1万、10万、100万位的绘制,但采用了不同的颜色设置方法。



复现代码
Python 实现用了最简单的方法。除了为了获取 π 的任意位数值用了 mpmath 库外,均为 Python 标准库,绘图部分通过 turtle 实现。
诸如图例绘制、颜色设置、绘图位置等等,尝试了几次以后才得到比较满意的结果。
有一些小细节学到了新的知识点,比如怎么输出希腊字母 π 。
还有些小问题以后再试,比如EPS文件输出时,中文字体的缺失问题。
Python 代码如下:
from mpmath import mp
import turtle
t = turtle.Pen()
# 设置要绘制的pi值
mp.dps = 1000
pi_value = str(mp.pi)
# 设置参数(画布大小、起始位置、线段长度、颜色表)
WIDTH = 600
HEIGHT = 800
START_X = -200
START_Y = -100
LINE_LENGTH = 16
turtle.colormode(255)
COLOR_TABLE = {
0:(248,191,29),
1:(254,153,0),
2:(228,8,10),
3:(210,1,3),
4:(171,20,213),
5:(108,45,226),
6:(55,48,238),
7:(15,5,248),
8:(42,139,3),
9:(158,186,1)
}
# 定义线段绘制函数
def drawLine(digit):
t.color(COLOR_TABLE[digit])
t.seth(90 - 36 * digit)
t.forward(LINE_LENGTH)
# 初始化画布,标记起点
turtle.setup(WIDTH,HEIGHT)
turtle.title("\u03C0")
t.speed(0)
t.pu()
t.goto(START_X,START_Y)
t.seth(90-3*36)
t.pd()
t.forward(LINE_LENGTH)
t.stamp()
t.ht()
# 开始绘制图形
for i in range(len(pi_value)-2):
drawLine(int(pi_value[i+2]))
# 标记终点
t.shape("circle")
t.stamp()
# 绘制图例
t.pu()
t.goto(0, -240)
for digit in range(10):
t.color(COLOR_TABLE[digit])
t.seth(90 - 36 * digit)
t.pd()
t.forward(LINE_LENGTH)
t.pu()
t.forward(LINE_LENGTH * 0.5)
t.goto(t.xcor()-2,t.ycor()-6)
t.write(str(digit))
t.goto(t.xcor()+2,t.ycor()+6)
t.rt(180)
t.forward(LINE_LENGTH * 1.5)
# 绘制标题
t.goto(0,-320)
t.color(96,96,96)
t.write("\u03C0", align="center",font=("Arial",20,"bold"))
t.goto(0,-335)
t.color(128,128,128)
t.write("小数点后 1000 位", align="center",font=("SimHei",8,"normal"))
turtle.done()
下步挑战
下面是两倍速视频,觉得看看绘制过程还挺解压的。1000位居然要50秒左右,小意外。那100万位岂不要5万秒,也就是说13.9个小时?有没有小伙伴想一起来试下,或者你有什么更快的好办法?
发表回复