如何在 seaborn 散点图中编辑多个图例框?

How can you edit multiple legend boxes in a seanborn scatter plot?

我想重命名并移动两个图例。我希望顶部图例位于图表的右上角,标题为 'Average Cost'。我希望第二个图例在图表之外,右下角,标题为 'Total Revenue'

figure = plt.figure(figsize=(10,5))
ax = sns.scatterplot(
        x=top_rev_mean['cost_of_the_order_y'],
        y='cost_of_the_order_x', 
        data=top_rev_mean, 
        size = "cost_of_the_order_x", 
        hue='cost_of_the_order_y'
    )
plt.ylabel('Total Order Revenue')
plt.xlabel('Average Order Cost Per Cuisine')
plt.show()

我想您正在使用这样的数据框:

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


N = 15
top_rev_mean = pd.DataFrame({'cost_of_the_order_y': 17.6 + 4*np.random.random(N),
                             'cost_of_the_order_x': 500 + 2000*np.random.random(N)})
    cost_of_the_order_y  cost_of_the_order_x
0             19.098160           866.809020
1             21.402857          1108.484486
2             20.527976          1549.512863
3             19.994634          1363.890037
4             18.224075          1082.458280
5             18.223978          1723.705789
6             17.832334           778.987721
7             21.064705          1084.289297
8             20.004460          1232.723687
9             20.432290          1412.139968
10            17.682338          2070.351923
11            21.479639           899.347564
12            20.929771          1528.468877
13            18.449356          1684.829138
14            18.327300           592.900825

当你设置散点图时,你必须确保绘制了图例,以便稍后获得句柄和标签,所以你需要将legend = True参数传递给seaborn.scatterplot

fig, ax = plt.subplots(figsize=(10,5))

sns.scatterplot(ax = ax, data = top_rev_mean, x = 'cost_of_the_order_y', y = 'cost_of_the_order_x', size = "cost_of_the_order_x", hue = 'cost_of_the_order_y', legend = True)

然后你可以提取当前图例的句柄和标签 ax.get_legend_handles_labels:

handles, labels = ax.get_legend_handles_labels()

现在您需要将第一个图例的元素与第二个图例的元素分开:

legend1 = {}
legend2 = {}
titles = {}

for handle, label in zip(handles, labels):
    if label.replace('.', '').isdigit() == False:
        titles[handle] = label
    else:
        if len(list(titles.keys())) == 1:
            legend1[handle] = label
        else:
            legend2[handle] = label

最后可以去掉seaborn绘制的图例,画出自己想要的两个图例:

ax.legend().remove()

upper_legend = ax.legend(handles = list(legend1.keys()), labels = list(legend1.values()), title = 'Average Cost', loc = 'upper left', bbox_to_anchor = (1.05, 1))
ax.add_artist(upper_legend)
lower_legend = ax.legend(handles = list(legend2.keys()), labels = list(legend2.values()), title = 'Total Revenue', loc = 'lower left', bbox_to_anchor = (1.05, 0))

完整代码

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


N = 15
top_rev_mean = pd.DataFrame({'cost_of_the_order_y': 17.6 + 4*np.random.random(N),
                             'cost_of_the_order_x': 500 + 2000*np.random.random(N)})


fig, ax = plt.subplots(figsize=(10,5))

sns.scatterplot(ax = ax, data = top_rev_mean, x = 'cost_of_the_order_y', y = 'cost_of_the_order_x', size = "cost_of_the_order_x", hue = 'cost_of_the_order_y', legend = True)

handles, labels = ax.get_legend_handles_labels()

legend1 = {}
legend2 = {}
titles = {}

for handle, label in zip(handles, labels):
    if label.replace('.', '').isdigit() == False:
        titles[handle] = label
    else:
        if len(list(titles.keys())) == 1:
            legend1[handle] = label
        else:
            legend2[handle] = label


ax.legend().remove()

upper_legend = ax.legend(handles = list(legend1.keys()), labels = list(legend1.values()), title = 'Average Cost', loc = 'upper left', bbox_to_anchor = (1.05, 1))
ax.add_artist(upper_legend)
lower_legend = ax.legend(handles = list(legend2.keys()), labels = list(legend2.values()), title = 'Total Revenue', loc = 'lower left', bbox_to_anchor = (1.05, 0))

ax.set_ylabel('Total Order Revenue')
ax.set_xlabel('Average Order Cost Per Cuisine')

plt.tight_layout()

plt.show()