import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
class MonteCarloArtist:
def __init__(self, width=800, height=600, dpi=100):
"""初始化蒙特卡罗绘图器"""
self.width = width
self.height = height
self.dpi = dpi
self.points = {'in': [], 'out': []}
# 创建图形和坐标轴
self.fig, self.ax = plt.subplots(figsize=(width/dpi, height/dpi), dpi=dpi)
self.ax.set_xlim(0, 1)
self.ax.set_ylim(0, 1)
self.ax.set_aspect('equal')
self.ax.set_title("蒙特卡罗方法绘制图形")
# 初始化散点图
self.scatter_in = self.ax.scatter([], [], c='blue', s=2, alpha=0.8)
self.scatter_out = self.ax.scatter([], [], c='red', s=2, alpha=0.8)
# 初始化文本信息
self.info_text = self.ax.text(0.02, 0.95, '', transform=self.ax.transAxes)
# 图形函数(默认为圆形)
self.shape_function = self._circle_function
def _circle_function(self, x, y):
"""圆形判定函数:(x-0.5)² + (y-0.5)² <= 0.25"""
return (x - 0.5)**2 + (y - 0.5)**2 <= 0.25
def _square_function(self, x, y):
"""正方形判定函数:0.25 <= x <= 0.75 且 0.25 <= y <= 0.75"""
return (0.25 <= x <= 0.75) and (0.25 <= y <= 0.75)
def _triangle_function(self, x, y):
"""三角形判定函数:y <= 2x 且 y <= -2x + 2"""
return y <= 2*x and y <= -2*x + 2
def set_shape(self, shape_name):
"""设置要绘制的图形"""
shapes = {
'circle': self._circle_function,
'square': self._square_function,
'triangle': self._triangle_function
}
if shape_name in shapes:
self.shape_function = shapes[shape_name]
self.ax.set_title(f"蒙特卡罗方法绘制:{shape_name}")
else:
print(f"不支持的图形:{shape_name},将使用默认圆形")
def generate_points(self, num_points=100):
"""生成随机点并分类"""
x = np.random.rand(num_points)
y = np.random.rand(num_points)
for xi, yi in zip(x, y):
if self.shape_function(xi, yi):
self.points['in'].append((xi, yi))
else:
self.points['out'].append((xi, yi))
def update(self, frame):
"""动画更新函数"""
self.generate_points(100)
# 更新散点数据
in_points = np.array(self.points['in'])
out_points = np.array(self.points['out'])
if len(in_points) > 0:
self.scatter_in.set_offsets(in_points)
if len(out_points) > 0:
self.scatter_out.set_offsets(out_points)
# 更新统计信息
total = len(in_points) + len(out_points)
inside = len(in_points)
ratio = inside / total if total > 0 else 0
self.info_text.set_text(f"总点数: {total}\n内部点数: {inside}\n比例: {ratio:.4f}")
return self.scatter_in, self.scatter_out, self.info_text
def animate(self, frames=100, interval=100):
"""创建动画"""
self.animation = FuncAnimation(
self.fig, self.update, frames=frames, interval=interval, blit=True
)
plt.tight_layout()
plt.show()
def static_plot(self, num_points=10000):
"""静态绘图"""
self.generate_points(num_points)
in_points = np.array(self.points['in'])
out_points = np.array(self.points['out'])
if len(in_points) > 0:
self.ax.scatter(in_points[:, 0], in_points[:, 1], c='blue', s=2, alpha=0.8)
if len(out_points) > 0:
self.ax.scatter(out_points[:, 0], out_points[:, 1], c='red', s=2, alpha=0.8)
total = len(in_points) + len(out_points)
inside = len(in_points)
ratio = inside / total if total > 0 else 0
self.info_text.set_text(f"总点数: {total}\n内部点数: {inside}\n比例: {ratio:.4f}")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
# 创建绘图器实例
artist = MonteCarloArtist()
# 设置要绘制的图形(可选:circle, square, triangle)
artist.set_shape('circle')
# 方式1:使用动画展示过程
artist.animate(frames=100, interval=100)
# 方式2:直接生成静态图(取消下面一行的注释)
# artist.static_plot(num_points=50000)