I am making an animated gif of heatmaps using pillow. As there are a lot of different values and each frame can only have 256 colors I was hoping pillow would give me a different palette per frame. But it seems it isn't using most of the available colors. Here is a MWE:
from PIL import Image
import seaborn as sns
import io
import matplotlib.pyplot as plt
import scipy
import math
import numpy as np
import imageio
vmin = 0
vmax = 0.4
images = []
for i in range(3):
mu = 0
variance = i+0.1
sigma = math.sqrt(variance)
x = np.linspace(mu - 3*sigma, mu + 3*sigma, 400)
row = scipy.stats.norm.pdf(x, mu, sigma)
matrix = []
for i in range(400):
matrix.append(row)
cmap = "viridis"
hmap = sns.heatmap(matrix, vmin=vmin, vmax=vmax, cmap=cmap, cbar=False)
hmap.set_xticks(range(0, 101, 4))
buffer = io.BytesIO()
plt.savefig(buffer, format='png')
buffer.seek(0)
images.append(Image.open(buffer))
plt.clf()
images[0].save("out.gif", save_all=True, duration=1000, loop=1, append_images=images[1:])
The animated gif produced is:
You can see that later frames use fewer than 256 colors. If I look at the palettes with
identify -verbose out.gif|grep Colors
I get these:
If I save png's instead we can see the third frame, for example, has many more than 19 colors.
What am I doing wrong?
Matplotlib is making palette images and that is causing PIL to carry on down the same track. Give PIL more latitude by using:
images.append(Image.open(buffer).convert('RGB')
and you'll get: