Chat
Search
Ithy Logo

使用 Python 绘制爱心图案的全面指南

python - how to draw a heart with pylab - Stack Overflow

利用 Python 创建爱心图案不仅是一种表达创意和浪漫的方式,也是学习编程基础的有趣项目。本文将详细介绍多种方法,帮助你使用 Python 绘制静态和动态的爱心图案,包括字符艺术、使用 turtle 模块、tkinter 动画以及终端字符绘制。无论你是编程新手还是有经验的开发者,都能从中找到适合自己的解决方案。

1. 使用字符和循环打印爱心

1.1 基础字符爱心

通过简单的循环和条件语句,可以在终端中打印一个由字符组成的爱心图案。以下示例代码实现了这一功能:


def print_heart(size):
    n = size
    m = size + 1

    # 绘制上半部分
    for i in range(n // 2 - 1):
        for j in range(m):
            if i == n // 2 - 2 and (j == 0 or j == m - 1):
                print("*", end=" ")
            elif j <= m // 2 and ((i + j == n // 2 - 3 and j <= m // 4) or (j - i == m // 2 - n // 2 + 3 and j > m // 4)):
                print("*", end=" ")
            else:
                print(" ", end=" ")
        print()

    # 绘制下半部分
    for i in range(n // 2 - 1, n):
        for j in range(m):
            if j >= n // 4 and j <= 3 * n // 4 and i >= n // 2 - 2:
                print("*", end=" ")
            else:
                print(" ", end=" ")
        print()

size = int(input("Enter the size of the heart pattern: "))
print_heart(size)
    

该代码根据用户输入的大小,使用嵌套循环和条件语句,在终端中打印出一个心形图案。星号 (*) 和空格的组合构成了爱心的形状。

1.2 固定大小字符爱心

以下代码展示了如何绘制一个固定大小的字符爱心:


def print_heart():
    for i in range(6):
        for j in range(7):
            if (i == 0 and j in [3]) or \
               (i == 1 and j in [2, 4]) or \
               (i == 2 and j in [1, 3, 5]) or \
               (i == 3 and j in [0, 2, 4, 6]) or \
               (i == 4 and j in [1, 3, 5]) or \
               (i == 5 and j in [2, 4]):
                print("*", end=" ")
            else:
                print(" ", end=" ")
        print()

print_heart()
    

该代码利用固定的行和列位置,打印出一个预定义大小的爱心图案,适合展示简洁的视觉效果。

2. 使用 Turtle 模块绘制爱心

2.1 静态爱心绘制

turtle 模块是 Python 标准库中的一个图形绘制工具,适合初学者用于绘制各种图形。以下代码示例展示了如何使用 turtle 绘制一个静态爱心图案:


import turtle

# 设置画笔属性
pen = turtle.Turtle()
pen.shape("turtle")
pen.color("red")
pen.speed(2)

# 开始绘制爱心
pen.begin_fill()
pen.left(50)
pen.forward(133)
pen.circle(50, 200)
pen.right(140)
pen.circle(50, 200)
pen.forward(133)
pen.end_fill()

# 隐藏画笔并结束绘制
pen.hideturtle()
turtle.done()
    

运行上述代码后,你会看到一个红色填充的爱心出现在黑色背景上。通过调整 forwardcircle 的参数,可以改变爱心的大小和形状。

2.2 动态爱心绘制

要使爱心具有动态效果,如跳动或闪烁,可以结合 tkinter 模块进行动画处理。以下是一个动态爱心的示例代码:


import tkinter as tk
import math
import time

# 定义画布参数
CANVAS_WIDTH = 800
CANVAS_HEIGHT = 600
CENTER_X = CANVAS_WIDTH / 2
CENTER_Y = CANVAS_HEIGHT / 2
IMAGE_ENLARGE = 11
HEART_COLOR = "#dc143c"

# 爱心函数生成坐标点
def heart_function(t, shrink_ratio=IMAGE_ENLARGE):
    x = 16 * (math.sin(t) ** 3)
    y = 13 * math.cos(t) - 5 * math.cos(2*t) - 2*math.cos(3*t) - math.cos(4*t)
    x *= shrink_ratio
    y *= shrink_ratio
    x += CENTER_X
    y += CENTER_Y
    return int(x), int(y)

# 创建主窗口
root = tk.Tk()
root.title("动态爱心")
canvas = tk.Canvas(root, width=CANVAS_WIDTH, height=CANVAS_HEIGHT, bg='white')
canvas.pack()

# 绘制动态爱心
def draw_heart():
    canvas.delete("all")
    points = []
    for t in range(0, 360, 1):
        rad = math.radians(t)
        x, y = heart_function(rad)
        points.append((x, y))
    for point in points:
        canvas.create_oval(point[0], point[1], point[0]+2, point[1]+2, fill=HEART_COLOR, outline=HEART_COLOR)
    root.update()
    root.after(100, draw_heart)

draw_heart()
root.mainloop()
    

该代码使用 tkinter 创建了一个动态爱心图案,爱心会不断刷新,产生跳动的效果。通过调整 after 方法中的时间间隔,可以改变动画的速度。

3. 使用 Tkinter 创建高级动态爱心

3.1 定义高级动态效果

为了使爱心更加复杂和有层次感,可以使用随机扩散和抖动效果。以下代码展示了如何实现这些高级动态效果:


import tkinter as tk
import math
import random
from math import sin, cos, pi, log

# 设置画布参数
CANVAS_WIDTH = 800
CANVAS_HEIGHT = 600
CENTER_X = CANVAS_WIDTH / 2
CENTER_Y = CANVAS_HEIGHT / 2
IMAGE_ENLARGE = 11
HEART_COLOR = "#e77c8e"

# 爱心坐标生成函数
def heart_function(t, shrink_ratio=IMAGE_ENLARGE):
    x = 16 * (sin(t) ** 3)
    y = -(13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t))
    x *= shrink_ratio
    y *= shrink_ratio
    x += CENTER_X
    y += CENTER_Y
    return int(x), int(y)

# 随机扩散函数
def scatter_inside(x, y, beta=0.15):
    ratio_x = -beta * log(random.random())
    ratio_y = -beta * log(random.random())
    dx = ratio_x * (x - CENTER_X)
    dy = ratio_y * (y - CENTER_Y)
    return x - dx, y - dy

# 爱心类
class Heart:
    def __init__(self, generate_frame=20):
        self.points = set()
        self.edge_diffusion_points = set()
        self.center_diffusion_points = set()
        self.all_points = {}
        self.build(2000)
        self.random_halo = 1000
        self.generate_frame = generate_frame
        for frame in range(generate_frame):
            self.calc(frame)

    def build(self, number):
        for _ in range(number):
            t = random.uniform(0, 2 * pi)
            x, y = heart_function(t)
            self.points.add((x, y))
            # 边缘扩散
            for _ in range(3):
                x_diff, y_diff = scatter_inside(x, y, 0.05)
                self.edge_diffusion_points.add((x_diff, y_diff))
            # 中心扩散
            for _ in range(4000):
                x_diff, y_diff = scatter_inside(x, y, 0.17)
                self.center_diffusion_points.add((x_diff, y_diff))

    def calc_position(self, x, y, ratio):
        force = -1 / (((x - CENTER_X) * 2 + (y - CENTER_Y) * 2) ** 0.6)
        dx = ratio * force * (x - CENTER_X)
        dy = ratio * force * (y - CENTER_Y)
        return x - dx, y - dy

    def calc(self, frame):
        ratio = 10 * (1 + sin(frame * pi / self.generate_frame))
        halo_radius = int(4 + 6 * (1 + sin(frame * pi / self.generate_frame)))
        halo_number = 3000
        heart_halo_point = set()
        for _ in range(halo_number):
            t = random.uniform(0, 2 * pi)
            x, y = heart_function(t, shrink_ratio=11.6)
            x, y = scatter_inside(x, y, halo_radius)
            x += random.randint(-14, 14)
            y += random.randint(-14, 14)
            size = random.choice((1, 2, 2))
            self.all_points.setdefault(frame, []).append((x, y, size))
        for x, y in self.points:
            x, y = self.calc_position(x, y, ratio)
            size = random.randint(1, 3)
            self.all_points[frame].append((x, y, size))
        for x, y in self.edge_diffusion_points:
            x, y = self.calc_position(x, y, ratio)
            size = random.randint(1, 2)
            self.all_points[frame].append((x, y, size))
        for x, y in self.center_diffusion_points:
            x, y = self.calc_position(x, y, ratio)
            size = random.randint(1, 2)
            self.all_points[frame].append((x, y, size))

    def render(self, canvas, frame):
        for x, y, size in self.all_points[frame % self.generate_frame]:
            canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=HEART_COLOR)

# 曲线函数
def curve(p):
    return 2 * (3 * sin(4 * p)) / (2 * pi)

# 绘图函数
def draw(main, render_canvas, render_heart, frame=0):
    render_canvas.delete('all')
    render_heart.render(render_canvas, frame)
    render_canvas.create_text(400, 300, text="宝贝爱你哟", fill=HEART_COLOR, font=('微软雅黑', 15, 'bold'))
    main.after(160, draw, main, render_canvas, render_heart, frame + 1)

# 主程序入口
if __name__ == '__main__':
    root = tk.Tk()
    root.title('爱心动画')
    canvas = tk.Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
    canvas.pack()
    heart = Heart()
    draw(root, canvas, heart)
    root.mainloop()
    

此代码通过 Heart 类管理爱心的点集,使用随机扩散和抖动效果,使爱心呈现出动态跳动和扩散的视觉效果。画布上还可以显示自定义文字,如“宝贝爱你哟”,增添情感表达。

4. 在终端中打印文字组成的爱心

4.1 字符艺术爱心

除了图形化的爱心,使用字符艺术在终端中打印爱心也是一个有趣的方式。以下代码示例通过字符“我爱你!”拼成一个爱心形状:


import time

# 定义打印的文字
sentence = "我爱你!"

# 打印爱心
for char in sentence.split():
    all_lines = []
    for y in range(12, -12, -1):
        line = ""
        for x in range(-30, 30):
            formula = ((x * 0.05) ** 2 + (y * 0.1) ** 2 - 1) ** 3 - (x * 0.05) ** 2 * (y * 0.1) ** 3
            if formula <= 0:
                line += char[(x) % len(char)]
            else:
                line += " "
        all_lines.append(line)
    print("\n".join(all_lines))
    time.sleep(1)
    

运行此代码后,你将在终端中看到由“我爱你!”字样组成的心形图案,适合用于表达情感信息或简单的终端展示。

5. 进一步扩展与定制

5.1 颜色与样式自定义

在以上所有示例中,都可以通过修改颜色参数(如 pen.color()HEART_COLOR)来改变爱心的颜色,以适应不同的主题或个人偏好。

5.2 添加文字说明

在动态爱心中,可以使用 canvas.create_text() 方法添加自定义文字,如“宝贝爱你哟”,以增强视觉效果和情感表达。

5.3 动画效果优化

通过调整 after 方法的时间间隔,可以优化动画的流畅度。例如,减少时间间隔会使动画更加平滑,但也可能增加 CPU 的使用率。

5.4 保存与分享

使用图像处理库如 Pillow,可以将每一帧动画保存为图片,最终合成为 GIF 动画,方便分享与展示。

6. 参考与资源

以下是一些有用的资源,可帮助你深入了解和扩展 Python 绘图技巧:

通过这些资源,你可以学习更多关于 Python 图形绘制的知识,尝试创造出更复杂和个性化的图案和动画。

7. 总结

使用 Python 绘制爱心图案是一个集学习与表达于一体的有趣项目。无论是使用字符艺术在终端中展示,还是利用 turtletkinter 模块创建图形化和动态效果,Python 提供了丰富的工具和库,满足不同层次和需求的开发者。通过本文提供的多种方法和详尽的代码示例,你可以轻松上手,创造出属于自己的美丽爱心图案,表达你的情感与创意。


Last updated January 4, 2025
Ask Ithy AI
Export Article
Delete Article