seaborn.lineplot 返回的带色调的 Line2D 对象代表什么?

med*_*nal 5 python matplotlib seaborn

import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd 

# generate data
rng = np.random.default_rng(12)

x = np.linspace(0, np.pi, 50)
y1, y2 = np.sin(x[:25]), np.cos(x[25:])
cat = rng.choice(["a", "b", "c"], 50)

data = pd.DataFrame({"x": x , "y" : y1.tolist() + y2.tolist(), "cat": cat})

# generate figure
fig, ax = plt.subplots(figsize=(8, 5), ncols=2)
g0 = sns.lineplot(x="x", y="y", data=data, hue='cat', ls="--", ax=ax[0])
g1 = sns.lineplot(x="x", y="y", data=data, hue='cat', ls="--", ax=ax[1])

g1.get_lines()[0].set_color('black')

print(ax[0].get_lines())

for line in ax[0].get_lines():
    print(line.get_label())

plt.tight_layout()
plt.show()
Run Code Online (Sandbox Code Playgroud)

这将返回一个列表:

<a list of 6 Line2D objects>
Run Code Online (Sandbox Code Playgroud)

其中前三个对象是图中左侧子图中的彩色虚线,通过更改右侧子图中其中一条线的颜色来确认。

在此输入图像描述

但我无法理解列表中最后三个 Line2D 对象是什么ax[0].get_lines()

如果我尝试使用访问 Line2D 对象的标签

[line.get_label() for line in ax[0].get_lines()]
Run Code Online (Sandbox Code Playgroud)

它给['_child0', '_child1', '_child2', 'b', 'a', 'c']

但列表中最后三个 Line2D 对象的行为与通常的 Line2D 对象不同,因为

  1. ax[0].get_lines()[-1].set_lw(0.2)没有改变图中任何可察觉的东西。
  2. 我预计ax[0].get_lines()[-1].remove() 会删除左侧子图中的绿色图例线,但它没有效果。

那么,列表中最后三个 Line2D 对象(其标签中ax[0].get_lines()没有该字符串)代表什么?_child

使用 matplotlib (v3.5.1) 和 seaborn (v0.11.2) 生成。

Joh*_*anC 4

这些是用于创建图例的虚拟线。由于选项众多,Seaborn 的传奇可能相当复杂。您可能想查看这个 github 问题,了解 Seaborn 试图创建比 matplotlib 目前允许的更复杂的图例。

如果在创建图例后更改这些虚拟线的属性,您将看不到效果。但是,之后再次创建图例将显示更改。

import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# generate data
rng = np.random.default_rng(12)

x = np.linspace(0, np.pi, 50)
y1, y2 = np.sin(x[:25]), np.cos(x[25:])
x = np.round(x / 2, 1) * 2
cat = rng.choice(["a", "b", "c"], 50)

data = pd.DataFrame({"x": x, "y": y1.tolist() + y2.tolist(), "cat": cat})

# generate figure
fig, ax = plt.subplots(figsize=(8, 5), ncols=2)
g0 = sns.lineplot(x="x", y="y", data=data, hue='cat', ls="--", ax=ax[0])
g1 = sns.lineplot(x="x", y="y", data=data, hue='cat', ls="--", ax=ax[1])

g1.get_lines()[0].set_color('black')
g1.get_lines()[3].set_color('purple')
g1.get_lines()[3].set_linewidth(5)
g1.legend()  # create the legend again

plt.tight_layout()
plt.show()
Run Code Online (Sandbox Code Playgroud)

虚拟线对象用于图例

PS:如果您只想更改图例符号(在matplotlib中称为“句柄”),您可以直接更改它们,例如:

for h in g1.legend_.legendHandles:
     h.set_linestyle("--")
Run Code Online (Sandbox Code Playgroud)

在此示例中,图例不会自动应用线条样式的原因是ls=参数直接发送到 matplotlib 以绘制线条,而不是发送到创建 seaborn 图例的代码。在未来的seaborn版本中,这个问题可能会得到解决。由于seaborn允许多种选项组合,因此要使所有这些组合都能令人满意地工作并非易事。另请参阅未决问题 2861

  • 很好的解释,但如果您想进行事后艺术家更新,最好从图例中获取艺术家,而不是在(重新)创建图例时用于填充它的艺术家。 (2认同)
  • 嗯,seaborn 是 matplotlib 周围的一层。查看例如 matplotlib 的 [图例指南](https://matplotlib.org/stable/tutorials/intermediate/legend_guide.html) 以获取更多信息。创建 matplotlib 图例的代码是“ax.legend()”。我现在添加了一些代码来直接更新图例句柄。 (2认同)