我正在寻找一种可以通过添加到现有绘图对象来修改绘图的方法。例如,我想在工作图中的特定日期添加注释,但想要一种构建基本图表的标准方法,然后如果我决定稍后“添加”注释。
以 Altair 为例可能更容易展示我想要的内容:
import altair as alt
import plotnine as plt
data = pd.DataFrame([
{'x': 0, 'y': 0},
{'x': 2, 'y': 1},
{'x': 3, 'y': 4}
])
events = pd.DataFrame([
{'x': 1, 'y': 3, 'label': 'the one'}
])
base = alt.Chart(data).mark_line().encode(
x='x',
y='y'
)
annotate = (
alt.Chart(events).mark_text().encode(
x='x',
y='y',
text='label'
) + alt.Chart(events).mark_rule().encode(
x='x', color=alt.value('red')
)
)
# display
base + annotate
做我想要的。
我也可以制作函数
def make_base_plot(data):
return alt.Chart(data).mark_line().encode(x='x', y='y')
def make_annotations(events):
return (
alt.Chart(events).mark_text().encode(
x='x',
y='y',
text='label'
) + alt.Chart(events).mark_rule().encode(
x='x', color=alt.value('red')
)
)
这使我能够在没有注释的情况下绘制基础数据,或者稍后提供注释消息,或者为绘图的目标受众编辑事件。
如果我想“一次性”完成此操作,我将如何创建此图:
import altair as alt
import plotnine as plt
data = pd.DataFrame([
{'x': 0, 'y': 0},
{'x': 2, 'y': 1},
{'x': 3, 'y': 4}
])
events = pd.DataFrame([
{'x': 1, 'y': 3, 'label': 'the one'}
])
(
p9.ggplot(data, p9.aes(x='x', y='y'))
+ p9.geom_line(color='blue')
+ p9.theme_bw()
+ p9.geom_text(mapping=p9.aes(x='x', y='y', label='label'), data=events)
+ p9.geom_vline(mapping=p9.aes(xintercept='x'), data=events, color='red')
)
然而,两种“自然”的分解尝试都失败了:
...
# This part is fine
base = (
p9.ggplot(data, p9.aes(x='x', y='y'))
+ p9.geom_line(color='blue')
+ p9.theme_bw()
)
# So is this
annotations = (
p9.ggplot(data, p9.aes(x='x', y='y'))
+ p9.geom_text(mapping=p9.aes(x='x', y='y', label='label'), data=events)
+ p9.geom_vline(mapping=p9.aes(xintercept='x'), data=events, color='red')
)
# This fails
base + annotations
# Error message
# AttributeError: 'ggplot' object has no attribute '__radd__'
当我尝试创建
annotations
对象时,在没有 p9.ggplot
对象启动的情况下尝试此操作会失败。我的问题是,如何分解plotnine中的图形语法,以便我可以让函数创建我可以组成的通用组件,类似于Altair?
我知道另一种方法是创建一个具有两个输入(
annotations
和
data
)的函数并一次性执行此操作,但这意味着在为图表创建模板时,我必须预测我想要的所有未来注释make,如果我想从图表模板构建。events
(请参阅
此处)类似,您可以或必须使用列表将绘图的创建分解为多个部分,其中每个部分由多个组件或层组成:
ggplot2
import plotnine as p9
import pandas as pd
data = pd.DataFrame([
{'x': 0, 'y': 0},
{'x': 2, 'y': 1},
{'x': 3, 'y': 4}
])
events = pd.DataFrame([
{'x': 1, 'y': 3, 'label': 'the one'}
])
base = (
p9.ggplot(data, p9.aes(x='x', y='y'))
+ p9.geom_line(color='blue')
+ p9.theme_bw()
)
annotations = [
p9.geom_text(mapping=p9.aes(x='x', y='y', label='label'), data=events),
p9.geom_vline(mapping=p9.aes(xintercept='x'), data=events, color='red')
]
base + annotations
重写您的
altair
函数,如下所示:plotnine