0

我正在尝试使用gganimate(R)等效plotnine项(python)。当其中一个情节引入新的美学比例类别时,我遇到了问题,导致控制台抛出错误:The fill scale of plot for frame 1 has different limits from those of the first frame.

这似乎是必须生成所有图的生成器然后将它们粘在一起的结果 - 根据 plotnine 文档(https://plotnine.readthedocs.io/en/stable/generated/plotnine.animation.PlotnineAnimation。 html ). 当我使用gganimate()图书馆时,它足够聪明,可以知道检查所有将被调用的比例并相应地打印完整的比例。

我尝试使用scale_fill_manual()将比例强制到第一个图上作为处理此问题的一种方式,但它不起作用(在 R 或 python 中)。

我正在 plotnine 中寻找解决此问题的方法(如果在 python 中有更好的动画模块,我可以了解,如果有建议)。

这是一个工作示例:

首先在plotnine中尝试:

#import modules
import pandas as pd
from plotnine import *
from plotnine.animation import PlotnineAnimation
#create the dataframe
df = pd.DataFrame({'run': [1, 1, 1, 2, 2, 2], 
             'x_pos': [1, 2, 3, 2, 3, 4], 
             'y_pos': [4, 5, 6, 5, 6, 7], 
             'status': ['A', 'B', 'A', 'A', 'B', 'C'] })

#write a function that creates all the plots
def plot(x):
    df2 = df[df['run'] == x]

    p = (ggplot(df2,
               aes(x = 'x_pos', y = 'y_pos', fill = 'status'))
         + geom_point()
    )
    return(p)

#save the plots as a generator as per the plotnine docs (https://plotnine.readthedocs.io/en/stable/generated/plotnine.animation.PlotnineAnimation.html)
plots = (plot(i) for i in range(1, 3))

#create the animation
animation = PlotnineAnimation(plots, interval=100, repeat_delay=500)

抛出错误:PlotnineError: 'The fill scale of plot for frame 1 has different limits from those of the first frame.'

如果我在 R 中执行此操作,使用gganimate(),一切正常 - 我从一开始就获得了所有三个色阶:

library('ggplot2')
library('gganimate')

df <- data.frame(run = c(1, 1, 1, 2, 2, 2), 
                 x_pos = c(1, 2, 3, 2, 3, 4), 
                 y_pos = c(4, 5, 6, 5, 6, 7), 
                 status = c('A', 'B', 'A', 'A', 'B', 'C'))

ggplot(df, aes(x = x_pos, y = y_pos, col = status)) + 
  geom_point() + 
  transition_states(run)

在此处输入图像描述

当我尝试在第一个情节上强制比例时它不起作用。R中的第一个:

library(dplyr)

df %>%
  filter(run == 1) %>%
  ggplot(aes(x = x_pos, y = y_pos, col = status)) + 
  geom_point() + 
  scale_color_manual(labels = c('A', 'B', 'C'), 
                     values = c('red', 'green', 'blue'))

该图仅显示两个色阶 - 尽管明确指出 3 in scale_color_manual()

在此处输入图像描述

然后在 Python 中:

#Filter the data frame created above
df2 = df[df['run'] == 1]

#Create the plot - stating scale_fill_manual()
p = (ggplot(df2,
        aes(x = 'x_pos', y = 'y_pos', fill = 'status'))
 + geom_point()
 + scale_fill_manual(labels = ['A', 'B', 'C'], 
                    values = ['red', 'blue', 'green'])
)

#Print the plot
print(p)

引发有关数组长度错误 ( ValueError: arrays must all be same length) 的错误,这是有道理的:我要求的值和颜色比过滤数据集中的值和颜色多。这意味着我不能让第一帧与第二帧匹配,这是我要解决的错误。

任何人都知道如何使它工作plotnine,它的方式gganimate()吗?此外(虽然不太重要),关于为什么plotnine需要 fill geom_point(),而ggplot2需要 col 的任何想法geom_point()

4

1 回答 1

1

在 python 中,你应该做status一个分类,最好是具体的并设置美学的限制xy如果你把它留给绘图系统,它可能会弄错。

在 Plotnine 中,所有关键的绘图形状geom_point都有内部区域和周围的笔划,因此您可以使用fillcolor定位其中任何一个。但这是一个复杂的细节,很可能会让用户感到沮丧,所以当你映射到color而不是fill它时,它会为两者设置相同的颜色。在这两者之间,Plotnine 不承认缩写col

import pandas as pd
from plotnine import *
from plotnine.animation import PlotnineAnimation

#create the dataframe
df = pd.DataFrame({'run': [1, 1, 1, 2, 2, 2], 
             'x_pos': [1, 2, 3, 2, 3, 4], 
             'y_pos': [4, 5, 6, 5, 6, 7], 
             'status': ['A', 'B', 'A', 'A', 'B', 'C'] })

# A categorical ensures that each of the sub-dataframes
# can be used to create a scale with the correct limits
df['status'] = pd.Categorical(df['status'])

#write a function that creates all the plots
def plot(x):
    df2 = df[df['run'] == x]

    p = (ggplot(df2,
               aes(x = 'x_pos', y = 'y_pos', color = 'status'))
         + geom_point()
         # Specify the limits for the x and y aesthetics
         + scale_x_continuous(limits=(df.x_pos.min(), df.x_pos.max()))
         + scale_y_continuous(limits=(df.y_pos.min(), df.y_pos.max()))
         + theme(subplots_adjust={'right': 0.85}) # Make space for the legend
        )
    return(p)


plots = (plot(i) for i in range(1, 3))

#create the animation
animation = PlotnineAnimation(plots, interval=1000, repeat_delay=500)
animation
于 2020-05-16T20:13:11.100 回答