【问题标题】:Seaborn scatterplot set hollow markers instead of filled markersSeaborn 散点图设置空心标记而不是填充标记
【发布时间】:2021-02-28 00:46:56
【问题描述】:

使用 Seaborn 散点图,如何将标记设置为空心圆而不是实心圆?

这是一个简单的例子:

import pandas as pd
import seaborn as sns

df = pd.DataFrame(
    {'x': [3,2,5,1,1,0],
     'y': [1,1,2,3,0,2],
     'cat': ['a','a','a','b','b','b']}
)

sns.scatterplot(data=df, x='x', y='y', hue='cat')

我尝试了以下但没有成功;其中大多数不会引发错误,而是会产生与上面相同的图。我认为这些不起作用,因为颜色是使用 hue 参数设置的,但我不确定修复方法是什么。

sns.scatterplot(data=df, x='x', y='y', hue='cat', facecolors = 'none')
sns.scatterplot(data=df, x='x', y='y', hue='cat', facecolors = None)
sns.scatterplot(data=df, x='x', y='y', hue='cat', markerfacecolor = 'none')
sns.scatterplot(data=df, x='x', y='y', hue='cat', markerfacecolor = None)

with sns.plotting_context(rc={"markerfacecolor": None}):
    sns.scatterplot(data=df, x='x', y='y', hue='cat')

【问题讨论】:

  • 看看这个链接:stackoverflow.com/questions/62778123/… - 在 matplotlib 中实现这一点的标准方法是将 facecolor 设置为 none
  • @MichelGokan 我试过了,但它不适用于 Seaborn:'PathCollection' object has no property 'markerfacecolor' 并且仅使用 facecolor='none'facecolor=None 会产生与 OP 中显示的相同的图
  • 我认为当facecolor 为“无”时,seaborn 将色调变量映射到边缘颜色是合理的。这需要一些深思熟虑,并且可能比一开始看起来更复杂,但如果你在 github 上提出问题,我会支持它。

标签: python seaborn scatter-plot


【解决方案1】:

原则上,您应该能够使用fillstyle="none" 创建一个圆形标记,但那里有一些deep complications,目前它不能像您希望的那样工作。

最简单的纯 seaborn 解决方案是利用您可以使用任意乳胶符号作为标记的事实:

sns.scatterplot(data=df, x='x', y='y', hue="cat", marker="$\circ$", ec="face", s=100)

这有点受限,因为您无法控制圆的厚度。

混合 seaborn-matplotlib 方法更灵活,但也更麻烦(您需要自己创建图例):

palette = {"a": "C0", "b": "C1"}
kws = {"s": 70, "facecolor": "none", "linewidth": 1.5}

ax = sns.scatterplot(
    data=df, x='x', y='y',
    edgecolor=df["cat"].map(palette),
    **kws,
)
handles, labels = zip(*[
    (plt.scatter([], [], ec=color, **kws), key) for key, color in palette.items()
])
ax.legend(handles, labels, title="cat")

第三种选择是使用FacetGrid。这不太灵活,因为情节必须在自己的图中。但这相当简单;另一个答案使用FacetGrid,但它有点过度设计,因为它忘记了hue_kws 参数:

palette = ["C0", "C1"]
g = sns.FacetGrid(
    data=df, hue="cat",
    height=4, aspect=1.25,
    hue_kws={"edgecolor": palette},
)
g.map(plt.scatter, "x", "y", facecolor="none", lw=1.5)
g.add_legend()

【讨论】:

    【解决方案2】:

    有时*,退回到 matplotlib 功能更容易:

    import matplotlib.pyplot as plt
    import pandas as pd
    
    df = pd.DataFrame({'x': [3,2,5,2,1,0],
                       'y': [1,1,2,3,0,2],
                       'cat': ['a','a','a','b','b','b']})
    
    fig, ax = plt.subplots()
    m_colors = ["blue", "tab:orange", "red", "green"]
    
    for (cat, group), col in zip(df.groupby("cat"), m_colors):
        ax.scatter(group.x, group.y, edgecolors=col, facecolors="none", alpha=0.7, label=cat)
    
    ax.legend(title="empty circles")
    plt.show()
    

    示例输出:

    *seaborn 和 pandas 非常适合他们提供的服务。但是我看到了很多例子,人们认为“这很容易,所以简单地添加 XYZ 功能应该很容易”,然后最终得到复杂的代码,如果他们首先在基本 matplotlib 中编写代码会简单得多地点。

    【讨论】:

      【解决方案3】:

      我使用seaborn.FacetGrid 修改了您的代码如下(基于@cphlewis 此处提供的code):

      import pandas as pd
      import seaborn as sns
      import matplotlib.pyplot as plt
      
      x1 = [3,2,5]
      y1 = [1,1,2]
      x2 = [1,1,0]
      y2 = [3,0,2]
      
      df1 = pd.DataFrame({'x1':x1, 'y1':y1})
      df2 = pd.DataFrame({'x2':x2, 'y2':y2})
      
      df = pd.concat([df1.rename(columns={'x1':'x','y1':'y'})
                      .join(pd.Series(['a']*len(df1), name='df')),
                      df2.rename(columns={'x2':'x','y2':'y'})
                      .join(pd.Series(['b']*len(df2), name='df'))],
                     ignore_index=True)
      
      pal = dict(a="blue", b="red")
      
      g = sns.FacetGrid(df, hue='df', palette=pal, size=5)
      
      g.map(plt.scatter, "x", "y", s=50, alpha=.7,
            linewidth=.5,
            facecolors = 'none',
            edgecolor=['red', 'blue'])
      
      markers = [plt.Line2D([0,0],[0,0], markeredgecolor=pal[key],
                            marker='o', markerfacecolor='none',
                            mew=0.3,
                            linestyle='')
                  for key in pal]
      
      plt.legend(markers, pal.keys(), numpoints=1, title="cat")
      plt.show()
      

      结果如下:

      【讨论】:

        【解决方案4】:

        基于一个类似的问题 (How to get markers with no fill, from seaborn 0.11+),这里有一个很好的新方法来处理这个问题:

        首先,定义您的颜色图。其次,设置适当的色调并在调色板和边缘颜色参数中指定颜色图。

        penguins = sns.load_dataset("penguins")
        
        colormap = {"Adelie": "purple", "Chinstrap": "orange", "Gentoo": "green"}
        
        sns.jointplot(
            data=penguins,
            x="bill_length_mm",
            y="bill_depth_mm",
            hue="species",
            palette=colormap,
            ec=penguins["species"].map(colormap),
            fc="none",
        )
        

        【讨论】:

          猜你喜欢
          • 2019-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-27
          • 1970-01-01
          • 2016-07-26
          • 2022-01-16
          • 1970-01-01
          相关资源
          最近更新 更多