I am trying to use the gganimate
(R) equivalent, plotnine
(python). I run into problems when one of the plots introduces a new aesthetic scale category, causing the console to throw the error: The fill scale of plot for frame 1 has different limits from those of the first frame.
This appears to be the result of having to produce a generator of all the plots and then stick them together - as per the plotnine documentation (https://plotnine.readthedocs.io/en/stable/generated/plotnine.animation.PlotnineAnimation.html). When I use gganimate()
the library is smart enough to know to check all the scales that will be called and print the complete scale accordingly.
I tried using scale_fill_manual()
to force a scale onto the first plot as a way to deal with this, but it doesn't work (in R or python).
I am looking for a way around this in plotnine (if there is a way better animation module in python i can learn that if there are suggestions).
Here is a worked example:
First trying in 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)
Throws the error: PlotnineError: 'The fill scale of plot for frame 1 has different limits from those of the first frame.'
If I do this in R, using gganimate()
, everything works fine - I get all three color scales from the start:
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)
When i try forcing the scale on the first plot it doesn't work. First in 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'))
The plot shows with just the two color scales - despite explicitly stating 3 in scale_color_manual()
:
Then in 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)
Throws errors about the arrays being the wrong length (ValueError: arrays must all be same length
), which makes sense: I am asking for more values and colors than are in the filtered dataset. That means that I cannot have the first frame match the second frame, which is the error i am trying to solve.
Anyone know how to make this work with plotnine
, the way it does in gganimate()
? Further (though less important), any ideas as to why plotnine
takes fill for geom_point()
, while ggplot2
takes col for geom_point()
?