matplotlib学习—画等高线图

本文介绍了使用matplotlib绘制等高线图的方法。首先通过设定坐标点及高度数据,然后运用contourf函数填充颜色,contour函数绘制等高线,并展示如何调整参数以改善图表效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近想寻找一种能利用已有数据画出地理位置分布图的方法,在看Vamei写的博客 绘图: matplotlib核心剖析 学习matplotlib绘图的过程中找到了名为“contour”(等高线图)的绘图方式

等高线图:等高线地图就是将地表高度相同的点连成一环线直接投影到平面形成水平曲线。不同高度的环线不会相合,除非地表显示悬崖或峭壁才能使某处线条太密集出现重叠现像,若地表出线平坦开阔的山坡,曲线间之距离就相当宽。
(ps:从百度百科上扒来的一段话。话说百科上面错别字还是不少的,最后一行的“出现”错写成了“出线”)

对我这种学计算机的工科生来说,接触等高线图大部分(甚至可以说唯一)的机会就在初中和高中时的地理课堂上了,such as :
百度百科上的例子

下面来介绍怎么用matplotlib画简单的等高线图:

代码的参考来自于 绘图: matplotlib核心剖析matplotlib的基本用法(九)——绘制等高线图

# -*- coding:utf-8 -*-
#引入numpy库和matplotlib库
import numpy as np
import matplotlib.pyplot as plt

# 定义等高线图的横纵坐标x,y
#从左边取值为从 -3 到 3 ,各取5个点,一共取 5*5 = 25 个点
x = np.linspace(-3, 3, 5)
y = np.linspace(-3, 3, 5)
# 将原始数据变成网格数据
X, Y = np.meshgrid(x, y)

# 各地点对应的高度数据
#Height是个 5*5 的数组,记录地图上 25 个点的高度汇总
Height = [[0,0,1,2,2],[0,-2,-2,1,5],[4,2,6,8,1],[3,-3,-3,0,5],[1,-5,-2,0,3]]

# 填充颜色
plt.contourf(X, Y, Height, 10, alpha = 0.6, cmap = plt.cm.hot)
# 绘制等高线
C = plt.contour(X, Y, Height, 10, colors = 'black', linewidth = 0.5)
# 显示各等高线的数据标签
plt.clabel(C, inline = True, fontsize = 10)
plt.show()

画出的图如下:

等高线图1

由于这25个取样点的高度数值都是我凭感觉设置的,所以制作出来的效果不是很好,但拿来说明问题基本足够了。

下面简单解释一下代码中主要的函数 contourfcontour 中参数的设置:

1.contourf 填充颜色函数

  • 前三个参数 X, Y, Height 用来引进点的位置和对应的高度数据;
  • 数字 10 代表将等高线图分成10块(这里不是硬性要求,但数值过小会造成部分分区颜色区分度不高);
  • alpha = 0.6 用来设置填充颜色的范围,alpha取值为 [0,1) 。alpha=0时,画出的是无色图,alpha越接近1,颜色的搭配就越向深色风格过渡,如下面几张图所示:
    alpha=0
    alpha=0.3
    alpha=0.9

2.contour 绘制等高线函数

  • 前面的参数跟contourf一样;
  • colors = ‘black’ 代表线条颜色是黑色;
  • linewidth = 0.5 代表线条粗细.

如果遇到不能靠单纯输入各点高度值的情况,就需要将Height数组变成一个以横纵坐标X和Y为参数的高度计算函数:

def f(x, y):
    return x * y #这里的函数是我简单定义的,要根据现实情况设置符合实际的函数

总代码:

# -*- coding:utf-8 -*-
#引入numpy库和matplotlib库
import numpy as np
import matplotlib.pyplot as plt

# 定义等高线图的横纵坐标x,y
#从左边取值为从 -3 到 3 ,各取5个点,一共取 5*5 = 25 个点
x = np.linspace(-3, 3, 5)
y = np.linspace(-3, 3, 5)
# 将原始数据变成网格数据
X, Y = np.meshgrid(x, y)

# 定义等高线高度函数
def f(x, y):
    return x * y

# 填充颜色
plt.contourf(X, Y, f(X,Y), 10, alpha = 0.5, cmap = plt.cm.hot)
# 绘制等高线
C = plt.contour(X, Y, f(X,Y), 10, colors = 'black', linewidth = 0.5)
# 显示各等高线的数据标签
plt.clabel(C, inline = True, fontsize = 10)
plt.show()

画出的图如下:(莫名地有一种对称的美感 2333)

等高线图2

可以在最后的 plt.show() 前加如下两行,将横纵坐标隐藏:

# 去除坐标轴
plt.xticks(())
plt.yticks(())

效果如下:
等高线图3

以上就是用matplotlib画等高线图的基本步骤,以后有机会的话得尝试一下如何绘制功能更强大、更符合实际应用的等高线图。
— 2:55 pm, 2017/6/25.

<think>好的,用户现在的问题是想要用Matplotlib绘制三元等高线图,并且解决热图底部空白的问题。之前用户提到的三元热图下半部分空白的问题,我之前已经分析过,可能涉及数据量不足、坐标系设置或者无效数据过滤等原因。现在用户进一步询问如何绘制三元等高线图以及解决空白问题,需要结合之前的回答和新的引用内容来给出解决方案。首先,我需要回顾用户提供的引用内容。引用[1]中的代码展示了使用Matplotlib的imshow和contour绘制热力图和等高线,这可能对绘制三元图的等高线有帮助。引用[2]和[4]提到Matplotlib的绘图功能,特别是引用[3]涉及浮动轴的使用,这可能对调整三元图的坐标轴有用。用户之前的问题涉及三元热图的空白区域,可能和origin参数或数据生成有关,需要将这些点结合起来。接下来,我需要考虑三元图的特殊性。三元图通常是在三个变量x+y+z=1的情况下绘制的,所以数据需要满足这个约束。用户提到的底部空白,可能是在使用imshow时,origin参数设置不正确,或者数据生成时没有覆盖到整个区域,导致部分区域没有数据。根据之前的回答,生成数据时可能没有正确处理有效区域,导致某些坐标点无效(比如z为负)。这时候需要确保生成的数据点都满足x+y+z=1且x,y,z≥0。可能需要使用网格生成方法,然后过滤掉无效点,或者使用等边三角形的坐标变换来正确映射数据。另外,绘制等高线可能需要将数据投影到二维的三角坐标系中。Matplotlib本身没有原生的三元坐标系支持,但可以通过自定义坐标变换来实现。引用[3]中的浮动轴可能可以用来创建旋转的轴,模拟三元坐标。这可能需要使用mpl_toolkits中的FloatingAxes和GridHelperCurveLinear来定义自定义的坐标系。然后,解决空白问题可能需要检查数据生成是否正确,是否覆盖了整个有效区域,以及绘图时是否正确地设置了origin参数。例如,在使用imshow时,如果origin设置为'lower',但数据矩阵的底部行对应的是低y值,而生成的数据可能没有填充这部分,导致空白。需要确保数据矩阵与origin参数一致,或者调整数据填充的顺序。可能的步骤包括: 1.生成满足x+y+z=1的三元数据点。2.将这些点映射到二维的等边三角形坐标系中。3.使用griddata进行插值,生成适合绘制等高线的网格数据。 4.使用自定义的坐标系和轴来绘制三元图。 5.确保数据覆盖整个区域,避免无效点导致的空白。同时,需要处理数据插值的问题,因为原始的三元数据可能是不规则的,需要转换为规则的网格数据才能使用contour函数。这可能需要使用griddata方法进行插值,并处理可能的NaN值。在代码示例中,可能需要展示如何生成数据、进行坐标变换、插值以及绘图设置。同时,要指出常见的错误,比如数据生成不完整、origin参数设置错误、无效数据未过滤等,并提供相应的解决方法。 最后,生成相关问题,可能涉及如何自定义Matplotlib坐标系、处理不规则数据的等高线、优化三元图显示效果等。</think>### 使用Matplotlib绘制三元等高线图及解决空白问题 #### 一、三元等高线图绘制原理 1. **坐标系转换** 三元数据需映射到二维平面坐标系,常用等边三角形坐标系: $$(x,y,z) \Rightarrow (X,Y) = \left( x + \frac{y}{2}, \frac{\sqrt{3}}{2}y \right)$$ 其中$x+y+z=1$且$x,y,z \geq 0$[^1] 2. **数据生成方法** ```python def generate_ternary_grid(n): """生成满足x+y+z=1的网格点""" t = np.linspace(0,1,n) x, y = np.meshgrid(t, t) z = 1 - x - y valid = (z >= 0) & (x >= 0) & (y >= 0) # 有效性过滤 return x[valid], y[valid], z[valid] ``` #### 二、解决底部空白问题的关键步骤 1. **坐标系方向校准** 使用`origin='lower'`时需确保数据矩阵第一行对应图像底部: ```python plt.imshow(data, origin='lower', extent=[0,1,0,1]) # 确保数据填充方向正确[^2] ``` 2. **有效区域覆盖验证** ```python print(f"有效数据占比: {np.mean(valid)*100:.1f}%") # 应接近100% ``` 3. **无效数据插值补偿** 使用`griddata`进行二维插值: ```python from scipy.interpolate import griddata grid_x, grid_y = np.mgrid[0:1:100j, 0:1:100j] grid_z = griddata((X, Y), values, (grid_x, grid_y), method='cubic') ``` #### 三、完整实现示例 ```python import numpy as np import matplotlib.pyplot as plt from matplotlib.tri import Triangulation from scipy.interpolate import griddata # 生成三元数据 n = 50 x, y, z = generate_ternary_grid(n) values = np.sin(2*np.pi*x) * np.cos(3*np.pi*y) # 示例数据 # 坐标转换 X = x + y/2 Y = (np.sqrt(3)/2)*y # 创建规则网格 xi = np.linspace(0, 1, 100) yi = np.linspace(0, np.sqrt(3)/2, 100) xi, yi = np.meshgrid(xi, yi) # 数据插值 zi = griddata((X, Y), values, (xi, yi), method='cubic') # 创建三角剖分 tri = Triangulation(X, Y) # 绘制等高线 plt.figure(figsize=(10,8)) contour = plt.tricontourf(tri, values, levels=15, cmap='coolwarm') plt.tricontour(tri, values, levels=15, colors='k') # 绘制三角坐标轴 vertices = np.array([[0,0], [1,0], [0.5,np.sqrt(3)/2], [0,0]]) plt.plot(vertices[:,0], vertices[:,1], 'k-') # 设置坐标标签 plt.text(0.05, 0.05, 'X', ha='center') plt.text(0.95, 0.05, 'Y', ha='center') plt.text(0.5, 0.95, 'Z', ha='center') plt.colorbar(contour) plt.show() ``` #### 四、常见问题解决方案 | 问题现象 | 原因分析 | 解决方法 | |---------|----------|---------| | 底部出现空白条纹 | 数据矩阵未覆盖底部区域 | 检查数据生成范围,确保包含$y=0$边界 | | 等高线断裂 | 插值方法不合适 | 改用`method='nearest'`或增加数据密度 | | 颜色映射异常 | 存在NaN值 | 使用`np.nan_to_num()`处理插值结果 | #### 五、数学验证方法 1. **坐标归一化验证** $$\max(x+y+z) = 1.0 \pm \epsilon$$ ```python print(f"最大坐标和: {np.max(x+y+z):.4f}") # 应接近1.0 ``` 2. **有效区域面积验证** 理论面积$S = \frac{\sqrt{3}}{4}$,实际覆盖面积应满足: $$\left| \frac{S_{\text{实际}}}{S} - 1 \right| < 0.01$$ 3. **数据连续性验证** 检查插值后数据梯度: $$\max\left( \left| \nabla z \right| \right) < \text{阈值}$$ #### 六、高级优化技巧 1. **自定义坐标变换** 使用`mpl_toolkits.axisartist`创建浮动轴: ```python from matplotlib.transforms import Affine2D from mpl_toolkits.axisartist import floating_axes transform = Affine2D().rotate_deg(60) # 旋转坐标轴[^3] grid_helper = floating_axes.GridHelperCurveLinear(transform) ax = floating_axes.FloatingSubplot(fig, 111, grid_helper=grid_helper) ``` 2. **动态分辨率调整** 根据数据密度自动调整网格分辨率: $$n_{\text{动态}} = \left\lceil \frac{\log(N_{\text{points}})}{\log(2)} \right\rceil$$
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值