在缺少公共 x 值的两条线之间填充

fill between two lines lacking common x values

我希望使用共享相同比例但缺少相互 x 值的数据系列以 Python 3x(我目前主要在 v3.7 中工作)填充两条线之间的区域。

'fill_between' 会很方便,但需要两个 y 系列的通用 x 值 matplotlib documentation matplotlib demo

数据如下:

x1 = [0.0, 3.2, 10.2, 15.4, 19.9, 24.2, 27.7, 33.9, 50.7, 67.9, 83.7, 102.0, 105.8, 119.4, 129.3, 140.3, 146.0, 150.2, 158.3, 166.7, 168.6, 171.7, 173.5, 175.3, 184.1, 203.7, 220.2, 221.8, 226.8, 231.9]
y1 = [99.95, 99.99, 100.11, 99.59, 98.24, 98.5, 99.21, 99.46, 99.35, 99.18, 98.71, 98.26, 97.92, 97.92, 98.02, 97.63, 97.63, 98.49, 99.17, 98.85, 97.35, 97.43, 98.66, 99.36, 99.14, 99.08, 99.25, 98.74, 98.82, 99.73]
x2 = [-1.5, 0.1, 4.1, 6.8, 7.4, 7.8, 11.5, 18.4, 25.2, 37.8, 46.3, 54.7, 59.7, 66.0, 75.1, 77.3, 91.4, 109.6, 122.5, 127.4, 133.2, 134.5, 138.3, 141.6, 145.1, 153.0, 153.7, 158.8, 162.8, 166.0, 167.2, 167.9, 172.7, 173.2, 175.0, 178.9, 183.0, 190.6, 199.5, 207.3, 210.5, 215.6, 222.2, 224.5, 227.7, 231.9]
y2 = [100.12, 100.16, 100.27, 100.26, 98.85, 98.22, 98.08, 98.2, 99.15, 99.41, 99.27, 98.88, 98.36, 98.24, 98.48, 99.42, 99.37, 99.13, 99.16, 99.1, 98.66, 98.31, 98.16, 98.46, 98.06, 97.96, 98.45, 99.32, 99.3, 99.23, 98.42, 97.62, 98.02, 98.74, 99.47, 99.24, 99.22, 99.12, 99.17, 99.1, 98.91, 99.16, 98.91, 98.82, 99.02, 99.78]

fig, ax = plt.subplots(1,1, figsize=(14,6))

ax = plt.subplot(1,1,1)
ax.plot(x1,y1,c='blue')
ax.plot(x2,y2,c='red')
plt.show()

如果我尝试在两者之间填充,我会得到一个 ValueError(因为系列是不同的形状)。例如:

ax.fill_between(x1,y1,y2)

returns:

ValueError: operands could not be broadcast together with shapes (30,) (46,)

我无法用常见的 x 来简单地表达我的 y 值,例如: approach2

通过过度绘制掩码,这种方法似乎有点 hack,并且不适用于我的多次反转数据:

我似乎需要将两个 x 系列相交并分别为每个系列插入缺失的 y 值?还是我缺少更简单的方法?

最终,我希望对区域进行不同的着色,例如:

ax.fill_between(x,y1,y2, interploate=True, where =(y1<y2),c="blue")
ax.fill_between(x,y1,y2, interploate=True, where =(y1>y2),c="red")

您可以通过对组合的 x1x2 进行排序来创建一个公共 x-axis。然后,您可以将 x1,y1 插入到新的 x-axis 中(与 x2,y2 类似):

import matplotlib.pyplot as plt
import numpy as np

x1 = [0.0, 3.2, 10.2, 15.4, 19.9, 24.2, 27.7, 33.9, 50.7, 67.9, 83.7, 102.0, 105.8, 119.4, 129.3, 140.3, 146.0, 150.2, 158.3, 166.7, 168.6, 171.7, 173.5, 175.3, 184.1, 203.7, 220.2, 221.8, 226.8, 231.9]
y1 = [99.95, 99.99, 100.11, 99.59, 98.24, 98.5, 99.21, 99.46, 99.35, 99.18, 98.71, 98.26, 97.92, 97.92, 98.02, 97.63, 97.63, 98.49, 99.17, 98.85, 97.35, 97.43, 98.66, 99.36, 99.14, 99.08, 99.25, 98.74, 98.82, 99.73]
x2 = [-1.5, 0.1, 4.1, 6.8, 7.4, 7.8, 11.5, 18.4, 25.2, 37.8, 46.3, 54.7, 59.7, 66.0, 75.1, 77.3, 91.4, 109.6, 122.5, 127.4, 133.2, 134.5, 138.3, 141.6, 145.1, 153.0, 153.7, 158.8, 162.8, 166.0, 167.2, 167.9, 172.7, 173.2, 175.0, 178.9, 183.0, 190.6, 199.5, 207.3, 210.5, 215.6, 222.2, 224.5, 227.7, 231.9]
y2 = [100.12, 100.16, 100.27, 100.26, 98.85, 98.22, 98.08, 98.2, 99.15, 99.41, 99.27, 98.88, 98.36, 98.24, 98.48, 99.42, 99.37, 99.13, 99.16, 99.1, 98.66, 98.31, 98.16, 98.46, 98.06, 97.96, 98.45, 99.32, 99.3, 99.23, 98.42, 97.62, 98.02, 98.74, 99.47, 99.24, 99.22, 99.12, 99.17, 99.1, 98.91, 99.16, 98.91, 98.82, 99.02, 99.78]


fig, ax = plt.subplots(1, 1, figsize=(14, 6))

ax.plot(x1, y1, c='dodgerblue')
ax.plot(x2, y2, c='crimson')

xfill = np.sort(np.concatenate([x1, x2]))
y1fill = np.interp(xfill, x1, y1)
y2fill = np.interp(xfill, x2, y2)
ax.fill_between(xfill, y1fill, y2fill, where=y1fill < y2fill, interpolate=True, color='dodgerblue', alpha=0.2)
ax.fill_between(xfill, y1fill, y2fill, where=y1fill > y2fill, interpolate=True, color='crimson', alpha=0.2)

plt.show()