1

I am trying to implement an option in my GUI to save an image sequence displayed using matplotlib. The code looks something like this:

import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import \
    FigureCanvasQTAgg as FigureCanvas
from matplotlib.animation import FuncAnimation
from PIL import Image


plt.rcParams['savefig.bbox'] = 'tight' 


class Printer:
    def __init__(self, data):
        self.fig, self.ax = plt.subplots()
        self.canvas = FigureCanvas(self.fig)

        # some irrelevant color adjustment here
        #self.ax.spines['bottom'].set_color('#f9f2d7')
        #self.ax.spines['top'].set_color('#f9f2d7')
        #self.ax.spines['right'].set_color('#f9f2d7')
        #self.ax.spines['left'].set_color('#f9f2d7')
        #self.ax.tick_params(axis='both', colors='#f9f2d7')
        #self.ax.yaxis.label.set_color('#f9f2d7')
        #self.ax.xaxis.label.set_color('#f9f2d7')
        #self.fig.subplots_adjust(left=0.1, right=0.975, bottom=0.09, top=0.98)
        self.fig.patch.set_alpha(0)
        self.fig.patch.set_visible(False)
        self.canvas.setStyleSheet("background-color:transparent;")
        self.fig.set_size_inches(10, 10, True)
        self.fig.tight_layout()

        self.data = data
        self.image_artist = self.ax.imshow(data[0])

    def animate(self, i):
        self.image_artist.set_data(self.data[i])
        self.canvas.draw()


def save_animation():
    data = [
        Image.open("test000.png"),
        Image.open("test001.png"),
    ]
    file = 'test.gif'
    printer = Printer(data)

    ani = FuncAnimation(
        printer.fig, printer.animate, interval=100, frames=len(data),
    )
    # writer = animation.writers['pillow'](bitrate=1000)
    ani.save(
        file, writer='pillow', savefig_kwargs={'transparent': True, 'bbox_inches': 'tight'}
    )


save_animation()

Transparency:

As you can see I have already tried several different approaches as suggested elsewhere (1, 2), but didn't manage to find a solution. All of the settings and arguments patch.set_alpha(0), patch.set_visible(False), canvas.setStyleSheet("background-color:transparent;"), savefig_kwargs={'transparent': True} seem to have no effect at all on the transparency. I found this post but I didn't get the code to work (for one I had to comment out this %matplotlib inline, but then I ended up getting some error during the MovieWriter.cleanup out = TextIOWrapper(BytesIO(out)).read() TypeError: a bytes-like object is required, not 'str'). Here, it was suggested that this is actually a bug, but the proposed workaroud doesn't work for me since I would have to rely on third-party software. There also exists this bug report which was supposedly solved, so maybe it is unrelated.

Tight layout

I actually couldn't really find much on this, but all the things I tried (plt.rcParams['savefig.bbox'] = 'tight', fig.tight_layout(), savefig_kwargs={'bbox_inches': 'tight'}) don't have any effect or are even actively discarded in the case of the bbox_inches argument. How does this work?

High quality

Since I cannot use ImageMagick and can't get ffmpeg to work (more on this below), I rely on pillow to save my animation. But the only argument in terms of quality that I can pass on seems to be the bitrate, which doesn't have any effect. The files still have the same size and the animation still looks like mush. The only way that I found to increase the resolution was to use fig.set_size_inches(10, 10, True), but this still doesn't improve the overall quality of the animation. It still looks bad. I saw that you can pass on codec and extra_args so maybe that is something that might help, but I have no idea how to use these because I couldn't find a list with allowed arguments.

ffmpeg

I can't get ffmpeg to work. I installed the python package from here and can import it into a python session but I don't know how I can get matplotlib to use that. I also got ffmpeg from here (Windows 64-bit version) and set the plt.rcParams['animation.ffmpeg_path'] to where I saved the files (there was no intaller to run, not sure if I did it correctly). But this didn't help either. Also this is of course also third-party software, so if somebody else were to use my code/program it wouldn't work.

mapf
  • 1,906
  • 1
  • 14
  • 40
  • 1
    You're mixing a lot of things here. So, Quality: Due to antialiasing there will always be some artifacts in transparent output. The best you can get at is most probably [this solution](https://stackoverflow.com/questions/38406617/mplot3d-animation-with-transparent-background), which you found already yourself. Of course you can reduce the artifacts by using a higher dpi. Transparency: It seems pillow writer cannot handle transparency as it stands. That may be considered a missing feature. In order to get ffmpeg to run you need to correctly install it. Not sure it can handle transparency though – ImportanceOfBeingErnest Nov 29 '19 at 16:04
  • Thanks for your reply! I know I am mixing several things but for me this is basically the one problem of getting the animation to work. Should I have rather made a new question for all the sub points? – mapf Dec 03 '19 at 09:27
  • That's pretty deflating that in a time where gifs are everywhere it's impossible to create something this basic with one of the most popular programing languages. I will stick to exporting image sequences then and use one of the many (online) tools to convert it to a gif. – mapf Dec 03 '19 at 09:35
  • 1
    At least "getting ffmpeg to work" and "tight_layout" are completely separate from getting a transparent high-quality animation. For both there is not enough information to know why it fails for you. "It's impossible..." is pretty exagerated, since even an answer exists for how to do it - just not the way you would have liked maybe. If something doesn't exist, it most probably means that there isn't high enough demand for it, but one can always create an issue at the tracker. – ImportanceOfBeingErnest Dec 03 '19 at 12:51
  • Well "tight_layout" also belongs to the same problem for me since I use it for displaying the images but it doesn't work anymore as soon as I try to export the animation. That's why I also included it in the title. But yes, it's not directly related to transparency or quality. So in the future I will make these separate issues. – mapf Dec 03 '19 at 14:24
  • I would stick to saying it's impossible to do it in Pyhton though because you have to rely on third-party software that is OS-dependent and not always straightforward to use/install. My application wouldn't run on another system without this software being installed. – mapf Dec 03 '19 at 14:34
  • 1
    Sure, you always have dependencies. Core Matplotlib would not run at all if freetype or libpng wasn't installed. Or here you use PyQt, for which you would also need to have the Qt bindings installed. So there is rarely anything which is "pure python". – ImportanceOfBeingErnest Dec 03 '19 at 14:43
  • That's true, though I don't really know about these dependencies. I never had to worry about them so I guess they come preinstalled on most systems? Many people (including me) do have problems getting ffmpeg or ImageMagick to work however. I guess my point is this: as a naive Python / matplotlib user I would expect the animation to work analog to how displaying single images work, i.e. all args, kwargs have the same effect. But it doesn't and I don't really know why. – mapf Dec 03 '19 at 15:07
  • I mean I can export an image sequence in matplotlib looking exactly the way I want it to and then later-on make an animation out of it. So I don't really understand why this 'making an animation out of the image sequence' part would work differently. But then again I don't know how gifs are made in the first place.. – mapf Dec 03 '19 at 15:09
  • Thanks for your input though! Maybe I'll have a look at how to make this an issue at the tracker. – mapf Dec 03 '19 at 15:11
  • 1
    That's what the solution I link to does. It creates a sequence of images, then calls imagemagick to produce the gif from it. There are other tools to create gifs as well. – ImportanceOfBeingErnest Dec 03 '19 at 15:13

0 Answers0