更改比例时的绘图显示将抛出错误:“第1帧的绘图填充比例与第一帧的填充比例具有不同的限制。”

2024-09-30 16:26:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图使用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)

enter image description here

当我尝试在第一个绘图上强制缩放时,它不起作用。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'))

尽管在scale_color_manual()中明确说明了3,但该图仅显示了两个色标:

enter image description here

然后在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()中所做的那样吗?此外(虽然不太重要),关于为什么plotninegeom_point()填充,而ggplot2geom_point()col填充,有什么想法吗


Tags: therunposdfplotstatus错误fill
1条回答
网友
1楼 · 发布于 2024-09-30 16:26:36

在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

相关问题 更多 >