简体   繁体   English

将图例添加到 Seaborn 点图

[英]Add Legend to Seaborn point plot

I am plotting multiple dataframes as point plot using seaborn .我正在使用seaborn将多个数据seaborn绘制为点图。 Also I am plotting all the dataframes on the same axis .我也在同一轴上绘制所有数据框。

How would I add legend to the plot ?我将如何在情节中添加图例?

My code takes each of the dataframe and plots it one after another on the same figure.我的代码获取每个数据框并在同一个图形上一个接一个地绘制它。

Each dataframe has same columns每个数据框都有相同的列

date        count
2017-01-01  35
2017-01-02  43
2017-01-03  12
2017-01-04  27 

My code :我的代码:

f, ax = plt.subplots(1, 1, figsize=figsize)
x_col='date'
y_col = 'count'
sns.pointplot(ax=ax,x=x_col,y=y_col,data=df_1,color='blue')
sns.pointplot(ax=ax,x=x_col,y=y_col,data=df_2,color='green')
sns.pointplot(ax=ax,x=x_col,y=y_col,data=df_3,color='red')

This plots 3 lines on the same plot.这在同一个图上绘制了 3 条线。 However the legend is missing.然而,传说不见了。 The documentation does not accept label argument . 该文档不接受label参数。

One workaround that worked was creating a new dataframe and using hue argument .一种有效的解决方法是创建一个新的数据框并使用hue argument

df_1['region'] = 'A'
df_2['region'] = 'B'
df_3['region'] = 'C'
df = pd.concat([df_1,df_2,df_3])
sns.pointplot(ax=ax,x=x_col,y=y_col,data=df,hue='region')

But I would like to know if there is a way to create a legend for the code that first adds sequentially point plot to the figure and then add a legend.但我想知道是否有一种方法可以为代码创建图例,该代码首先向图中添加顺序点图,然后添加图例。

Sample output :示例输出:

Seaborn 图像

I would suggest not to use seaborn pointplot for plotting.我建议不要使用 seaborn pointplot进行绘图。 This makes things unnecessarily complicated.这使事情变得不必要地复杂。
Instead use matplotlib plot_date .而是使用 matplotlib plot_date This allows to set labels to the plots and have them automatically put into a legend with ax.legend() .这允许为绘图设置标签,并使用ax.legend()将它们自动放入图例中。

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

date = pd.date_range("2017-03", freq="M", periods=15)
count = np.random.rand(15,4)
df1 = pd.DataFrame({"date":date, "count" : count[:,0]})
df2 = pd.DataFrame({"date":date, "count" : count[:,1]+0.7})
df3 = pd.DataFrame({"date":date, "count" : count[:,2]+2})

f, ax = plt.subplots(1, 1)
x_col='date'
y_col = 'count'

ax.plot_date(df1.date, df1["count"], color="blue", label="A", linestyle="-")
ax.plot_date(df2.date, df2["count"], color="red", label="B", linestyle="-")
ax.plot_date(df3.date, df3["count"], color="green", label="C", linestyle="-")

ax.legend()

plt.gcf().autofmt_xdate()
plt.show()

在此处输入图片说明


In case one is still interested in obtaining the legend for pointplots, here a way to go: 如果仍然有兴趣获得点图的图例,这里有一种方法:

 sns.pointplot(ax=ax,x=x_col,y=y_col,data=df1,color='blue') sns.pointplot(ax=ax,x=x_col,y=y_col,data=df2,color='green') sns.pointplot(ax=ax,x=x_col,y=y_col,data=df3,color='red') ax.legend(handles=ax.lines[::len(df1)+1], labels=["A","B","C"]) ax.set_xticklabels([t.get_text().split("T")[0] for t in ax.get_xticklabels()]) plt.gcf().autofmt_xdate() plt.show()

Old question, but there's an easier way.老问题,但有一个更简单的方法。

sns.pointplot(x=x_col,y=y_col,data=df_1,color='blue')
sns.pointplot(x=x_col,y=y_col,data=df_2,color='green')
sns.pointplot(x=x_col,y=y_col,data=df_3,color='red')
plt.legend(labels=['legendEntry1', 'legendEntry2', 'legendEntry3'])

This lets you add the plots sequentially, and not have to worry about any of the matplotlib crap besides defining the legend items.这使您可以按顺序添加图,而不必担心除了定义图例项之外的任何 matplotlib 废话。

I tried using Adam B's answer, however, it didn't work for me.我尝试使用 Adam B 的答案,但是,它对我不起作用。 Instead, I found the following workaround for adding legends to pointplots.相反,我找到了以下解决方法来向点图添加图例。

import matplotlib.patches as mpatches
red_patch = mpatches.Patch(color='#bb3f3f', label='Label1')
black_patch = mpatches.Patch(color='#000000', label='Label2')

In the pointplots, the color can be specified as mentioned in previous answers.在点图中,可以按照前面的答案中所述指定颜色。 Once these patches corresponding to the different plots are set up,一旦设置了对应于不同图的这些补丁,

plt.legend(handles=[red_patch, black_patch])

And the legend ought to appear in the pointplot.并且图例应该出现在点图中。

This goes a bit beyond the original question, but also builds on @PSub 's response to something more general---I do know some of this is easier in Matplotlib directly, but many of the default styling options for Seaborn are quite nice, so I wanted to work out how you could have more than one legend for a point plot (or other Seaborn plot) without dropping into Matplotlib right at the start.这又有点超出了原来的问题,同时也建立在@PSub的东西更普遍反应---我知道在Matplotlib一些这方面是比较容易直接,但许多默认样式Seaborn选项都相当不错,所以我想工作,你怎么有一个情节点(或其他Seaborn积)超过一个传说,而不落入Matplotlib在一开始。

Here's one solution:这是一种解决方案:


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

# We will need to access some of these matplotlib classes directly
from matplotlib.lines import Line2D # For points and lines
from matplotlib.patches import Patch # For KDE and other plots
from matplotlib.legend import Legend

from matplotlib import cm

# Initialise random number generator
rng = np.random.default_rng(seed=42)

# Generate sample of 25 numbers
n = 25
clusters = []

for c in range(0,3):
    
    # Crude way to get different distributions
    # for each cluster
    p = rng.integers(low=1, high=6, size=4)
    
    df = pd.DataFrame({
        'x': rng.normal(p[0], p[1], n),
        'y': rng.normal(p[2], p[3], n),
        'name': f"Cluster {c+1}"
    })
    clusters.append(df)

# Flatten to a single data frame
clusters = pd.concat(clusters)

# Now do the same for data to feed into
# the second (scatter) plot... 
n = 8
points = []

for c in range(0,2):
    
    p = rng.integers(low=1, high=6, size=4)
    
    df = pd.DataFrame({
        'x': rng.normal(p[0], p[1], n),
        'y': rng.normal(p[2], p[3], n),
        'name': f"Group {c+1}"
    })
    points.append(df)

points = pd.concat(points)

# And create the figure
f, ax = plt.subplots(figsize=(8,8))

# The KDE-plot generates a Legend 'as usual'
k = sns.kdeplot(
    data=clusters,
    x='x', y='y',
    hue='name',
    shade=True,
    thresh=0.05,
    n_levels=2,
    alpha=0.2,
    ax=ax,
)

# Notice that we access this legend via the
# axis to turn off the frame, set the title, 
# and adjust the patch alpha level so that
# it closely matches the alpha of the KDE-plot
ax.get_legend().set_frame_on(False)
ax.get_legend().set_title("Clusters")
for lh in ax.get_legend().get_patches(): 
    lh.set_alpha(0.2)

# You would probably want to sort your data 
# frame or set the hue and style order in order
# to ensure consistency for your own application
# but this works for demonstration purposes
groups  = points.name.unique()
markers = ['o', 'v', 's', 'X', 'D', '<', '>']
colors  = cm.get_cmap('Dark2').colors

# Generate the scatterplot: notice that Legend is
# off (otherwise this legend would overwrite the 
# first one) and that we're setting the hue, style,
# markers, and palette using the 'name' parameter 
# from the data frame and the number of groups in 
# the data.
p = sns.scatterplot(
    data=points,
    x="x",
    y="y",
    hue='name',
    style='name',
    markers=markers[:len(groups)],
    palette=colors[:len(groups)],
    legend=False,
    s=30,
    alpha=1.0
)

# Here's the 'magic' -- we use zip to link together 
# the group name, the color, and the marker style. You
# *cannot* retreive the marker style from the scatterplot
# since that information is lost when rendered as a 
# PathCollection (as far as I can tell). Anyway, this allows
# us to loop over each group in the second data frame and 
# generate a 'fake' Line2D plot (with zero elements and no
# line-width in our case) that we can add to the legend. If
# you were overlaying a line plot or a second plot that uses
# patches you'd have to tweak this accordingly.
patches = []
for x in zip(groups, colors[:len(groups)], markers[:len(groups)]):
    patches.append(Line2D([0],[0], linewidth=0.0, linestyle='', 
                   color=x[1], markerfacecolor=x[1],
                   marker=x[2], label=x[0], alpha=1.0))

# And add these patches (with their group labels) to the new
# legend item and place it on the plot.
leg = Legend(ax, patches, labels=groups, 
             loc='upper left', frameon=False, title='Groups')
ax.add_artist(leg);

# Done
plt.show();

Here's the output:这是输出: 2 使用 Seaborn 的传奇

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM