首页 > 解决方案 > 如何根据列条件在python中调整文本来绘制不同的颜色和样式

问题描述

我有以下数据,df

name   age    weight    is_friend
Joe     23      180           0
Jane    27      150           1
Josh    20      200           1

我想为我的朋友( )的人的点和文本着色。is_friend==1我能够做到这一点,但需要对数据进行子集化并制作两个不同的图。请看下面的代码:

#subset
friend = df[(df.is_friend==1)
not_friend = df[(~df.is_friend==1)

#plot 1
ax.scatter(friend['age'], friend['weight'], alpha=.7, color='red')

texts = [plt.text(x0,y0,name,ha='right',va='bottom',color='red',style='italic') for x0,y0,name in zip(friend['age'], friend['weight'], friend.name)]

adjust_text(texts)

#plot 2
ax.scatter(not_friend['age'], not_friend['weight'],color='black')

texts1 = [plt.text(x0,y0,name,ha='right',va='bottom') for x0,y0,name in zip(not_friend['age'], not_friend['weight'], not_friend.name)]

adjust_text(texts1)

如上所示,我必须对数据进行子集化,并为点和标签创建两个不同颜色和样式的图。这有效,但也有例外:

由于有两个不同的adjustText对象,因此它们不能相互配合。的重点adjustText是调整文本,使标签看起来不错,但是,有多个数据点,标签来自textstexts1重叠,因为它们不是来自同一个对象并且相互考虑。有关不同数据的示例,请参见下文。

在此处输入图像描述

我想知道我是否可以使用一个if else语句来不仅缩短此代码,而且确保没有点重叠。这是我尝试导致错误的方法:

if df['is_friend'] == 1:
  texts = [plt.text(x0,y0,name,ha='right',va='bottom',color='red',style='italic') for x0,y0,name in zip(df['age'], df['weight'], df.name)]
else:
  texts = [plt.text(x0,y0,name,ha='right',va='bottom') for x0,y0,name in zip(df['age'], df['weight'], df.name)]

adjust_text(texts))

但是,我得到了错误

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

同样,我正在尝试更改adjustText对象中某些标签和点的颜色,而不必创建两个不同的图,因此可能会出现重叠点,并且由于更多代码而导致运行时间更长。我真的很感激这里的任何帮助。谢谢!

标签: pythonpandasmatplotlib

解决方案


正如@JohanC 评论的那样,连接两个文本可以解决您的问题。但是,调用scatter一次当然更理想。您可以根据您的朋友逻辑制作一个颜色列表,并将其传递给scatterand text

fig = plt.figure()
ax = fig.add_subplot(111)

cond_color, cond_alpha, cond_style = [], [], []
for f in df['is_friend']:
    cond_color.append('r' if f==1 else 'grey')
    cond_alpha.append(0.2 if f==1 else 1)
    cond_style.append('italic' if f==1 else None)

cond_color2 = np.asarray([(*mpl_c.to_rgb(c), a) for c,a in zip(cond_color, cond_alpha)])
ax.scatter(df['age'], df['weight'], c=cond_color2)

texts = [plt.text(x0, y0, name, color=c, style=sty) for x0,y0,name,c,sty in zip(df['age'], df['weight'], df.index, cond_color, cond_style)]
plt.show()

推荐阅读