使用 Python 进行数学艺术创作
最初发表于Simple Programmer。
数学可能会令人生畏。
根据老师和教学方式的不同,课程可能既难以理解又无聊,令人恼火。
但数学也有其美——数字背后蕴含的智慧与逻辑的对称性。我热爱数学,也希望其他人也能热爱它。
让数学更平易近人、并以视觉方式展现其美感的一个巧妙方法是将其与所谓的“生成艺术”相结合。生成艺术是指创建一些通常基于数学或几何的简单规则,然后让计算机处理这些规则。
由于计算机能够快速处理指令,并且处理规模比人类大得多,因此所创建的设计通常比您根据这些简单规则所预期的更复杂、更有趣。
这个例子展示了一群漂浮的粒子,它们以一种令人着迷的自然运动方式移动。它们四处漂浮,与其他粒子连接,并自行改变方向。这是“群集算法”的一种变体,令人惊奇的是,这种自然运动的大部分源于每个粒子都遵循“不撞到任何人”、“保持群集”和“与附近的粒子大致相同的方向”的规则。
Python是创建这些生成艺术项目的绝佳选择;它被数据科学家、数学家和工程师(以及许多其他人)用作处理数值计算和生成可视化的开源选项。
它也非常容易阅读和编写清晰的代码,这使其成为概述创建这种生成艺术所需的简单规则的理想语言。
使用这些规则可以创建的最简单的数学结构之一是整数序列,它是整数(整数,包括:正数、负数和零)的有序列表。通常,这些整数之间的关系会通过一组规则以某种逻辑方式阐明,以帮助人们找出模式中的下一个数字。
在本文中,我们将采用整数序列的数学原理,利用 Python 编程的强大功能对其进行增强,并使用它们来创建一些有趣且美丽的生成艺术。
这是一个有趣的练习,计算和代码示例足够简单,程序员、数学家和艺术家都应该参与其中。
不过,这篇文章并非面向 Python 初学者,因此我假设你对 Python 的语法有所了解(或者至少愿意边学边学),并且知道如何运行 Python 程序。如果你不确定如何运行 Python 程序,并且想在一个带有巨大“播放”按钮的应用程序中编写代码,那么Mu 文本编辑器非常适合初学者。
这次我想讲的序列是雷卡曼序列。它的规则看似简单,但当数字被赋予视觉或听觉形态时,结果可能会很有趣,甚至有点令人毛骨悚然。
雷卡曼序列
规则如下:
- 从零开始。
- 你迈出的每一步都会比上一步大1。
- 如果可以(消极地)后退,就后退。否则,就前进。
- 仅当结果位置为正(大于零)并且我们之前从未到过该数字时才允许向后移动。
我们以前几个为例。
我们从零开始。
- 0
下一步的大小将是 1。向后退会将我们置于 -1,这是不允许的,所以我们将向前迈进。
- 0 -> 1
下一步的步长是 2。后退一步会将步长设为 -1。这仍然不被允许,所以我们必须前进。
- 0 -> 1 -> 3
下一步的步长是 3。后退一步会回到 0。由于我们已经去过 0(我们的第一个起点),所以这不是一个有效的移动。我保证接下来的序列很快就会变得有趣,但现在我们先向前走。
- 0 -> 1 -> 3 -> 6
下一步的大小是 4。向后退一步,我们得到的是 2。由于 2 是正数,而且我们还没有看到它,所以我们可以迈出第一步合法的后退!
- 0 -> 1 -> 3 -> 6 -> 2
希望你已经开始明白这些规则是如何运作的了。想想还挺有意思的,但我不确定我会不会把五个数字组成的列表称之为“美”。到了这里,我们再稍微深入一点,谈谈艺术和代码。幸运的是,Python 的标准库中有一个有趣又可爱的模块,Turtle ,为我们提供了这两者。
介绍 Turtle Graphics
Turtle Graphics 最初是Logo 编程语言的一个关键特性。
它是一种相对简单的领域特定语言 (DSL),屏幕上会显示一个虚拟角色——传统上形状像一只小乌龟——你可以指示它前进、后退或后退。当它移动时,它会用尾巴在所到之处画一条线,你也可以根据需要指示它抬起或放下尾巴。它甚至可以跳跃位置并改变颜色!
Python 的标准库中也包含一个“turtle”库。我们来看一个示例程序来了解它的工作原理。创建一个名为“example1.py”的文件,内容如下。
import turtle
window = turtle.Screen()
joe = turtle.Turtle()
joe.forward(50)
joe.left(90)
joe.forward(100)
turtle.done()
以下是重要内容:
- 在第一行,我们导入了“turtle”模块。它包含许多我们将要使用的函数,如果不先导入该模块,我们将无法使用它们。我们将通过“turtle.function_name”来使用这些函数,正如你所见。
- 在第 3 行,我们创建了一个窗口。运行代码时,这个窗口就会弹出。它包含了我们要绘制的所有内容。
- 在第 4 行,我们实际上创建了 Turtle。我们将它命名为“joe”,并将其存储在一个变量中,以便稍后向它发出命令。
- 第 6-8 行是我们向“joe”发出命令。你会看到“点”语法,这应该很熟悉了。
- 第 10 行只是在“joe”完成绘图后阻止窗口关闭。
如果您运行代码,您应该会看到类似以下内容:
附注:如果您想要真正的、老式的 Logo 体验,您可以在代码中添加“joe.shape(“turtle”)”,就在定义“joe”的那一行下面。他是不是很可爱?
好的,既然您已经了解了“乌龟”的含义,让我们回到我们正在处理的序列。
编码序列
就像任何好东西一样,我们绝对不可能一次就获得完美的结果。我们需要进行一些迭代。我会带你完成这个艺术项目的三遍,每一遍都会变得更复杂一些,视觉效果也更有趣一些。之后,我会提出一些潜在的迭代想法,如果你的创意火花燃起,可以尝试一下。开始吧!
首次尝试
我们编写的代码将与描述序列步骤的英语非常相似。记住两个规则:尽可能后退,否则前进,并且每一步后将步长增加一。
创建一个名为“recaman1.py”的新文件。我们将从这些基本规则开始,然后弄清楚如何让它真正发挥作用。我将把我们的新乌龟命名为欧拉,以某个人的名字命名。
import turtle
window = turtle.Screen()
euler = turtle.Turtle() # A good mathy name for our turtle
euler.shape("turtle")
current = 0 # Here's how we know where we are
seen = set() # Here's where we'll keep track of where we've been
# Step increases by 1 each time
for step_size in range(1, 100):
backwards = current - step_size
# Step backwards if its positive and we've never been there before
if backwards > 0 and backwards not in seen:
euler.backward(step_size)
current = backwards
seen.add(current)
# Otherwise, go forwards
else:
euler.forward(step_size)
current += step_size
seen.add(current)
turtle.done()
然而,当我们运行它时,结果看起来不太好。事实上,看起来好像有人给欧拉喝了太多咖啡。
第二次尝试
所以,这很合理。代码读起来就像我们给别人解释一样,这很好。
不过,恐怕线性运动有点无聊。这时我们就需要戴上艺术家的帽子(艺术家戴帽子吗?),想出一个更有创意的方法,让欧拉从A点走到B点。
幸运的是,海龟不必沿直线移动!它们也可以沿圆弧和圆圈移动。让我们让它在数轴上从一个点跳到另一个点!要让海龟画一个圆或部分圆弧,我们将使用“circle”命令,该命令使海龟沿着一个圆圈移动,该圆圈的假想圆心位于海龟左侧“radius”个单位处。
这意味着我们必须在绘制之前使用“setheading”命令来确定乌龟是向前还是向后移动。
请记住,您可以在官方文档中找到所有 turtle 命令,以防您好奇。
import turtle
window = turtle.Screen()
euler = turtle.Turtle() # A good mathy name for our turtle
euler.shape("turtle")
current = 0 # Here's how we know where we are
seen = set() # Here's where we'll keep track of where we've been
# Step increases by 1 each time
for step_size in range(1, 100):
backwards = current - step_size
# Step backwards if its positive and we've never been there before
if backwards > 0 and backwards not in seen:
euler.setheading(90) # 90 degrees is pointing straight up
euler.circle(step_size/2, 180) # 180 degrees means "draw a semicircle"
current = backwards
seen.add(current)
# Otherwise, go forwards
else:
euler.setheading(270) # 270 degrees is straight down
euler.circle(step_size/2, 180)
current += step_size
seen.add(current)
turtle.done()
这很巧妙,但刚开始的时候,他好像只是在原地晃来晃去,而且线条很近。而且,他不会用到整个屏幕的左半部分!
让我们再一起进行一次迭代,让它看起来更加美观。
第三次尝试
这次迭代的目标是让画面变得更大,并给他更多的工作空间。
import turtle
window = turtle.Screen()
window.setup(width=800, height=600, startx=10, starty=0.5)
euler = turtle.Turtle() # A good mathy name for our turtle
euler.shape("turtle")
scale = 5 # This isn't a turtle module setting. This is just for us.
# Move the little buddy over to the left side to give him more room to work
euler.penup()
euler.setpos(-390, 0)
euler.pendown()
current = 0 # Here's how we know where we are
seen = set() # Here's where we'll keep track of where we've been
# Step increases by 1 each time
for step_size in range(1, 100):
backwards = current - step_size
# Step backwards if its positive and we've never been there before
if backwards > 0 and backwards not in seen:
euler.setheading(90) # 90 degrees is pointing straight up
# 180 degrees means "draw a semicircle"
euler.circle(scale * step_size/2, 180)
current = backwards
seen.add(current)
# Otherwise, go forwards
else:
euler.setheading(270) # 270 degrees is straight down
euler.circle(scale * step_size/2, 180)
current += step_size
seen.add(current)
turtle.done()
如您所见,我们添加了一个缩放系数,您可以根据自己的喜好进行调整。我尝试了几个系数,最终选出了我最喜欢的一个,并最终确定了它。我们还将他的位置进行了调整,让他从屏幕左侧开始移动。由于他的位置永远不会为负数,所以我们知道他只会从起始位置向右移动。
进一步调整
现在,我想你已经掌握了要点,并且希望你开始看到整数序列的魔力:通过一些简单的规则(并在不知疲倦的爬行动物助手的帮助下),你可以获得一些真正有趣和迷人的结果。
你已经拥有了所有必要的工具,可以做些更酷的事情了。以下是一些激发你创意的点子:
- 如果你改变线条的颜色会怎么样?如果你连续改变它又会怎么样?
- 如果将绘图倾斜一定角度以占据更多的屏幕空间,会怎么样呢?
- 如果有多只海龟同时绘制序列会怎么样?
- 如果以一点随机性来改变可预测的序列会怎样?
- 如果您结合用户输入(鼠标单击、键盘按下等)来影响海龟的行为,结果会怎样?
- 如果你制作一只可以画画但由某种非常缓慢的东西(比如月亮的周期)驱动的乌龟,会怎么样?
- 有没有办法将乌龟与物联网项目或网络应用程序结合起来?
该序列的其他版本
如果你觉得雷卡曼序列特别引人入胜,那你并不孤单。人们创作了无数不同的版本,将线条与色彩、声音等等巧妙地融合在一起。以下是我最喜欢的几个。
这个有点恐怖的有声版本:
Numberphile 的这个关于该序列的视频非常有趣:
如果您想在一位出色的老师的指导下观看精彩的视频演示,并且不介意编写 JavaScript,那么 Coding Train 还制作了几个有关编码的视频:
事实上,P5.js(及其基于 Java 的前身Processing)都是使用代码制作艺术和动画的绝佳替代品;它们配有专门的编辑器来帮助您做到这一点,并且它们支持声音和其他插件!
让你的海龟做好准备
希望本教程足以激发您使用代码创作艺术的兴趣,并且希望(如果您以前有过这种兴趣),您不再害怕将数学作为艺术创意的源泉。
几何、无穷常数、黄金比例、斐波那契螺旋、分形和数论都是令人惊叹的视觉项目金矿,只等着通过编程来生成,现在您已经拥有了获取自己的一组海龟并开始生成所需的所有工具!
鏂囩珷鏉ユ簮锛�https://dev.to/rpalo/using-python-to-make-art-with-math-5add