使用matplotlib的cmap填充子图间的空白区域

3
我在同一张图上用pandas数据框绘制了两条线图。
我想用渐变/颜色映射填充它们之间的区域。
我知道可以使用cmap来实现这一点,但是对我来说不起作用(请参见下面的代码)。
我找到的通用示例是在x轴和线之间填充,我不想要那个,并且我对最简单的解决方案感兴趣,因为我是一个新手,复杂的代码只会让我更加困惑。
填充为纯蓝色的代码:
import matplotlib.pyplot as plt
import pandas as pd

ax = plt.gca()

df0.plot(kind='line', x='something', y='other', color='orange', ax=ax, legend=False, figsize=(20,10))
df1.plot(kind='line', x='something', y='other2', color='c', ax=ax, legend=False, figsize=(20,10))

ax.fill_between(x=df0['daysInAYear'], y1=df0['other'], y2 = df1['other2'], alpha=0.2, cmap=plt.cm.get_cmap("winter"))
plt.show()

编辑/更新:数据示例 other总是>= other2

other  other2  something (same for both)
15.6    -16.0      1
13.9    -26.7      2
13.3    -26.7      3
10.6    -26.1      4
12.8    -15.0      5

最终的图表示例: example

我希望填充颜色从上面的橙色到下面的蓝色。


你能为 df0 和 df1 添加一些简单的数据吗? - Scott Boston
在原帖中添加了内容,还有一张图片。 - ryuuzako
@ryuuzako,你有机会尝试一下我回答中的方法了吗? - William Miller
1
@WilliamMiller 嘿,我还没处理这个问题,但我保证一旦处理完了,我会在这里更新! - ryuuzako
1个回答

3

编辑

针对编辑后的问题,这里提供一种替代方法,可以在垂直方向上进行渐变,但不使用imshow

import matplotlib.pyplot as plt
from  matplotlib import colors, patches
import numpy as np
import pandas as pd

n = 100
nc = 100

x = np.linspace(0, np.pi*5, n)
y1 = [-50.0]
y2 = [50.0]
for ii in range(1, n):
    y1.append(y1[ii-1] + (np.random.random()-0.3)*3)
    y2.append(y2[ii-1] + (np.random.random()-0.5)*3)
y1 = np.array(y1)
y2 = np.array(y2)
z = np.linspace(0, 10, nc)
normalize = colors.Normalize(vmin=z.min(), vmax=z.max())
cmap = plt.cm.get_cmap('winter')

fig, ax = plt.subplots(1)
for ii in range(len(df['x'].values)-1):
    y = np.linspace(y1[ii], y2[ii], nc)
    yn = np.linspace(y1[ii+1], y2[ii+1], nc)
    for kk in range(nc - 1):
        p = patches.Polygon([[x[ii], y[kk]], 
                             [x[ii+1], yn[kk]], 
                             [x[ii+1], yn[kk+1]], 
                             [x[ii], y[kk+1]]], color=cmap(normalize(z[kk])))
        ax.add_patch(p)

plt.plot(x, y1, 'k-', lw=1)
plt.plot(x, y2, 'k-', lw=1)
plt.show()

enter image description here

这里的想法与我的原始答案类似,只是将梯形分成nc个部分,并分别着色。这样做的优点是可以正确地缩放不同的y1[ii]y2[ii]距离,如此比较所示。

enter image description here

然而,它有比使用imshow或水平梯度方法要慢得多的缺点,并且无法正确处理“交叉”情况。

生成上述比较中第二张图片的代码:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib import patches
from matplotlib.path import Path

x = np.linspace(0, 10, n)
y1 = [-50.0]
y2 = [50.0]
for ii in range(1, n):
    y1.append(y1[ii-1] + (np.random.random()-0.2)*3)
    y2.append(y2[ii-1] + (np.random.random()-0.5)*3)
y1 = np.array(y1)
y2 = np.array(y2)

verts = np.vstack([np.stack([x, y1], 1), np.stack([np.flip(x), np.flip(y2)], 1)])
path = Path(verts)

patch = patches.PathPatch(path, facecolor='k', lw=2, alpha=0.0)
plt.gca().add_patch(patch)

plt.imshow(np.arange(10).reshape(10,-1), cmap=plt.cm.winter, interpolation="bicubic",
             origin='upper', extent=[0,10,-60,60], aspect='auto', clip_path=patch, 
             clip_on=True)
plt.show()

Translated

这是一个有些巧妙的方法,部分基于这个问题中的答案。它似乎运行得相当不错,但在 x 轴方向上密度更高时效果最好。思路是为每对 x[ii], x[ii+1] 对应的梯形单独调用 fill_between 方法。以下是使用一些生成的数据的完整示例:

import matplotlib.pyplot as plt
from  matplotlib import colors
import numpy as np
import pandas as pd

n = 1000

X = np.linspace(0, np.pi*5, n)
Y1 = np.sin(X)
Y2 = np.cos(X)
Z = np.linspace(0, 10, n)
normalize = colors.Normalize(vmin=Z.min(), vmax=Z.max())
cmap = plt.cm.get_cmap('winter')

df = pd.DataFrame({'x': X, 'y1': Y1, 'y2': Y2, 'z': Z})
x = df['x'].values
y1 = df['y1'].values
y2 = df['y2'].values
z = df['z'].values

for ii in range(len(df['x'].values)-1):
    plt.fill_between([x[ii], x[ii+1]], [y1[ii], y1[ii+1]], 
                     [y2[ii], y2[ii+1]], color=cmap(normalize(z[ii])))

plt.plot(x, y1, 'k-', x, y2, 'k-')
plt.show()

enter image description here

这可以推广到二维颜色网格,但需要进行非平凡的修改。

@ImportanceOfBeingErnest 或许我表达不够清晰。我并不是说应该避免使用 imshow,我只是在说这是一种不使用 imshow 的方法。 - William Miller
@ImportanceOfBeingErnest 我认为使用这种方法而不是imshow的原因在于这里这里,其中使用imshow进行裁剪时,无法正确生成具有可变y1y2距离或当y1和/或y2x一起使用时的渐变。您如何使用imshow在这些情况下生成正确的渐变? - William Miller
请问您能否提供基于imshow的代码,使用水平梯度法,其中颜色仅根据y值定义?我有完全相同的问题,但是我发现答案令人不满意。这是在fill_between内部进行颜色渐变的唯一方法吗? - Vladimir
我指的是垂直渐变,就像上面比较中右侧面板中的那样。 - Vladimir
1
@Vladimir 我已经添加了 plt.imshow 方法的代码。 - William Miller
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接