修正 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()
我经常需要用简洁的图表来表示一些数据的分布,如下图。我通过绘制几个 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()