【问题标题】:Matplotlib Scatterplot Point Size LegendMatplotlib 散点图点大小图例
【发布时间】:2017-04-03 15:58:39
【问题描述】:

以下是使用 matplotlib 的散点图生成附加图像的少量代码。

我试图获得一个“图例”,它显示几个点的大小和相应的“z 值”。

自己建的少,有这样的吗?类似于颜色条的“大小”?

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(8,6))
inset = fig.add_subplot(111)

np.random.seed(0) # so the image is reproducible
x1 = np.random.rand(30)
y1 = np.random.rand(30)
z1 = np.random.rand(30)


axis = inset.scatter(x1,y1,s=z1*100,c=z1,vmin=0,vmax=1)

inset.set_xlabel("X axis")
inset.set_ylabel("Y axis")

cbar = fig.colorbar(axis,ticks=[0,0.5,1])
cbar.ax.set_yticklabels(["Low","Medium","High"])

plt.savefig('scatterplot-zscale.png',bbox_inches='tight')

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    要获得图例,您需要在至少一个数据点上调用scatter 时传递关键字label。一种方法是从数据中选择 3 个代表点,然后使用标签再次将它们添加到图中。

    import matplotlib.pyplot as plt
    import numpy as np
    
    np.random.seed(0) # so the image is reproducible
    x1 = np.random.rand(30)
    y1 = np.random.rand(30)
    z1 = np.random.rand(30)
    
    fig = plt.figure(figsize=(8,6))
    inset = fig.add_subplot(111)
    # i prefer no outlines on the dots, so edgecolors='none'
    axis = inset.scatter(x1,y1,s=z1*100,c=z1,vmin=0,vmax=1,edgecolors='none')
    
    inset.set_xlabel("X axis")
    inset.set_ylabel("Y axis")
    
    cbar = fig.colorbar(axis,ticks=[0,0.5,1])
    cbar.ax.set_yticklabels(["Low","Medium","High"])
    
    # here we step over the sorted data into 4 or 5 strides and select the 
    # last 3 steps as a representative sample, this only works if your 
    # data is fairly uniformly distributed
    legend_sizes = np.sort(z1)[::len(z1)//4][-3:]
    
    # get the indices for each of the legend sizes
    indices = [np.where(z1==v)[0][0] for v in legend_sizes]
    
    # plot each point again, and its value as a label
    for i in indices:
        inset.scatter(x1[i],y1[i],s=100*z1[i],c=z1[i], vmin=0,vmax=1,edgecolors='none',
                      label='{:.2f}'.format(z1[i]))
    # add the legend
    inset.legend(scatterpoints=1)
    

    【讨论】:

    • 效果很好。谢谢!
    【解决方案2】:

    * 上的一个更新的答案提供了一个更简单的解决方案。 creating a matplotlib scatter legend size related

    使用 .legend_elements("sizes"):

    import matplotlib.pyplot as plt
    import numpy as np
    
    fig = plt.figure(figsize=(8,6))
    inset = fig.add_subplot(111)
    
    np.random.seed(0) # so the image is reproducible
    x1 = np.random.rand(30)
    y1 = np.random.rand(30)
    z1 = np.random.rand(30)
    
    
    axis = inset.scatter(x1,y1,s=z1*100,c=z1,vmin=0,vmax=1)
    
    inset.set_xlabel("X axis")
    inset.set_ylabel("Y axis")
    
    cbar = fig.colorbar(axis,ticks=[0,0.5,1])
    cbar.ax.set_yticklabels(["Low","Medium","High"])
    
    plt.legend(*axis.legend_elements("sizes", num=5), loc = 'upper right')
    
    plt.savefig('scatterplot-zscale.png',bbox_inches='tight')
    

    Figure with size legend

    【讨论】:

      【解决方案3】:

      上述解决方案创建的尺寸图例在美学上与颜色条不一致。

      要以与颜色条相同的格式显示尺寸信息,您可以在颜色条轴旁边创建一个新轴并在该轴上绘制一些示例标记,如下所示。

      import matplotlib.pyplot as plt
      import numpy as np
      
      fig = plt.figure(figsize=(8,6))
      inset = fig.add_subplot(111)
      
      np.random.seed(0) # so the image is reproducible
      x1 = np.random.rand(30)
      y1 = np.random.rand(30)
      z1 = np.random.rand(30)
      
      
      axis = inset.scatter(x1,y1,s=z1*100,c=z1,vmin=0,vmax=1)
      
      inset.set_xlabel("X axis")
      inset.set_ylabel("Y axis")
      
      cbar = fig.colorbar(axis,ticks=[0,0.5,1])
      cbar.ax.set_yticklabels(["Low","Medium","High"])
      
      legend_values = np.sort(z1)[::len(z1)//4][-3:]
      
      # get the indices for each of the legend sizes
      indices = [np.where(z1==v)[0][0] for v in legend_values]
      
      # Create new axis to record size legend
      
      # Get bounds of colorbar axis
      xmin, ymin, dx, dy = cbar.ax.get_position().bounds
      
      # Create new axis that is shorter but hase same width and aligns with the top of the colourbar axis
      xmin = xmin+0.11
      ymin = ymin+dy - dy/3
      dx = dx
      dy = dy/3
      sax = fig.add_axes([xmin, ymin, dx, dy])
      
      # Plot legend size entries onto this axis
      x = [0]*len(legend_values)
      y = range(len(legend_values))
      sizes = legend_values*100
      sax.scatter(x, y, s = sizes, c = 'black', edgecolors = 'none', marker = 'o')
      
      # Add y axis labels and remove x ticks
      sax.yaxis.set_label_position("right")
      sax.yaxis.tick_right()
      sax.set_yticks(y)
      sax.set_yticklabels(np.round_(legend_values, decimals=1), fontdict = {'size':11})
      sax.set_ylabel('Z', rotation=0, labelpad = 10, fontdict = {'size':11})
      sax.set_xticks([])
      
      # remove spines
      for pos in ['right', 'top', 'bottom', 'left']:
          sax.spines[pos].set_visible(False)
      
      plt.savefig('scatterplot-zscale.png',bbox_inches='tight')
      

      Figure with colorbar and 'sizebar'

      【讨论】: