修正 Matplotlib 中相交透明层的图例颜色

Correct legend color for intersecting transparent layers in Matplotlib

我经常需要用简洁的图表来表示一些数据的分布,如下图。我通过绘制几个 fill_between 区域来做到这一点,这些区域受分布的分位数限制。

ax.fill_between(x, quantile1, quantile2, alpha=0.2)

在 for 循环中,我通过计算分位数 1 和 2(如图例所示)作为 0% 到 100% 分位数,然后是 10% 到 90% 等等来绘制这样的图,每个 fill_between 在前面的 "layer".

之上绘制

这是带有三层透明颜色以及中线 (0.5) 的输出:

但是,图例颜色不是我想要的颜色,因为它们(自然地)使用每个单独图层的颜色,没有考虑多个图层的组合效果。

ax.legend([0.5]+[['0.0%', '100.0%'], ['10.0%', '90.0%'], ['30.0%', '70.0%']])

在图例命令中覆盖面颜色值的最佳方法是什么?

我想通过先绘制透明度为“0.2”的 0% 到 10%,然后绘制透明度为“0.4”的 10% 到 30% 等等来避免这样做,因为这将花费两倍的时间计算,会使代码更复杂。

您可以使用代理艺术家放置在图例中,其透明度与绘图生成的叠加层完全相同。
作为代理艺术家,您可以使用一个简单的矩形。然而,透明度需要计算,因为两个具有透明度 0.2 的对象一起将显示为具有透明度 0.36 的单个对象(而不是 0.4!)。

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches

a = np.sort(np.random.rand(6,18), axis=0)
x = np.arange(len(a[0]))

def alpha(i, base=0.2):
    l = lambda x: x+base-x*base
    ar = [l(0)]
    for j in range(i):
        ar.append(l(ar[-1]))
    return ar[-1]

fig, ax = plt.subplots(figsize=(4,2))

handles = []
labels=[]
for i in range(len(a)/2):
    ax.fill_between(x, a[i, :], a[len(a)-1-i, :], color="blue", alpha=0.2)
    handle = matplotlib.patches.Rectangle((0,0),1,1,color="blue", alpha=alpha(i, base=0.2))
    handles.append(handle)
    label = "quant {:.1f} to {:.1f}".format(float(i)/len(a)*100, 100-float(i)/len(a)*100)
    labels.append(label)

plt.legend(handles=handles, labels=labels, framealpha=1)
plt.show()


人们必须决定这是否真的值得付出努力。一个不透明但结果完全相同的解决方案可以更短地实现:

import matplotlib.pyplot as plt
import numpy as np

a = np.sort(np.random.rand(6,18), axis=0)
x = np.arange(len(a[0]))

fig, ax = plt.subplots(figsize=(4,2))

for i in range(len(a)/2):
    label = "quant {:.1f} to {:.1f}".format(float(i)/len(a)*100, 100-float(i)/len(a)*100)
    c = plt.cm.Blues(0.2+.6*(float(i)/len(a)*2)  )
    ax.fill_between(x, a[i, :], a[len(a)-1-i, :], color=c, label=label)

plt.legend( framealpha=1)
plt.show()