{"id":239,"date":"2019-07-25T18:30:39","date_gmt":"2019-07-25T18:30:39","guid":{"rendered":"https:\/\/www.allendowney.com\/blog\/?p=239"},"modified":"2019-07-25T18:30:39","modified_gmt":"2019-07-25T18:30:39","slug":"matplotlib-animation-in-jupyter","status":"publish","type":"post","link":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/","title":{"rendered":"Matplotlib animation in Jupyter"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">For two of my books, <em><a href=\"https:\/\/greenteapress.com\/wp\/think-complexity-2e\/\">Think Complexity<\/a><\/em> and <em><a href=\"https:\/\/greenteapress.com\/wp\/modsimpy\/\">Modeling and Simulation in Python<\/a><\/em>, many of the examples involve animation.  Fortunately, there are <a href=\"https:\/\/stackoverflow.com\/questions\/35532498\/animation-in-ipython-notebook\/46878531#46878531\">several ways to do animation with Matplotlib in Jupyter<\/a>.  Unfortunately, none of them is ideal.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">FuncAnimation<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Until recently, I was using <code>FuncAnimation<\/code>, provided by the <a href=\"https:\/\/matplotlib.org\/3.1.1\/api\/_as_gen\/matplotlib.animation.FuncAnimation.html\"><code>matplotlib.animation<\/code><\/a> package, as in <a href=\"https:\/\/github.com\/AllenDowney\/ThinkComplexity2\/blob\/72fc41cce7659c7d5d2027527f9623097b59dfcc\/code\/Cell2D.py#L117\">this example<\/a> from <em>Think Complexity<\/em>.  The documentation of this function is pretty sparse, but if you want to use it, you can find examples.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For me, there are a few drawbacks:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>It requires a back end like <code>ffmpeg<\/code> to display the animation.  Based on my email, many readers have trouble installing packages like this, so I avoid using them.<\/li><li>It runs the entire computation before showing the result, so it takes longer to debug, and makes for a less engaging interactive experience.<\/li><li>For each element you want to animate, you have to use one API to create the element and another to update it.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For example, if you are using <code>imshow<\/code> to visualize an array, you would run<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    im = plt.imshow(a, **options)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">to create an <code>AxesImage<\/code>, and then<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    im.set_array(a)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">to update it.  For beginners, this is a lot to ask.  And even for experienced people, it can be hard to find documentation that shows how to update various display elements.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As another example, suppose you have a 2-D array and plot it like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    plot(a)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The result is a list of <code>Line2D<\/code> objects.  To update them, you have to traverse the list and invoke <code>set_xdata()<\/code> on each one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Updating a display is often more complicated than creating it, and requires substantial navigation of the documentation.  Wouldn&#8217;t it be nice to just call <code>plot(a)<\/code> again?<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Clear output<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Recently I discovered simpler alternative using <a href=\"https:\/\/ipython.readthedocs.io\/en\/stable\/api\/generated\/IPython.display.html#functions\"><code>clear_output()<\/code> from <code>Ipython.display<\/code><\/a> and <code>sleep()<\/code> from the <code>time<\/code> module.  If you have Python and Jupyter, you already have these modules, so there&#8217;s nothing to install.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s a minimal example using <code>imshow<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">%matplotlib inline\n\nimport numpy as np\nfrom matplotlib import pyplot as plt\nfrom IPython.display import clear_output\nfrom time import sleep\n\nn = 10\na = np.zeros((n, n))\nplt.figure()\n\nfor i in range(n):\n    plt.imshow(a)\n    plt.show()\n    a[i, i] = 1\n    sleep(0.1)\n    clear_output(wait=True)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The drawback of this method is that it is relatively slow, but for the examples I&#8217;ve worked on, the performance has been good enough.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the ModSimPy library, I provide a function that encapsulates this pattern:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">def animate(results, draw_func, interval=None):\n    plt.figure()\n    try:\n        for t, state in results.iterrows():\n            draw_func(state, t)\n            plt.show()\n            if interval:\n                sleep(interval)\n            clear_output(wait=True)\n        draw_func(state, t)\n        plt.show()\n    except KeyboardInterrupt:\n        pass<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>results<\/code> is a Pandas DataFrame that contains results from a simulation; each row represents the state of a system at a point in time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>draw_func<\/code> is a function that takes a state and draws it in whatever way is appropriate for the context.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>interval<\/code> is the time between frames in seconds (not counting the time to draw the frame).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because the loop is wrapped in a <code>try<\/code> statement that captures <code>KeyboardInterrupt<\/code>, you can interrupt an animation cleanly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can see an example that uses this function in <a href=\"https:\/\/github.com\/AllenDowney\/ModSimPy\/blob\/master\/notebooks\/chap22.ipynb\">this notebook from Chapter 22<\/a> of <em>Modeling and Simulation in Python<\/em>, and you can <a href=\"https:\/\/mybinder.org\/v2\/gh\/AllenDowney\/ModSimPy\/master?filepath=notebooks%2Fchap22.ipynb\">run it on Binder<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And here&#8217;s <a href=\"https:\/\/github.com\/AllenDowney\/ThinkComplexity2\/blob\/master\/notebooks\/chap06.ipynb\">an example from Chapter 6<\/a> of <em>Think Complexity<\/em>, which you can also <a href=\"https:\/\/mybinder.org\/v2\/gh\/AllenDowney\/ThinkComplexity2\/master?filepath=notebooks%2Fchap06.ipynb\">run on Binder<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For two of my books, Think Complexity and Modeling and Simulation in Python, many of the examples involve animation. Fortunately, there are several ways to do animation with Matplotlib in Jupyter. Unfortunately, none of them is ideal. FuncAnimation Until recently, I was using FuncAnimation, provided by the matplotlib.animation package, as in this example from Think Complexity. The documentation of this function is pretty sparse, but if you want to use it, you can find examples. For me, there are a&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1],"tags":[25,24,16],"class_list":["post-239","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-animation","tag-jupyter","tag-python"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Matplotlib animation in Jupyter - Probably Overthinking It<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Matplotlib animation in Jupyter - Probably Overthinking It\" \/>\n<meta property=\"og:description\" content=\"For two of my books, Think Complexity and Modeling and Simulation in Python, many of the examples involve animation. Fortunately, there are several ways to do animation with Matplotlib in Jupyter. Unfortunately, none of them is ideal. FuncAnimation Until recently, I was using FuncAnimation, provided by the matplotlib.animation package, as in this example from Think Complexity. The documentation of this function is pretty sparse, but if you want to use it, you can find examples. For me, there are a... Read More Read More\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/\" \/>\n<meta property=\"og:site_name\" content=\"Probably Overthinking It\" \/>\n<meta property=\"article:published_time\" content=\"2019-07-25T18:30:39+00:00\" \/>\n<meta name=\"author\" content=\"AllenDowney\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@AllenDowney\" \/>\n<meta name=\"twitter:site\" content=\"@AllenDowney\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"AllenDowney\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/2019\\\/07\\\/25\\\/matplotlib-animation-in-jupyter\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/2019\\\/07\\\/25\\\/matplotlib-animation-in-jupyter\\\/\"},\"author\":{\"name\":\"AllenDowney\",\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/#\\\/schema\\\/person\\\/4e5bfb2e9af6c3446cb0031a7bf83207\"},\"headline\":\"Matplotlib animation in Jupyter\",\"datePublished\":\"2019-07-25T18:30:39+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/2019\\\/07\\\/25\\\/matplotlib-animation-in-jupyter\\\/\"},\"wordCount\":455,\"publisher\":{\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/#organization\"},\"keywords\":[\"animation\",\"jupyter\",\"python\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/2019\\\/07\\\/25\\\/matplotlib-animation-in-jupyter\\\/\",\"url\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/2019\\\/07\\\/25\\\/matplotlib-animation-in-jupyter\\\/\",\"name\":\"Matplotlib animation in Jupyter - Probably Overthinking It\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/#website\"},\"datePublished\":\"2019-07-25T18:30:39+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/2019\\\/07\\\/25\\\/matplotlib-animation-in-jupyter\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/2019\\\/07\\\/25\\\/matplotlib-animation-in-jupyter\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/2019\\\/07\\\/25\\\/matplotlib-animation-in-jupyter\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Matplotlib animation in Jupyter\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/\",\"name\":\"Probably Overthinking It\",\"description\":\"Data science, Bayesian Statistics, and other ideas\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/#organization\",\"name\":\"Probably Overthinking It\",\"url\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/03\\\/probably_logo.png\",\"contentUrl\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/03\\\/probably_logo.png\",\"width\":714,\"height\":784,\"caption\":\"Probably Overthinking It\"},\"image\":{\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/AllenDowney\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/allendowney\\\/\",\"https:\\\/\\\/bsky.app\\\/profile\\\/allendowney.bsky.social\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/#\\\/schema\\\/person\\\/4e5bfb2e9af6c3446cb0031a7bf83207\",\"name\":\"AllenDowney\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fb01b3a7f7190bea1bbf7f0852e686c2f8c03b099222df2ce4bc7926f15bcb43?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fb01b3a7f7190bea1bbf7f0852e686c2f8c03b099222df2ce4bc7926f15bcb43?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fb01b3a7f7190bea1bbf7f0852e686c2f8c03b099222df2ce4bc7926f15bcb43?s=96&d=mm&r=g\",\"caption\":\"AllenDowney\"},\"url\":\"https:\\\/\\\/www.allendowney.com\\\/blog\\\/author\\\/allendowney_6dbrc4\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Matplotlib animation in Jupyter - Probably Overthinking It","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/","og_locale":"en_US","og_type":"article","og_title":"Matplotlib animation in Jupyter - Probably Overthinking It","og_description":"For two of my books, Think Complexity and Modeling and Simulation in Python, many of the examples involve animation. Fortunately, there are several ways to do animation with Matplotlib in Jupyter. Unfortunately, none of them is ideal. FuncAnimation Until recently, I was using FuncAnimation, provided by the matplotlib.animation package, as in this example from Think Complexity. The documentation of this function is pretty sparse, but if you want to use it, you can find examples. For me, there are a... Read More Read More","og_url":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/","og_site_name":"Probably Overthinking It","article_published_time":"2019-07-25T18:30:39+00:00","author":"AllenDowney","twitter_card":"summary_large_image","twitter_creator":"@AllenDowney","twitter_site":"@AllenDowney","twitter_misc":{"Written by":"AllenDowney","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/#article","isPartOf":{"@id":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/"},"author":{"name":"AllenDowney","@id":"https:\/\/www.allendowney.com\/blog\/#\/schema\/person\/4e5bfb2e9af6c3446cb0031a7bf83207"},"headline":"Matplotlib animation in Jupyter","datePublished":"2019-07-25T18:30:39+00:00","mainEntityOfPage":{"@id":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/"},"wordCount":455,"publisher":{"@id":"https:\/\/www.allendowney.com\/blog\/#organization"},"keywords":["animation","jupyter","python"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/","url":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/","name":"Matplotlib animation in Jupyter - Probably Overthinking It","isPartOf":{"@id":"https:\/\/www.allendowney.com\/blog\/#website"},"datePublished":"2019-07-25T18:30:39+00:00","breadcrumb":{"@id":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.allendowney.com\/blog\/2019\/07\/25\/matplotlib-animation-in-jupyter\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.allendowney.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Matplotlib animation in Jupyter"}]},{"@type":"WebSite","@id":"https:\/\/www.allendowney.com\/blog\/#website","url":"https:\/\/www.allendowney.com\/blog\/","name":"Probably Overthinking It","description":"Data science, Bayesian Statistics, and other ideas","publisher":{"@id":"https:\/\/www.allendowney.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.allendowney.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.allendowney.com\/blog\/#organization","name":"Probably Overthinking It","url":"https:\/\/www.allendowney.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.allendowney.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.allendowney.com\/blog\/wp-content\/uploads\/2025\/03\/probably_logo.png","contentUrl":"https:\/\/www.allendowney.com\/blog\/wp-content\/uploads\/2025\/03\/probably_logo.png","width":714,"height":784,"caption":"Probably Overthinking It"},"image":{"@id":"https:\/\/www.allendowney.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/AllenDowney","https:\/\/www.linkedin.com\/in\/allendowney\/","https:\/\/bsky.app\/profile\/allendowney.bsky.social"]},{"@type":"Person","@id":"https:\/\/www.allendowney.com\/blog\/#\/schema\/person\/4e5bfb2e9af6c3446cb0031a7bf83207","name":"AllenDowney","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/fb01b3a7f7190bea1bbf7f0852e686c2f8c03b099222df2ce4bc7926f15bcb43?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/fb01b3a7f7190bea1bbf7f0852e686c2f8c03b099222df2ce4bc7926f15bcb43?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/fb01b3a7f7190bea1bbf7f0852e686c2f8c03b099222df2ce4bc7926f15bcb43?s=96&d=mm&r=g","caption":"AllenDowney"},"url":"https:\/\/www.allendowney.com\/blog\/author\/allendowney_6dbrc4\/"}]}},"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/posts\/239","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/comments?post=239"}],"version-history":[{"count":3,"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/posts\/239\/revisions"}],"predecessor-version":[{"id":242,"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/posts\/239\/revisions\/242"}],"wp:attachment":[{"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/media?parent=239"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/categories?post=239"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.allendowney.com\/blog\/wp-json\/wp\/v2\/tags?post=239"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}