공돌이 공룡의 서재

파이썬으로 크리스마스 트리 만들기 / Python - How to make Christmas tree 본문

코딩

파이썬으로 크리스마스 트리 만들기 / Python - How to make Christmas tree

구름위의공룡 2020. 12. 28. 11:15

코로나때문에 집에서 보내는 크리스마스였는데 심심해서 만들어보았다.

2D로 만든 코드들은 많았는데 3D로 만든 것이 없어서 Numpy 모델로 구현해보았다.

만들면서 numpy와 matplotlib.pyplot의 3D scatter에 대한 여러 함수들을 다뤄볼 수 있다.

 

There are many 2D tree but no 3D tree, so I made christmas tree 3D model by using Numpy library. We can learn how to use numpy and matplotlib library for 3D scatter. 

#!/usr/bin/env python
# coding: utf-8

import numpy as np
import matplotlib.pyplot as plt

n = 1800
vmin, vmax, zmin, zmax = -30, 30, -1, 2

# green leaves 
tree = [] 
colors = []
r = 30
for i in range(19):
    color = np.array([(i*0.1) * np.random.random_sample() + 0.1*i for i in range(int(vmax-vmin)*20)])
    colors.append(color)
    zmin += 3
    zmax += 3
    length = np.random.uniform(0, r, size=int(vmax-vmin)*20)
    angle = np.pi * np.random.uniform(0, 2, size=int(vmax-vmin)*20)
    xt = length * np.cos(angle)
    yt = length * np.sin(angle)
    zt = np.random.uniform(zmin, zmax, size=int(vmax-vmin)*20)
    tree.append([xt, yt, zt])
    r -= 1.5


# brown stem
tree2 = []
z2max, z2min = 0, -2
for j in range(15):
    length = np.sqrt(np.random.uniform(9, 100, size=100))
    angle = np.pi * np.random.uniform(0, 2, size=100)
    x = length * np.cos(angle)
    y = length * np.sin(angle)
    zs = np.random.uniform(z2min, z2max, size=(100))
    z2min -= 1.5
    z2max -= 1.5
    tree2.append([x, y, zs]) 

# background snow
snow = []
z3min = -21
z3max = -19
snow_colors = []
for j in range(10):
    xs = np.random.uniform(-40, 40, size=2000)
    ys = np.random.uniform(-40, 40, size=2000)
    zs = np.random.uniform(z3min, z3max, size=(2000))
    z3max -= 1.5
    z3min -= 1.5
    snow.append([xs, ys, zs]) 
    color = np.array([(i*0.1) * np.random.random_sample() + 0.1*i for i in range(2000)])
    snow_colors.append(colors)

# function for falling snow
n = 250
def randrange(n, vmin, vmax):
    '''
    Helper function to make an array of random numbers having shape (n, )
    with each number distributed Uniform(vmin, vmax).
    '''
    return (vmax - vmin)*np.random.rand(n) + vmin



fig = plt.figure(figsize=(15, 15))
ax = plt.axes(projection='3d')
fig.set_facecolor('black') 
ax.set_facecolor('black')
# set 3D axes and its background color as black

ax.w_xaxis.pane.fill = False
ax.w_yaxis.pane.fill = False
ax.w_zaxis.pane.fill = False
# remove axis line silhouette

ax.set_xlabel('$Merry\ Christmas$', fontsize=20, c='white') # Message 1
ax.set_ylabel('$2020$', fontsize=20, c='white') # Message 2
# put message as axis label. message form is Latex

ax.w_xaxis.set_pane_color((0.0, 0.0, 0.0, 0.0))
ax.w_yaxis.set_pane_color((0.0, 0.0, 0.0, 0.0))
ax.w_zaxis.set_pane_color((0.0, 0.0, 0.0, 0.0))
# set axis wall color as black

ax.grid(False)
ax.view_init(elev=10., azim=30)
# set angle of view

#scatter leaves, stem, snow
for i in range(10):
    ax.scatter(snow[i][0], snow[i][1], snow[i][2], c='#ffffe4', marker='*', s=12, cmap='Greys')
for i in range(15):
    ax.scatter(tree2[i][0], tree2[i][1], tree2[i][2], c='#8c564b', marker='o', s=15)
for i in range(19):
    ax.scatter(tree[i][0], tree[i][1], tree[i][2], c=colors[i], marker='o', s=10, cmap='Greens')
for m, zlow, zhigh in [('*', -15, 60)]:
    xs = randrange(n, -40, 40)
    ys = randrange(n, -40, 40)
    zs = randrange(n, zlow, zhigh)
    ax.scatter(xs, ys, zs, c='#ffffe4', marker=m, s=10)
    
# scatter decoration. 
r = 28.5
z = 2
color = ['red', 'yellow', 'orange']
for i in range(20):
    theta = np.linspace(-2* np.pi, 2 * np.pi, 21 - i)
    for j in range(len(theta)):
        x = r * np.sin(theta[j])*np.sqrt(1.69)
        y = r * np.cos(theta[j])
        ax.scatter(x, y, z, c=color[j%len(color)], marker='D', s=15)
    z += 3
    r -= 1.5
r = 22
z = 20
for i in range(10):
    theta = np.linspace(-2* np.pi, 2 * np.pi, 21 - i)
    for j in range(len(theta)):
        x = r * np.sin(theta[j])*np.sqrt(1.69)
        y = r * np.cos(theta[j])
        ax.scatter(x, y, z, c=color[j%len(color)], marker='^', s=15)
    z += 3
    r -= 1.4

plt.show()  

 

결과

 

 

Comments