用 matplotlib 设置图例符号不透明度?

我正在用半透明的“ x”标记(20% alpha)绘制一幅图。如何使标记在图例中显示为100% 不透明?

import matplotlib.pyplot as plt
plt.plot_date( x = xaxis, y = yaxis, marker = 'x', color=[1, 0, 0, .2], label='Data Series' )
plt.legend(loc=3, mode="expand", numpoints=1, scatterpoints=1 )
34148 次浏览

如果希望在图例中具有特定的内容,则使用适当的文本更容易定义放置在图例中的对象。例如:

import matplotlib.pyplot as plt
import pylab


plt.plot_date( x = xaxis, y = yaxis, marker = 'x', color=[1, 0, 0, .2], label='Data Series' )
line1 = pylab.Line2D(range(1),range(1),color='white',marker='x',markersize=10, markerfacecolor="red",alpha=1.0)
line2 = pylab.Line2D(range(10),range(10),marker="_",linewidth=3.0,color="dodgerblue",alpha=1.0)
plt.legend((line1,line2),('Text','Other Text'),numpoints=1,loc=1)

在这里,line1定义了一个短的白色行(因此基本上是不可见的) ,标记‘ x’为红色并且是完全不透明的。例如,line2给出了一条较长的蓝色线,没有可见的标记。通过创建这些“行”,您可以更容易地控制它们在图例中的属性。

按照宇宙的回答,为了使图例的“假”线在情节上看不见,你可以使用 NaNs,它们仍然可以用来生成图例条目:

import numpy as np
import matplotlib.pyplot as plt
# Plot data with alpha=0.2
plt.plot((0,1), (0,1), marker = 'x', color=[1, 0, 0, .2])
# Plot non-displayed NaN line for legend, leave alpha at default of 1.0
legend_line_1 = plt.plot( np.NaN, np.NaN, marker = 'x', color=[1, 0, 0], label='Data Series' )
plt.legend()

我发现 .set_alpha()函数适用于许多图例对象,但不幸的是,许多图例对象都有几个部分(例如 errorbar()的输出) ,而 .set_alpha()调用只会影响其中的一个。

人们可以使用 .get_legend_handles_labels(),然后循环通过部分句柄和 .set_alpha(),但不幸的是,copy.deepcopy()似乎不工作的句柄列表,因此情节本身将受到影响。我能找到的最好的解决办法是保存原始的阿尔法,.set_alpha()到我想要的,创建图例,然后重置情节阿尔法回到他们的原始值。如果我能深拷贝 handles(我不需要保存 alpha 值或者重置它们) ,它会干净得多,但是我不能在 python2.7中这样做(也许这取决于图例中的对象是什么)。

f,ax=plt.subplots(1)


ax.plot(  ...  )


def legend_alpha(ax,newalpha=1.0):
#sets alpha of legends to some value
#this would be easier if deepcopy worked on handles, but it doesn't
handles,labels=ax.get_legend_handles_labels()
alphass=[None]*len(handles) #make a list to hold lists of saved alpha values
for k,handle in enumerate(handles): #loop through the legend entries
alphas=[None]*len(handle) #make a list to hold the alphas of the pieces of this legend entry
for i,h in enumerate(handle): #loop through the pieces of this legend entry (there could be a line and a marker, for example)
try: #if handle was a simple list of parts, then this will work
alphas[i]=h.get_alpha()
h.set_alpha(newalpha)
except: #if handle was a list of parts which themselves were made up of smaller subcomponents, then we must go one level deeper still.
#this was needed for the output of errorbar() and may not be needed for simpler plot objects
alph=[None]*len(h)
for j,hh in enumerate(h):
alph[j]=hh.get_alpha() #read the alpha values of the sub-components of the piece of this legend entry
hh.set_alpha(newalpha)
alphas[i]=alph #save the list of alpha values for the subcomponents of this piece of this legend entry
alphass[k]=alphas #save the list of alpha values for the pieces of this legend entry
leg=ax.legend(handles,labels) #create the legend while handles has updated alpha values
for k,handle in enumerate(handles): #loop through legend items to restore origina alphas on the plot
for i,h in enumerate(handle): #loop through pieces of this legend item to restore alpha values on the plot
try:
h.set_alpha(alphass[k][i])
except:
for j,hh in enumerate(h): #loop through sub-components of this piece of this legend item to restore alpha values
hh.set_alpha(alphass[k][i][j])
return leg


leg=legend_alpha(ax)
leg.draggable()

更新: 有一个更简单的方法! 首先,在创建一个变量时,将您的图例分配给它:

leg = plt.legend()

然后:

for lh in leg.legendHandles:
lh.set_alpha(1)

或者如果上面的方法不起作用(你可能使用的是旧版本的 matplotlib) :

for lh in leg.legendHandles:
lh._legmarker.set_alpha(1)

使你的标记不透明的 plt.plotplt.scatter,分别。

请注意,在 plt.plot上简单地使用 lh.set_alpha(1)将使图例中的线条不透明,而不是使用标记。您应该能够将这两种可能性应用于其他情节类型。

资料来源: 由 DrV合成了一些关于标记大小的 好建议。更新的灵感来自于 欧文的有用的评论。

我找到了另一种方法,而不是把传说的不透明性搞得一团糟。首先,我创建了一个情节线的风格,我希望的传奇是。然后我改变了情节线的风格,并且,奇迹般地,图例风格保持不变。MWE:

plt.plot(x, y, 'ro', label='label')
for lh in plt.gca().get_legend_handles_labels():
lh[0].set_alpha(new_alpha)

我想解释一下,为什么它能工作,但是我不能。我也不确定它是否适用于所有的后端。


是的,我知道这个问题很老套。由于它仍然出现在谷歌,我会找到它以后,并帮助我的未来自己。

它看起来像 matplotlib 绘制的情节线 之后它复制到图例的阿尔法水平。这意味着您可以使用图例中需要的 alpha 级别创建绘图线,创建用于复制该 alpha 级别的图例,然后更改绘图线上的 alpha 级别。

这里有一个完整的例子:

import matplotlib.pyplot as plt


x = (0, 1, 2)
y = (0, 2, 1)
line, = plt.plot(x, y, 'ro', label='label')  # Default alpha is 1.0.
plt.legend()  # Copy alpha to legend.
line.set_alpha(0.2)  # Change alpha for data points.


plt.show()

当我在 Python 2.7.15上使用 matplotlib 2.2.3运行这个图时,它看起来是这样的:

Example plot

这里的其他答案提供了很好的实用解决方案,或者在创建图例之后改变图例中的 alpha 值,或者在图例创建之后改变线条的 alpha 值。

一个解决方案,以实现一个不同的不透明度在图例没有操作任何后来将如下。它使用一个 handler_map和一个更新函数。

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(43)
from matplotlib.collections import PathCollection
from matplotlib.legend_handler import HandlerPathCollection, HandlerLine2D




plt.plot(np.linspace(0,1,8), np.random.rand(8), marker="o", markersize=12, label="A line", alpha=0.2)


plt.scatter(np.random.rand(8),np.random.rand(8), s=144,
c="red", marker=r"$\clubsuit$",  label="A scatter", alpha=0.2)


def update(handle, orig):
handle.update_from(orig)
handle.set_alpha(1)


plt.legend(handler_map={PathCollection : HandlerPathCollection(update_func= update),
plt.Line2D : HandlerLine2D(update_func = update)})


plt.show()

enter image description here

在我的例子中,set_alpha(1)也修改了 edgecolors,这是我不想要的: 我有“不可见”的边缘,并且将 alpha 设置为不透明使它们在图例中可见。以下代码片段(OOP) 在不改变边框颜色的情况下改变面部的不透明度:

leg = ax.legend()
for lh in leg.legendHandles:
fc_arr = lh.get_fc().copy()
fc_arr[:, -1] = 1  # set opacity here
lh.set_fc(fc_arr)

请注意对 .copy()的调用,如果我们不这样做,它将修改整个绘图的不透明度。调用复制意味着我们只是修改颜色 在传奇盒子里

或者,您可以将此函数添加到库中:

def opaque_legend(ax):
"""
Calls legend, and sets all the legend colors opacity to 100%.
Returns the legend handle.
"""
leg = ax.legend()
for lh in leg.legendHandles:
fc_arr = lh.get_fc().copy()
fc_arr[:, -1] = 1
lh.set_fc(fc_arr)
return leg

然后简单地用 leg = opaque_legend(ax)代替 leg = ax.legend()。希望这有所帮助!

安德烈斯