Repository: matplotlib/matplotlib
File: lib/matplotlib/animation.py (Python)

Code before:
            writer = writer_cls(fps, **writer_kwargs)
        _log.info('Animation.save using %s', type(writer))

        if 'bbox_inches' in savefig_kwargs:
            _log.warning("Warning: discarding the 'bbox_inches' argument in "
                         "'savefig_kwargs' as it may cause frame size "
                         "to vary, which is inappropriate for animation.")
            savefig_kwargs.pop('bbox_inches')

        # Create a new sequence of frames for saved data. This is different
        # from new_frame_seq() to give the ability to save 'live' generated
        # frame information to be saved later.
        # TODO: Right now, after closing the figure, saving a movie won't work
        # since GUI widgets are gone. Either need to remove extra code to
        # allow for this non-existent use case or find a way to make it work.

        def _pre_composite_to_white(color):
            r, g, b, a = mcolors.to_rgba(color)
            return a * np.array([r, g, b]) + 1 - a

        # canvas._is_saving = True makes the draw_event animation-starting
        # callback a no-op; canvas.manager = None prevents resizing the GUI
        # widget (both are likewise done in savefig()).
        with (writer.saving(self._fig, filename, dpi),
              cbook._setattr_cm(self._fig.canvas, _is_saving=True, manager=None)):
            if not getattr(writer, '_supports_transparency', False):
                facecolor = savefig_kwargs.get('facecolor',
                                               mpl.rcParams['savefig.facecolor'])
                if facecolor == 'auto':
                    facecolor = self._fig.get_facecolor()
                savefig_kwargs['facecolor'] = _pre_composite_to_white(facecolor)
                savefig_kwargs['transparent'] = False   # just to be safe!

            for anim in all_anim:
                anim._init_draw()  # Clear the initial frame
            frame_number = 0
            # TODO: Currently only FuncAnimation has a save_count
            #       attribute. Can we generalize this to all Animations?
            save_count_list = [getattr(a, '_save_count', None)
                               for a in all_anim]
            if None in save_count_list:
                total_frames = None
            else:
                total_frames = sum(save_count_list)
            for data in zip(*[a.new_saved_frame_seq() for a in all_anim]):
                for anim, d in zip(all_anim, data):
                    # TODO: See if turning off blit is really necessary
                    anim._draw_next_frame(d, blit=False)
                    if progress_callback is not None:
                        progress_callback(frame_number, total_frames)
                        frame_number += 1

Review comment (suggestion):
Let's not make dynamic attributes, instead add `_supports_transparency` to the writer base class.

I'm also a bit wary of using a property. This sounds like a static setting of the writer, but logically may depend on the file type and codec. I suggest to turn this into a function to communicate that it's not a pure state but inherently a computed quantity.


Code after:
                _log.warning("MovieWriter %s unavailable; using Pillow "
                             "instead.", writer)
            writer = writer_cls(fps, **writer_kwargs)
        _log.info('Animation.save using %s', type(writer))

        if 'bbox_inches' in savefig_kwargs:
            _log.warning("Warning: discarding the 'bbox_inches' argument in "
                         "'savefig_kwargs' as it may cause frame size "
                         "to vary, which is inappropriate for animation.")
            savefig_kwargs.pop('bbox_inches')

        # Create a new sequence of frames for saved data. This is different
        # from new_frame_seq() to give the ability to save 'live' generated
        # frame information to be saved later.
        # TODO: Right now, after closing the figure, saving a movie won't work
        # since GUI widgets are gone. Either need to remove extra code to
        # allow for this non-existent use case or find a way to make it work.

        def _pre_composite_to_white(color):
            r, g, b, a = mcolors.to_rgba(color)
            return a * np.array([r, g, b]) + 1 - a

        # canvas._is_saving = True makes the draw_event animation-starting
        # callback a no-op; canvas.manager = None prevents resizing the GUI
        # widget (both are likewise done in savefig()).
        with (writer.saving(self._fig, filename, dpi),
              cbook._setattr_cm(self._fig.canvas, _is_saving=True, manager=None)):
            if not writer._supports_transparency():
                facecolor = savefig_kwargs.get('facecolor',
                                               mpl.rcParams['savefig.facecolor'])
                if facecolor == 'auto':
                    facecolor = self._fig.get_facecolor()
                savefig_kwargs['facecolor'] = _pre_composite_to_white(facecolor)
                savefig_kwargs['transparent'] = False   # just to be safe!

            for anim in all_anim:
                anim._init_draw()  # Clear the initial frame
            frame_number = 0
            # TODO: Currently only FuncAnimation has a save_count
            #       attribute. Can we generalize this to all Animations?
            save_count_list = [getattr(a, '_save_count', None)
                               for a in all_anim]
            if None in save_count_list:
                total_frames = None
            else:
                total_frames = sum(save_count_list)
            for data in zip(*[a.new_saved_frame_seq() for a in all_anim]):
                for anim, d in zip(all_anim, data):
                    # TODO: See if turning off blit is really necessary
                    anim._draw_next_frame(d, blit=False)
                    if progress_callback is not None: