跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Python大前端算法

使用 Python 绘制树木的几种方法

利用 Python 的 turtle 图形库和分形算法,可以绘制出多种风格的树木图像。文章包含樱花树、绿叶树、落叶树及基于 L 系统生成的芦苇风树等四个示例,通过递归函数和随机数控制树枝生长与花瓣飘落效果,展示了编程绘图的数学之美与实现细节。内容涵盖代码结构解析、关键函数说明及运行环境要求,适合对图形编程感兴趣的开发者参考。

ApiHolic发布于 2025/2/6更新于 2026/10/2093 浏览
使用 Python 绘制树木的几种方法

使用 Python 绘制树木的几种方法

古人有诗云'庭中有奇树,绿叶发华滋',树之美,或婀娜、或繁茂、或苍劲、或青翠。Python 的 turtle 库提供了强大的绘图功能,结合递归算法和随机数,可以生动地模拟出不同季节和风格的树木。

1. 樱花树:递归与色彩变化

本示例通过递归函数 Tree 模拟樱花树的生长过程。树干颜色根据分支长度动态变化,末端花瓣飘落效果增加了画面的动感。

import turtle as T
import random
import time

# 画樱花的躯干 (branch, t)
def Tree(branch, t):
    time.sleep(0.0005)
    if branch > 3:
        if 8 <= branch <= 12:
            if random.randint(0, 2) == 0:
                t.color('snow') # 白色
            else:
                t.color('lightcoral') # 淡珊瑚色
            t.pensize(branch / 3)
        elif branch < 8:
            if random.randint(0, 1) == 0:
                t.color('snow')
            else:
                t.color('lightcoral') # 淡珊瑚色
            t.pensize(branch / 2)
        else:
            t.color('sienna') # 赭色
            t.pensize(branch / 10)
        
        t.forward(branch)
        a = 1.5 * random.random()
        t.right( * a)
        b =  * random.random()
        Tree(branch -  * b, t)
        t.left( * a)
        Tree(branch -  * b, t)
        t.right( * a)
        t.up()
        t.backward(branch)
        t.down()


 ():
     i  (m):
        a =  -  * random.random()
        b =  -  * random.random()
        t.up()
        t.forward(b)
        t.left()
        t.forward(a)
        t.down()
        t.color() 
        t.circle()
        t.up()
        t.backward(a)
        t.right()
        t.backward(b)


t = T.Turtle()
w = T.Screen()
t.hideturtle()
t.getscreen().tracer(, )
w.screensize(bg=)

t.left()
t.up()
t.backward()
t.down()
t.color()


Tree(, t)

Petal(, t)

w.exitonclick()
20
1.5
10
40
10
20
# 掉落的花瓣
def
Petal
m, t
for
in
range
200
400
10
20
90
'lightcoral'
# 淡珊瑚色
1
90
# 绘图区域
5
0
'white'
90
150
'sienna'
# 画樱花的躯干
60
# 掉落的花瓣
200

代码解析:

  • 递归逻辑:Tree 函数不断调用自身,每次调用减少分支长度 (branch - 10 * b),直到小于 3 时停止,形成树的分叉结构。
  • 随机性:使用 random 模块控制分支角度和长度,使每棵树形态各异。
  • 画笔设置:根据分支粗细调整 pensize,模拟真实树木的根部粗、梢部细的特征。

2. 绿叶树:面向对象与阴影效果

此示例采用面向对象的方式封装树类,利用三角函数计算阴影效果,使树叶呈现立体感。

from turtle import *
from random import *
from math import *

class Tree:
    def __init__(self):
        setup(1000, 500)
        bgcolor(1, 1, 1) # 背景色
        speed(10) # 速度 1-10 渐进,0 最快
        tracer(0, 0)
        pu() # 抬笔
        backward(100)
        left(90) # 左转 90 度
        backward(300) # 后退 300

    def tree(self, n, l):
        pd() # 下笔
        # 阴影效果
        t = cos(radians(heading() + 45)) / 8 + 0.25
        pencolor(t, t, t)
        pensize(n / 1.2)
        forward(l) # 画树枝
        if n > 0:
            b = random() * 15 + 10 # 右分支偏转角度
            c = random() * 15 + 10 # 左分支偏转角度
            d = l * (random() * 0.25 + 0.7) # 下一个分支的长度
            # 右转一定角度,画右分支
            right(b)
            self.tree(n - 1, d)
            # 左转一定角度,画左分支
            left(b + c)
            self.tree(n - 1, d)
            # 转回来
            right(c)
        else:
            # 画叶子
            right(90)
            n = cos(radians(heading() - 45)) / 4 + 0.5
            pencolor(n, n * 0.8, n * 0.8)
            fillcolor(n, n * 0.8, n * 0.8)
            begin_fill()
            circle(3)
            left(90)
            end_fill()
            # 添加 0.3 倍的飘落叶子
            if random() > 0.7:
                pu()
                # 飘落
                t = heading()
                an = -40 + random() * 40
                setheading(an)
                dis = int(800 * random() * 0.5 + 400 * random() * 0.3 + 200 * random() * 0.2)
                forward(dis)
                setheading(t)
                # 画叶子
                pd()
                right(90)
                n = cos(radians(heading() - 45)) / 4 + 0.5
                pencolor(n * 0.5 + 0.5, 0.4 + n * 0.4, 0.4 + n * 0.4)
                fillcolor(n, n * 0.8, n * 0.8)
                begin_fill()
                circle(2)
                left(90)
                end_fill()
                pu()
                # 返回
                t = heading()
                setheading(an)
                backward(dis)
                setheading(t)

def main():
    tree = Tree()
    tree.tree(12, 100) # 递归 7 层
    done()

if __name__ == '__main__':
    main()

代码解析:

  • 类封装:将绘图环境初始化和树形生成逻辑封装在 Tree 类中,便于管理状态。
  • 数学计算:利用 cos 和 radians 计算颜色深浅,模拟光照下的阴影效果。
  • 叶子绘制:当递归深度为 0 时,绘制圆形代表叶子,并随机决定是否生成落叶效果。

3. 落叶树:花瓣位置生成

本示例重点展示花瓣(叶子)在特定坐标区域的分布,模拟风吹花落的情景。

from turtle import *
from random import *

# 画树方法
def drawTree(n, l):
    pendown()
    pencolor('#5d3c3c')
    pensize(n / 1.5)
    forward(l)
    if n > 0:
        dr = randint(30, 40)
        dl = randint(30, 40)
        move = l * (random() * 0.4 + 0.5)
        right(dr)
        drawTree(n - 1, move)
        left(dr + dl)
        drawTree(n - 1, move)
        right(dl)
    else:
        drawPetal(3)
    penup()
    backward(l)

# 花瓣位置生成
def petalPlace(m, x, y):
    penup()
    goto(x, y)
    pendown()
    setheading(0)
    tracer(False)
    for i in range(m):
        if i == 0:
            drawPetal(5)
        else:
            penup()
            goto(x, y)
            a = randint(20, 400)
            b = randint(-50, 50)
            forward(a)
            left(90)
            forward(b)
            right(90)
            pendown()
            drawPetal(5)

# 花朵绘画方法
def drawPetal(n):
    colormode(255)
    r = randint(200, 255)
    g = randint(8, 158)
    b = randint(8, 158)
    begin_fill()
    fillcolor(r, g, b)
    pencolor(r, g, b)
    circle(n)
    end_fill()

# 启动方法
def run():
    setup(1.0, 1.0)
    penup()
    goto(-50, -150)
    left(90)
    pendown()
    hideturtle()
    tracer(False)
    drawTree(13, 150)
    petalPlace(160, -100, -150)
    run()
    done()

if __name__ == '__main__':
    run()

代码解析:

  • 坐标定位:petalPlace 函数允许在指定坐标 (x, y) 处生成花瓣,增加了布局的灵活性。
  • 颜色随机:RGB 值随机生成,确保每一片花瓣颜色略有不同。

4. L-系统:分形芦苇风树

L-系统(Lindenmayer System)是一种形式文法,常用于模拟植物生长。本例通过重写规则生成复杂的分形结构。

import turtle
import random

stack = []

def createWord(max_it, word, proc_rules, x, y, turn):
    turtle.up()
    turtle.home()
    turtle.goto(x, y)
    turtle.right(turn)
    turtle.down()
    t = 0
    while t < max_it:
        word = rewrite(word, proc_rules)
        drawit(word, 5, 20)
        t = t + 1

def rewrite(word, proc_rules):
    wordList = list(word)
    for i in range(len(wordList)):
        curChar = wordList[i]
        if curChar in proc_rules:
            wordList[i] = proc_rules[curChar]
    return "".join(wordList)

def drawit(newWord, d, angle):
    newWordLs = list(newWord)
    for i in range(len(newWordLs)):
        cur_Char = newWordLs[i]
        if cur_Char == 'F':
            turtle.forward(d)
        elif cur_Char == '+':
            turtle.right(angle)
        elif cur_Char == '-':
            turtle.left(angle)
        elif cur_Char == '[':
            state_push()
        elif cur_Char == ']':
            state_pop()

def state_push():
    global stack
    stack.append((turtle.position(), turtle.heading()))

def state_pop():
    global stack
    position, heading = stack.pop()
    turtle.up()
    turtle.goto(position)
    turtle.setheading(heading)
    turtle.down()

def randomStart():
    x = random.randint(-300, 300)
    y = random.randint(-320, -280)
    heading = random.randint(-100, -80)
    return ((x, y), heading)

def main():
    rule_sets = []
    rule_sets.append(((3, 5), 'F', {'F': 'F[+F][-F]F'}))
    rule_sets.append(((4, 6), 'B', {'B': 'F[-B][+ B]', 'F': 'FF'}))
    rule_sets.append(((2, 4), 'F', {'F': 'FF+[+F-F-F]-[-F+F+F]'}))
    tree_count = 50
    turtle.tracer(10, 0)
    for x in range(tree_count):
        rand_i = random.randint(0, len(rule_sets) - 1)
        selected_ruleset = rule_sets[rand_i]
        i_range, word, rule = selected_ruleset
        low, high = i_range
        i = random.randint(low, high)
        start_position, start_heading = randomStart()
        start_x, start_y = start_position
        createWord(i, word, rule, start_x, start_y, start_heading)

if __name__ == '__main__':
    main()

代码解析:

  • 重写规则:rewrite 函数根据预定义的规则集替换字符,例如 F 替换为 F[+F][-F]F,实现分形迭代。
  • 状态栈:使用 stack 保存画笔位置和方向,支持 [ 和 ] 符号进行分支回溯。
  • 批量生成:循环生成多棵树木,展示不同规则下的形态差异。

总结

以上四个示例展示了从基础递归到复杂分形算法的多种树木绘制方案。运行这些代码需要安装 Python 环境并导入标准库 turtle 和 random。通过调整参数如分支长度、角度范围和颜色阈值,你可以创造出独一无二的数字艺术作品。建议尝试修改代码中的随机种子或规则集,探索更多可能性。

目录

  1. 使用 Python 绘制树木的几种方法
  2. 1. 樱花树:递归与色彩变化
  3. 画樱花的躯干 (branch, t)
  4. 掉落的花瓣
  5. 绘图区域
  6. 画樱花的躯干
  7. 掉落的花瓣
  8. 2. 绿叶树:面向对象与阴影效果
  9. 3. 落叶树:花瓣位置生成
  10. 画树方法
  11. 花瓣位置生成
  12. 花朵绘画方法
  13. 启动方法
  14. 4. L-系统:分形芦苇风树
  15. 总结

更多推荐文章

查看全部
  • 五分钟构建动态知识图谱:利用大模型提取实体关系与数据对话
  • OpenClaw 对接飞书群机器人配置踩坑:消息不回与 Gateway 断开排查
  • Java 面试核心考点梳理:基础、并发与容器篇
  • Java BigDecimal 解决浮点精度问题
  • GitHub Copilot 学生认证指南及 Python 自动化实现
  • 仿生学突破:SILD 模型助力无人机电力线避障
  • 利用 B 站评论区数据构建大语言模型微调数据集
  • OpenClaw 对接腾讯 QQ 实战操作详解
  • 如何成为懂 AI 的产品经理
  • Secure Boot 关闭指南:本地部署 GLM-4.6V-Flash-WEB
  • GitHub Actions 工作流自动化创建 Release 实践
  • TCP TIME_WAIT 状态的作用及服务端堆积原因分析
  • 人工智能赋能招聘行业:从效率革新到平台经济重构
  • 【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)
  • 基于 FastAPI 的 Web 上位机系统设计与实现
  • Trae AI 插件在 PyCharm 中的配置与使用实践
  • Trae AI 将设计稿自动生成前端代码指南
  • 前端大文件分片上传与断点续传实现方案
  • Clerk 完全指南:现代 Web 应用用户认证
  • Seq2Seq 模型实战:ScheduledEmbeddingTrainingHelper 原理与使用
  • 相关免费在线工具

    • 加密/解密文本

      使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

    • Gemini 图片去水印

      基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

    • curl 转代码

      解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

    • Markdown转HTML

      将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online