【问题标题】:Showing a correct legend when doing scatter plot with palette使用调色板进行散点图时显示正确的图例
【发布时间】:2019-02-01 08:59:19
【问题描述】:

绘制散点图的愚蠢方法

假设我有一个包含 3 个类的数据,下面的代码可以给我一个带有正确图例的完美图表,我在其中按类绘制数据。

import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import make_blobs
import numpy as np

X, y = make_blobs()

X0 = X[y==0]
X1 = X[y==1]
X2 = X[y==2]

ax = plt.subplot(1,1,1)
ax.scatter(X0[:,0],X0[:,1], lw=0, s=40)
ax.scatter(X1[:,0],X1[:,1], lw=0, s=40)
ax.scatter(X2[:,0],X2[:,1], lw=0, s=40)
ax.legend(['0','1','2'])

绘制散点图的更好方法

但是,如果我有一个包含 3000 个类的数据集,则上述方法不再适用。 (你不会指望我写3000行对应每个类吧?) 所以我想出了下面的绘图代码。

num_classes = len(set(y))
palette = np.array(sns.color_palette("hls", num_classes))

ax = plt.subplot(1,1,1)
ax.scatter(X[:,0], X[:,1], lw=0, s=40, c=palette[y.astype(np.int)])
ax.legend(['0','1','2'])

这段代码很完美,我们可以只用 1 行绘制出所有的类。但是,这次的图例显示不正确。

问题

当我们使用以下方式绘制图形时,如何保持正确的图例?

ax.scatter(X[:,0], X[:,1], lw=0, s=40, c=palette[y.astype(np.int)])

【问题讨论】:

  • 我认为 Matplotlib 的散点图从未打算按颜色、宽度或大小进行分组:后一种选择是传达附加信息,实际上是第三或第四轴,但不是按数据分组。相反,您应该只遍历数据集,创建单独的散点图。在分配子组的地方使用数组或字典,或者实际上不分配子组,而是在循环条件时立即绘制它们。
  • 如果您有一个包含 3000 个类(或超过 20 个类)的数据集,那么您的标签和可读性问题与必须编写 3000 个几乎相同的行不同。

标签: python python-3.x matplotlib


【解决方案1】:

plt.legend() 在情节中有多个“艺术家”时效果最佳。在您的第一个示例中就是这种情况,这就是为什么调用 plt.legend(labels) 可以毫不费力地工作的原因。

如果您担心编写大量代码行,那么您可以利用 for 循环。

正如我们在这个使用 5 个类的示例中看到的:

import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
import numpy as np

X, y = make_blobs(centers=5)
ax = plt.subplot(1,1,1)

for c in np.unique(y):
    ax.scatter(X[y==c,0],X[y==c,1],label=c)

ax.legend()

np.unique() 返回 y 的唯一元素的排序数组,通过循环遍历这些元素并用自己的艺术家绘制每个类plt.legend() 可以轻松提供图例。

编辑:

您还可以在制作地块时为其分配标签,这可能更安全。

plt.scatter(..., label=c) 后跟plt.legend()

【讨论】:

    【解决方案2】:

    为什么不简单地执行以下操作?

    import matplotlib.pyplot as plt
    import seaborn as sns
    from sklearn.datasets import make_blobs
    import numpy as np
    
    X, y = make_blobs()
    ngroups = 3
    
    ax = plt.subplot(1, 1, 1)
    for i in range(ngroups):
        ax.scatter(X[y==i][:,0], X[y==i][:,1], lw=0, s=40, label=i)
    ax.legend()
    

    【讨论】:

    • 因为为大量点创建单个散点图比创建多个散点图更有效。
    • @ImportanceOfBeingErnest 是吗?那是怎么测量的?而且我必须说,我发现使用绘制一个空数组来在第二个副本的公认答案中创建句柄有点尴尬,而简单的循环更直接。
    • 感谢您的提问。这让我意识到在用单一颜色绘制散点图时有一个优化。因此,如果总散点的数量非常大,则循环中单个颜色的少量散点确实比具有多种颜色的单个散点更有效。更有效的是使用plot 而不是scatter
    猜你喜欢
    • 2023-01-12
    • 2018-12-20
    • 1970-01-01
    • 1970-01-01
    • 2021-08-10
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多