I'm trying to create an animated gif that takes a python graph in something like the plt.style.use('dark_background') (i.e black background with white text) and fades it to something like the default style (ie. white background with black text).
The above is the result of running the below. You'll see that it doesn't quite work because the area around the plot area and legend area stubbornly remains white. I've tried numerous variations on the below, but can't figure it out.
I'm also trying to get it not to loop. The repeat=False doesn't seem to do it. But that's a secondary issue. The main one is: how do I get the background of the figure to change its color during an animation?
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
import matplotlib as mpl
# Data for the plot
x1 = np.linspace(1,100)
y1 = np.sin(x1)
#####################################
# STEP 1: FADE TO WHITE - FAILED
#####################################
# Create the figure and axis
fig, ax = plt.subplots()
# Plot the data
line1, = ax.plot(x1, y1, label='sin')
# Set the title and axis labels
ax.set_title('Title')
ax.set_xlabel('x axis')
ax.set_ylabel('y axis')
# Add a legend
#ax.legend(loc='right')
legend = ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.subplots_adjust(right=0.79)
# Function to update the plot for the animation
def update1(frame):
if frame>=noFrames:
frame=noFrames-1
startWhite = tuple([(noFrames-frame-1)/(noFrames-1)]*3)
startBlack = tuple([frame/(noFrames-1)]*3)
ax.cla()
# Plot the data
line1, = ax.plot(x1, y1, label='sin')
# Set the title and axis labels
ax.set_title('Title',color=startWhite)
ax.set_xlabel('X Axis',color=startWhite)
ax.set_ylabel('Y Axis',color=startWhite)
# Add a legend
#ax.legend(loc='right')
legend = ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.subplots_adjust(right=0.79)
fig.patch.set_color(None)
fig.patch.set_facecolor(startBlack)
ax.patch.set_facecolor(startBlack)
fig.patch.set_edgecolor(startBlack)
fig.patch.set_color(startBlack)
plt.rcParams['axes.facecolor'] = startBlack
plt.rcParams['axes.edgecolor'] = startBlack
plt.rcParams['axes.labelcolor'] = startWhite
plt.rcParams['axes.titlecolor'] = startWhite
plt.rcParams['legend.facecolor'] = startBlack
plt.rcParams['legend.edgecolor'] = startWhite
plt.rcParams['legend.labelcolor'] = startWhite
plt.rcParams['figure.facecolor'] = startBlack
plt.rcParams['figure.edgecolor'] = startBlack
plt.rcParams['xtick.color'] = startWhite
plt.rcParams['ytick.color'] = startWhite
plt.rcParams['text.color'] = startWhite
fig.canvas.draw_idle()
return fig,
noFrames = 50
# Create the animation
ani = animation.FuncAnimation(fig, update1, frames=range(noFrames*5), blit=False, repeat=False)
ani.event_source.stop() #stop the looping
# Save the animation as a GIF
ani.save('TEST01_fade.gif', writer='pillow', fps=10)
plt.close()
I couldn't figure out how to make the figure facecolor transition, but a workaround is to use a single subfigure, and adjust the facecolor of that. I also set the color properties directly on the artists rather than using rcParams as I think there is sometimes inconsistency about exactly when rcParams get applied (e.g. when the artist is created or when the artist is drawn). Rather than clear the axes and re-add everything, I just keep the original artists where possible. Legend does not seem to have the required set
methods so I re-create that, but Legend always replaces the existing one anyway (as do the title and x-, y-labels).
Tested with Matplotlib v3.8.2.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
# Data for the plot
x1 = np.linspace(1,100)
y1 = np.sin(x1)
#######################
# STEP 1: FADE TO WHITE
#######################
# Create the figure, subfigure and axis
fig = plt.figure()
sfig = fig.subfigures()
ax = sfig.add_subplot()
# Plot the data
line1, = ax.plot(x1, y1, label='sin')
# Set the title and axis labels
ax.set_title('Title')
ax.set_xlabel('x axis')
ax.set_ylabel('y axis')
# Add a legend
legend = ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.subplots_adjust(right=0.79)
# Function to update the plot for the animation
def update1(frame):
if frame>=noFrames:
frame=noFrames-1
startWhite = tuple([(noFrames-frame-1)/(noFrames-1)]*3)
startBlack = tuple([frame/(noFrames-1)]*3)
# Update background colours
sfig.set_facecolor(startBlack)
ax.set_facecolor(startBlack)
# Set the title and axis labels
ax.set_title('Title',color=startWhite)
ax.set_xlabel('X Axis',color=startWhite)
ax.set_ylabel('Y Axis',color=startWhite)
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.,
facecolor=startBlack, edgecolor=startWhite, labelcolor=startWhite)
# Update tick/label colours
ax.tick_params(color=startWhite, labelcolor=startWhite)
# Update spine colours
ax.spines[:].set_color(startWhite)
noFrames = 50
# Create the animation
ani = animation.FuncAnimation(fig, update1, frames=range(noFrames*5), blit=False, repeat=False)
# Save the animation as a GIF
ani.save('TEST01_fade.gif', writer='pillow', fps=10)
plt.close()