您可以创建一个额外的列,其中每个值都四舍五入到所需的界限之一。该新列可用于 sizes 和 hue。要更新图例,值位于边界列表中;该值本身和前一个值构成了新的图例标签。
以下代码说明了简化测试数据的概念。
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
from scipy import interpolate
df = pd.DataFrame({'val': np.arange(1, 61),
'x': np.arange(60) % 10,
'y': np.arange(60) // 10 * 10})
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(16, 5))
sns.scatterplot(data=df, x="x", y="y", hue='val', palette='flare',
size='val', sizes=(100, 300), legend='full', ax=ax1)
sns.move_legend(ax1, loc='center left', bbox_to_anchor=(1.01, 0.5), ncol=6, title='Sizes')
ax1.set_title('using the given values')
# create an extra column with the values rounded up towards one of the bounds
bounds = [0, 5, 10, 20, 40, 60]
round_to_bound = interpolate.interp1d(bounds, bounds, kind='next', fill_value='extrapolate', bounds_error=False)
df['rounded'] = round_to_bound(df['val']).astype(int)
sns.scatterplot(data=df, x="x", y="y", hue='rounded', palette='flare',
size='rounded', sizes=(100, 300), ax=ax2)
sns.move_legend(ax2, loc='center left', bbox_to_anchor=(1.01, 0.5), ncol=1, title='Sizes')
for t in ax2.legend_.texts:
v = int(t.get_text())
t.set_text(f"{bounds[bounds.index(v) - 1]} - {v}")
ax2.set_title('rounding up the values towards given bounds')
sns.despine()
plt.tight_layout()
plt.show()
视情况而定,将海上传说与其他元素结合起来可能会很复杂。如果你只是在 seaborn 散点图之上添加一个熊猫图,它似乎效果很好。在这种情况下,pandas 向现有图例添加了一个新元素,可以在末尾通过sns.move_legend() 移动它。
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
from scipy import interpolate
df = pd.DataFrame({'val': np.arange(1, 61),
'x': np.arange(60) % 10,
'y': np.arange(60) // 10 * 10})
fig, ax = plt.subplots(figsize=(16, 5))
# create an extra column with the values rounded up towards one of the bounds
bounds = [0, 5, 10, 20, 40, 60]
round_to_bound = interpolate.interp1d(bounds, bounds, kind='next', fill_value='extrapolate', bounds_error=False)
df['rounded'] = round_to_bound(df['val']).astype(int)
sns.scatterplot(data=df, x="x", y="y", hue='rounded', palette='flare',
size='rounded', sizes=(100, 300), ax=ax)
for t in ax.legend_.texts:
v = int(t.get_text())
t.set_text(f"{bounds[bounds.index(v) - 1]} - {v}")
# add a pandas plot on top, which extends the legend
xs = np.linspace(0, 9, 200)
ys = np.random.randn(len(xs)).cumsum() * 2 + 25
dams_clip = pd.DataFrame({'dams_ys': ys}, index=xs)
dams_clip.plot(ax=ax, color="Red", linewidth=0.5, markersize=150, zorder=3)
sns.move_legend(ax, loc='center left', bbox_to_anchor=(1.01, 0.5), ncol=1, title='Sizes')
sns.despine()
plt.tight_layout()
plt.show()