问题
I wish to fill regions between two lines in Python 3x (I mostly work in v3.7 presently) using data series that share a common scale, but lack mutual x-values.
'fill_between' would be handy but requires common x values for the two y-series matplotlib documentation matplotlib demo
data follows:
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()
if I try to fill between, I get a ValueError (because the series are different shapes). For example:
ax.fill_between(x1,y1,y2)
returns:
ValueError: operands could not be broadcast together with shapes (30,) (46,)
I'm unable to simply express my y values in terms of a common x like: approach2
this approach seems a bit of a hack by overplotting a mask and won't work for my data with multiple reversals: approach3
It would seem that I need to intersect the two x-series and interpolate the missing y-values for each series respectively? or is there an easier way I'm missing?
Eventually, I'm looking to shade the regions differentially, e.g.:
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")
回答1:
You can create a common x-axis by sorting the combined x1
and x2
. Then, you can interpolate x1,y1
onto that new x-axis (and similar for 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()
来源:https://stackoverflow.com/questions/63541222/fill-between-two-lines-lacking-common-x-values