Plotnine (ggplot) :绘图区域外的注释
Plotnine (ggplot) : Annotation outside of plotting area
我在 plotnine
中有以下情节。我想添加一个标签,显示 y 轴左侧的系列平均值(基本上与 y 轴标签一致)。如果标签的形状可以如下所示,指向中线,那就更好了。这可能吗?
import numpy as np
import pandas as pd
import datetime
from plotnine import *
df = pd.DataFrame({
'date':pd.date_range(start='1/1/2000', periods=10, freq='A'),
'a': np.random.choice(range(20),10),
'b': np.random.choice(range(20),10),
})
mean_a = df['a'].mean()
mean_b = df['b'].mean()
df = pd.melt(df,id_vars=['date'])
p = (ggplot(df, aes(x='date', y='value', fill='variable'))
+ theme_light()
+ geom_col(position='dodge', alpha=0.8)
+ geom_hline(yintercept=mean_a, linetype='dotted', color='#770d50', size=1.5)
+ geom_hline(yintercept=mean_b, linetype='dotted', color='#0055b3', size=1.5)
+ annotate('label', x=datetime.datetime(2010, 10, 1), y=mean_a, label='{:.1f}'.format(mean_a), color='#770d50', size=8, label_size=0.2)
+ annotate('label', x=datetime.datetime(2010, 10, 1), y=mean_b, label='{:.1f}'.format(mean_b), color='#0055b3', size=8, label_size=0.2)
+ annotate('label', x=datetime.datetime(2011, 1, 1), y=mean_b, label='')
+ scale_x_date(expand=(0,0), labels= lambda l: [v.strftime("%Y") for v in l])
+ scale_fill_manual(('#770d50','#0055b3'))
)
p
如here所述,您可以使用 ggplot 对象的 draw
方法获取 matplotlib 图。然后,您可以使用轴和传统的 matplotlib 函数使用 ax.text
或 ax.annotate
函数绘制所需的注释,如下所示。您可能需要尝试使用文本的实际 x 位置。
# original graph
p = (ggplot(df, aes(x='date', y='value', fill='variable'))
+ theme_light()
+ geom_col(position='dodge', alpha=0.8)
+ geom_hline(yintercept=mean_a, linetype='dotted', color='#770d50', size=1.5)
+ geom_hline(yintercept=mean_b, linetype='dotted', color='#0055b3', size=1.5)
+ annotate('label', x=datetime.datetime(2010, 10, 1), y=mean_a, label='{:.1f}'.format(mean_a), color='#770d50', size=8, label_size=0.2)
+ annotate('label', x=datetime.datetime(2010, 10, 1), y=mean_b, label='{:.1f}'.format(mean_b), color='#0055b3', size=8, label_size=0.2)
+ annotate('label', x=datetime.datetime(2011, 1, 1), y=mean_b, label='')
+ scale_x_date(expand=(0,0), labels= lambda l: [v.strftime("%Y") for v in l])
+ scale_fill_manual(('#770d50','#0055b3'))
)
# graph with annotation
fig = p.draw() # get the matplotlib figure object
ax = fig.axes[0] # get the matplotlib axis (may be more than one if faceted)
x_ticks = ax.get_xticks() # get the original x tick locations
x_loc = x_ticks.min() - (sorted(x_ticks)[1] - sorted(x_ticks)[0])*.75 # location for the annotation based on the original xticks
# annotation for mean_a using text
ax.text(x_loc,mean_a,'{:.2f}'.format(mean_a),
horizontalalignment='right',verticalalignment='center',
color='#770d50')
# annotation for mean_b using annotate with an arrow
ax.annotate(xy=(x_ticks.min(),mean_b),
xytext=(x_loc,mean_b+.5),text='{:.2f}'.format(mean_b),
horizontalalignment='right',verticalalignment='center',
arrowprops={'arrowstyle':'->'},
color='#0055b3')
我在 plotnine
中有以下情节。我想添加一个标签,显示 y 轴左侧的系列平均值(基本上与 y 轴标签一致)。如果标签的形状可以如下所示,指向中线,那就更好了。这可能吗?
import numpy as np
import pandas as pd
import datetime
from plotnine import *
df = pd.DataFrame({
'date':pd.date_range(start='1/1/2000', periods=10, freq='A'),
'a': np.random.choice(range(20),10),
'b': np.random.choice(range(20),10),
})
mean_a = df['a'].mean()
mean_b = df['b'].mean()
df = pd.melt(df,id_vars=['date'])
p = (ggplot(df, aes(x='date', y='value', fill='variable'))
+ theme_light()
+ geom_col(position='dodge', alpha=0.8)
+ geom_hline(yintercept=mean_a, linetype='dotted', color='#770d50', size=1.5)
+ geom_hline(yintercept=mean_b, linetype='dotted', color='#0055b3', size=1.5)
+ annotate('label', x=datetime.datetime(2010, 10, 1), y=mean_a, label='{:.1f}'.format(mean_a), color='#770d50', size=8, label_size=0.2)
+ annotate('label', x=datetime.datetime(2010, 10, 1), y=mean_b, label='{:.1f}'.format(mean_b), color='#0055b3', size=8, label_size=0.2)
+ annotate('label', x=datetime.datetime(2011, 1, 1), y=mean_b, label='')
+ scale_x_date(expand=(0,0), labels= lambda l: [v.strftime("%Y") for v in l])
+ scale_fill_manual(('#770d50','#0055b3'))
)
p
如here所述,您可以使用 ggplot 对象的 draw
方法获取 matplotlib 图。然后,您可以使用轴和传统的 matplotlib 函数使用 ax.text
或 ax.annotate
函数绘制所需的注释,如下所示。您可能需要尝试使用文本的实际 x 位置。
# original graph
p = (ggplot(df, aes(x='date', y='value', fill='variable'))
+ theme_light()
+ geom_col(position='dodge', alpha=0.8)
+ geom_hline(yintercept=mean_a, linetype='dotted', color='#770d50', size=1.5)
+ geom_hline(yintercept=mean_b, linetype='dotted', color='#0055b3', size=1.5)
+ annotate('label', x=datetime.datetime(2010, 10, 1), y=mean_a, label='{:.1f}'.format(mean_a), color='#770d50', size=8, label_size=0.2)
+ annotate('label', x=datetime.datetime(2010, 10, 1), y=mean_b, label='{:.1f}'.format(mean_b), color='#0055b3', size=8, label_size=0.2)
+ annotate('label', x=datetime.datetime(2011, 1, 1), y=mean_b, label='')
+ scale_x_date(expand=(0,0), labels= lambda l: [v.strftime("%Y") for v in l])
+ scale_fill_manual(('#770d50','#0055b3'))
)
# graph with annotation
fig = p.draw() # get the matplotlib figure object
ax = fig.axes[0] # get the matplotlib axis (may be more than one if faceted)
x_ticks = ax.get_xticks() # get the original x tick locations
x_loc = x_ticks.min() - (sorted(x_ticks)[1] - sorted(x_ticks)[0])*.75 # location for the annotation based on the original xticks
# annotation for mean_a using text
ax.text(x_loc,mean_a,'{:.2f}'.format(mean_a),
horizontalalignment='right',verticalalignment='center',
color='#770d50')
# annotation for mean_b using annotate with an arrow
ax.annotate(xy=(x_ticks.min(),mean_b),
xytext=(x_loc,mean_b+.5),text='{:.2f}'.format(mean_b),
horizontalalignment='right',verticalalignment='center',
arrowprops={'arrowstyle':'->'},
color='#0055b3')