matplotlib 将省略号放在海运猫图上

2nc8po8w  于 2023-01-31  发布在  其他
关注(0)|答案(1)|浏览(154)

我有一个seaborn.catplot,如下所示:

我所要做的是用下面的规则来突出图形中的差异:

  • 如果A-B〉4,则将其着色为绿色
  • 如果A-B〈-1,则将其着色为红色
  • 如果A-B =〈2=且〉=0,则将其着色为蓝色

我期待着产生类似于下面的图像:

这里有一个MRE

# Stack Overflow Example
import numpy as np, pandas as pd, seaborn as sns
from random import choice
from string import ascii_lowercase, digits

chars = ascii_lowercase + digits
lst = [''.join(choice(chars) for _ in range(2)) for _ in range(100)]

np.random.seed(8)
t = pd.DataFrame(
    {
    'Key': [''.join(choice(chars) for _ in range(2)) for _ in range(5)]*2,
    'Value': np.random.uniform(low=1, high=10, size=(10,)), 
    'Type': ['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B']
    }
)

ax = sns.catplot(data=t, x='Value', y='Key', hue='Type', palette="dark").set(title="Stack Overflow Help Me")
plt.show()

我认为需要在关注点周围画一个省略号,我已经研究了一些问题:

但是似乎没有人特别针对catplot,或者定制它们的颜色和规则来这样做。
我怎样才能用我的玩具例子达到预期的效果?

ffscu2ro

ffscu2ro1#

你可以围绕A和B的中点创建椭圆,使用A和B之间的距离,加上一些填充,作为宽度。高度应该比1小一点。
要获得完整的轮廓和透明的内部颜色,可以使用to_rgba()。将zorder设置为一个较小的数字会将椭圆放置在散布点后面。
sns.scatterplotsns.catplot的轴级等效项,在只有一个子图时更易于使用。
使Key列的类型为pd.Categorical,可以在y位置和标签之间给出固定的关系。

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib.colors import to_rgba
import seaborn as sns
import pandas as pd
import numpy as np
from string import ascii_lowercase, digits

chars = ascii_lowercase + digits
num = 9
df = pd.DataFrame({'Key': [''.join(np.random.choice([*chars], 2)) for _ in range(num)] * 2,
                   'Value': np.random.uniform(low=1, high=10, size=2 * num),
                   'Type': np.repeat(['A', 'B'], num)})
df['Key'] = pd.Categorical(df['Key'])  # make the key categorical for a consistent ordering

sns.set_style('white')
ax = sns.scatterplot(data=df, x='Value', y='Key', hue='Type', palette="dark")
df_grouped = df.groupby(['Key', 'Type'])['Value'].mean().unstack()
for y_pos, y_label in enumerate(df['Key'].cat.categories):
    A = df_grouped.loc[y_label, 'A']
    B = df_grouped.loc[y_label, 'B']
    dif = A - B
    color = 'limegreen' if dif > 4 else 'crimson' if dif < -1 else 'dodgerblue' if 0 <= dif < 2 else None
    if color is not None:
        ell = Ellipse(xy=((A + B) / 2, y_pos), width=abs(dif) + 0.8, height=0.8,
                      fc=to_rgba(color, 0.1), lw=1, ec=color, zorder=0)
        ax.add_patch(ell)
plt.tight_layout()
plt.show()

相关问题