python | matplotlib | 迟到的圣诞树
Posted slandarer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python | matplotlib | 迟到的圣诞树相关的知识,希望对你有一定的参考价值。
羊了一周,总算好了,一好起来立马开始码字!之前写了两款圣诞树得到了很多人的喜欢,就有很多人问有没有python版本的,毕竟这都快2023年了,大部分网上的python版圣诞树还是一些海龟绘图老古董,
于是用matplotlib整了个3D的,我是属实python用的不是很熟练(要是熟悉的话一开始写这个代码就不会选择matplotlib),matplotlib居然不能正常的表示3D图形的遮挡,于是进行了简单的运算尽量让被遮挡的部分设置为NaN,算是勉强能看,在绘图这一块matplotlib属实一言难尽。
此外scatter函数居然不像plot函数一样具有set_xdata等方法,对此不熟悉的我就采用了remove后再重新绘制的笨办法。。。
总之,撰写了远远长于MATLAB版本的一系列代码后(可能因为我python水平不过关),总算有了这个3D版圣诞树(光影函数也属实没找到,就没加):
完整代码
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
# @author : slandarer
# 生成半径数据
t=np.arange(start=0, stop=25.2, step=.2)
t[(t>0) & (t<=3)]=1.5
t[t>3]=8-(t[t>3]-3)*0.3636
# 生成锥形曲面
theta=np.linspace(0,2*np.pi,21)
X=np.cos(theta).reshape((1,21))
Y=np.sin(theta).reshape((1,21))
Z=np.linspace(0,1,126).reshape((126,1))
t=np.array(t).reshape((126,1))
X=X*t;Y=Y*t;Z=Z*np.ones_like(X)*25
# 随机移动树冠上点的位置
angle=np.arctan(Y[15:126,0:21]/X[15:126,0:21])
treeDiffusion=np.random.rand(111,21)-.5
X[15:126,0:21]=X[15:126,0:21]+np.cos(angle)*treeDiffusion
Y[15:126,0:21]=Y[15:126,0:21]+np.sin(angle)*treeDiffusion
Z[15:126,0:21]=Z[15:126,0:21]+(np.random.rand(111,21)-.5)*.5
X[:,-1]=X[:,0];Y[:,-1]=Y[:,0];Z[:,-1]=Z[:,0]
# colormap自定义
r=np.arange(start=0.0430, stop=0.2492, step=0.2061/50)
g=np.arange(start=0.2969, stop=0.6982, step=0.4012/50)
b=np.arange(start=0.0625, stop=0.3322, step=0.2696/50)
rgb=np.append(r.reshape(51,1),g.reshape(51,1),axis=1)
rgb=np.append(rgb,b.reshape(51,1),axis=1)
rgb[0:6,0]=77/265;rgb[0:6,1]=63/265;rgb[0:6,2]=5/265
rgb=LinearSegmentedColormap.from_list('slandarer',rgb)
# 创建figure窗口及axis坐标区域
fig, ax=plt.subplots(subplot_kw="projection": "3d")
# 绘制圣诞树本体
ax.plot_surface(X, Y, Z, cmap=rgb)
# 绘制星星
ax.scatter(0, 0, 25.6, marker="*", c="#FFDF99", s=500)
ax.scatter(0, 0, 25, marker="o", c="#FFDF99", s=7000, alpha=.1)
# 绘制彩灯
def lightFuncX(h,r,a,z):
return (h-z)/h*r*np.cos(a*z)
def lightFuncY(h,r,a,z):
return (h-z)/h*r*np.sin(a*z)
h=25;r=8;azim=0/180*np.pi
lightZ1=np.linspace(4,25-4,300);a1=0.3*np.pi
lightX1=lightFuncX(h,r*1.5,a1,lightZ1)
lightY1=lightFuncY(h,r*1.5,a1,lightZ1)
tlightX1=lightX1.copy()
tlightX1[lightX1*np.cos(azim)+lightY1*np.sin(azim)<-2.5]=float("nan")
lightHdl1=ax.scatter(tlightX1, lightY1, lightZ1+.1, marker=".", c="#FDF9DC", s=5, alpha=.8)
lightZ2=np.linspace(4,25-4,45);a2=0.3*np.pi
lightX2=lightFuncX(h,r*1.5,a2,lightZ2)
lightY2=lightFuncY(h,r*1.5,a2,lightZ2)
tlightX2=lightX2.copy()
tlightX2[lightX2*np.cos(azim)+lightY2*np.sin(azim)<-2.5]=float("nan")
lightHdl2_1=ax.scatter(tlightX2, lightY2, lightZ2+.1, marker="o", c="#FDF9DC", s=60, alpha=.8, edgecolors='none')
lightHdl2_2=ax.scatter(tlightX2, lightY2, lightZ2+.1, marker="o", c="#FDF9DC", s=400, alpha=.05, edgecolors='none')
lightZ3=np.linspace(4,25-6,200);a3=-0.35*np.pi
lightX3=lightFuncX(h,r*1.45,a3,lightZ3)
lightY3=lightFuncY(h,r*1.45,a3,lightZ3)
tlightX3=lightX3.copy()
tlightX3[lightX3*np.cos(azim)+lightY3*np.sin(azim)<-2.5]=float("nan")
lightHdl3=ax.scatter(tlightX3, lightY3, lightZ3+.1, marker=".", c="white", s=5, alpha=.8)
lightZ4=np.linspace(4,25-6,17);a4=-0.35*np.pi
lightX4=lightFuncX(h,r*1.45,a4,lightZ4)
lightY4=lightFuncY(h,r*1.45,a4,lightZ4)
tlightX4=lightX4.copy()
tlightX4[lightX4*np.cos(azim)+lightY4*np.sin(azim)<-2.5]=float("nan")
lightHdl4_1=ax.scatter(tlightX4, lightY4, lightZ4+.1, marker="o", c="white", s=60, alpha=.8, edgecolors='none')
lightHdl4_2=ax.scatter(tlightX4, lightY4, lightZ4+.1, marker="o", c="white", s=400, alpha=.05, edgecolors='none')
# 绘制礼物盒子
def drawPresent(dx,dy,dz,scalex,scaley,scalez):
presentX=np.array([[0.5,0.5,0.5,0.5,0.5],[0,1,1,0,0],[0,1,1,0,0],[0,1,1,0,0],[0.5,0.5,0.5,0.5,0.5]])
presentY=np.array([[0.5,0.5,0.5,0.5,0.5],[0,0,1,1,0],[0,0,1,1,0],[0,0,1,1,0],[0.5,0.5,0.5,0.5,0.5]])
presentZ=np.array([[0,0,0,0,0],[0,0,0,0,0],[0.5,0.5,0.5,0.5,0.5],[1,1,1,1,1],[1,1,1,1,1]])
ax.plot_surface((presentX*scalex+dx), (presentY*scaley+dy), (presentZ*scalez+dz))
return 0
drawPresent(-4,4,0,2,3,1.5)
drawPresent(5,3,0,4,3,3)
drawPresent(-7,-5,0,5,3,1)
drawPresent(-9,-6,0,2,2,2)
drawPresent(0,7,0,4,3,3)
# 绘制雪花
snowXYZ1=np.random.rand(40,3)
snowXYZ1[:,0]=snowXYZ1[:,0]*26-13
snowXYZ1[:,1]=snowXYZ1[:,1]*26-13
snowXYZ1[:,2]=snowXYZ1[:,2]*30
snowXYZ2=np.random.rand(20,3)
snowXYZ2[:,0]=snowXYZ2[:,0]*26-13
snowXYZ2[:,1]=snowXYZ2[:,1]*26-13
snowXYZ2[:,2]=snowXYZ2[:,2]*30
snowHdl1=ax.scatter(snowXYZ1[:,0], snowXYZ1[:,1], snowXYZ1[:,2], marker=".", c="white", s=20, alpha=.3, edgecolors='none')
snowHdl2=ax.scatter(snowXYZ2[:,0], snowXYZ2[:,1], snowXYZ2[:,2], marker="$*$", c="white", s=80, alpha=.9, edgecolors='none')
# figure, axis基础修饰
plt.rcParams['font.sans-serif']=['Cambria']
plt.rcParams['axes.unicode_minus']=False
plt.rcParams['font.size']=20
plt.rcParams['text.color']='white'
ax.text(0,0,30,'Chirstmas Tree By slandarer', ha='center')
ax.set_box_aspect((1, 1, 1))
ax.set_position((-.15,-.2,1.3,1.3))
ax.set_xlim(-10,10)
ax.set_ylim(-10,10)
ax.set_zlim(0,30)
ax.set_facecolor("#162033")
ax.axis('off')
ax.view_init(elev=10,azim=0)
# 绘图刷新
for i in range(100):
snowXYZ1[:,2]=snowXYZ1[:,2]-.25
snowXYZ2[:,2]=snowXYZ2[:,2]-.5
snowXYZ1[snowXYZ1[:,2]<0,2]=30
snowXYZ2[snowXYZ2[:,2]<0,2]=30
snowHdl1.remove()
snowHdl2.remove()
snowHdl1=ax.scatter(snowXYZ1[:,0], snowXYZ1[:,1], snowXYZ1[:,2], marker=".", c="white", s=20, alpha=.3, edgecolors='none')
snowHdl2=ax.scatter(snowXYZ2[:,0], snowXYZ2[:,1], snowXYZ2[:,2], marker="$*$", c="white", s以上是关于python | matplotlib | 迟到的圣诞树的主要内容,如果未能解决你的问题,请参考以下文章