{"id":1568,"date":"2022-02-24T19:00:10","date_gmt":"2022-02-24T19:00:10","guid":{"rendered":"https:\/\/www.pyxll.com\/blog\/?p=1568"},"modified":"2024-11-19T16:08:58","modified_gmt":"2024-11-19T16:08:58","slug":"animated-plots-with-matplotlib-in-excel","status":"publish","type":"post","link":"https:\/\/www.pyxll.com\/blog\/animated-plots-with-matplotlib-in-excel\/","title":{"rendered":"Animated Plots with matplotlib in Excel"},"content":{"rendered":"\n<p>Animated plots are a great way to liven up a spreadsheet or show a complex data set in a more intuitive way. We can use matplotlib to create animations and display them directly in Excel using <a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/plotting\/index.html\" target=\"_blank\" rel=\"noreferrer noopener\">PyXLL&#8217;s plotting capabilities<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-preparing-some-example-data\">Preparing some example data<\/h2>\n\n\n\n<p>To begin with we need some data to plot. I&#8217;ve chosen a dataset from the plotly examples we we will load directly from the web, but you could plot data directly from a worksheet or loaded from another source such as a database.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom pyxll import xl_func\nimport pandas as pd\n\n\n@xl_func\ndef load_data():\n    url = &quot;https:\/\/raw.githubusercontent.com\/plotly\/datasets\/master\/volcano.csv&quot;\n    df = pd.read_csv(url)\n\n    # Transform it to a long format\n    df = df.unstack().reset_index()\n    df.columns = &#x5B;&quot;X&quot;, &quot;Y&quot;, &quot;Z&quot;]\n\n    # And transform the old column name in something numeric\n    df&#x5B;&#039;X&#039;] = pd.Categorical(df&#x5B;&#039;X&#039;])\n    df&#x5B;&#039;X&#039;] = df&#x5B;&#039;X&#039;].cat.codes\n\n    return df\n<\/pre><\/div>\n\n\n<p>This function above loads the data from github into a pandas DataFrame and shuffles it into the format ready for plotting with the columns &#8216;X&#8217;, &#8216;Y&#8217; and &#8216;Z&#8217;. The <code><a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/udfs\/introduction.html\" target=\"_blank\" rel=\"noreferrer noopener\">@xl_func<\/a><\/code> decorator exposes this function to Excel so we can call it directly from our worksheet as <code>=load_data()<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating a 3d plot of our data<\/h2>\n\n\n\n<p>Next we&#8217;re ready to plot our data. Let&#8217;s start by writing another function which will plot the DataFrame returned by the first function. It would work just as well with any DataFrame from another data source with the columns X, Y and Z. We could easily pass it a range directly from the worksheet if we had some suitable data.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom pyxll import xl_func, plot\nimport matplotlib.pyplot as plt\n\n@xl_func(&quot;dataframe: str&quot;)\ndef plot_3d(df):\n    # Create the matplotlib figure\n    fig = plt.figure(facecolor=&#039;white&#039;)\n    ax = fig.gca(projection=&#039;3d&#039;)\n\n    # Plot our X, Y, Z data\n    ax.plot_trisurf(df&#x5B;&#039;Y&#039;], df&#x5B;&#039;X&#039;], df&#x5B;&#039;Z&#039;], cmap=plt.cm.viridis, linewidth=0.2)\n    ax.view_init(30, 60)\n\n    # Show the plot in Excel\n    plot(fig)\n\n    # Return a string to Excel\n    return &quot;&#x5B;OK!]&quot;\n<\/pre><\/div>\n\n\n<p>When we call this function with our loaded DataFrame the plot shows in Excel using the <a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/plotting\/index.html\" target=\"_blank\" rel=\"noreferrer noopener\"><code>pyxll.plot<\/code><\/a> function. Next we&#8217;ll make it animate!<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><a href=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/Capture.png\"><img decoding=\"async\" data-attachment-id=\"1571\" data-permalink=\"https:\/\/www.pyxll.com\/blog\/animated-plots-with-matplotlib-in-excel\/capture-3\/\" data-orig-file=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/Capture.png\" data-orig-size=\"1049,1053\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Capture\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/Capture-1020x1024.png\" src=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/Capture-1020x1024.png\" alt=\"\" class=\"wp-image-1571\" width=\"510\" height=\"512\" srcset=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/Capture-1020x1024.png 1020w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/Capture-300x300.png 300w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/Capture-150x150.png 150w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/Capture-768x771.png 768w, https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/Capture.png 1049w\" sizes=\"(max-width: 510px) 100vw, 510px\" \/><\/a><figcaption>Our 3d data plotted in Excel<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Animating the 3d plot<\/h2>\n\n\n\n<p>To make this plot animated we&#8217;ll use <code><a href=\"https:\/\/matplotlib.org\/stable\/api\/_as_gen\/matplotlib.animation.FuncAnimation.html\" target=\"_blank\" rel=\"noreferrer noopener\">matplotlib.animation.FuncAnimation<\/a><\/code>. The FuncAnimation class takes a function as an argument that will be called several times to update the plot and build up the frames of our animation. In each frame we want to rotate the graph, which is done by calling <code>ax.view_init(30, angle)<\/code> with the angle we want to set. We&#8217;ll do this for angles between 0 and 360 degrees to get a complete rotation.<\/p>\n\n\n\n<p>The dataset I&#8217;ve chosen is quite large and rendering the whole animation takes a little bit of time. Depending on the size of your data set you may want to use more or fewer frames to get the right balance between a smooth animation and not having to wait too long for it to render.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom pyxll import xl_func, plot\nfrom matplotlib.animation import FuncAnimation\nimport matplotlib.pyplot as plt\n\n@xl_func(&quot;dataframe: str&quot;)\ndef plot_3d(df):\n    fig = plt.figure(facecolor=&#039;white&#039;)\n    ax = fig.gca(projection=&#039;3d&#039;)\n\n    def init():\n        ax.plot_trisurf(df&#x5B;&#039;Y&#039;], df&#x5B;&#039;X&#039;], df&#x5B;&#039;Z&#039;], cmap=plt.cm.viridis, linewidth=0.2)\n\n    # The animate function is called for each frame of the animation\n    def animate(angle):\n        ax.view_init(30, angle)\n\n    anim = FuncAnimation(fig,\n                         animate,\n                         init_func=init,\n                         frames=range(0, 360, 10),\n                         interval=200)\n\n    # Show the animation in Excel\n    plot(anim)\n\n    # Return a string to Excel\n    return &quot;&#x5B;OK!]&quot;\n<\/pre><\/div>\n\n\n<p>With some small changes to our original plot_3d function we&#8217;re now producing an animated plot of our data set. The animate function is called for each angle in the range passed to FuncAnimation, rotating our 3d plot 360 degrees to create the animation. Calling the <code><a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/plotting\/index.html\" target=\"_blank\" rel=\"noreferrer noopener\">pyxll.plot<\/a><\/code> function renders the animation into a shape object in Excel.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/animated-plot-1.gif\"><img decoding=\"async\" width=\"640\" height=\"360\" data-attachment-id=\"1592\" data-permalink=\"https:\/\/www.pyxll.com\/blog\/animated-plots-with-matplotlib-in-excel\/animated-plot-2\/\" data-orig-file=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/animated-plot-1.gif\" data-orig-size=\"640,360\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"animated-plot\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/animated-plot-1.gif\" src=\"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/animated-plot-1.gif\" alt=\"Animated plot using matplotlib in Excel\" class=\"wp-image-1592\"\/><\/a><figcaption>An animated 3d plot in Excel using matplotlib and PyXLL.<\/figcaption><\/figure>\n\n\n\n<p>For more information about how to plot using matplotlib and PyXLL please see the following resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/www.pyxll.com\/docs\/userguide\/plotting\/index.html\" target=\"_blank\" rel=\"noreferrer noopener\">Charts and Plotting in the PyXLL User Guide<\/a><\/li><li><a href=\"https:\/\/matplotlib.org\/stable\/gallery\/animation\/simple_anim.html\" target=\"_blank\" rel=\"noreferrer noopener\">Simple animation example in the matplotlib user guide<\/a><\/li><li><a href=\"https:\/\/matplotlib.org\/stable\/api\/animation_api.html\" target=\"_blank\" rel=\"noreferrer noopener\">matplotlib animation API reference<\/a><\/li><\/ul>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Animated plots are a great way to liven up a spreadsheet or show a complex data set in a more intuitive way. We can use matplotlib to create animations and display them directly in Excel using PyXLL&#8217;s plotting capabilities.<\/p>\n","protected":false},"author":1,"featured_media":1592,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[11,12,2,272],"tags":[],"class_list":["post-1568","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-matplotlib","category-python","category-pyxll","category-visualization"],"acf":[],"jetpack_featured_media_url":"https:\/\/www.pyxll.com\/blog\/wp-content\/uploads\/2022\/02\/animated-plot-1.gif","jetpack_shortlink":"https:\/\/wp.me\/p7l3LP-pi","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts\/1568","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/comments?post=1568"}],"version-history":[{"count":1,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts\/1568\/revisions"}],"predecessor-version":[{"id":1881,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/posts\/1568\/revisions\/1881"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/media\/1592"}],"wp:attachment":[{"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/media?parent=1568"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/categories?post=1568"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pyxll.com\/blog\/wp-json\/wp\/v2\/tags?post=1568"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}