【问题标题】:Fill between subplots with matplotlib cmap使用 matplotlib cmap 在子图之间填充
【发布时间】:2019-12-30 19:21:40
【问题描述】:

我在同一个图上有 2 个线图,是从 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()

编辑/更新:数据示例 其他总是 >= 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

最终图表示例:

我希望填充从顶部的橙色变为底部的蓝色

【问题讨论】:

  • 可以为df0和df1添加一些简单的数据吗?
  • 在原帖中添加,也是一张图片。
  • @ryuuzako 你有机会尝试我回答中的方法吗?
  • @WilliamMiller 嘿,我没有绕过它,但我保证一旦我这样做了,我会在这里更新!

标签: python matplotlib gradient


【解决方案1】:

编辑

针对已编辑的问题,这是一种替代方法,它垂直渐变但不使用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()

这里的想法与我原来的答案类似,除了梯形被分成nc 块并且每块单独着色。这样做的好处是可以针对不同的y1[ii]y2[ii] 距离正确缩放,如本比较所示,

然而,它确实有缺点,比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()

原创

这是一个小技巧,部分基于this question 中的答案。它似乎工作得相当好,但在x 轴上的密度更高时效果最好。这个想法是为每个对应于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()

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

【讨论】:

  • 由于 imshow 比绘制数百个补丁要快得多,因此不太清楚为什么要尽量避免使用它。
  • @ImportanceOfBeingErnest 也许我不清楚。我并不是说应该避免使用imshow,我只是说这是一种不使用imshow 的方法。
  • @ImportanceOfBeingErnest 正如我所见,在imshow 上使用此方法的原因由thisthis 概述,其中剪切imshow 不会产生带有变量的正确渐变y1y2 距离或当 y1 和/或 y2x 有时。在这些情况下,您将如何使用 imshow 生成正确的渐变?
  • 这个问题仍然有点不清楚梯度应该看起来如何(即它是 per x data point 的梯度还是全局梯度。后者会虽然更有意义(?))。无论如何,您总是可以创建一个看起来像预期结果的图像,所以不确定到底是什么问题。
  • @Vladimir 我添加了plt.imshow 方法的代码
猜你喜欢
  • 1970-01-01
  • 2017-11-28
  • 2018-11-03
  • 2015-12-29
  • 1970-01-01
  • 1970-01-01
  • 2018-05-14
相关资源
最近更新 更多