用 matplotlib 绘制会动的雪花

缘起

今天无意中看到这篇博客为2020年的第一场雪锦上添花:用 matplotlib 绘制雪花和雪景,加上正在学习numpy跟matplotlib,一时忍不住遂记下自己点滴学习所得

源码

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

plt.rcParams['font.sans-serif'] = ['FangSong']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决中文显示为方块的问题


def rotate(p, d):
    """返回点p绕原点逆时针旋转d度的坐标"""

    a = np.radians(d)
    m = np.array([[np.cos(a), np.sin(a)], [-np.sin(a), np.cos(a)]])
    return np.dot(p, m)


def koch_curve(p, q):
    """将线段pq生成科赫曲线,返回uvw三个点"""

    p, q = np.array(p), np.array(q)
    u = p + (q - p) / 3  # 三等分点u的坐标
    v = q - (q - p) / 3  # 三等分点V的坐标
    w = rotate(v - u, 60) + u  # 线段uv绕u点逆时针旋转60°得到点w的坐标

    return u.tolist(), v.tolist(), w.tolist()


def snow(triangle, k):
    """给定三角形,生成封闭的科赫雪花"""

    for i in range(k):
        result = list()
        t_len = len(triangle)
        for j in range(t_len):
            p = triangle[j]
            q = triangle[(j + 1) % t_len]
            u, v, w = koch_curve(p, q)
            result.extend([p, u, w, v])
        triangle = result.copy()

    triangle.append(triangle[0])
    return triangle


def draw_scenery():
    """绘制雪景图"""

    im = Image.open('brage.png')
    bg = np.array(im)
    fig, ax = plt.subplots(frameon=False)
    while 1:
        ax.cla()
        for i in range(80):
            x = np.random.randint(80, im.size[0] - 80)
            y = np.random.randint(30, im.size[1] - 30)
            r = np.random.randint(5, 20)
            a = np.random.random() * 0.6 + 0.2
            v = np.array((x - r / 2, y))
            u = np.array((x + r / 2, y))
            w = rotate(v - u, 60) + u

            data = np.array(
                snow([(u[0], u[1]), (w[0], w[1]), (v[0], v[1])], 5))
            x, y = np.split(data, 2, axis=1)
            plt.plot(x, y, c='#AABBCC', lw=1, ls='-', alpha=a)
        plt.imshow(bg)  # 绘制背景图
        plt.pause(0.01)

    #  plt.axis('equal')
    #  plt.show()


def snow_dats(snn=80):
    dats = []
    for i in range(snn):
        x = np.random.randint(80, im.size[0] - 80)
        y = np.random.randint(30, im.size[1] - 30)
        r = np.random.randint(5, 20)
        a = np.random.random() * 0.6 + 0.2
        v = np.array((x - r / 2, y))
        u = np.array((x + r / 2, y))
        w = rotate(v - u, 60) + u

        data = np.array(snow([(u[0], u[1]), (w[0], w[1]), (v[0], v[1])], 5))
        x, y = np.split(data, 2, axis=1)
        tmp = x, y, a
        dats.append(tmp)
    return dats


def get_snows(nn=24, snn=40):
    """
    调用生成雪花的函数生成,指定的次数

    nn: 雪花场景的次数
    snn: 雪花的次数
    """
    import os
    snow_file = f"snows_{nn}_{snn}.npy"
    if not os.path.exists(snow_file):
        snows = [snow_dats(snn) for x in range(nn)]
        snows = np.array(snows)
        np.save(snow_file, snows)
    else:
        snows = np.load(snow_file, allow_pickle=True)
    return snows


if __name__ == "__main__":
    #  draw_scenery()
    im = Image.open('yk.jpg')
    bg = np.array(im)
    fig, ax = plt.subplots(frameon=False)
    snows = get_snows()
    for sss in snows:
        ax.cla()
        for x, y, a in sss:
            ax.plot(x, y, c='#AABBCC', lw=1, ls='-', alpha=a)
        plt.imshow(bg)  # 绘制背景图
        plt.axis("off")
        plt.pause(0.1)
    plt.show()

代码说明

matplotlib绘图不少人遇到的问题就是要绘制动态的图,关键是要在暂停的地方放一个plt.pause(要暂停的秒数),在每次开始的时候要清除所有的。当然, 也可以只设置图里相应对象的数据。要清楚的话就是代码里面的ax.cla()
这个代码里面另外一个有用的地方是怎么隐藏坐标轴。那就是:plt.axis(“off”)。关于这个要感谢 Inside_Zhang 这篇文章,有兴趣的可以去学习下。

题外话

分形

分形简单说就是 “一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似地)是整体缩小后的形状”。 前文提到的博客中说到的科赫曲线,就是其中的一种。还有常见的,山脉的外形,海岸线,树叶的脉络轮廓等等,真的让人佩服,数学的伟大。因为每个分形几乎都有一个数学公式。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值