【问题标题】:increase the linewidth of the legend lines in matplotlib增加 matplotlib 中图例线的线宽
【发布时间】:2012-03-31 04:48:37
【问题描述】:

我知道,如果我更改线条的线宽,它会在图例中自动更新。 但是我想只更改图例线宽而不影响绘图。

【问题讨论】:

    标签: python matplotlib legend


    【解决方案1】:

    下面是一个简单的例子:

    import numpy as np
    import matplotlib.pyplot as plt
    
    # make some data
    x = np.linspace(0, 2*np.pi)
    y1 = np.sin(x)
    y2 = np.cos(x)
    
    # plot sin(x) and cos(x)
    p1 = plt.plot(x, y1, 'b-', linewidth=1.0)
    p2 = plt.plot(x, y2, 'r-', linewidth=1.0)
    
    # make a legend for both plots
    leg = plt.legend([p1, p2], ['sin(x)', 'cos(x)'], loc=1)
    
    # set the linewidth of each legend object
    for legobj in leg.legendHandles:
        legobj.set_linewidth(2.0)
    
    plt.show()
    

    【讨论】:

      【解决方案2】:

      @Brendan Wood 的方法使用pyplot 提供的api。在 matplotlib 中,object oriented style using axes is prefered。以下是使用axes 方法实现此目的的方法。

      import numpy as np
      import matplotlib.pyplot as plt
      
      # make some data
      x = np.linspace(0, 2*np.pi)
      y1 = np.sin(x)
      y2 = np.cos(x)
      
      fig, ax = plt.subplots()
      ax.plot(x, y1, linewidth=1.0, label='sin(x)')
      ax.plot(x, y2, linewidth=1.0, label='cos(x)')
      leg = ax.legend()
      
      for line in leg.get_lines():
          line.set_linewidth(4.0)
      
      plt.show()
      

      产生的情节如下图所示,

      【讨论】:

        【解决方案3】:

        默认情况下,图例包含线条本身。因此,改变画布中线条的线宽也会改变图例中的线条(反之亦然,因为它们本质上是同一个对象)。

        一种可能的解决方案是使用画布上的艺术家副本并仅更改副本的线宽。

        import numpy as np
        import matplotlib.pyplot as plt
        import copy
        
        x = np.linspace(0, 2*np.pi)
        y1 = np.sin(x)
        y2 = np.cos(x)
        fig = plt.figure()
        ax  = fig.add_subplot(111)
        ax.plot(x, y1, c='b', label='y1',linewidth=1.0)
        ax.plot(x, y2, c='r', label='y2')
        
        # obtain the handles and labels from the figure
        handles, labels = ax.get_legend_handles_labels()
        # copy the handles
        handles = [copy.copy(ha) for ha in handles ]
        # set the linewidths to the copies
        [ha.set_linewidth(7) for ha in handles ]
        # put the copies into the legend
        leg = plt.legend(handles=handles, labels=labels)
        
        plt.savefig('leg_example')
        plt.show()
        

        另一种选择是使用handler_map 和更新功能。这在某种程度上是自动的,指定处理程序映射会自动使图例中的任何线宽 7 磅。

        import numpy as np
        import matplotlib.pyplot as plt
        from matplotlib.legend_handler import HandlerLine2D
        
        x = np.linspace(0, 2*np.pi)
        y1 = np.sin(x)
        y2 = np.cos(x)
        fig = plt.figure()
        ax  = fig.add_subplot(111)
        ax.plot(x, y1, c='b', label='y1',linewidth=1.0)
        ax.plot(x, y2, c='r', label='y2')
        
        linewidth=7
        def update(handle, orig):
            handle.update_from(orig)
            handle.set_linewidth(7)
        
        plt.legend(handler_map={plt.Line2D : HandlerLine2D(update_func=update)})
        
        plt.show()
        

        结果同上。

        【讨论】:

        • 很好,我之前一直在寻找这个。希望它在这里被接受;]
        • @Alnitak 我用不同的选项更新了这个答案。
        【解决方案4】:

        如果您想更改绘图中的所有线条,定义您自己的图例处理程序可能会很有用:

        import matplotlib.pyplot as plt
        from matplotlib import legend_handler
        from matplotlib.lines import Line2D
        import numpy as np
        
        class MyHandlerLine2D(legend_handler.HandlerLine2D):
            def create_artists(self, legend, orig_handle,
                               xdescent, ydescent, width, height, fontsize,
                               trans):
        
                xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent,
                                                     width, height, fontsize)
        
                ydata = ((height-ydescent)/2.)*np.ones(xdata.shape, float)
                legline = Line2D(xdata, ydata)
        
                self.update_prop(legline, orig_handle, legend)
                #legline.update_from(orig_handle)
                #legend._set_artist_props(legline) # after update
                #legline.set_clip_box(None)
                #legline.set_clip_path(None)
                legline.set_drawstyle('default')
                legline.set_marker("")
                legline.set_linewidth(10)
        
        
                legline_marker = Line2D(xdata_marker, ydata[:len(xdata_marker)])
                self.update_prop(legline_marker, orig_handle, legend)
                #legline_marker.update_from(orig_handle)
                #legend._set_artist_props(legline_marker)
                #legline_marker.set_clip_box(None)
                #legline_marker.set_clip_path(None)
                legline_marker.set_linestyle('None')
                if legend.markerscale != 1:
                    newsz = legline_marker.get_markersize()*legend.markerscale
                    legline_marker.set_markersize(newsz)
                # we don't want to add this to the return list because
                # the texts and handles are assumed to be in one-to-one
                # correpondence.
                legline._legmarker = legline_marker
        
                return [legline, legline_marker]
        
        
        plt.plot( [0, 1], [0, 1], '-r', lw=1, label='Line' )
        plt.legend(handler_map={Line2D:MyHandlerLine2D()})
        
        plt.show()
        

        【讨论】:

          猜你喜欢
          • 2016-09-29
          • 1970-01-01
          • 2020-10-09
          • 2011-02-19
          • 2014-03-27
          • 1970-01-01
          • 2020-09-16
          • 2014-09-09
          • 1970-01-01
          相关资源
          最近更新 更多