【问题标题】:Set legend symbol opacity with matplotlib?使用matplotlib设置图例符号不透明度?
【发布时间】:2012-10-11 21:30:17
【问题描述】:

我正在绘制带有半透明“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 )

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

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

    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) 将使图例中的线条不透明,而不是标记。您应该能够为其他绘图类型调整这两种可能性。

    来源: 从一些good adviceDrV 合成关于标记大小。更新的灵感来自 Owen 的有用评论。

    【讨论】:

    • 这是迄今为止我的问题最简单的答案!我要添加两个注释:1)您可以在创建图例时通过leg = plt.legend() 获取图例选项。 2)对我来说,我需要lh.set_alpha(1) 而不是lh._legmarker.set_alpha(1)(不确定 API 是否已更改...)
    • 好消息。你用的是plt.scatter()吗?在玩了一会儿之后,根据你的情节类型,它看起来有一些细微的变化(可能是因为plt.scatter 没有特定的_legmarker,因为它从不需要区分线条和标记。)跨度>
    • 另外,我的原始答案和您的评论都使用 alpha=1。获得透明度,但是当我现在玩它时,我发现需要 alpha=0。 (matplotlib.__version__ == '1.5.1')。我是在吃疯狂的药片还是什么?
    • 或者set_alpha(1)如果你想要OP的期望结果。
    【解决方案2】:

    按照宇宙的回答,要使图例的“假”线在图上不可见,您可以使用 NaN,它们仍可用于生成图例条目:

    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()
    

    【讨论】:

      【解决方案3】:

      此处的其他答案通过在创建后更改图例中的 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()
      

      【讨论】:

        【解决方案4】:

        如果您想在图例中添加特定内容,使用适当的文本定义您放置在图例中的对象会更容易。例如:

        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 为您提供了一条更长的蓝线,没有可见的标记。通过创建这些“线条”,您可以更轻松地在图例中控制它们的属性。

        【讨论】:

          【解决方案5】:

          看起来 matplotlib 在 之后绘制了绘图线,它将 alpha 级别复制到了图例。这意味着您可以在图例中创建具有所需 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 运行它时,该图如下所示:

          【讨论】:

            【解决方案6】:

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

            可以使用.get_legend_handles_labels(),然后循环遍历部分句柄和.set_alpha(),但不幸的是,copy.deepcopy() 似乎不适用于句柄列表,因此情节本身会受到影响。我能找到的最佳解决方法是将原始 alphas .set_alpha() 保存为我想要的,创建图例,然后将绘图 alphas 重置为其原始值。如果我可以深度复制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()
            

            【讨论】:

              【解决方案7】:

              在我的例子中,set_alpha(1) 还修改了我不想要的 edgecolors:我有“不可见”的边缘,并且将 alpha 设置为不透明使它们在图例中可见。下面的 sn-p (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() 的调用,如果我们不这样做,它将修改整个绘图的不透明度。调用 copy 意味着我们只是在修改图例框内的 facecolor

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

              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 = ax.legend() 替换为leg = opaque_legend(ax)。希望这会有所帮助!

              安德烈斯

              【讨论】:

                【解决方案8】:

                我没有弄乱传说的不透明性,而是找到了另一种方法。首先,我创建了一条具有我想要的图例风格的情节线。然后我更改了情节线样式,奇迹般地,图例样式保持不变。 MWE:

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

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


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

                【讨论】:

                • 我升级到 2.2.3,但它仍然不适合我。但是,您在创建图例后更改 alpha 的想法确实有效,因此我发布了一个单独的 answer 并附有完整示例。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-06-02
                • 2018-01-19
                • 1970-01-01
                • 1970-01-01
                • 2020-10-27
                相关资源
                最近更新 更多