基于Matplotlib用图形填充函数区域:空隙问题求助
解决Matplotlib函数曲线下方图案填充空隙问题
核心问题分析
你当前的填充方案存在大量空隙,核心原因是网格排列方式错误和图形尺寸/位置计算偏差:
- 六边形、三角形这类图形需要蜂窝状交错排列,而你用了矩形网格(x/y均按固定步长平铺),必然留下空隙;
- 图形的位置、半径计算不准确,导致相邻图形无法接触顶点/边;
- 关于
numVertices参数:它就是RegularPolygon的第一个参数(比如三角形传3、六边形传6),你代码里已经在正确使用,只是可能没对应上参数名而已。
优化方案
- 蜂窝状排列适配:对六边形、三角形,奇数行x坐标偏移
base_size/2,y方向步长调整为适合图形紧密排列的尺寸; - 精准顶点判断:通过检查图形所有顶点是否在曲线下方,替代原有的单点判断,避免误判;
- 修正图形参数:调整正多边形的中心坐标、半径,确保相邻图形刚好接触顶点。
修改后的代码
import matplotlib.pyplot as plt import numpy as np from matplotlib.patches import Rectangle, RegularPolygon from scipy.integrate import quad def plot_function_with_pattern(func, x_range, y_range, base_size, shape="rectangle", include_touching=True, start_x=None, start_y=None): fig, ax = plt.subplots() x = np.linspace(x_range[0], x_range[1], 1000) y = func(x) ax.plot(x, y) num_figures = 0 start_x = start_x if start_x is not None else x_range[0] start_y = start_y if start_y is not None else y_range[0] # 根据图形类型设置排列参数 if shape in ["hexagon", "triangle"]: # 蜂窝排列的y步长:正六边形高为 base_size * √3/2 y_step = base_size * np.sqrt(3) / 2 x_offset = base_size / 2 else: y_step = base_size x_offset = 0 row_idx = 0 for y_i in np.arange(start_y, y_range[1], y_step): # 奇数行x轴偏移,实现蜂窝排列 current_x_start = start_x + (x_offset if row_idx % 2 == 1 else 0) for x_i in np.arange(current_x_start, x_range[1], base_size): # 计算图形顶点,用于判断是否在曲线范围内 if shape == "rectangle": center = (x_i + base_size/2, y_i + base_size/2) vertices = [(x_i, y_i), (x_i+base_size, y_i), (x_i+base_size, y_i+base_size), (x_i, y_i+base_size)] elif shape == "triangle": center = (x_i + base_size/2, y_i + y_step/2) vertices = [(x_i, y_i), (x_i+base_size, y_i), (x_i+base_size/2, y_i + y_step)] elif shape == "square": center = (x_i + base_size/2, y_i + base_size/2) vertices = [(x_i, y_i), (x_i+base_size, y_i), (x_i+base_size, y_i+base_size), (x_i, y_i+base_size)] elif shape == "hexagon": center = (x_i, y_i + y_step/2) angles = np.linspace(0, 2*np.pi, 7)[:-1] + np.pi/2 vertices = [(center[0] + base_size/2 * np.cos(a), center[1] + y_step * np.sin(a)) for a in angles] # 判断图形是否完全在曲线下方 all_inside = all(func(vx) >= vy for vx, vy in vertices) # 判断是否接触曲线(兼容浮点误差) touching = any(abs(func(vx) - vy) < 1e-6 or func(vx) >= vy for vx, vy in vertices) if (include_touching and (all_inside or touching)) or (not include_touching and all_inside): facecolor = 'green' if include_touching else 'red' if shape == "rectangle": patch = Rectangle((x_i, y_i), base_size, base_size, facecolor=facecolor) elif shape == "triangle": patch = RegularPolygon(center, 3, radius=base_size/np.sqrt(3), orientation=0, facecolor=facecolor) elif shape == "square": patch = RegularPolygon(center, 4, radius=base_size/np.sqrt(2), orientation=np.pi/4, facecolor=facecolor) elif shape == "hexagon": patch = RegularPolygon(center, 6, radius=base_size/np.sqrt(3), orientation=np.pi/2, facecolor=facecolor) ax.add_patch(patch) num_figures += 1 row_idx += 1 # 固定坐标轴比例,避免图形变形 ax.set_aspect('equal') plt.show() integral, _ = quad(func, x_range[0], x_range[1]) if not include_touching: print(f"{num_figures} {shape}(s)完全在函数内部且不接触曲线。基础尺寸{base_size}单位,x范围{x_range},y范围{y_range},函数面积{integral:.4f}。") else: print(f"{num_figures} {shape}(s)在函数内部(包含接触曲线的)。基础尺寸{base_size}单位,x范围{x_range},y范围{y_range},函数面积{integral:.4f}。") # 示例函数 def func(x): return -0.00002*x**6 + 0.0011*x**5 -0.024 *x**4 + 0.24*x**3 -0.8*x**2 -x + 10 # 调用示例:六边形填充 plot_function_with_pattern(func, x_range=(0, 19.308), y_range=(0, 17.55), base_size=1, shape="hexagon", include_touching=True)
效果说明
修改后,六边形会以蜂窝状紧密排列,消除原有空隙;同时通过顶点判断,确保图形准确贴合曲线范围。
内容的提问来源于stack exchange,提问作者NooberPlays
相关产品推荐
相关产品推荐

