{"id":47,"date":"2022-02-18T15:31:33","date_gmt":"2022-02-18T15:31:33","guid":{"rendered":"http:\/\/www.pulsars.info\/wordpress\/?p=47"},"modified":"2022-02-18T15:41:15","modified_gmt":"2022-02-18T15:41:15","slug":"gif-animation-with-python","status":"publish","type":"post","link":"http:\/\/www.pulsars.info\/wordpress\/uncategorized\/gif-animation-with-python\/","title":{"rendered":"gif animation with Python"},"content":{"rendered":"\n<p>Sometimes the outcomes of our models are very complicated and are worth showing as a short video or animation. The best format for a short animation is a gif file. If the outcome is longer and contains more than ~100 frames it is better to use video format because they allow some additional compression. <\/p>\n\n\n\n<p>In the following example I demonstrate how to create a simple animation using Python. One of the best discussions is available <a href=\"https:\/\/towardsdatascience.com\/basics-of-gifs-with-pythons-matplotlib-54dd544b6f30\">here<\/a>. For the input function I will use the sinus with constantly increasing frequency.<\/p>\n\n\n\n<div class=\"wp-block-image is-style-default\"><figure class=\"aligncenter\"><img decoding=\"async\" src=\"http:\/\/pulsars.info\/ignotur\/wp-content\/uploads\/2021\/06\/sinus_gif.gif\" alt=\"\" class=\"wp-image-309\"\/><\/figure><\/div>\n\n\n\n<p>First we import all packages which we use:<\/p>\n\n\n\n<div style=\"background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #008800; font-weight: bold\">from<\/span> <span style=\"color: #0e84b5; font-weight: bold\">pygifsicle<\/span> <span style=\"color: #008800; font-weight: bold\">import<\/span> optimize\n<span style=\"color: #008800; font-weight: bold\">import<\/span> <span style=\"color: #0e84b5; font-weight: bold\">os<\/span>\n<span style=\"color: #008800; font-weight: bold\">import<\/span> <span style=\"color: #0e84b5; font-weight: bold\">imageio<\/span>\n<span style=\"color: #008800; font-weight: bold\">from<\/span> <span style=\"color: #0e84b5; font-weight: bold\">math<\/span> <span style=\"color: #008800; font-weight: bold\">import<\/span> <span style=\"color: #333333\">*<\/span>\n<span style=\"color: #008800; font-weight: bold\">import<\/span> <span style=\"color: #0e84b5; font-weight: bold\">numpy<\/span> <span style=\"color: #008800; font-weight: bold\">as<\/span> <span style=\"color: #0e84b5; font-weight: bold\">np<\/span>\n<span style=\"color: #008800; font-weight: bold\">import<\/span> <span style=\"color: #0e84b5; font-weight: bold\">matplotlib<\/span> <span style=\"color: #008800; font-weight: bold\">as<\/span> <span style=\"color: #0e84b5; font-weight: bold\">mpl<\/span>\n<span style=\"color: #008800; font-weight: bold\">import<\/span> <span style=\"color: #0e84b5; font-weight: bold\">matplotlib.pyplot<\/span> <span style=\"color: #008800; font-weight: bold\">as<\/span> <span style=\"color: #0e84b5; font-weight: bold\">plt<\/span>\nplt<span style=\"color: #333333\">.<\/span>rc(<span style=\"background-color: #fff0f0\">'font'<\/span>, family<span style=\"color: #333333\">=<\/span><span style=\"background-color: #fff0f0\">'serif'<\/span>) <span style=\"color: #888888\">## setting for figures which I usually use in my publications<\/span>\nmpl<span style=\"color: #333333\">.<\/span>rcParams<span style=\"color: #333333\">.<\/span>update({<span style=\"background-color: #fff0f0\">'font.size'<\/span>: <span style=\"color: #0000DD; font-weight: bold\">12<\/span>})\nmpl<span style=\"color: #333333\">.<\/span>rcParams<span style=\"color: #333333\">.<\/span>update({<span style=\"background-color: #fff0f0\">'legend.labelspacing'<\/span>:<span style=\"color: #6600EE; font-weight: bold\">0.25<\/span>, <span style=\"background-color: #fff0f0\">'legend.fontsize'<\/span>: <span style=\"color: #0000DD; font-weight: bold\">12<\/span>})\nmpl<span style=\"color: #333333\">.<\/span>rcParams<span style=\"color: #333333\">.<\/span>update({<span style=\"background-color: #fff0f0\">'errorbar.capsize'<\/span>: <span style=\"color: #0000DD; font-weight: bold\">4<\/span>})\n<\/pre><\/div>\n\n\n\n<p>I change standard parameters for font in Matplotlib, so the final product can be inserted in an article. I use package pygifsicle to make the final gif more compact. In this example the file is compressed from 19 MB to 4.9 MB with a single command. Next I write a function which generates data for individual frame. Instead of data generation it is possible to read individual files in this function.<\/p>\n\n\n\n<div style=\"background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #888888\">## Define a function which produces numerical input for our individual frame.<\/span>\n<span style=\"color: #888888\">## It could be simply a fuction which reads individual files <\/span>\n\n<span style=\"color: #008800; font-weight: bold\">def<\/span> <span style=\"color: #0066BB; font-weight: bold\">fun<\/span> (i, x): <span style=\"color: #888888\">## argument of the function is the frame number<\/span>\n\n        <span style=\"color: #008800; font-weight: bold\">return<\/span> np<span style=\"color: #333333\">.<\/span>sin ((i<span style=\"color: #333333\">\/<\/span><span style=\"color: #6600EE; font-weight: bold\">30.0<\/span><span style=\"color: #333333\">+<\/span><span style=\"color: #0000DD; font-weight: bold\">1<\/span>)<span style=\"color: #333333\">*<\/span>x) <span style=\"color: #888888\">## we increase frequency in each frame <\/span>\n<\/pre><\/div>\n\n\n\n<p>At the next stage we plot our data and save them as individual png files.<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\"><pre style=\"margin: 0; line-height: 125%\">filenames <span style=\"color: #333333\">=<\/span> []\n\nN <span style=\"color: #333333\">=<\/span> <span style=\"color: #0000DD; font-weight: bold\">300<\/span> <span style=\"color: #888888\">## Total number of separate frames in animation<\/span>\n\nx <span style=\"color: #333333\">=<\/span> np<span style=\"color: #333333\">.<\/span>linspace (<span style=\"color: #0000DD; font-weight: bold\">0<\/span>, <span style=\"color: #0000DD; font-weight: bold\">2<\/span><span style=\"color: #333333\">*<\/span>pi, <span style=\"color: #0000DD; font-weight: bold\">200<\/span>)\n\n<span style=\"color: #008800; font-weight: bold\">for<\/span> i <span style=\"color: #000000; font-weight: bold\">in<\/span> <span style=\"color: #007020\">range<\/span> (<span style=\"color: #0000DD; font-weight: bold\">0<\/span>, N):\n\n        y <span style=\"color: #333333\">=<\/span> fun (i, x)\n\n        plt<span style=\"color: #333333\">.<\/span>plot (x,y) <span style=\"color: #888888\">#, rasterized=True)<\/span>\n\n        filename <span style=\"color: #333333\">=<\/span> <span style=\"background-color: #fff0f0\">'frame_'<\/span><span style=\"color: #333333\">+<\/span><span style=\"color: #007020\">str<\/span>(i)<span style=\"color: #333333\">+<\/span><span style=\"background-color: #fff0f0\">'.png'<\/span>\n\n        filenames<span style=\"color: #333333\">.<\/span>append (filename)\n\n        plt<span style=\"color: #333333\">.<\/span>xlim([<span style=\"color: #0000DD; font-weight: bold\">0<\/span>, <span style=\"color: #6600EE; font-weight: bold\">2.0<\/span><span style=\"color: #333333\">*<\/span>pi]) <span style=\"color: #888888\">## This adds stability to the axis<\/span>\n        plt<span style=\"color: #333333\">.<\/span>ylim([<span style=\"color: #333333\">-<\/span><span style=\"color: #6600EE; font-weight: bold\">1.1<\/span>, <span style=\"color: #6600EE; font-weight: bold\">1.3<\/span>])\n\n        plt<span style=\"color: #333333\">.<\/span>text (<span style=\"color: #6600EE; font-weight: bold\">1.5<\/span><span style=\"color: #333333\">*<\/span>pi, <span style=\"color: #6600EE; font-weight: bold\">1.1<\/span>, <span style=\"background-color: #fff0f0\">r'$\\omega=$'<\/span><span style=\"color: #333333\">+<\/span><span style=\"color: #007020\">str<\/span>(<span style=\"color: #007020\">round<\/span>(i<span style=\"color: #333333\">\/<\/span><span style=\"color: #6600EE; font-weight: bold\">30.0<\/span><span style=\"color: #333333\">+<\/span><span style=\"color: #0000DD; font-weight: bold\">1<\/span>, <span style=\"color: #0000DD; font-weight: bold\">1<\/span>)))\n\n        plt<span style=\"color: #333333\">.<\/span>savefig (filename)\n        <span style=\"color: #888888\">#plt.show() ## this part could be used for debugging to see how individual frame looks like.<\/span>\n        plt<span style=\"color: #333333\">.<\/span>close()     \n<\/pre><\/div>\n\n\n\n<p>plt.close() is used here to clean information from current plot, so the next frame does not have data shown at the previous frame. If our data are three-dimensional we can use plt.imshow() instead of plt.plot(). <\/p>\n\n\n\n<p>At the final step we call function get_writer from package imageio. This function combines all our individual figures into a single .gif file. After this step we can remove individual .png files.<\/p>\n\n\n\n<div style=\"background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\"><pre style=\"margin: 0; line-height: 125%\">gif_filename <span style=\"color: #333333\">=<\/span> <span style=\"background-color: #fff0f0\">'sinus_gif.gif'<\/span>\n\n<span style=\"color: #008800; font-weight: bold\">with<\/span> imageio<span style=\"color: #333333\">.<\/span>get_writer(gif_filename, mode<span style=\"color: #333333\">=<\/span><span style=\"background-color: #fff0f0\">'I'<\/span>) <span style=\"color: #008800; font-weight: bold\">as<\/span> writer:\n        <span style=\"color: #008800; font-weight: bold\">for<\/span> filename <span style=\"color: #000000; font-weight: bold\">in<\/span> filenames:  <span style=\"color: #888888\">## here we go through all prepared files<\/span>\n                image <span style=\"color: #333333\">=<\/span> imageio<span style=\"color: #333333\">.<\/span>imread(filename) \n                writer<span style=\"color: #333333\">.<\/span>append_data(image)\n\n                os<span style=\"color: #333333\">.<\/span>remove(filename) <span style=\"color: #888888\">## now we remove individual frames<\/span>\n\noptimize(gif_filename) <span style=\"color: #888888\">## to optimise the file size<\/span>\n<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Sometimes the outcomes of our models are very complicated and are worth showing as a short video or animation. The best format for a short&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"http:\/\/www.pulsars.info\/wordpress\/uncategorized\/gif-animation-with-python\/\">Continue Reading<span class=\"screen-reader-text\">gif animation with Python<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/posts\/47"}],"collection":[{"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/comments?post=47"}],"version-history":[{"count":1,"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/posts\/47\/revisions"}],"predecessor-version":[{"id":48,"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/posts\/47\/revisions\/48"}],"wp:attachment":[{"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/media?parent=47"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/categories?post=47"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.pulsars.info\/wordpress\/wp-json\/wp\/v2\/tags?post=47"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}