基于Matplotlib的抛物线路径连接图:曲率参数增强需求
实现带抛物弧线的英国多点汇聚连接图
问题根源
你的代码当前绘制直线的核心原因是三个拟合点共线:你取了起点、终点的中点作为第二个点,这三个点在同一条直线上,导致拟合出的二次函数系数a=0,退化成一次直线,自然没有曲率。
解决方案
给中间点添加垂直于两点连线的偏移量,让它脱离直线,这样拟合的抛物线就会产生明显弧度。我们新增一个curvature参数控制偏移大小,适配英国区域的EPSG:3857坐标系(单位为米,偏移量设为几万米比较合适)。
修改后的完整代码
import numpy as np import matplotlib.pyplot as plt import contextily as ctx import sympy as sm def plot_connection(ax, start_point, end_point, curvature=50000): x1, y1 = start_point[0], start_point[1] x3, y3 = end_point[0], end_point[1] # 计算两点中点 x_mid = (x1 + x3) / 2 y_mid = (y1 + y3) / 2 # 计算连线的垂直方向向量,保证弧线统一向上弯曲 dx = x3 - x1 dy = y3 - y1 perp_dx = -dy perp_dy = dx # 归一化垂直向量 vec_length = np.sqrt(perp_dx**2 + perp_dy**2) perp_dx /= vec_length perp_dy /= vec_length # 偏移中间点,生成带曲率的拟合点 x2 = x_mid + perp_dx * curvature y2 = y_mid + perp_dy * curvature x = np.array([x1, x2, x3]) y = np.array([y1, y2, y3]) a, b, c = sm.symbols('a b c', real=True) eq1 = sm.Eq((x[0]**2) * a + x[0] * b + c, y[0]) eq2 = sm.Eq((x[1]**2) * a + x[1] * b + c, y[1]) eq3 = sm.Eq((x[2]**2) * a + x[2] * b + c, y[2]) sol = sm.solve([eq1, eq2, eq3], (a, b, c)) def f(x_val): return sol[a] * (x_val**2) + sol[b] * x_val + sol[c] # 用plot替代scatter,绘制更流畅的弧线,提升渲染效率 x_vals = np.linspace(x[0], x[-1], 1500) y_vals = f(x_vals) ax.plot(x_vals, y_vals, color='gray', alpha=0.6, zorder=-3) # 目标点与各城市坐标(EPSG:3857坐标系) target = (-251467.639557, 7014473.211674) london = (-23236.856599, 6713617.068344) glasgow = (-472686.582916, 7534245.004013) leeds = (-173664.928264, 7133714.975799) brighton = (-14675.909431, 6599267.274029) darmstadt = (88791.533909, 6672007.566294) manchester = (-251095.637917, 7069851.838667) fig, ax = plt.subplots(figsize=(15, 15)) # 绘制各连接弧线,可针对不同城市调整curvature值优化视觉效果 plot_connection(ax, target, london, curvature=60000) plot_connection(ax, target, glasgow, curvature=60000) plot_connection(ax, target, leeds, curvature=40000) plot_connection(ax, target, brighton, curvature=60000) plot_connection(ax, target, darmstadt, curvature=60000) plot_connection(ax, target, manchester, curvature=20000) # 聚焦英国区域范围 ax.set_xlim(-520000, 175000) ax.set_ylim(6500000, 8200000) ctx.add_basemap(ax, source=ctx.providers.CartoDB.PositronNoLabels, zorder=-4, crs='EPSG:3857') ax.axis('off') plt.tight_layout() plt.show()
关键修改说明
- 新增
curvature参数:控制中间点的偏移距离,值越大弧线曲率越明显,可针对不同城市单独调整,让视觉效果更协调。 - 统一偏移方向:通过计算连线的垂直向量,保证所有弧线向上弯曲,避免杂乱的方向差异。
- 替换渲染方式:用
ax.plot替代plt.scatter,绘制连续线条更流畅,同时提升代码运行效率。
内容的提问来源于stack exchange,提问作者Samuel
相关产品推荐
相关产品推荐

