Seaborn线图:注释最后一个值

时间:2020-07-02 17:59:06

标签: matplotlib seaborn

我想通过使用subplot绘制2个图形。 我有一个数据框(simple_line_final_df)

    Madagascar Covid-19 Totaly olona
Daty        
2020-05-20  Marary  371
2020-05-20  Sitrana 131
2020-05-20  Tsaboana    238
2020-05-21  Marary  405
2020-05-21  Sitrana 131
... ... ...
2020-06-28  Sitrana 944
2020-06-28  Tsaboana    1116
2020-06-29  Marary  2138
2020-06-29  Sitrana 966
2020-06-29  Tsaboana    1152

我的目标是在lineplot中显示最后一个值(图1):

具有以下代码:

fig ,axes = plt.subplots(ncols=1,nrows=2,constrained_layout=True)

# # ------------------------------Plot first figure --------------------------------------------
palette = ['#F70A0A','#2A930C','#930C85']
sns.set(rc={'figure.figsize':(30,15)},palette= palette, font_scale=1.7)
# # pour les axes 

ax1 = sns.lineplot(x=simple_line_final_df.index,y= 'Totaly olona',data=simple_line_final_df,hue='Madagascar Covid-19',style='Madagascar Covid-19',markers=True,dashes=False,ax=axes[0])

# style 
sns.set_style("darkgrid" , {"ytick.major.size": 10 , "ytick.minor.size": 2 , 'grid.linestyle': '--'})
plt.xticks(rotation=90)
plt.xlabel('Daty', fontsize = 20)
plt.ylabel('Totaly olona', fontsize = 20)
plt.minorticks_on()
plt.legend(loc='upper left')
plt.grid(b=True, which='minor', color='#999999', linestyle='-', alpha=0.2 , axis='y')
ax1.set_ylim(0)
last_index = simple_line_final_df.last_valid_index()
ax1.set_xlim(simple_line_final_df.first_valid_index(),simple_line_final_df.last_valid_index())

# -----------------Put annotation ----------
# for line , name in zip (ax1.lines ,simple_line_final_df['Madagascar Covid-19']):
#     y = line.get_ydata()[-1]
#     #ax.annotate(y,xy=(1,y),xytext=(6,0),color=line.get_color(),size=14,xycoords = ax.get_yaxis_transform(),textcoords ="offset points")
#     ax1.annotate(y,xy=(last_index,y),color=line.get_color())

#  ------------------------------Plot second figure barplot  --------------------------------------------

sns.set(rc={'figure.figsize':(30,15)},palette=['#F70A0A','#2A930C','#930C85'], font_scale=1.7)
# pour les axes 
ax = sns.barplot(x=df_final_seaborn.index,y='Isan\'ny olona',data=df_final_seaborn,hue='Covid-19 Madagascar',ax=axes[1])
sns.set_style("darkgrid" , {"ytick.major.size": 10 , "ytick.minor.size": 2 , 'grid.linestyle': '--'})
plt.xticks(rotation=90)
plt.xlabel('Daty', fontsize = 20)
plt.ylabel('Isan\'ny olona', fontsize = 20)
plt.minorticks_on()
plt.legend(loc='upper left')
plt.grid(b=True, which='minor', color='#999999', linestyle='-', alpha=0.2 , axis='y')
ax.xaxis.set_major_formatter(plt.FixedFormatter(df_sea.index.to_series().dt.strftime("%Y-%m-%d")))
for patch in ax.patches:
    x , width , height = patch.get_x(),patch.get_width(),patch.get_height()
    color = patch.get_facecolor()
    #ignore . and nan values 
    if height is None or height ==0:continue
      
    
    ax.text(x+width/2,height+0.1,height.astype(int),ha='center',color=color)
    
plt.show()

结果是: :No handles with labels found to put in legend.

如您所见,它不会显示最后一个值,因为我在注释中添加了批注代码

enter image description here

但是当我通过取消注释注释部分添加以下代码时:

# -----------------Put annotation ----------
for line , name in zip (ax1.lines ,simple_line_final_df['Madagascar Covid-19']):
    y = line.get_ydata()[-1]
    ax1.annotate(y,xy=(last_index,y),color=line.get_color())

结果是图2消失了:

,并显示以下消息: enter image description here

enter image description here

问题是这一行:y = line.get_ydata()[-1]

我尝试通过以下代码来解决注释:首先获取最后一个值(索引错误)而不是最后一个

for x , y in zip(simple_line_final_df.index,simple_line_final_df['Totaly olona'].loc[simple_line_final_df.last_valid_index()]):
    
    print(x,y)
    #ax.annotate(y,xy=(1))
    #ax.annotate(y,xy=(x,y),color=line.get_color())
    ax.text(x,y,f'{y:.2f}')

出:

2020-05-20 00:00:00 2138
2020-05-20 00:00:00 966
2020-05-20 00:00:00 1152

enter image description here

以下是解决方法:

palette = ['#F70A0A','#2A930C','#930C85']
sns.set(rc={'figure.figsize':(30,15)},palette= palette, font_scale=1.7)
# Plot lines 
ax = sns.lineplot(x=simple_line_final_df.index,y= 'Totaly olona',data=simple_line_final_df,hue='Madagascar Covid-19',style='Madagascar Covid-19',markers=True,dashes=False)

# styling figure 
#sns.set_style("darkgrid" , {"ytick.major.size": 10 , "ytick.minor.size": 2 , 'grid.linestyle': '--'})
ax.set_ylim(0)
ax.set_xlim(simple_line_final_df.first_valid_index(),simple_line_final_df.last_valid_index())
#ax.set_ylim(simple_line_final_df.last_valid_index())
plt.xticks(rotation=90)
plt.xlabel('Daty', fontsize = 20)
plt.ylabel('Totaly olona', fontsize = 20)
plt.minorticks_on()
plt.legend(loc='upper left')
plt.grid(b=True, which='minor', color='#999999', linestyle='-', alpha=0.2 , axis='y')
# for annotation 

for value in ax.lines:
    y = value.get_ydata()
    if len(y)>0:
        ax.annotate(f'{y[-1]:.2f}',xy=(1,y[-1]),xycoords=('axes fraction','data'),ha='left',va='center',color=value.get_color())
plt.show()

enter image description here

1 个答案:

答案 0 :(得分:2)

lineplot创建一些用于图例的空Line2D对象,因此line.get_data()返回一个空数组。如果您查看ax1.lines,应该看到它包含6-7个对象,而不是您期望的3个。一种解决方法是在提取数据之前测试该行是否为空:

fmri = sns.load_dataset('fmri')
ax1 = sns.lineplot(x="timepoint", y="signal", hue="event",
                      data=fmri, ci=None)
for l in ax1.lines:
    y = l.get_ydata()
    if len(y)>0:
        ax1.annotate(f'{y[-1]:.2f}', xy=(1,y[-1]), xycoords=('axes fraction', 'data'), 
                     ha='left', va='center', color=l.get_color())

enter image description here