<?xml version="1.0" encoding="utf-8"?> 
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us">
    <generator uri="https://gohugo.io/" version="0.152.2">Hugo</generator><title type="html"><![CDATA[Tutorials on Blog]]></title>
    
    
    
            <link href="https://blog.scientific-python.org/tags/tutorials/" rel="alternate" type="text/html" title="html" />
            <link href="https://blog.scientific-python.org/tags/tutorials/atom.xml" rel="self" type="application/atom" title="atom" />
    <updated>2026-04-04T04:32:36+00:00</updated>
    
    
    
    
        <id>https://blog.scientific-python.org/tags/tutorials/</id>
    
        
        <entry>
            <title type="html"><![CDATA[Best Practices for Using NumPy's Random Number Generators]]></title>
            <link href="https://blog.scientific-python.org/numpy/numpy-rng/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/scientific-python/dev-summit-1-development-guide/?utm_source=atom_feed" rel="related" type="text/html" title="The Scientific Python Development Guide" />
                <link href="https://blog.scientific-python.org/numpy/fellowship-program/?utm_source=atom_feed" rel="related" type="text/html" title="NumPy&#39;s first Developer in Residence: Sayed Adel" />
                <link href="https://blog.scientific-python.org/numpy/mukulikapahari/?utm_source=atom_feed" rel="related" type="text/html" title="NumPy Contributor Spotlight: Mukulika Pahari" />
                <link href="https://blog.scientific-python.org/matplotlib/how-to-create-custom-tables/?utm_source=atom_feed" rel="related" type="text/html" title="How to create custom tables" />
                <link href="https://blog.scientific-python.org/matplotlib/visualising-usage-using-batteries/?utm_source=atom_feed" rel="related" type="text/html" title="Battery Charts - Visualise usage rates &amp; more" />
            
                <id>https://blog.scientific-python.org/numpy/numpy-rng/</id>
            
            
            <published>2024-01-26T23:22:46+02:00</published>
            <updated>2024-01-26T23:22:46+02:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Best Practices for Using NumPy&rsquo;s Random Number Generators</blockquote><p>Given the practical challenges of achieving true randomness, deterministic algorithms, known as Pseudo Random Number Generators (RNGs), are employed in science to create sequences that mimic randomness. These generators are used for simulations, experiments, and analysis where it is essential to have numbers that appear unpredictable. I want to share here what I have learned about best practices with pseudo RNGs and especially the ones available in <a href="https://numpy.org/">NumPy</a>.</p>
<p>A pseudo RNG works by updating an internal state through a deterministic algorithm. This internal state is initialized with a value known as a seed and each update produces a number that appears randomly generated. The key here is that the process is deterministic, meaning that if you start with the same seed and apply the same algorithm, you will get the same sequence of internal states (and numbers). Despite this determinism, the resulting numbers exhibit properties of randomness, appearing unpredictable and evenly distributed. Users can either specify the seed manually, providing a degree of control over the generated sequence, or they can opt to let the RNG object automatically derive the seed from system entropy. The latter approach enhances unpredictability by incorporating external factors into the seed.</p>
<p>I assume a certain knowledge of NumPy and that NumPy 1.17 or greater is used. The reason for this is that great new features were introduced in the <a href="https://numpy.org/doc/stable/reference/random/index.html">random</a> module of version 1.17. As <code>numpy</code> is usually imported as <code>np</code>, I will sometimes use <code>np</code> instead of <code>numpy</code>. Finally, RNG will always mean pseudo RNG in the rest of this blog post.</p>
<h3 id="the-main-messages">The main messages<a class="headerlink" href="#the-main-messages" title="Link to this heading">#</a></h3>
<ol>
<li>Avoid using the global NumPy RNG. This means that you should avoid using <a href="https://numpy.org/doc/stable/reference/random/generated/numpy.random.seed.html"><code>np.random.seed</code></a> and <code>np.random.*</code> functions, such as <code>np.random.random</code>, to generate random values.</li>
<li>Create a new RNG and pass it around using the <a href="https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.default_rng"><code>np.random.default_rng</code></a> function.</li>
<li>Be careful with parallel random number generation and use the <a href="https://numpy.org/doc/stable/reference/random/parallel.html">strategies provided by NumPy</a>.</li>
</ol>
<p>Note that, with older versions of NumPy (&lt;1.17), the way to create a new RNG is to use <a href="https://numpy.org/doc/stable/reference/random/legacy.html#numpy.random.RandomState"><code>np.random.RandomState</code></a> which is based on the popular Mersenne Twister 19937 algorithm. This is also how the global NumPy RNG is created. This function is still available in newer versions of NumPy, but it is now recommended to use <code>default_rng</code> instead, which returns an instance of the statistically better <a href="https://www.pcg-random.org">PCG64</a> RNG. You might still see <code>np.random.RandomState</code> being used in tests as it has strong stability guarantees between different NumPy versions.</p>
<h2 id="random-number-generation-with-numpy">Random number generation with NumPy<a class="headerlink" href="#random-number-generation-with-numpy" title="Link to this heading">#</a></h2>
<p>When you import <code>numpy</code> in your Python script, an RNG is created behind the scenes. This RNG is the one used when you generate a new random value using a function such as <code>np.random.random</code>. I will here refer to this RNG as the global NumPy RNG.</p>
<p>Although not recommended, it is a common practice to reset the seed of this global RNG at the beginning of a script using the <code>np.random.seed</code> function. Fixing the seed at the beginning ensures that the script is reproducible: the same values and results will be produced each time you run it. However, although sometimes convenient, using the global NumPy RNG is a bad practice. A simple reason is that using global variables can lead to undesired side effects. For instance one might use <code>np.random.random</code> without knowing that the seed of the global RNG was set somewhere else in the codebase. Quoting <a href="https://numpy.org/neps/nep-0019-rng-policy.html">Numpy Enhancement Proposal (NEP) 19</a> by Robert Kern:</p>
<blockquote>
<p>The implicit global RandomState behind the <code>np.random.*</code> convenience functions can cause problems, especially when threads or other forms of concurrency are involved. Global state is always problematic. We categorically recommend avoiding using the convenience functions when reproducibility is involved. [&hellip;] The preferred best practice for getting reproducible pseudorandom numbers is to instantiate a generator object with a seed and pass it around.</p>
</blockquote>
<p>In short:</p>
<ul>
<li>Instead of using <code>np.random.seed</code>, which reseeds the already created global NumPy RNG, and then using <code>np.random.*</code> functions, you should create a new RNG.</li>
<li>You should create an RNG at the beginning of your script (with your own seed if you want reproducibility) and use this RNG in the rest of the script.</li>
</ul>
<p>To create a new RNG you can use the <code>default_rng</code> function as illustrated in the <a href="https://numpy.org/doc/stable/reference/random/index.html">introduction of the random module documentation</a>:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">default_rng</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">rng</span><span class="o">.</span><span class="n">random</span><span class="p">()</span>  <span class="c1"># generate a floating point number between 0 and 1</span></span></span></code></pre>
</div>
<p>If you want to use a seed for reproducibility, <a href="https://numpy.org/doc/stable/reference/random/index.html#quick-start">the NumPy documentation</a> recommends using a large random number, where large means at least 128 bits. The first reason for using a large random number is that this increases the probability of having a different seed than anyone else and thus independent results. The second reason is that relying only on small numbers for your seeds can lead to biases as they do not fully explore the state space of the RNG. This limitation implies that the first number generated by your RNG may not seem as random as expected due to inaccessible first internal states. For example, some numbers will never be produced as the first output. One possibility would be to pick the seed at random in the state space of the RNG but <a href="https://github.com/numpy/numpy/issues/25778#issuecomment-1930441151">according to Robert Kern</a> a 128-bit random number is large enough<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. To generate a 128-bit random number for your seed you can rely on the <a href="https://docs.python.org/3/library/secrets.html">secrets module</a>:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">secrets</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">secrets</span><span class="o">.</span><span class="n">randbits</span><span class="p">(</span><span class="mi">128</span><span class="p">)</span></span></span></code></pre>
</div>
<p>When running this code I get <code>65647437836358831880808032086803839626</code> for the number to use as my seed. This number is randomly generated so you need to copy paste the value that is returned by <code>secrets.randbits(128)</code> otherwise you will have a different seed each time you run your code and thus break reproducibility:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">seed</span> <span class="o">=</span> <span class="mi">65647437836358831880808032086803839626</span>
</span></span><span class="line"><span class="cl"><span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">default_rng</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">rng</span><span class="o">.</span><span class="n">random</span><span class="p">()</span></span></span></code></pre>
</div>
<p>The reason for seeding your RNG only once (and passing that RNG around) is that with a good RNG such as the one returned by <code>default_rng</code> you will be ensured good randomness and independence of the generated numbers. However, if not done properly, using several RNGs (each one created with its own seed) might lead to streams of random numbers that are less independent than the ones created from the same seed<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. That being said, <a href="https://github.com/numpy/numpy/issues/15322#issuecomment-573890207">as explained by Robert Kern</a>, with the RNGs and seeding strategies introduced in NumPy 1.17, it is considered fairly safe to create RNGs using system entropy, i.e. using <code>default_rng(None)</code> multiple times. However as explained later be careful when running jobs in parallel and relying on <code>default_rng(None)</code>. Another reason for seeding your RNG only once is that obtaining a good seed can be time consuming. Once you have a good seed to instantiate your generator, you might as well use it.</p>
<h2 id="passing-a-numpy-rng-around">Passing a NumPy RNG around<a class="headerlink" href="#passing-a-numpy-rng-around" title="Link to this heading">#</a></h2>
<p>As you write functions that you will use on their own as well as in a more complex script it is convenient to be able to pass a seed or your already created RNG. The function <code>default_rng</code> allows you to do this very easily. As written above, this function can be used to create a new RNG from your chosen seed, if you pass a seed to it, or from system entropy when passing <code>None</code> but you can also pass an already created RNG. In this case the returned RNG is the one that you passed.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">stochastic_function</span><span class="p">(</span><span class="n">high</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">rng</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">default_rng</span><span class="p">(</span><span class="n">rng</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">rng</span><span class="o">.</span><span class="n">integers</span><span class="p">(</span><span class="n">high</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span></span></span></code></pre>
</div>
<p>You can either pass an <code>int</code> seed or your already created RNG to <code>stochastic_function</code>. To be perfectly exact, the <code>default_rng</code> function returns the exact same RNG passed to it for certain kind of RNGs such at the ones created with <code>default_rng</code> itself. You can refer to the <a href="https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.default_rng"><code>default_rng</code> documentation</a> for more details on the arguments that you can pass to this function<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<h2 id="parallel-processing">Parallel processing<a class="headerlink" href="#parallel-processing" title="Link to this heading">#</a></h2>
<p>You must be careful when using RNGs in conjunction with parallel processing. Let&rsquo;s consider the context of Monte Carlo simulation: you have a random function returning random outputs and you want to generate these random outputs a lot of times, for instance to compute an empirical mean. If the function is expensive to compute, an easy solution to speed up the computation time is to resort to parallel processing. Depending on the parallel processing library or backend that you use different behaviors can be observed. For instance if you do not set the seed yourself it can be the case that forked Python processes use the same random seed, generated for instance from system entropy, and thus produce the exact same outputs which is a waste of computational resources. A very nice example illustrating this when using the Joblib parallel processing library is available <a href="https://joblib.readthedocs.io/en/latest/auto_examples/parallel_random_state.html">here</a>.</p>
<p>If you fix the seed at the beginning of your main script for reproducibility and then pass your seeded RNG to each process to be run in parallel, most of the time this will not give you what you want as this RNG will be deep copied. The same results will thus be produced by each process. One of the solutions is to create as many RNGs as parallel processes with a different seed for each of these RNGs. The issue now is that you cannot choose the seeds as easily as you would think. When you choose two different seeds to instantiate two different RNGs how do you know that the numbers produced by these RNGs will appear as statistically independent?<sup id="fnref1:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> The design of independent RNGs for parallel processes has been an important research question. See, for example, <a href="https://www.sciencedirect.com/science/article/pii/S0378475416300829">Random numbers for parallel computers: Requirements and methods, with emphasis on GPUs</a> by L&rsquo;Ecuyer et al. (2017) for a good summary of different methods.</p>
<p>Starting with NumPy 1.17, it is now very easy to instantiate independent RNGs. Depending on the type of RNG you use, different strategies are available as documented in the <a href="https://numpy.org/doc/stable/reference/random/parallel.html">Parallel random number generation section</a> of the NumPy documentation. One of the strategies is to use <code>SeedSequence</code> which is an algorithm that makes sure that poor input seeds are transformed into good initial RNG states. More precisely, this ensures that you will not have a degenerate behavior from your RNG and that the subsequent numbers will appear random and independent. Additionally, it ensures that close seeds are mapped to very different initial states, resulting in RNGs that are, with very high probability, independent of each other. You can refer to the documentation of <a href="https://numpy.org/doc/stable/reference/random/parallel.html#seedsequence-spawning">SeedSequence Spawning</a> for examples on how to generate independent RNGs from a <code>SeedSequence</code> or an existing RNG. I here show how to apply this to the <a href="https://joblib.readthedocs.io/en/latest/auto_examples/parallel_random_state.html#fixing-the-random-state-to-obtain-deterministic-results">joblib example</a> mentioned above.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">joblib</span> <span class="kn">import</span> <span class="n">Parallel</span><span class="p">,</span> <span class="n">delayed</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">stochastic_function</span><span class="p">(</span><span class="n">high</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">rng</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">default_rng</span><span class="p">(</span><span class="n">rng</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">rng</span><span class="o">.</span><span class="n">integers</span><span class="p">(</span><span class="n">high</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">seed</span> <span class="o">=</span> <span class="mi">319929794527176038403653493598663843656</span>
</span></span><span class="line"><span class="cl"><span class="c1"># creating the RNG that is passed around.</span>
</span></span><span class="line"><span class="cl"><span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">default_rng</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># create 5 independent RNGs</span>
</span></span><span class="line"><span class="cl"><span class="n">child_rngs</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># use 2 processes to run the stochastic_function 5 times with joblib</span>
</span></span><span class="line"><span class="cl"><span class="n">random_vector</span> <span class="o">=</span> <span class="n">Parallel</span><span class="p">(</span><span class="n">n_jobs</span><span class="o">=</span><span class="mi">2</span><span class="p">)(</span>
</span></span><span class="line"><span class="cl">    <span class="n">delayed</span><span class="p">(</span><span class="n">stochastic_function</span><span class="p">)(</span><span class="n">rng</span><span class="o">=</span><span class="n">child_rng</span><span class="p">)</span> <span class="k">for</span> <span class="n">child_rng</span> <span class="ow">in</span> <span class="n">child_rngs</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">random_vector</span><span class="p">)</span></span></span></code></pre>
</div>
<p>By using a fixed seed you always get the same results each time you run this code and by using <code>rng.spawn</code> you have an independent RNG for each call to <code>stochastic_function</code>. Note that here you could also spawn from a <code>SeedSequence</code> that you would create with the seed instead of creating an RNG. However, in general you pass around an RNG therefore I only assume to have access to an RNG. Also note that spawning from an RNG is only possible from version 1.25 of NumPy<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.</p>
<p>I hope this blog post helped you understand the best ways to use NumPy RNGs. The new Numpy API gives you all the tools you need for that. The resources below are available for further reading. Finally, I would like to thank Pamphile Roy, Stefan van der Walt and Jarrod Millman for their great feedbacks and comments which contributed to greatly improve the original version of this blog post.</p>
<h2 id="resources">Resources<a class="headerlink" href="#resources" title="Link to this heading">#</a></h2>
<h3 id="numpy-rngs">Numpy RNGs<a class="headerlink" href="#numpy-rngs" title="Link to this heading">#</a></h3>
<ul>
<li><a href="https://numpy.org/doc/stable/reference/random/index.html">The documentation of the NumPy random module</a> is the best place to find information and where I found most of the information that I share here.</li>
<li><a href="https://numpy.org/neps/nep-0019-rng-policy.html">The Numpy Enhancement Proposal (NEP) 19 on the Random Number Generator Policy</a> which lead to the changes introduced in NumPy 1.17</li>
<li>A <a href="https://github.com/numpy/numpy/issues/15322">NumPy issue</a> about the <code>check_random_state</code> function and RNG good practices, especially <a href="https://github.com/numpy/numpy/issues/15322#issuecomment-573890207">this comment</a> by Robert Kern.</li>
<li>Check also <a href="https://github.com/numpy/numpy/issues/25778#issuecomment-1930441151">this answer of Robert Kern</a> to my question about what <code>SeedSequence</code> can and cannot do. This also explains why it is recommended to use very large random numbers for seeds.</li>
<li><a href="https://scikit-learn.org/stable/faq.html#how-do-i-set-a-random-state-for-an-entire-execution">How do I set a random_state for an entire execution?</a> from the scikit-learn FAQ.</li>
<li>There are <a href="https://github.com/scientific-python/specs/pull/180">ongoing discussions</a> about uniformizing the APIs used by different libraries to seed RNGs.</li>
</ul>
<h3 id="rngs-in-general">RNGs in general<a class="headerlink" href="#rngs-in-general" title="Link to this heading">#</a></h3>
<ul>
<li><a href="https://www.sciencedirect.com/science/article/pii/S0378475416300829">Random numbers for parallel computers: Requirements and methods, with emphasis on GPUs</a> by L&rsquo;Ecuyer et al. (2017)</li>
<li>To know more about the default RNG used in NumPy, named PCG, I recommend the <a href="https://www.pcg-random.org/paper.html">PCG paper</a> which also contains lots of useful information about RNGs in general. The <a href="https://www.pcg-random.org">pcg-random.org website</a> is also full of interesting information about RNGs.</li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>If you only need a seed for reproducibility and do not need independence with respect to others, say for a unit test, a small seed is perfectly fine.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>A good RNG is expected to produce independent numbers for a given seed. However, the independence of sequences generated from two different seeds is not always guaranteed. For instance, it is possible that the sequence started with the second seed might quickly converge to an internal state also obtained by the first seed. This can result in both RNGs producing the same subsequent numbers, which would compromise the randomness expected from distinct seeds.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Before knowing about <code>default_rng</code>, and before NumPy 1.17, I was using the scikit-learn function <a href="https://scikit-learn.org/stable/modules/generated/sklearn.utils.check_random_state.html"><code>check_random_state</code></a> which is of course heavily used in the scikit-learn codebase. While writing this post I discovered that this function is now available in <a href="https://github.com/scipy/scipy/blob/62d2af2e13280d29781585aa39a3c5a5dfdfba17/scipy/_lib/_util.py#L231">scipy</a>. A look at the docstring and/or the source code of this function will give you a good idea about what it does. The differences with <code>default_rng</code> are that <code>check_random_state</code> currently relies on <code>np.random.RandomState</code> and that when <code>None</code> is passed to <code>check_random_state</code> then the function returns the already existing global NumPy RNG. The latter can be convenient because if you fix the seed of the global RNG before in your script using <code>np.random.seed</code>, <code>check_random_state</code> returns the generator that you seeded. However, as explained above, this is not the recommended practice and you should be aware of the risks and the side effects.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Before 1.25 you need to get the <code>SeedSequence</code> from the RNG using the <code>_seed_seq</code> private attribute of the underlying bit generator: <code>rng.bit_generator._seed_seq</code>. You can then spawn from this <code>SeedSequence</code> to get child seeds that will result in independent RNGs.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="numpy" label="numpy" />
                             
                                <category scheme="taxonomy:Tags" term="rng" label="rng" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[The Scientific Python Development Guide]]></title>
            <link href="https://blog.scientific-python.org/scientific-python/dev-summit-1-development-guide/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/scientific-python/scientific-python-project/?utm_source=atom_feed" rel="related" type="text/html" title="Scientific Python: Community developed, community owned" />
                <link href="https://blog.scientific-python.org/matplotlib/how-to-create-custom-tables/?utm_source=atom_feed" rel="related" type="text/html" title="How to create custom tables" />
                <link href="https://blog.scientific-python.org/matplotlib/visualising-usage-using-batteries/?utm_source=atom_feed" rel="related" type="text/html" title="Battery Charts - Visualise usage rates &amp; more" />
                <link href="https://blog.scientific-python.org/matplotlib/python-graph-gallery.com/?utm_source=atom_feed" rel="related" type="text/html" title="The Python Graph Gallery: hundreds of python charts with reproducible code." />
                <link href="https://blog.scientific-python.org/matplotlib/stellar-chart-alternative-radar-chart/?utm_source=atom_feed" rel="related" type="text/html" title="Stellar Chart, a Type of Chart to Be on Your Radar" />
            
                <id>https://blog.scientific-python.org/scientific-python/dev-summit-1-development-guide/</id>
            
            
            <published>2023-08-26T12:00:00-05:00</published>
            <updated>2023-08-26T12:00:00-05:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Introducing the Scientific Python Development Guide!</blockquote><p>One outcome of the
<a href="https://scientific-python.org/summits/developer/2023/">2023 Scientific Python Developer Summit</a>
was the <a href="https://learn.scientific-python.org/development">Scientific Python Development Guide</a>, a comprehensive guide to modern
Python package development, complete with a <a href="https://github.com/scientific-python/cookie">new project template</a>
supporting 10+ build backends and a <a href="https://learn.scientific-python.org/development/guides/repo-review">WebAssembly-powered checker</a>
with checks linked to the guide. The guide covers topics like <a href="https://learn.scientific-python.org/development/guides/packaging-simple/">modern</a>,
<a href="https://learn.scientific-python.org/development/guides/packaging-compiled/">compiled</a>, and <a href="https://learn.scientific-python.org/development/guides/packaging-classic/">classic</a> packaging, <a href="https://learn.scientific-python.org/development/guides/style/">style</a> checks, <a href="https://learn.scientific-python.org/development/guides/mypy/">type
checking</a>, <a href="https://learn.scientific-python.org/development/guides/docs/">docs</a>, <a href="https://learn.scientific-python.org/development/guides/tasks/">task runners</a>, <a href="https://learn.scientific-python.org/development/guides/gha-basic/">CI</a>, <a href="https://learn.scientific-python.org/development/guides/pytest/">tests</a>,
and much more! There also are sections of <a href="https://learn.scientific-python.org/development/tutorials/">tutorials</a>, <a href="https://learn.scientific-python.org/development/principles/">principles</a>, and
some common <a href="https://learn.scientific-python.org/development/patterns/">patterns</a>.</p>
<p>This guide (along with cookie &amp; repo-review) started in <a href="https://scikit-hep.org">Scikit-HEP</a> in 2020.
During the summit, it was merged with the <a href="https://nsls-ii.github.io/">NSLS-II</a> guidelines, which provided
the basis for the <a href="https://learn.scientific-python.org/development/principles/">principles</a> section. I&rsquo;d like to thank and acknowledge Dan
Allan and Gregory Lee for working tirelessly during the summit to rework,
rewrite, merge, and fix the guide, including writing most of the <a href="https://learn.scientific-python.org/development/tutorials/">tutorials</a>
pages and first <a href="https://learn.scientific-python.org/development/patterns/">patterns</a> page, and rewriting the <a href="https://learn.scientific-python.org/development/tutorials/dev-environment/">environment</a> page as a
tutorial.</p>
<h2 id="the-guide">The guide<a class="headerlink" href="#the-guide" title="Link to this heading">#</a></h2>
<p>The core of the project is the guide, which is comprised of four sections:</p>
<ul>
<li><a href="https://learn.scientific-python.org/development/tutorials/">Tutorials</a>: How to go from &ldquo;research&rdquo; code to a basic package, for
beginning readers.</li>
<li><a href="https://learn.scientific-python.org/development/guides/">Topical guides</a>: The core of the guide, for intermediate to advanced
readers.</li>
<li><a href="https://learn.scientific-python.org/development/principles/">Principles</a>: Some general principles from the <a href="https://nsls-ii.github.io/">NSLS-II</a> guide.</li>
<li><a href="https://learn.scientific-python.org/development/patterns/">Patterns</a>: Recipes for common situations. Three pages are there now;
<a href="https://learn.scientific-python.org/development/patterns/data-files/">including data</a>, <a href="https://learn.scientific-python.org/development/patterns/backports/">backports</a>, and <a href="https://learn.scientific-python.org/development/patterns/exports/">exports</a>.</li>
</ul>
<p>From the original <a href="https://scikit-hep.org/developer">Scikit-HEP dev pages</a>, a lot was added:</p>
<ul>
<li>Brand new guide page on documentation, along with new <a href="https://learn.scientific-python.org/development/guides/repo-review">sp-repo-review</a> checks to
help with readthedocs.</li>
<li>A compiled projects page! Finally! With <a href="https://scikit-build-core.readthedocs.io">scikit-build-core</a>,
<a href="https://meson-python.readthedocs.io">meson-python</a>, and <a href="https://www.maturin.rs">maturin</a>. The page shows real outputs from the
<a href="https://www.cookiecutter.io">cookiecutter</a>, kept in sync with <a href="https://nedbatchelder.com/code/cog">cog</a> (a huge benefit of using a single
repo for all three components!)</li>
<li>Big update to <a href="https://learn.scientific-python.org/development/guides/gha-basic/">GHA CI page</a> including a section on Composite
Actions given at the Dev summit.</li>
<li>CLI entry points are now included.</li>
<li>Python 3.12 support added, Python 3.7 dropped.</li>
<li>New <a href="https://learn.scientific-python.org/development/guides/repo-review">sp-repo-review</a> badges throughout (more on that later!)</li>
<li>Updates for <a href="https://beta.ruff.rs">Ruff</a>&rsquo;s move and support for requires-python.</li>
<li>Lots of additions for GitHub Actions.</li>
</ul>
<p>The infrastructure was updated too:</p>
<ul>
<li>Using latest Jekyll (version 4) and latest Just the Docs theme. More colorful
callout boxes. Plugins are used now.</li>
<li>Live PR preview (provided by probably the world’s first readthedocs Jekyll
build!). Developed with the Zarr developers during the summit.</li>
<li>Better advertising for <a href="https://github.com/scientific-python/cookie">cookie</a> and <a href="https://learn.scientific-python.org/development/guides/repo-review">sp-repo-review</a> on the index page(s).</li>
<li>Auto bump and auto-sync CI jobs.</li>
</ul>
<h2 id="cookie">Cookie<a class="headerlink" href="#cookie" title="Link to this heading">#</a></h2>
<p>We also did something I&rsquo;ve wanted to do for a long time: the guide, the
cookiecutter template, and the checks are all in a single repo! The repo is
<a href="https://github.com/scientific-python/cookie">scientific-python/cookie</a>, which is the moved <code>scikit-hep/cookie</code> (the
old URL for cookiecutter still works!).</p>
<p>Cookie is a new project template supporting multiple backends (including
compiled ones), kept in sync with the dev guide. We recommend starting with
the dev guide and setting up your first package by hand, so that you understand
what each part is for, but once you&rsquo;ve done that, <a href="https://github.com/scientific-python/cookie">cookie</a> allows you to get
started on a new project in seconds.</p>
<p>A lot of work went into <a href="https://github.com/scientific-python/cookie">cookie</a>, too!</p>
<ul>
<li>Generalized defaults. We still have special integration if someone sets the
org to <code>scikit-hep</code>; the same integration can be offered to other orgs.</li>
<li>All custom hooks removed; standard jinja now used throughout templates. Using
cookiecutter computed variables idiom too. Windows still fully supported and
tested. Adding new choices is much easier now.</li>
<li>Added cruft (a cookiecutter updater) testing.</li>
<li>Dual-supporting <a href="https://copier.readthedocs.io">copier</a> now too, a <a href="https://www.cookiecutter.io">cookiecutter</a> replacement with a huge
CLI improvement (and also supports updating). Might be the first project to
support both at the same time. CI (or <a href="https://nox.thea.codes">nox</a> locally) checks to ensure
generation is identical. Much better interface with copier, including
validation, descriptive text, arrow selection, etc.</li>
<li>Improved CLI experience even if using cookiecutter (like no longer requesting
current year).</li>
<li>Reworked docs template.</li>
<li>Support for cookiecutter 2.2 pretty descriptions (added about four hours after
cookiecutter 2.2.0 was released) and cookiecutter 2.2.3 choice descriptions.</li>
<li>GitLab CI support when not targeting github.com URLs (added by Giordon Stark).</li>
<li>Support for selecting VCS or classic versioning.</li>
</ul>
<h2 id="repo-review">Repo-review<a class="headerlink" href="#repo-review" title="Link to this heading">#</a></h2>
<p>See the <a href="https://iscinumpy.dev/post/repo-review/">introduction to repo-review</a>
for information about this one!</p>
<p>Along with this was probably the biggest change, one requested by several people
at the summit: <a href="https://github.com/scientific-python/repo-review">scientific-python/repo-review</a> (was
<code>scikit-hep/repo-review</code>) is now a completely general framework for implementing
checks in Python 3.10+. The checks have been moved to <code>sp-repo-review</code>, which is
now part of scientific-python/cookie. There are too many changes to list here,
so just the key ones in 0.6, 0.7, 0.8, 0.9, and 0.10:</p>
<ul>
<li>Extensive, beautiful <a href="https://repo-review.readthedocs.io">documentation</a> for
check authors at (used to help guide the new docs guide page &amp; template
update!)</li>
<li>Support for four output formats, <a href="https://rich.readthedocs.io">rich</a> (improved), svg, json (new), html
(new).</li>
<li>Support for listing all checks.</li>
<li>GitHub Actions support with HTML step summary, <a href="https://pre-commit.com">pre-commit</a> support.</li>
<li>Generalized topological sorting to fixtures, dynamic fixtures.</li>
<li>Dynamic check selection (via fixtures! Basically everything is powered by
fixtures now.)</li>
<li>URL support in all output formats (including the terminal and WebApp!)</li>
<li>Support for package not at root of repo.</li>
<li>Support for running on a remote repo from the command line.</li>
<li>Support for select/ignore config in <code>pyproject.toml</code> or command line.</li>
<li>Pretty printed and controllable sorting for families.</li>
<li>Supports running from Python, including inside a readme with something like
cog.</li>
<li>Support for dynamic family descriptions (such as to output build system and
licence used).</li>
<li>Support for limiting the output to just errors or errors and skips.</li>
<li>Support for running on multiple repos at once, with output tailored to
multiple repos. Also supports passing <code>pyproject.toml</code> path instead to make
running on mixed repos easier.</li>
<li>Support for linting <code>[tool.repo-review]</code> with <a href="https://validate-pyproject.readthedocs.io">validate-pyproject</a>.</li>
</ul>
<p>The
<a href="https://repo-review.readthedocs.io/en/latest/changelog.html">full changelog</a>
has more - you can even see the 10 beta releases in-between 0.6.x and 0.7.0
where a lot of this refactoring work was happening. If you have configuration
you’d like to write check for, feel free to write a plugin!</p>
<p><a href="https://validate-pyproject.readthedocs.io">validate-pyproject</a> 0.14 has added support for being used as a repo-review
plugin, so you can validate <code>pyproject.toml</code> files with repo-review! This lints
<code>[project]</code> and <code>[build-system]</code> tables, <code>[tool.setuptools]</code>, and other tools
via plugins. <a href="https://scikit-build-core.readthedocs.io">Scikit-build-core</a> 0.5 can be used as a validate-project plugin
to lint <code>[tool.scikit-build]</code>. Repo-review has a plugin for
<code>[tool.repo-review]</code>.</p>
<h2 id="sp-repo-review">sp-repo-review<a class="headerlink" href="#sp-repo-review" title="Link to this heading">#</a></h2>
<p>Finally, <a href="https://learn.scientific-python.org/development/guides/repo-review">sp-repo-review</a> contains the previous repo-review plugins with checks:</p>
<ul>
<li>Fully cross-linked with the development guide. Every check has a URL that
points to a matching badge inside the development guide where the thing the
check is looking for is being discussed!</li>
<li>Full list of checks (including URLs), produced by cog, in
<a href="https://pypi.org/p/sp-repo-review">readme</a>.</li>
<li>Also ships with GitHub Action and <a href="https://pre-commit.com">pre-commit</a> checks</li>
<li>Released (in sync with cookie &amp; guide, as they are in the same repo) as
CalVer,
<a href="https://github.com/scientific-python/cookie/releases">with release notes</a>.</li>
<li>Split CI that selects just want to run based on changed files, with green
checkmark that respects skips (based on the excellent contrition to
pypa/build).</li>
</ul>
<!-- prettier-ignore-start -->
<figure class="align-default" id="id000">
<img src="cibw_example.png" alt="Image of sp-repo-review showing checks" class="align-center" width="60%">



<figcaption>
<p><span class="caption-text">Running sp-repo-review on cibuildwheel</span>
</figcaption>
</figure>

<!-- prettier-ignore-end -->
<h2 id="using-the-guide">Using the guide<a class="headerlink" href="#using-the-guide" title="Link to this heading">#</a></h2>
<p>If you have a guide, we&rsquo;d like for you to compare it with the Scientific Python
Development Guide, and see if we are missing anything - bring it to our
attention, and maybe we can add it. And then you can link to the centrally
maintained guide instead of manually maintaining a complete custom guide. See
<a href="https://scikit-hep.org/developer">scikit-hep/developer</a> for an example; many pages now point at this guide.
We can also provide org integrations for <a href="https://github.com/scientific-python/cookie">cookie</a>, providing some
customizations when a user targets your org (targeting <code>scikit-hep</code> will add a
badge).</p>]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="cookie" label="cookie" />
                             
                                <category scheme="taxonomy:Tags" term="scientific-python" label="scientific-python" />
                             
                                <category scheme="taxonomy:Tags" term="summit" label="summit" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[How to create custom tables]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/how-to-create-custom-tables/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/visualising-usage-using-batteries/?utm_source=atom_feed" rel="related" type="text/html" title="Battery Charts - Visualise usage rates &amp; more" />
                <link href="https://blog.scientific-python.org/matplotlib/python-graph-gallery.com/?utm_source=atom_feed" rel="related" type="text/html" title="The Python Graph Gallery: hundreds of python charts with reproducible code." />
                <link href="https://blog.scientific-python.org/matplotlib/stellar-chart-alternative-radar-chart/?utm_source=atom_feed" rel="related" type="text/html" title="Stellar Chart, a Type of Chart to Be on Your Radar" />
                <link href="https://blog.scientific-python.org/matplotlib/ipcc-sr15/?utm_source=atom_feed" rel="related" type="text/html" title="Figures in the IPCC Special Report on Global Warming of 1.5°C (SR15)" />
                <link href="https://blog.scientific-python.org/matplotlib/codeswitching-visualization/?utm_source=atom_feed" rel="related" type="text/html" title="Visualizing Code-Switching with Step Charts" />
            
                <id>https://blog.scientific-python.org/matplotlib/how-to-create-custom-tables/</id>
            
            
            <published>2022-03-11T11:10:06+00:00</published>
            <updated>2022-03-11T11:10:06+00:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>A tutorial on how to create custom tables in Matplotlib which allow for flexible design and customization.</blockquote><h1 id="introduction">Introduction<a class="headerlink" href="#introduction" title="Link to this heading">#</a></h1>
<p>This tutorial will teach you how to create custom tables in Matplotlib, which are extremely flexible in terms of the design and layout. You’ll hopefully see that the code is very straightforward! In fact, the main methods we will be using are <code>ax.text()</code> and <code>ax.plot()</code>.</p>
<p>I want to give a lot of credit to <a href="https://twitter.com/CrumpledJumper">Todd Whitehead</a> who has created these types of tables for various Basketball teams and players. His approach to tables is nothing short of fantastic due to the simplicity in design and how he manages to effectively communicate data to his audience. I was very much inspired by his approach and wanted to be able to achieve something similar in Matplotlib.</p>
<p>Before I begin with the tutorial, I wanted to go through the logic behind my approach as I think it&rsquo;s valuable and transferable to other visualizations (and tools!).</p>
<p>With that, I would like you to <strong>think of tables as highly structured and organized scatterplots</strong>. Let me explain why: for me, scatterplots are the most fundamental chart type (regardless of tool).</p>
<p><img src="/matplotlib/how-to-create-custom-tables/scatterplots.png" alt="Scatterplots"></p>
<p>For example <code>ax.plot()</code> automatically &ldquo;connects the dots&rdquo; to form a line chart or <code>ax.bar()</code> automatically &ldquo;draws rectangles&rdquo; across a set of coordinates. Very often (again regardless of tool) we may not always see this process happening. The point is, it is useful to think of any chart as a scatterplot or simply as a collection of shapes based on xy coordinates. This logic / thought process can unlock a ton of <em>custom</em> charts as the only thing you need are the coordinates (which can be mathematically computed).</p>
<p>With that in mind, we can move on to tables! So rather than plotting rectangles or circles we want to plot text and gridlines in a highly organized manner.</p>
<p>We will aim to create a table like this, which I have posted on Twitter <a href="https://twitter.com/TimBayer93/status/1476926897850359809">here</a>. Note, the only elements added outside of Matplotlib are the fancy arrows and their descriptions.</p>
<p><img src="/matplotlib/how-to-create-custom-tables/0_example.png" alt="Example"></p>
<h1 id="creating-a-custom-table">Creating a custom table<a class="headerlink" href="#creating-a-custom-table" title="Link to this heading">#</a></h1>
<p>Importing required libraries.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib</span> <span class="k">as</span> <span class="nn">mpl</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.patches</span> <span class="k">as</span> <span class="nn">patches</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib</span> <span class="kn">import</span> <span class="n">pyplot</span> <span class="k">as</span> <span class="n">plt</span></span></span></code></pre>
</div>
<p>First, we will need to set up a coordinate space - I like two approaches:</p>
<ol>
<li>working with the standard Matplotlib 0-1 scale (on both the x- and y-axis) or</li>
<li>an index system based on row / column numbers (this is what I will use here)</li>
</ol>
<p>I want to create a coordinate space for a table containing 6 columns and 10 rows - this means (similar to pandas row/column indices) each row will have an index between 0-9 and each column will have an index between 0-6 (this is technically 1 more column than what we defined but one of the columns with a lot of text will span two column “indices”)</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># first, we&#39;ll create a new figure and axis object</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># set the number of rows and cols for our table</span>
</span></span><span class="line"><span class="cl"><span class="n">rows</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="n">cols</span> <span class="o">=</span> <span class="mi">6</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># create a coordinate system based on the number of rows/columns</span>
</span></span><span class="line"><span class="cl"><span class="c1"># adding a bit of padding on bottom (-1), top (1), right (0.5)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">rows</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">cols</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/how-to-create-custom-tables/1_coordinate_space.png" alt="Empty Coordinate Space"></p>
<p>Now, the data we want to plot is sports (football) data. We have information about 10 players and some values against a number of different metrics (which will form our columns) such as goals, shots, passes etc.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># sample data</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player10&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">79</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player9&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">72</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player8&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">47</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player7&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">99</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">5</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player6&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">84</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">4</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player5&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">6</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">56</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player4&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">7</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">67</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player3&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">8</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">91</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player2&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">9</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">75</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;player1&#34;</span><span class="p">,</span> <span class="s2">&#34;shots&#34;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span> <span class="s2">&#34;passes&#34;</span><span class="p">:</span> <span class="mi">70</span><span class="p">,</span> <span class="s2">&#34;goals&#34;</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span> <span class="s2">&#34;assists&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span></span></span></code></pre>
</div>
<p>Next, we will start plotting the table (as a structured scatterplot). I did promise that the code will be very simple, less than 10 lines really, here it is:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># from the sample data, each dict in the list represents one row</span>
</span></span><span class="line"><span class="cl"><span class="c1"># each key in the dict represents a column</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">rows</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># extract the row data from the list</span>
</span></span><span class="line"><span class="cl">    <span class="n">d</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">row</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># the y (row) coordinate is based on the row index (loop)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># the x (column) coordinate is defined based on the order I want to display the data in</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># player name column</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="n">row</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="n">d</span><span class="p">[</span><span class="s2">&#34;id&#34;</span><span class="p">],</span> <span class="n">va</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;left&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># shots column - this is my &#34;main&#34; column, hence bold text</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="n">row</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="n">d</span><span class="p">[</span><span class="s2">&#34;shots&#34;</span><span class="p">],</span> <span class="n">va</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;right&#34;</span><span class="p">,</span> <span class="n">weight</span><span class="o">=</span><span class="s2">&#34;bold&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># passes column</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="n">row</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="n">d</span><span class="p">[</span><span class="s2">&#34;passes&#34;</span><span class="p">],</span> <span class="n">va</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;right&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># goals column</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="n">row</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="n">d</span><span class="p">[</span><span class="s2">&#34;goals&#34;</span><span class="p">],</span> <span class="n">va</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;right&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># assists column</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="n">row</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="n">d</span><span class="p">[</span><span class="s2">&#34;assists&#34;</span><span class="p">],</span> <span class="n">va</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;right&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/how-to-create-custom-tables/2_adding_data.png" alt="Adding data"></p>
<p>As you can see, we are starting to get a basic wireframe of our table. Let&rsquo;s add column headers to further make this <em>scatterplot</em> look like a table.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># Add column headers</span>
</span></span><span class="line"><span class="cl"><span class="c1"># plot them at height y=9.75 to decrease the space to the</span>
</span></span><span class="line"><span class="cl"><span class="c1"># first data row (you&#39;ll see why later)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">9.75</span><span class="p">,</span> <span class="s2">&#34;Player&#34;</span><span class="p">,</span> <span class="n">weight</span><span class="o">=</span><span class="s2">&#34;bold&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;left&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mf">9.75</span><span class="p">,</span> <span class="s2">&#34;Shots&#34;</span><span class="p">,</span> <span class="n">weight</span><span class="o">=</span><span class="s2">&#34;bold&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;right&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mf">9.75</span><span class="p">,</span> <span class="s2">&#34;Passes&#34;</span><span class="p">,</span> <span class="n">weight</span><span class="o">=</span><span class="s2">&#34;bold&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;right&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mf">9.75</span><span class="p">,</span> <span class="s2">&#34;Goals&#34;</span><span class="p">,</span> <span class="n">weight</span><span class="o">=</span><span class="s2">&#34;bold&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;right&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mf">9.75</span><span class="p">,</span> <span class="s2">&#34;Assists&#34;</span><span class="p">,</span> <span class="n">weight</span><span class="o">=</span><span class="s2">&#34;bold&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;right&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="mf">9.75</span><span class="p">,</span> <span class="s2">&#34;Special</span><span class="se">\n</span><span class="s2">Column&#34;</span><span class="p">,</span> <span class="n">weight</span><span class="o">=</span><span class="s2">&#34;bold&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;right&#34;</span><span class="p">,</span> <span class="n">va</span><span class="o">=</span><span class="s2">&#34;bottom&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/how-to-create-custom-tables/3_headers.png" alt="Adding Headers"></p>
<h1 id="formatting-our-table">Formatting our table<a class="headerlink" href="#formatting-our-table" title="Link to this heading">#</a></h1>
<p>The rows and columns of our table are now done. The only thing that is left to do is formatting - much of this is personal choice. The following elements I think are generally useful when it comes to good table design (more research <a href="https://www.storytellingwithdata.com/blog/2019/10/29/how-i-improved-the-table">here</a>):</p>
<p>Gridlines: Some level of gridlines are useful (less is more). Generally some guidance to help the audience trace their eyes or fingers across the screen can be helpful (this way we can <em>group</em> items too by drawing gridlines around them).</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">rows</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="n">cols</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="n">row</span> <span class="o">-</span> <span class="mf">0.5</span><span class="p">,</span> <span class="n">row</span> <span class="o">-</span> <span class="mf">0.5</span><span class="p">],</span> <span class="n">ls</span><span class="o">=</span><span class="s2">&#34;:&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="s2">&#34;.5&#34;</span><span class="p">,</span> <span class="n">c</span><span class="o">=</span><span class="s2">&#34;grey&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># add a main header divider</span>
</span></span><span class="line"><span class="cl"><span class="c1"># remember that we plotted the header row slightly closer to the first data row</span>
</span></span><span class="line"><span class="cl"><span class="c1"># this helps to visually separate the header row from the data rows</span>
</span></span><span class="line"><span class="cl"><span class="c1"># each data row is 1 unit in height, thus bringing the header closer to our</span>
</span></span><span class="line"><span class="cl"><span class="c1"># gridline gives it a distinctive difference.</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="n">cols</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mf">9.5</span><span class="p">,</span> <span class="mf">9.5</span><span class="p">],</span> <span class="n">lw</span><span class="o">=</span><span class="s2">&#34;.5&#34;</span><span class="p">,</span> <span class="n">c</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/how-to-create-custom-tables/4_gridlines.png" alt="Adding Gridlines"></p>
<p>Another important element for tables in my opinion is highlighting the <em>key</em> data points. We already bolded the values that are in the &ldquo;Shots&rdquo; column but we can further shade this column to give it further importance to our readers.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># highlight the column we are sorting by</span>
</span></span><span class="line"><span class="cl"><span class="c1"># using a rectangle patch</span>
</span></span><span class="line"><span class="cl"><span class="n">rect</span> <span class="o">=</span> <span class="n">patches</span><span class="o">.</span><span class="n">Rectangle</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="mf">1.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span><span class="p">),</span>  <span class="c1"># bottom left starting position (x,y)</span>
</span></span><span class="line"><span class="cl">    <span class="mf">0.65</span><span class="p">,</span>  <span class="c1"># width</span>
</span></span><span class="line"><span class="cl">    <span class="mi">10</span><span class="p">,</span>  <span class="c1"># height</span>
</span></span><span class="line"><span class="cl">    <span class="n">ec</span><span class="o">=</span><span class="s2">&#34;none&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">fc</span><span class="o">=</span><span class="s2">&#34;grey&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">alpha</span><span class="o">=</span><span class="mf">0.2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">zorder</span><span class="o">=-</span><span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">rect</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/how-to-create-custom-tables/5_highlight_column.png" alt="Highlight column"></p>
<p>We&rsquo;re almost there. The magic piece is <code>ax.axis(‘off’)</code>. This hides the axis, axis ticks, labels and everything “attached” to the axes, which means our table now looks like a clean table!</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">&#34;off&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/how-to-create-custom-tables/6_hide_axis.png" alt="Hide axis"></p>
<p>Adding a title is also straightforward.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="s2">&#34;A title for our table!&#34;</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s2">&#34;left&#34;</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">18</span><span class="p">,</span> <span class="n">weight</span><span class="o">=</span><span class="s2">&#34;bold&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/how-to-create-custom-tables/6_title.png" alt="Title"></p>
<h1 id="bonus-adding-special-columns">Bonus: Adding special columns<a class="headerlink" href="#bonus-adding-special-columns" title="Link to this heading">#</a></h1>
<p>Finally, if you wish to add images, sparklines, or other custom shapes and patterns then we can do this too.</p>
<p>To achieve this we will create new floating axes using <code>fig.add_axes()</code> to create a new set of floating axes based on the figure coordinates (this is different to our axes coordinate system!).</p>
<p>Remember that figure coordinates by default are between 0 and 1. [0,0] is the bottom left corner of the entire figure. If you’re unfamiliar with the differences between a figure and axes then check out <a href="https://matplotlib.org/stable/gallery/showcase/anatomy.html">Matplotlib&rsquo;s Anatomy of a Figure</a> for further details.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">newaxes</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">rows</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># offset each new axes by a set amount depending on the row</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># this is probably the most fiddly aspect (TODO: some neater way to automate this)</span>
</span></span><span class="line"><span class="cl">    <span class="n">newaxes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">([</span><span class="mf">0.75</span><span class="p">,</span> <span class="mf">0.725</span> <span class="o">-</span> <span class="p">(</span><span class="n">row</span> <span class="o">*</span> <span class="mf">0.063</span><span class="p">),</span> <span class="mf">0.12</span><span class="p">,</span> <span class="mf">0.06</span><span class="p">]))</span></span></span></code></pre>
</div>
<p>You can see below what these <em>floating</em> axes will look like (I say floating because they’re on top of our main axis object). The only tricky thing is figuring out the xy (figure) coordinates for these.</p>
<p>These <em>floating</em> axes behave like any other Matplotlib axes. Therefore, we have access to the same methods such as ax.bar(), ax.plot(), patches, etc. Importantly, each axis has its own independent coordinate system. We can format them as we wish.</p>
<p><img src="/matplotlib/how-to-create-custom-tables/7_floating_axes.png" alt="Floating axes"></p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># plot dummy data as a sparkline for illustration purposes</span>
</span></span><span class="line"><span class="cl"><span class="c1"># you can plot _anything_ here, images, patches, etc.</span>
</span></span><span class="line"><span class="cl"><span class="n">newaxes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="n">c</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">newaxes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># once again, the key is to hide the axis!</span>
</span></span><span class="line"><span class="cl"><span class="n">newaxes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">&#34;off&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/how-to-create-custom-tables/8_sparklines.png" alt="Sparklines"></p>
<p>That’s it, custom tables in Matplotlib. I did promise very simple code and an ultra-flexible design in terms of what you want / need. You can adjust sizes, colors and pretty much anything with this approach and all you need is simply a loop that plots text in a structured and organized manner. I hope you found it useful. Link to a Google Colab notebook with the code is <a href="https://colab.research.google.com/drive/1JshATKxjs7NWz2U8Oy6xOJaLgjldC1CW">here</a></p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Battery Charts - Visualise usage rates & more]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/visualising-usage-using-batteries/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/python-graph-gallery.com/?utm_source=atom_feed" rel="related" type="text/html" title="The Python Graph Gallery: hundreds of python charts with reproducible code." />
                <link href="https://blog.scientific-python.org/matplotlib/stellar-chart-alternative-radar-chart/?utm_source=atom_feed" rel="related" type="text/html" title="Stellar Chart, a Type of Chart to Be on Your Radar" />
                <link href="https://blog.scientific-python.org/matplotlib/ipcc-sr15/?utm_source=atom_feed" rel="related" type="text/html" title="Figures in the IPCC Special Report on Global Warming of 1.5°C (SR15)" />
                <link href="https://blog.scientific-python.org/matplotlib/codeswitching-visualization/?utm_source=atom_feed" rel="related" type="text/html" title="Visualizing Code-Switching with Step Charts" />
                <link href="https://blog.scientific-python.org/matplotlib/elementary-cellular-automata/?utm_source=atom_feed" rel="related" type="text/html" title="Elementary Cellular Automata" />
            
                <id>https://blog.scientific-python.org/matplotlib/visualising-usage-using-batteries/</id>
            
            
            <published>2021-08-19T16:52:58+05:30</published>
            <updated>2021-08-19T16:52:58+05:30</updated>
            
            
            <content type="html"><![CDATA[<blockquote>A tutorial on how to show usage rates and more using batteries</blockquote><h1 id="introduction">Introduction<a class="headerlink" href="#introduction" title="Link to this heading">#</a></h1>
<p>I have been creating common visualisations like scatter plots, bar charts, beeswarms etc. for a while and thought about doing something different. Since I&rsquo;m an avid football fan, I thought of ideas to represent players&rsquo; usage or involvement over a period (a season, a couple of seasons). I have seen some cool visualisations like donuts which depict usage and I wanted to make something different and simple to understand. I thought about representing batteries as a form of player usage and it made a lot of sense.</p>
<p>For players who have been barely used (played fewer minutes) show a <strong><em>large amount of battery</em></strong> present since they have enough energy left in the tank. And for heavily used players, do the opposite i.e. show <strong><em>drained or less amount of battery</em></strong></p>
<p>So, what is the purpose of a battery chart? You can use it to show usage, consumption, involvement, fatigue etc. (anything usage related).</p>
<p>The image below is a sample view of how a battery would look in our figure, although a single battery isn&rsquo;t exactly what we are going to recreate in this tutorial.</p>
<p><img src="/matplotlib/visualising-usage-using-batteries/battery.png" alt="A sample visualisation"></p>
<h1 id="tutorial">Tutorial<a class="headerlink" href="#tutorial" title="Link to this heading">#</a></h1>
<p>Before jumping on to the tutorial, I would like to make it known that the function can be tweaked to fit accordingly depending on the number of subplots or any other size parameter. Coming to the figure we are going to plot, there are a series of steps that is to be considered which we will follow one by one. The following are those steps:-</p>
<ol>
<li>Outlining what we are going to plot</li>
<li>Import necessary libraries</li>
<li>Write a function to draw the battery
<ul>
<li>This is the function that will be called to plot the battery chart</li>
</ul>
</li>
<li>Read the data and plot the chart accordingly
<ul>
<li>We will demonstrate it with an example</li>
</ul>
</li>
</ol>
<h2 id="plot-outline"><span style="text-decoration: underline">Plot Outline</span><a class="headerlink" href="#plot-outline" title="Link to this heading">#</a></h2>
<p>What is our use case?</p>
<ul>
<li>We are given a dataset where we have data of Liverpool&rsquo;s players and their minutes played in the last 2 seasons (for whichever club they for played in that time period). We will use this data for our visualisation.</li>
<li>The final visualisation is the featured image of this blog post. We will navigate step-by-step as to how we&rsquo;ll create the visualisation.</li>
</ul>
<h2 id="importing-libraries"><span style="text-decoration: underline">Importing Libraries</span><a class="headerlink" href="#importing-libraries" title="Link to this heading">#</a></h2>
<p>The first and foremost part is to import the essential libraries so that we can leverage the functions within. In this case, we will import the libraries we need.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib.path</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib.patches</span> <span class="kn">import</span> <span class="n">FancyBboxPatch</span><span class="p">,</span> <span class="n">PathPatch</span><span class="p">,</span> <span class="n">Wedge</span></span></span></code></pre>
</div>
<p>The functions imported from <code>matplotlib.path</code> and <code>matplotlib.patches</code> will be used to draw lines, rectangles, boxes and so on to display the battery as it is.</p>
<h2 id="drawing-the-battery---a-function"><span style="text-decoration: underline">Drawing the Battery - A function</span><a class="headerlink" href="#drawing-the-battery---a-function" title="Link to this heading">#</a></h2>
<p>The next part is to define a function named <code>draw_battery()</code>, which will be used to draw the battery. Later on, we will call this function by specifying certain parameters to build the figure as we require. The following below is the code to build the battery -</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">draw_battery</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">percentage</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">bat_ec</span><span class="o">=</span><span class="s2">&#34;grey&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">tip_fc</span><span class="o">=</span><span class="s2">&#34;none&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">tip_ec</span><span class="o">=</span><span class="s2">&#34;grey&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">bol_fc</span><span class="o">=</span><span class="s2">&#34;#fdfdfd&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">bol_ec</span><span class="o">=</span><span class="s2">&#34;grey&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">invert_perc</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Parameters
</span></span></span><span class="line"><span class="cl"><span class="s2">    ----------
</span></span></span><span class="line"><span class="cl"><span class="s2">    fig : figure
</span></span></span><span class="line"><span class="cl"><span class="s2">        The figure object for the plot
</span></span></span><span class="line"><span class="cl"><span class="s2">    ax : axes
</span></span></span><span class="line"><span class="cl"><span class="s2">        The axes/axis variable of the figure.
</span></span></span><span class="line"><span class="cl"><span class="s2">    percentage : int, optional
</span></span></span><span class="line"><span class="cl"><span class="s2">        This is the battery percentage - size of the fill. The default is 0.
</span></span></span><span class="line"><span class="cl"><span class="s2">    bat_ec : str, optional
</span></span></span><span class="line"><span class="cl"><span class="s2">        The edge color of the battery/cell. The default is &#34;grey&#34;.
</span></span></span><span class="line"><span class="cl"><span class="s2">    tip_fc : str, optional
</span></span></span><span class="line"><span class="cl"><span class="s2">        The fill/face color of the tip of battery. The default is &#34;none&#34;.
</span></span></span><span class="line"><span class="cl"><span class="s2">    tip_ec : str, optional
</span></span></span><span class="line"><span class="cl"><span class="s2">        The edge color of the tip of battery. The default is &#34;grey&#34;.
</span></span></span><span class="line"><span class="cl"><span class="s2">    bol_fc : str, optional
</span></span></span><span class="line"><span class="cl"><span class="s2">        The fill/face color of the lightning bolt. The default is &#34;#fdfdfd&#34;.
</span></span></span><span class="line"><span class="cl"><span class="s2">    bol_ec : str, optional
</span></span></span><span class="line"><span class="cl"><span class="s2">        The edge color of the lightning bolt. The default is &#34;grey&#34;.
</span></span></span><span class="line"><span class="cl"><span class="s2">    invert_perc : bool, optional
</span></span></span><span class="line"><span class="cl"><span class="s2">        A flag to invert the percentage shown inside the battery. The default is False
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">    Returns
</span></span></span><span class="line"><span class="cl"><span class="s2">    -------
</span></span></span><span class="line"><span class="cl"><span class="s2">    None.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">fig</span><span class="o">.</span><span class="n">set_size_inches</span><span class="p">((</span><span class="mi">15</span><span class="p">,</span> <span class="mi">15</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">xlim</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">20</span><span class="p">),</span> <span class="n">ylim</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">&#34;off&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">invert_perc</span> <span class="o">==</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">percentage</span> <span class="o">=</span> <span class="mi">100</span> <span class="o">-</span> <span class="n">percentage</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># color options - #fc3d2e red &amp; #53d069 green &amp; #f5c54e yellow</span>
</span></span><span class="line"><span class="cl">        <span class="n">bat_fc</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;#fc3d2e&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">percentage</span> <span class="o">&lt;=</span> <span class="mi">20</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="s2">&#34;#53d069&#34;</span> <span class="k">if</span> <span class="n">percentage</span> <span class="o">&gt;=</span> <span class="mi">80</span> <span class="k">else</span> <span class="s2">&#34;#f5c54e&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">        Static battery and tip of battery
</span></span></span><span class="line"><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">battery</span> <span class="o">=</span> <span class="n">FancyBboxPatch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mf">2.1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="mf">0.8</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;round, pad=0.2, rounding_size=0.5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">fc</span><span class="o">=</span><span class="s2">&#34;none&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ec</span><span class="o">=</span><span class="n">bat_ec</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">fill</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ls</span><span class="o">=</span><span class="s2">&#34;-&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">lw</span><span class="o">=</span><span class="mf">1.5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">tip</span> <span class="o">=</span> <span class="n">Wedge</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mf">15.35</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">),</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mi">270</span><span class="p">,</span> <span class="mi">90</span><span class="p">,</span> <span class="n">fc</span><span class="o">=</span><span class="s2">&#34;none&#34;</span><span class="p">,</span> <span class="n">ec</span><span class="o">=</span><span class="n">bat_ec</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">ls</span><span class="o">=</span><span class="s2">&#34;-&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">3</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">add_artist</span><span class="p">(</span><span class="n">battery</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">add_artist</span><span class="p">(</span><span class="n">tip</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">        Filling the battery cell with the data
</span></span></span><span class="line"><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">filler</span> <span class="o">=</span> <span class="n">FancyBboxPatch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mf">5.1</span><span class="p">,</span> <span class="mf">2.13</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="n">percentage</span> <span class="o">/</span> <span class="mi">10</span><span class="p">)</span> <span class="o">-</span> <span class="mf">0.2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="mf">0.74</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;round, pad=0.2, rounding_size=0.5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">fc</span><span class="o">=</span><span class="n">bat_fc</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ec</span><span class="o">=</span><span class="n">bat_fc</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">fill</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ls</span><span class="o">=</span><span class="s2">&#34;-&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">lw</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">add_artist</span><span class="p">(</span><span class="n">filler</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">        Adding a lightning bolt in the centre of the cell
</span></span></span><span class="line"><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">verts</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mf">10.5</span><span class="p">,</span> <span class="mf">3.1</span><span class="p">),</span>  <span class="c1"># top</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mf">8.5</span><span class="p">,</span> <span class="mf">2.4</span><span class="p">),</span>  <span class="c1"># left</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mf">9.5</span><span class="p">,</span> <span class="mf">2.4</span><span class="p">),</span>  <span class="c1"># left mid</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mf">1.9</span><span class="p">),</span>  <span class="c1"># bottom</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="mf">2.6</span><span class="p">),</span>  <span class="c1"># right</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">2.6</span><span class="p">),</span>  <span class="c1"># right mid</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="mf">10.5</span><span class="p">,</span> <span class="mf">3.1</span><span class="p">),</span>  <span class="c1"># top</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">codes</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="n">Path</span><span class="o">.</span><span class="n">MOVETO</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">Path</span><span class="o">.</span><span class="n">LINETO</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">Path</span><span class="o">.</span><span class="n">LINETO</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">Path</span><span class="o">.</span><span class="n">LINETO</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">Path</span><span class="o">.</span><span class="n">LINETO</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">Path</span><span class="o">.</span><span class="n">LINETO</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">Path</span><span class="o">.</span><span class="n">CLOSEPOLY</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">path</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">verts</span><span class="p">,</span> <span class="n">codes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">bolt</span> <span class="o">=</span> <span class="n">PathPatch</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">fc</span><span class="o">=</span><span class="n">bol_fc</span><span class="p">,</span> <span class="n">ec</span><span class="o">=</span><span class="n">bol_ec</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">1.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">add_artist</span><span class="p">(</span><span class="n">bolt</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="kn">import</span> <span class="nn">traceback</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;EXCEPTION FOUND!!! SAFELY EXITING!!! Find the details below:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">traceback</span><span class="o">.</span><span class="n">print_exc</span><span class="p">()</span></span></span></code></pre>
</div>
<h2 id="reading-the-data"><span style="text-decoration: underline">Reading the Data</span><a class="headerlink" href="#reading-the-data" title="Link to this heading">#</a></h2>
<p>Once we have created the API or function, we can now implement the same. And for that, we need to feed in required data. In our example, we have a dataset that has the list of Liverpool players and the minutes they have played in the past two seasons. The data was collected from <a href="http://www.fbref.com">Football Reference aka FBRef</a>.</p>
<p>We use the read excel function in the pandas library to read our dataset that is stored as an excel file.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_excel</span><span class="p">(</span><span class="s2">&#34;Liverpool Minutes Played.xlsx&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p>Now, let us have a look at how the data looks by listing out the first five rows of our dataset -</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">data</span><span class="o">.</span><span class="n">head</span><span class="p">()</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/visualising-usage-using-batteries/head_data.PNG" alt="The first 5 rows of our dataset"></p>
<h2 id="plotting-our-data"><span style="text-decoration: underline">Plotting our data</span><a class="headerlink" href="#plotting-our-data" title="Link to this heading">#</a></h2>
<p>Now that everything is ready, we go ahead and plot the data. We have 25 players in our dataset, so a 5 x 5 figure is the one to go for. We&rsquo;ll also add some headers and set the colors accordingly.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">facecolor</span> <span class="o">=</span> <span class="s2">&#34;#00001a&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">set_facecolor</span><span class="p">(</span><span class="n">facecolor</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="mf">0.35</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mf">0.95</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Liverpool: Player Usage/Involvement&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span><span class="o">=</span><span class="s2">&#34;white&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">size</span><span class="o">=</span><span class="mi">18</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">fontname</span><span class="o">=</span><span class="s2">&#34;Libre Baskerville&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">fontweight</span><span class="o">=</span><span class="s2">&#34;bold&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="mf">0.25</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mf">0.92</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Data from 19/20 and 20/21 | Battery percentage indicate usage | less battery = played more/ more involved&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span><span class="o">=</span><span class="s2">&#34;white&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">size</span><span class="o">=</span><span class="mi">12</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">fontname</span><span class="o">=</span><span class="s2">&#34;Libre Baskerville&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre>
</div>
<p>We have now now filled in appropriate headers, figure size etc. The next step is to plot all the axes i.e. batteries for each and every player. <code>p</code> is the variable used to iterate through the dataframe and fetch each players data. The <code>draw_battery()</code> function call will obviously plot the battery. We also add the required labels along with that - player name and usage rate/percentage in this case.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">p</span> <span class="o">=</span> <span class="mi">0</span>  <span class="c1"># The variable that&#39;ll iterate through each row of the dataframe (for every player)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nb">str</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">p</span><span class="p">,</span> <span class="mi">0</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">            <span class="n">color</span><span class="o">=</span><span class="s2">&#34;white&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">size</span><span class="o">=</span><span class="mi">14</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">fontname</span><span class="o">=</span><span class="s2">&#34;Lora&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">va</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">set_facecolor</span><span class="p">(</span><span class="n">facecolor</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">draw_battery</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">],</span> <span class="nb">round</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">p</span><span class="p">,</span> <span class="mi">8</span><span class="p">]),</span> <span class="n">invert_perc</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">        Add the battery percentage as text if a label is required
</span></span></span><span class="line"><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="mf">0.9</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Usage - &#34;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="mi">100</span> <span class="o">-</span> <span class="nb">round</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">p</span><span class="p">,</span> <span class="mi">8</span><span class="p">])))</span> <span class="o">+</span> <span class="s2">&#34;%&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">fontsize</span><span class="o">=</span><span class="mi">12</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">color</span><span class="o">=</span><span class="s2">&#34;white&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span> <span class="o">+=</span> <span class="mi">1</span></span></span></code></pre>
</div>
<p>Now that everything is almost done, we do some final touchup and this is a completely optional part anyway. Since the visualisation is focused on Liverpool players, I add Liverpool&rsquo;s logo and also add my watermark. Also, crediting the data source/provider is more of an ethical habit, so we go ahead and do that as well before displaying the plot.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">liv</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s2">&#34;Liverpool.png&#34;</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">liv</span> <span class="o">=</span> <span class="n">liv</span><span class="o">.</span><span class="n">resize</span><span class="p">((</span><span class="mi">80</span><span class="p">,</span> <span class="mi">80</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">liv</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">liv</span><span class="p">)</span><span class="o">.</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">float</span><span class="p">)</span> <span class="o">/</span> <span class="mi">255</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">figimage</span><span class="p">(</span><span class="n">liv</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="mi">890</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="mf">0.11</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mf">0.08</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;viz: Rithwik Rajendran/@rithwikrajendra&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span><span class="o">=</span><span class="s2">&#34;lightgrey&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">size</span><span class="o">=</span><span class="mi">14</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">fontname</span><span class="o">=</span><span class="s2">&#34;Lora&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="mf">0.8</span><span class="p">,</span> <span class="mf">0.08</span><span class="p">,</span> <span class="s2">&#34;data: FBRef/Statsbomb&#34;</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;lightgrey&#34;</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">14</span><span class="p">,</span> <span class="n">fontname</span><span class="o">=</span><span class="s2">&#34;Lora&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre>
</div>
<p>So, we have the plot below. You can customise the design as you want in the <code>draw_battery()</code> function - change size, colours, shapes etc</p>
<p><img src="/matplotlib/visualising-usage-using-batteries/Liverpool_Usage_Chart.png" alt="Usage Chart Liverpool"></p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[The Python Graph Gallery: hundreds of python charts with reproducible code.]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/python-graph-gallery.com/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/codeswitching-visualization/?utm_source=atom_feed" rel="related" type="text/html" title="Visualizing Code-Switching with Step Charts" />
                <link href="https://blog.scientific-python.org/matplotlib/draw-all-graphs-of-n-nodes/?utm_source=atom_feed" rel="related" type="text/html" title="Draw all graphs of N nodes" />
                <link href="https://blog.scientific-python.org/matplotlib/stellar-chart-alternative-radar-chart/?utm_source=atom_feed" rel="related" type="text/html" title="Stellar Chart, a Type of Chart to Be on Your Radar" />
                <link href="https://blog.scientific-python.org/matplotlib/ipcc-sr15/?utm_source=atom_feed" rel="related" type="text/html" title="Figures in the IPCC Special Report on Global Warming of 1.5°C (SR15)" />
                <link href="https://blog.scientific-python.org/matplotlib/elementary-cellular-automata/?utm_source=atom_feed" rel="related" type="text/html" title="Elementary Cellular Automata" />
            
                <id>https://blog.scientific-python.org/matplotlib/python-graph-gallery.com/</id>
            
            
            <published>2021-07-24T14:06:57+02:00</published>
            <updated>2021-07-24T14:06:57+02:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>The Python Graph Gallery is a website that displays hundreds of chart examples made with python. It goes from very basic to highly customized examples and is based on common viz libraries like matplotlib, seaborn or plotly.</blockquote><p>Data visualization is a key step in a data science pipeline. <a href="https://www.python.org">Python</a> offers great possibilities when it comes to representing some data graphically, but it can be hard and time-consuming to create the appropriate chart.</p>
<p>The <a href="https://www.python-graph-gallery.com">Python Graph Gallery</a> is here to help. It displays many examples, always providing the reproducible code. It allows to build the desired chart in minutes.</p>
<h1 id="about-400-charts-in-40-sections">About 400 charts in 40 sections<a class="headerlink" href="#about-400-charts-in-40-sections" title="Link to this heading">#</a></h1>
<p>The gallery currently provides more than <a href="https://www.python-graph-gallery.com/all-charts/">400 chart examples</a>. Those examples are organized in 40 sections, one for each chart types: <a href="https://www.python-graph-gallery.com/scatter-plot/">scatterplot</a>, <a href="https://www.python-graph-gallery.com/boxplot/">boxplot</a>, <a href="https://www.python-graph-gallery.com/barplot/">barplot</a>, <a href="https://www.python-graph-gallery.com/treemap/">treemap</a> and so on. Those chart types are organized in 7 big families as suggested by <a href="https://www.data-to-viz.com">data-to-viz.com</a>: one for each visualization purpose.</p>
<p>It is important to note that not only the most common chart types are covered. Lesser known charts like <a href="https://www.python-graph-gallery.com/chord-diagram/">chord diagrams</a>, <a href="https://www.python-graph-gallery.com/streamchart/">streamgraphs</a> or <a href="https://www.python-graph-gallery.com/bubble-map/">bubble maps</a> are also available.</p>
<p><img src="/matplotlib/python-graph-gallery.com/sections-overview.png" alt="overview of the python graph gallery sections"></p>
<h1 id="master-the-basics">Master the basics<a class="headerlink" href="#master-the-basics" title="Link to this heading">#</a></h1>
<p>Each section always starts with some very basic examples. It allows to understand how to build a chart type in a few seconds. Hopefully applying the same technique on another dataset will thus be very quick.</p>
<p>For instance, the <a href="https://www.python-graph-gallery.com/scatter-plot/">scatterplot section</a> starts with this <a href="https://matplotlib.org/">matplotlib</a> example. It shows how to create a dataset with <a href="https://pandas.pydata.org/">pandas</a> and plot it with the <code>plot()</code> function. The main graph argument like <code>linestyle</code> and <code>marker</code> are described to make sure the code is understandable.</p>
<p><a href="https://www.python-graph-gallery.com/130-basic-matplotlib-scatterplot"><em>blogpost overview</em>:</a></p>
<p><img src="/matplotlib/python-graph-gallery.com/scatterplot-example.png" alt="a basic scatterplot example"></p>
<h1 id="matplotlib-customization">Matplotlib customization<a class="headerlink" href="#matplotlib-customization" title="Link to this heading">#</a></h1>
<p>The gallery uses several libraries like <a href="https://www.python-graph-gallery.com/seaborn/">seaborn</a> or <a href="https://www.python-graph-gallery.com/plotly/">plotly</a> to produce its charts, but is mainly focus on matplotlib. Matplotlib comes with great flexibility and allows to build any kind of chart without limits.</p>
<p>A <a href="https://www.python-graph-gallery.com/matplotlib/">whole page</a> is dedicated to matplotlib. It describes how to solve recurring issues like customizing <a href="https://www.python-graph-gallery.com/191-custom-axis-on-matplotlib-chart">axes</a> or <a href="https://www.python-graph-gallery.com/190-custom-matplotlib-title">titles</a>, adding <a href="https://www.python-graph-gallery.com/193-annotate-matplotlib-chart">annotations</a> (see below) or even using <a href="https://www.python-graph-gallery.com/custom-fonts-in-matplotlib">custom fonts</a>.</p>
<p><img src="/matplotlib/python-graph-gallery.com/annotations.png" alt="annotation examples"></p>
<p>The gallery is also full of non-straightforward examples. For instance, it has a <a href="https://www.python-graph-gallery.com/streamchart-basic-matplotlib">tutorial</a> explaining how to build a streamchart with matplotlib. It is based on the <code>stackplot()</code> function and adds some smoothing to it:</p>
<p><img src="/matplotlib/python-graph-gallery.com/streamchart.png" alt="stream chart with python and matplotlib"></p>
<p>Last but not least, the gallery also displays some publication ready charts. They usually involve a lot of matplotlib code, but showcase the fine grain control one has over a plot.</p>
<p>Here is an example with a post inspired by <a href="https://www.r-graph-gallery.com/web-violinplot-with-ggstatsplot.html">Tuo Wang</a>&rsquo;s work for the tidyTuesday project. (Code translated from R available <a href="https://www.python-graph-gallery.com/web-ggbetweenstats-with-matplotlib">here</a>)</p>
<p><img src="/matplotlib/python-graph-gallery.com/boxplot.png" alt="python violin and boxplot example"></p>
<h1 id="contributing">Contributing<a class="headerlink" href="#contributing" title="Link to this heading">#</a></h1>
<p>The python graph gallery is an ever growing project. It is open-source, with all its related code hosted on <a href="https://github.com/holtzy/The-Python-Graph-Gallery">github</a>.</p>
<p>Contributions are very welcome to the gallery. Each blogpost is just a jupyter notebook so suggestion should be very easy to do through issues or pull requests!</p>
<h1 id="conclusion">Conclusion<a class="headerlink" href="#conclusion" title="Link to this heading">#</a></h1>
<p>The <a href="https://www.python-graph-gallery.com">python graph gallery</a> is a project developed by <a href="https://www.yan-holtz.com">Yan Holtz</a> in his free time. It can help you improve your technical skills when it comes to visualizing data with python.</p>
<p>The gallery belongs to an ecosystem of educative websites. <a href="https://www.data-to-viz.com">Data to viz</a> describes best practices in data visualization, the <a href="https://www.r-graph-gallery.com">R</a>, <a href="https://www.python-graph-gallery.com">python</a> and <a href="https://www.d3-graph-gallery.com">d3.js</a> graph galleries provide technical help to build charts with the 3 most common tools.</p>
<p>For any question regarding the project, please say hi on twitter at <a href="https://twitter.com/R_Graph_Gallery">@R_Graph_Gallery</a>!</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="graphs" label="graphs" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Stellar Chart, a Type of Chart to Be on Your Radar]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/stellar-chart-alternative-radar-chart/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/ipcc-sr15/?utm_source=atom_feed" rel="related" type="text/html" title="Figures in the IPCC Special Report on Global Warming of 1.5°C (SR15)" />
                <link href="https://blog.scientific-python.org/matplotlib/codeswitching-visualization/?utm_source=atom_feed" rel="related" type="text/html" title="Visualizing Code-Switching with Step Charts" />
                <link href="https://blog.scientific-python.org/matplotlib/elementary-cellular-automata/?utm_source=atom_feed" rel="related" type="text/html" title="Elementary Cellular Automata" />
                <link href="https://blog.scientific-python.org/matplotlib/animated-fractals/?utm_source=atom_feed" rel="related" type="text/html" title="Animate Your Own Fractals in Python with Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/animated-polar-plot/?utm_source=atom_feed" rel="related" type="text/html" title="Animated polar plot with oceanographic data" />
            
                <id>https://blog.scientific-python.org/matplotlib/stellar-chart-alternative-radar-chart/</id>
            
            
            <published>2021-01-10T20:29:40+00:00</published>
            <updated>2021-01-10T20:29:40+00:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Learn how to create a simple stellar chart, an alternative to the radar chart.</blockquote><p>In May 2020, Alexandre Morin-Chassé published a blog post about the <strong>stellar chart</strong>. This type of chart is an (approximately) direct alternative to the <strong>radar chart</strong> (also known as web, spider, star, or cobweb chart) — you can read more about this chart <a href="https://medium.com/nightingale/the-stellar-chart-an-elegant-alternative-to-radar-charts-ae6a6931a28e">here</a>.</p>
<p><img src="/matplotlib/stellar-chart-alternative-radar-chart/radar_stellar_chart.png" alt="Comparison of a radar chart and a stellar chart"></p>
<p>In this tutorial, we will see how we can create a quick-and-dirty stellar chart. First of all, let&rsquo;s get the necessary modules/libraries, as well as prepare a dummy dataset (with just a single record).</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">chain</span><span class="p">,</span> <span class="n">zip_longest</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">ceil</span><span class="p">,</span> <span class="n">pi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;V1&#34;</span><span class="p">,</span> <span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;V2&#34;</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;V3&#34;</span><span class="p">,</span> <span class="mi">9</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;V4&#34;</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;V5&#34;</span><span class="p">,</span> <span class="mi">6</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;V6&#34;</span><span class="p">,</span> <span class="mi">14</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;V7&#34;</span><span class="p">,</span> <span class="mi">15</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;V8&#34;</span><span class="p">,</span> <span class="mi">25</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span></span></span></code></pre>
</div>
<p>We will also need some helper functions, namely a function to round up to the nearest 10 (<code>round_up()</code>) and a function to join two sequences (<code>even_odd_merge()</code>). In the latter, the values of the first sequence (a list or a tuple, basically) will fill the even positions and the values of the second the odd ones.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">round_up</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    &gt;&gt;&gt; round_up(25)
</span></span></span><span class="line"><span class="cl"><span class="s2">    30
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">ceil</span><span class="p">(</span><span class="n">value</span> <span class="o">/</span> <span class="mf">10.0</span><span class="p">))</span> <span class="o">*</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">even_odd_merge</span><span class="p">(</span><span class="n">even</span><span class="p">,</span> <span class="n">odd</span><span class="p">,</span> <span class="n">filter_none</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    &gt;&gt;&gt; list(even_odd_merge([1,3], [2,4]))
</span></span></span><span class="line"><span class="cl"><span class="s2">    [1, 2, 3, 4]
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">filter_none</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">filter</span><span class="p">(</span><span class="kc">None</span><span class="o">.</span><span class="fm">__ne__</span><span class="p">,</span> <span class="n">chain</span><span class="o">.</span><span class="n">from_iterable</span><span class="p">(</span><span class="n">zip_longest</span><span class="p">(</span><span class="n">even</span><span class="p">,</span> <span class="n">odd</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">chain</span><span class="o">.</span><span class="n">from_iterable</span><span class="p">(</span><span class="n">zip_longest</span><span class="p">(</span><span class="n">even</span><span class="p">,</span> <span class="n">odd</span><span class="p">))</span></span></span></code></pre>
</div>
<p>That said, to plot <code>data</code> on a stellar chart, we need to apply some transformations, as well as calculate some auxiliary values. So, let&rsquo;s start by creating a function (<code>prepare_angles()</code>) to calculate the angle of each axis on the chart (<code>N</code> corresponds to the number of variables to be plotted).</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">prepare_angles</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">angles</span> <span class="o">=</span> <span class="p">[</span><span class="n">n</span> <span class="o">/</span> <span class="n">N</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">pi</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Repeat the first angle to close the circle</span>
</span></span><span class="line"><span class="cl">    <span class="n">angles</span> <span class="o">+=</span> <span class="n">angles</span><span class="p">[:</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">angles</span></span></span></code></pre>
</div>
<p>Next, we need a function (<code>prepare_data()</code>) responsible for adjusting the original data (<code>data</code>) and separating it into several easy-to-use objects.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">prepare_data</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">labels</span> <span class="o">=</span> <span class="p">[</span><span class="n">d</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">data</span><span class="p">]</span>  <span class="c1"># Variable names</span>
</span></span><span class="line"><span class="cl">    <span class="n">values</span> <span class="o">=</span> <span class="p">[</span><span class="n">d</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">data</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Repeat the first value to close the circle</span>
</span></span><span class="line"><span class="cl">    <span class="n">values</span> <span class="o">+=</span> <span class="n">values</span><span class="p">[:</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">N</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">labels</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">angles</span> <span class="o">=</span> <span class="n">prepare_angles</span><span class="p">(</span><span class="n">N</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">labels</span><span class="p">,</span> <span class="n">values</span><span class="p">,</span> <span class="n">angles</span><span class="p">,</span> <span class="n">N</span></span></span></code></pre>
</div>
<p>Lastly, for this specific type of chart, we require a function (<code>prepare_stellar_aux_data()</code>) that, from the previously calculated angles, prepares two lists of auxiliary values: a list of <strong>intermediate angles</strong> for each pair of angles (<code>stellar_angles</code>) and a list of small <strong>constant values</strong> (<code>stellar_values</code>), which will act as the values of the variables to be plotted in order to achieve the <strong>star-like shape</strong> intended for the stellar chart.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">prepare_stellar_aux_data</span><span class="p">(</span><span class="n">angles</span><span class="p">,</span> <span class="n">ymax</span><span class="p">,</span> <span class="n">N</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">angle_midpoint</span> <span class="o">=</span> <span class="n">pi</span> <span class="o">/</span> <span class="n">N</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">stellar_angles</span> <span class="o">=</span> <span class="p">[</span><span class="n">angle</span> <span class="o">+</span> <span class="n">angle_midpoint</span> <span class="k">for</span> <span class="n">angle</span> <span class="ow">in</span> <span class="n">angles</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]]</span>
</span></span><span class="line"><span class="cl">    <span class="n">stellar_values</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.05</span> <span class="o">*</span> <span class="n">ymax</span><span class="p">]</span> <span class="o">*</span> <span class="n">N</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">stellar_angles</span><span class="p">,</span> <span class="n">stellar_values</span></span></span></code></pre>
</div>
<p>At this point, we already have all the necessary <em>ingredients</em> for the stellar chart, so let&rsquo;s move on to the Matplotlib side of this tutorial. In terms of <strong>aesthetics</strong>, we can rely on a function (<code>draw_peripherals()</code>) designed for this specific purpose (feel free to customize it!).</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">draw_peripherals</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">labels</span><span class="p">,</span> <span class="n">angles</span><span class="p">,</span> <span class="n">ymax</span><span class="p">,</span> <span class="n">outer_color</span><span class="p">,</span> <span class="n">inner_color</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># X-axis</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">angles</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_xticklabels</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">outer_color</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Y-axis</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_yticks</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">ymax</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_yticklabels</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">ymax</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span> <span class="n">color</span><span class="o">=</span><span class="n">inner_color</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">ymax</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_rlabel_position</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Both axes</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_axisbelow</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Boundary line</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;polar&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_color</span><span class="p">(</span><span class="n">outer_color</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Grid lines</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">xaxis</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">inner_color</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s2">&#34;-&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">yaxis</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">inner_color</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s2">&#34;-&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p>To <strong>plot the data</strong> and orchestrate (almost) all the steps necessary to have a stellar chart, we just need one last function: <code>draw_stellar()</code>.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">draw_stellar</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">labels</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">values</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">angles</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">N</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">shape_color</span><span class="o">=</span><span class="s2">&#34;tab:blue&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">outer_color</span><span class="o">=</span><span class="s2">&#34;slategrey&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">inner_color</span><span class="o">=</span><span class="s2">&#34;lightgrey&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Limit the Y-axis according to the data to be plotted</span>
</span></span><span class="line"><span class="cl">    <span class="n">ymax</span> <span class="o">=</span> <span class="n">round_up</span><span class="p">(</span><span class="nb">max</span><span class="p">(</span><span class="n">values</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Get the lists of angles and variable values</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># with the necessary auxiliary values injected</span>
</span></span><span class="line"><span class="cl">    <span class="n">stellar_angles</span><span class="p">,</span> <span class="n">stellar_values</span> <span class="o">=</span> <span class="n">prepare_stellar_aux_data</span><span class="p">(</span><span class="n">angles</span><span class="p">,</span> <span class="n">ymax</span><span class="p">,</span> <span class="n">N</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">all_angles</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">even_odd_merge</span><span class="p">(</span><span class="n">angles</span><span class="p">,</span> <span class="n">stellar_angles</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">all_values</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">even_odd_merge</span><span class="p">(</span><span class="n">values</span><span class="p">,</span> <span class="n">stellar_values</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Apply the desired style to the figure elements</span>
</span></span><span class="line"><span class="cl">    <span class="n">draw_peripherals</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="n">labels</span><span class="p">,</span> <span class="n">angles</span><span class="p">,</span> <span class="n">ymax</span><span class="p">,</span> <span class="n">outer_color</span><span class="p">,</span> <span class="n">inner_color</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Draw (and fill) the star-shaped outer line/area</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">all_angles</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">all_values</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">linewidth</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">linestyle</span><span class="o">=</span><span class="s2">&#34;solid&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">solid_joinstyle</span><span class="o">=</span><span class="s2">&#34;round&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="n">shape_color</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">fill</span><span class="p">(</span><span class="n">all_angles</span><span class="p">,</span> <span class="n">all_values</span><span class="p">,</span> <span class="n">shape_color</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Add a small hole in the center of the chart</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">marker</span><span class="o">=</span><span class="s2">&#34;o&#34;</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;white&#34;</span><span class="p">,</span> <span class="n">markersize</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span></span></span></code></pre>
</div>
<p>Finally, let&rsquo;s get our chart on a <em>blank canvas</em> (figure).</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">dpi</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">111</span><span class="p">,</span> <span class="n">polar</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>  <span class="c1"># Don&#39;t forget the projection!</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">draw_stellar</span><span class="p">(</span><span class="n">ax</span><span class="p">,</span> <span class="o">*</span><span class="n">prepare_data</span><span class="p">(</span><span class="n">data</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/stellar-chart-alternative-radar-chart/stellar_chart.png" alt="Example of a stellar chart"></p>
<p>It&rsquo;s done! Right now, you have an example of a stellar chart and the boilerplate code to add this type of chart to your <em>repertoire</em>. If you end up creating your own stellar charts, feel free to share them with the <em>world</em> (and <a href="https://twitter.com/joaompalmeiro">me</a>!). I hope this tutorial was useful and interesting for you!</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Figures in the IPCC Special Report on Global Warming of 1.5°C (SR15)]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/ipcc-sr15/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/warming-stripes/?utm_source=atom_feed" rel="related" type="text/html" title="Creating the Warming Stripes in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/codeswitching-visualization/?utm_source=atom_feed" rel="related" type="text/html" title="Visualizing Code-Switching with Step Charts" />
                <link href="https://blog.scientific-python.org/matplotlib/elementary-cellular-automata/?utm_source=atom_feed" rel="related" type="text/html" title="Elementary Cellular Automata" />
                <link href="https://blog.scientific-python.org/matplotlib/animated-fractals/?utm_source=atom_feed" rel="related" type="text/html" title="Animate Your Own Fractals in Python with Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/animated-polar-plot/?utm_source=atom_feed" rel="related" type="text/html" title="Animated polar plot with oceanographic data" />
            
                <id>https://blog.scientific-python.org/matplotlib/ipcc-sr15/</id>
            
            
            <published>2020-12-31T08:32:45+01:00</published>
            <updated>2020-12-31T08:32:45+01:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Many figures in the IPCC SR15 were generated using Matplotlib.
The data and open-source notebooks were published to increase the transparency and reproducibility of the analysis.</blockquote><h2 id="background">Background<a class="headerlink" href="#background" title="Link to this heading">#</a></h2>
<figure style="float: right; ">
  <a href="https://www.ipcc.ch/sr15">
  <img src="IPCC-SR15-cover.jpg" style="width: 180px; "/>
  <figcaption style="text-align: center; color: grey; font-size: small">
  Cover of the IPCC SR15</figcaption></a>
</figure>
<p>The IPCC&rsquo;s <em>Special Report on Global Warming of 1.5°C</em> (SR15), published in October 2018,
presented the latest research on anthropogenic climate change.
It was written in response to the 2015 UNFCCC&rsquo;s &ldquo;Paris Agreement&rdquo; of</p>
<blockquote>
<p>holding the increase in the global average temperature to well below 2 °C
above pre-industrial levels and to pursue efforts to limit the temperature increase to 1.5 °C [&hellip;]&quot;.</p>
</blockquote>
<p>cf. <a href="https://unfccc.int/process-and-meetings/the-paris-agreement/the-paris-agreement">Article 2.1.a of the Paris Agreement</a></p>
<p>As part of the SR15 assessment, an ensemble of quantitative, model-based scenarios
was compiled to underpin the scientific analysis.
Many of the headline statements widely reported by media
are based on this scenario ensemble, including the finding that</p>
<blockquote>
<p>global net anthropogenic CO2 emissions decline by ~45% from 2010 levels by 2030</p>
</blockquote>
<p>in all pathways limiting global warming to 1.5°C
(cf. <a href="https://www.ipcc.ch/sr15/chapter/spm/">statement C.1</a> in the <em>Summary For Policymakers</em>).</p>
<h2 id="open-source-notebooks-for-transparency-and-reproducibility-of-the-assessment">Open-source notebooks for transparency and reproducibility of the assessment<a class="headerlink" href="#open-source-notebooks-for-transparency-and-reproducibility-of-the-assessment" title="Link to this heading">#</a></h2>
<p>When preparing the SR15, the authors wanted to go beyond previous reports
not just regarding the scientific rigor and scope of the analysis,
but also establish new standards in terms of openness, transparency and reproducibility.</p>
<p>The scenario ensemble was made accessible via an interactive <em>IAMC 1.5°C Scenario Explorer</em>
(<a href="http://data.ene.iiasa.ac.at/iamc-1.5c-explorer/#/workspaces">link</a>) in line with the
<a href="https://www.go-fair.org/fair-principles/">FAIR principles for scientific data management and stewardship</a>.
The process for compiling, validating and analyzing the scenario ensemble
was described in an open-access manuscript published in <em>Nature Climate Change</em>
(doi: <a href="https://doi.org/10.1038/s41558-018-0317-4">10.1038/s41558-018-0317-4</a>).</p>
<p>In addition, the Jupyter notebooks generating many of the headline statements,
tables and figures (using Matplotlib) were released under an open-source license
to facilitate a better understanding of the analysis
and enable reuse for subsequent research.
The notebooks are available in <a href="https://data.ene.iiasa.ac.at/sr15_scenario_analysis">rendered format</a>
and on <a href="https://github.com/iiasa/ipcc_sr15_scenario_analysis">GitHub</a>.</p>
<figure style="width: 600px ">
  <img src="sr15-fig2.4.png" style="width: 600px; "/>
  <figcaption style="text-align: center; color: grey; font-size: small">
  Figure 2.4 of the IPCC SR15, showing the range of assumptions of socioeconomic drivers<br />
  across the IAMC 1.5°C Scenario Ensemble<br />
  Drawn with Matplotlib, source code available <a href="https://data.ene.iiasa.ac.at/sr15_scenario_analysis/assessment/sr15_2.3.1_range_of_assumptions.html">here</a>
  </figcaption>
</figure>
<figure style="width: 600px ">
  <img src="sr15-fig2.15.png" style="width: 600px; "/>
  <figcaption style="text-align: center; color: grey; font-size: small">
  Figure 2.15 of the IPCC SR15, showing the primary energy development in illustrative pathways<br />
  Drawn with Matplotlib, source code available <a href="https://data.ene.iiasa.ac.at/sr15_scenario_analysis/assessment/sr15_2.4.2.1_primary_energy_marker-scenarios.html">here</a>
  </figcaption>
</figure>
<h2 id="a-package-for-scenario-analysis--visualization">A package for scenario analysis &amp; visualization<a class="headerlink" href="#a-package-for-scenario-analysis--visualization" title="Link to this heading">#</a></h2>
<p>To facilitate reusability of the scripts and plotting utilities
developed for the SR15 analysis, we started the open-source Python package <strong>pyam</strong>
as a toolbox for working with scenarios from integrated-assessment and energy system models.</p>
<p>The package is a wrapper for <a href="https://pandas.pydata.org">pandas</a> and Matplotlib
geared for several data formats commonly used in energy modelling.
<a href="https://pyam-iamc.readthedocs.io">Read the docs!</a></p>
<p><a href="https://pyam-iamc.readthedocs.io"><img src="pyam-header.png"></a></p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="academia" label="academia" />
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Visualizing Code-Switching with Step Charts]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/codeswitching-visualization/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/draw-all-graphs-of-n-nodes/?utm_source=atom_feed" rel="related" type="text/html" title="Draw all graphs of N nodes" />
                <link href="https://blog.scientific-python.org/matplotlib/elementary-cellular-automata/?utm_source=atom_feed" rel="related" type="text/html" title="Elementary Cellular Automata" />
                <link href="https://blog.scientific-python.org/matplotlib/animated-fractals/?utm_source=atom_feed" rel="related" type="text/html" title="Animate Your Own Fractals in Python with Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/animated-polar-plot/?utm_source=atom_feed" rel="related" type="text/html" title="Animated polar plot with oceanographic data" />
                <link href="https://blog.scientific-python.org/matplotlib/emoji-mosaic-art/?utm_source=atom_feed" rel="related" type="text/html" title="Emoji Mosaic Art" />
            
                <id>https://blog.scientific-python.org/matplotlib/codeswitching-visualization/</id>
            
            
            <published>2020-09-26T19:41:21-07:00</published>
            <updated>2020-09-26T19:41:21-07:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Learn how to easily create step charts through examining the multilingualism of pop group WayV</blockquote><p><img src="/matplotlib/codeswitching-visualization/Image1.png" alt="Frequency of Code-Switching 200403 WayV Instagram Live, a step chart. The figure shows a plot of ‘cumulative number of times of code-switching’ against the ‘duration of Instagram Live (in seconds)’. There are four members in the livestream: Yangyang (represented with a dark red line), Hendery (represented with a pink line), Ten (represented with a light blue line), Kun (represented with a dark blue line)."></p>
<h1 id="introduction">Introduction<a class="headerlink" href="#introduction" title="Link to this heading">#</a></h1>
<p>Code-switching is the practice of alternating between two or more languages in the context of a single conversation, either consciously or unconsciously. As someone who grew up bilingual and is currently learning other languages, I find code-switching a fascinating facet of communication from not only a purely linguistic perspective, but also a social one. In particular, I&rsquo;ve personally found that code-switching often helps build a sense of community and familiarity in a group and that the unique ways in which speakers code-switch with each other greatly contribute to shaping group dynamics.</p>
<p>This is something that&rsquo;s evident in seven-member pop boy group WayV. Aside from their discography, artistry, and group chemistry, WayV is well-known among fans and many non-fans alike for their multilingualism and code-switching, which many fans have affectionately coined as &ldquo;WayV language.&rdquo; Every member in the group is fluent in both Mandarin and Korean, and at least one member in the group is fluent in one or more of the following: English, Cantonese, Thai, Wenzhounese, and German. It&rsquo;s an impressive trait that&rsquo;s become a trademark of WayV as they&rsquo;ve quickly drawn a global audience since their debut in January 2019. Their multilingualism is reflected in their music as well. On top of their regular album releases in Mandarin, WayV has also released singles in Korean and English, with their latest single &ldquo;Bad Alive (English Ver.)&rdquo; being a mix of English, Korean, and Mandarin.</p>
<p>As an independent translator who translates WayV content into English, I&rsquo;ve become keenly aware of the true extent and rate of WayV&rsquo;s code-switching when communicating with each other. In a lot of their content, WayV frequently switches between three or more languages every couple of seconds, a phenomenon that can make translating quite challenging at times, but also extremely rewarding and fun. I wanted to be able to present this aspect of WayV in a way that would both highlight their linguistic skills and present this dimension of their group dynamic in a more concrete, quantitative, and visually intuitive manner, beyond just stating that &ldquo;they code-switch a lot.&rdquo; This prompted me to make step charts - perfect for displaying data that changes at irregular intervals but remains constant between the changes - in hopes of enriching the viewer&rsquo;s experience and helping make a potentially abstract concept more understandable and readily consumable. With a step chart, it becomes more apparent to the viewer the extent of how a group communicates, and cross-sections of the graph allow a rudimentary look into how multilinguals influence each other in code-switching.</p>
<h1 id="tutorial">Tutorial<a class="headerlink" href="#tutorial" title="Link to this heading">#</a></h1>
<p>This tutorial on creating step charts uses one of WayV&rsquo;s livestreams as an example. There were four members in this livestream and a total of eight languages/dialects spoken. I will go through the basic steps of creating a step chart that depicts the frequency of code-switching for just one member. A full code chunk that shows how to layer two or more step chart lines in one graph to depict code-switching for multiple members can be found near the end.</p>
<h2 id="dataset">Dataset<a class="headerlink" href="#dataset" title="Link to this heading">#</a></h2>
<p>First, we import the required libraries and load the data into a Pandas dataframe.</p>
<pre><code>import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
</code></pre>
<p>This dataset includes the timestamp of every switch (in seconds) and the language of switch for one speaker.</p>
<pre><code>df_h = pd.read_csv(&quot;WayVHendery.csv&quot;)
HENDERY = df_h.reset_index()
HENDERY.head()
</code></pre>
<table>
  <thead>
      <tr>
          <th>index</th>
          <th>time</th>
          <th>lang</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>0</td>
          <td>2</td>
          <td>ENG</td>
      </tr>
      <tr>
          <td>1</td>
          <td>3</td>
          <td>KOR</td>
      </tr>
      <tr>
          <td>2</td>
          <td>10</td>
          <td>ENG</td>
      </tr>
      <tr>
          <td>3</td>
          <td>13</td>
          <td>MAND</td>
      </tr>
      <tr>
          <td>4</td>
          <td>15</td>
          <td>ENG</td>
      </tr>
  </tbody>
</table>
<h2 id="plotting">Plotting<a class="headerlink" href="#plotting" title="Link to this heading">#</a></h2>
<p>With the dataset loaded, we can now set up our graph in terms of determining the size of the figure, dpi, font size, and axes limits. We can also play around with the aesthetics, such as modifying the colors of our plot. These few simple steps easily transform the default all-white graph into a more visually appealing one.</p>
<h3 id="without-customization">Without Customization<a class="headerlink" href="#without-customization" title="Link to this heading">#</a></h3>
<pre><code>fig, ax = plt.subplots(figsize = (20,12))
</code></pre>
<p><img src="/matplotlib/codeswitching-visualization/fig1.png" alt="An all-white graph with the x and y axis defined on the range [0, 1]."></p>
<h3 id="with-customization">With Customization<a class="headerlink" href="#with-customization" title="Link to this heading">#</a></h3>
<pre><code>sns.set(rc={'axes.facecolor':'aliceblue', 'figure.facecolor':'c'})
fig, ax = plt.subplots(figsize = (20,12), dpi = 300)

plt.xlabel(&quot;Duration of Instagram Live (seconds)&quot;, fontsize = 18)
plt.ylabel(&quot;Cumulative Number of Times of Code-Switching&quot;, fontsize = 18)

plt.xlim(0, 570)
plt.ylim(0, 85)
</code></pre>
<p><img src="/matplotlib/codeswitching-visualization/fig2.png" alt="A styled, blank graph with the ‘cumulative number of times of code-switching’ values on the y-axis and the ‘duration of Instagram Live (in seconds)’ values on the x-axis"></p>
<!--     ax.step(HENDERY.time, HENDERY.index, label = "HENDERY") -->
<p>Following this, we can make our step chart line easily with matplotlib.pyplot.step, in which we plot the x and y values and determine the text of the legend, color of the step chart line, and width of the step chart line.</p>
<pre><code>ax.step(HENDERY.time, HENDERY.index, label = &quot;HENDERY&quot;, color = &quot;palevioletred&quot;, linewidth = 4)
</code></pre>
<p><img src="/matplotlib/codeswitching-visualization/fig3.png" alt="A graph with the ‘cumulative number of times of code-switching’ values on the y-axis and the ‘duration of Instagram Live (in seconds)’ values on the x-axis showing a step chart line (in pink) for Hendery."></p>
<h2 id="labeling">Labeling<a class="headerlink" href="#labeling" title="Link to this heading">#</a></h2>
<p>Of course, we want to know not only how many switches there were and when they occurred, but also to what language the member switched. For this, we can write a for loop that labels each switch with its respective language as recorded in our dataset.</p>
<pre><code>for x,y,z in zip(HENDERY[&quot;time&quot;], HENDERY[&quot;index&quot;], HENDERY[&quot;lang&quot;]):
    label = z
    ax.annotate(label, #text
                 (x,y), #label coordinate
                 textcoords = &quot;offset points&quot;, #how to position text
                 xytext = (15,-5), #distance from text to coordinate (x,y)
                 ha = &quot;center&quot;, #alignment
                 fontsize = 8.5) #font size of text
</code></pre>
<p><img src="/matplotlib/codeswitching-visualization/fig4.png" alt="Language labels for each step on the graph. Languages include English, Korean, Mandarin, and German. The graph has the ‘cumulative number of times of code-switching’ values on the y-axis and the ‘duration of Instagram Live (in seconds)’ values on the x-axis showing a step chart line (in pink) for Hendery."></p>
<h2 id="final-touches">Final Touches<a class="headerlink" href="#final-touches" title="Link to this heading">#</a></h2>
<p>Now add a title, save the graph, and there you have it!</p>
<pre><code>plt.title(&quot;WayV Livestream Code-Switching&quot;, fontsize = 35)

fig.savefig(&quot;wayv_codeswitching.png&quot;, bbox_inches = &quot;tight&quot;, facecolor = fig.get_facecolor())
</code></pre>
<p>Below is the complete code for layering step chart lines for multiple speakers in one graph. You can see how easy it is to take the code for visualizing the code-switching of one speaker and adapt it to visualizing that of multiple speakers. In addition, you can see that I&rsquo;ve intentionally left the title blank so I can incorporate external graphic adjustments after I created the chart in Matplotlib, such as the addition of my social media handle and the use of a specific font I wanted, which you can see in the final graph. With visualizations being all about communicating information, I believe using Matplotlib in conjunction with simple elements of graphic design can be another way to make whatever you&rsquo;re presenting that little bit more effective and personal, especially when you&rsquo;re doing so on social media platforms.</p>
<h2 id="complete-code-for-step-chart-of-multiple-speakers">Complete Code for Step Chart of Multiple Speakers<a class="headerlink" href="#complete-code-for-step-chart-of-multiple-speakers" title="Link to this heading">#</a></h2>
<!-- ![](fig5.png) -->
<pre><code># Initialize graph color and size
sns.set(rc={'axes.facecolor':'aliceblue', 'figure.facecolor':'c'})

fig, ax = plt.subplots(figsize = (20,12), dpi = 120)

# Set up axes and labels
plt.xlabel(&quot;Duration of Instagram Live (seconds)&quot;, fontsize = 18)
plt.ylabel(&quot;Cumulative Number of Times of Code-Switching&quot;, fontsize = 18)

plt.xlim(0, 570)
plt.ylim(0, 85)

# Layer step charts for each speaker
ax.step(YANGYANG.time, YANGYANG.index, label = &quot;YANGYANG&quot;, color = &quot;firebrick&quot;, linewidth = 4)
ax.step(HENDERY.time, HENDERY.index, label = &quot;HENDERY&quot;, color = &quot;palevioletred&quot;, linewidth = 4)
ax.step(TEN.time, TEN.index, label = &quot;TEN&quot;, color = &quot;mediumpurple&quot;, linewidth = 4)
ax.step(KUN.time, KUN.index, label = &quot;KUN&quot;, color = &quot;mediumblue&quot;, linewidth = 4)

# Add legend
ax.legend(fontsize = 17)

# Label each data point with the language switch
for i in (KUN, TEN, HENDERY, YANGYANG): #for each dataset
    for x,y,z in zip(i[&quot;time&quot;], i[&quot;index&quot;], i[&quot;lang&quot;]): #looping within the dataset
        label = z
        ax.annotate(label, #text
                     (x,y), #label coordinate
                     textcoords = &quot;offset points&quot;, #how to position text
                     xytext = (15,-5), #distance from text to coordinate (x,y)
                     ha = &quot;center&quot;, #alignment
                     fontsize = 8.5) #font size of text

# Add title (blank to leave room for external graphics)
plt.title(&quot;\n\n&quot;, fontsize = 35)

# Save figure
fig.savefig(&quot;wayv_codeswitching.png&quot;, bbox_inches = &quot;tight&quot;, facecolor = fig.get_facecolor())
</code></pre>
<p><img src="/matplotlib/codeswitching-visualization/Image1.png" alt="Frequency of Code-Switching 200403 WayV Instagram Live, a step chart. The figure shows a plot of ‘cumulative number of times of code-switching’ against the ‘duration of Instagram Live (in seconds)’. There are four members in the livestream: Yangyang (represented with a dark red line), Hendery (represented with a pink line), Ten (represented with a light blue line), Kun (represented with a dark blue line)."></p>
<p>Languages/dialects: Korean (KOR), English (ENG), Mandarin (MAND), German (GER), Cantonese (CANT), Hokkien (HOKK), Teochew (TEO), Thai (THAI)</p>
<p>186 total switches! That&rsquo;s approximately one code-switch in the group every 2.95 seconds.</p>
<p>And voilà! There you have it: a brief guide on how to make step charts. While I utilized step charts here to visualize code-switching, you can use them to visualize whatever data you would like. Please feel free to contact me <a href="https://twitter.com/WayVSubs2019">here</a> if you have any questions or comments. I hope you enjoyed this tutorial, and thank you so much for reading!</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="graphs" label="graphs" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Elementary Cellular Automata]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/elementary-cellular-automata/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/animated-fractals/?utm_source=atom_feed" rel="related" type="text/html" title="Animate Your Own Fractals in Python with Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/animated-polar-plot/?utm_source=atom_feed" rel="related" type="text/html" title="Animated polar plot with oceanographic data" />
                <link href="https://blog.scientific-python.org/matplotlib/emoji-mosaic-art/?utm_source=atom_feed" rel="related" type="text/html" title="Emoji Mosaic Art" />
                <link href="https://blog.scientific-python.org/matplotlib/draw-all-graphs-of-n-nodes/?utm_source=atom_feed" rel="related" type="text/html" title="Draw all graphs of N nodes" />
                <link href="https://blog.scientific-python.org/matplotlib/matplotlib-cyberpunk-style/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib Cyberpunk Style" />
            
                <id>https://blog.scientific-python.org/matplotlib/elementary-cellular-automata/</id>
            
            
            <published>2020-07-14T15:48:23-04:00</published>
            <updated>2020-07-14T15:48:23-04:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>A brief tour through the world of elementary cellular automata</blockquote><p><a href="https://en.wikipedia.org/wiki/Cellular_automaton">Cellular automata</a> are discrete models, typically on a grid, which evolve in time. Each grid cell has a finite state, such as 0 or 1, which is updated based on a certain set of rules. A specific cell uses information of the surrounding cells, called it&rsquo;s <em>neighborhood</em>, to determine what changes should be made. In general cellular automata can be defined in any number of dimensions. A famous two dimensional example is <a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Conway&rsquo;s Game of Life</a> in which cells &ldquo;live&rdquo; and &ldquo;die&rdquo;, sometimes producing beautiful patterns.</p>
<p>In this post we will be looking at a one dimensional example known as <a href="https://en.wikipedia.org/wiki/Elementary_cellular_automaton">elementary cellular automaton</a>, popularized by <a href="https://en.wikipedia.org/wiki/Stephen_Wolfram">Stephen Wolfram</a> in the 1980s.</p>
<p><img src="/matplotlib/elementary-cellular-automata/ca-bar.png" alt="A row of cells, arranged side by side, each of which is colored black or white. The first few cells are white, then one black cell, and alternates in a similar pattern."></p>
<p>Imagine a row of cells, arranged side by side, each of which is colored black or white. We label black cells 1 and white cells 0, resulting in an array of bits. As an example lets consider a random array of 20 bits.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">RandomState</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span></span></span></code></pre>
</div>
<pre><code>[0 1 0 0 0 1 0 0 0 1 0 0 0 0 1 0 1 1 1 0]
</code></pre>
<p>To update the state of our cellular automaton we will need to define a set of rules.
A given cell \(C\) only knows about the state of it&rsquo;s left and right neighbors, labeled \(L\) and \(R\) respectively. We can define a function or rule, \(f(L, C, R)\), which maps the cell state to either 0 or 1.</p>
<p>Since our input cells are binary values there are \(2^3=8\) possible inputs into the function.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">binary_repr</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span></span></span></code></pre>
</div>
<pre><code>000
001
010
011
100
101
110
111
</code></pre>
<p>For each input triplet, we can assign 0 or 1 to the output. The output of \(f\) is the value which will replace the current cell \(C\) in the next time step. In total there are \(2^{2^3} = 2^8 = 256\) possible rules for updating a cell. Stephen Wolfram introduced a naming convention, now known as the <a href="https://en.wikipedia.org/wiki/Wolfram_code">Wolfram Code</a>, for the update rules in which each rule is represented by an 8 bit binary number.</p>
<p>For example &ldquo;Rule 30&rdquo; could be constructed by first converting to binary and then building an array for each bit</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">rule_number</span> <span class="o">=</span> <span class="mi">30</span>
</span></span><span class="line"><span class="cl"><span class="n">rule_string</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">binary_repr</span><span class="p">(</span><span class="n">rule_number</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">rule</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="nb">int</span><span class="p">(</span><span class="n">bit</span><span class="p">)</span> <span class="k">for</span> <span class="n">bit</span> <span class="ow">in</span> <span class="n">rule_string</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">rule</span><span class="p">)</span></span></span></code></pre>
</div>
<pre><code>[0 0 0 1 1 1 1 0]
</code></pre>
<p>By convention the Wolfram code associates the leading bit with &lsquo;111&rsquo; and the final bit with &lsquo;000&rsquo;. For rule 30 the relationship between the input, rule index and output is as follows:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">triplet</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">binary_repr</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;input:</span><span class="si">{</span><span class="n">triplet</span><span class="si">}</span><span class="s2">, index:</span><span class="si">{</span><span class="mi">7</span><span class="o">-</span><span class="n">i</span><span class="si">}</span><span class="s2">, output </span><span class="si">{</span><span class="n">rule</span><span class="p">[</span><span class="mi">7</span><span class="o">-</span><span class="n">i</span><span class="p">]</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<pre><code>input:000, index:7, output 0
input:001, index:6, output 1
input:010, index:5, output 1
input:011, index:4, output 1
input:100, index:3, output 1
input:101, index:2, output 0
input:110, index:1, output 0
input:111, index:0, output 0
</code></pre>
<p>We can define a function which maps the input cell information with the associated rule index. Essentially we are converting the binary input to decimal and adjusting the index range.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">rule_index</span><span class="p">(</span><span class="n">triplet</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">L</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">R</span> <span class="o">=</span> <span class="n">triplet</span>
</span></span><span class="line"><span class="cl">    <span class="n">index</span> <span class="o">=</span> <span class="mi">7</span> <span class="o">-</span> <span class="p">(</span><span class="mi">4</span> <span class="o">*</span> <span class="n">L</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">C</span> <span class="o">+</span> <span class="n">R</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">index</span><span class="p">)</span></span></span></code></pre>
</div>
<p>Now we can take in any input and look up the output based on our rule, for example:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">rule</span><span class="p">[</span><span class="n">rule_index</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))]</span></span></span></code></pre>
</div>
<pre><code>0
</code></pre>
<p>Finally, we can use Numpy to create a data structure containing all the triplets for our state array and apply the function across the appropriate axis to determine our new state.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">all_triplets</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">stack</span><span class="p">([</span><span class="n">np</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="n">data</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)])</span>
</span></span><span class="line"><span class="cl"><span class="n">new_data</span> <span class="o">=</span> <span class="n">rule</span><span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">apply_along_axis</span><span class="p">(</span><span class="n">rule_index</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">all_triplets</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">new_data</span><span class="p">)</span></span></span></code></pre>
</div>
<pre><code>[1 1 1 0 1 1 1 0 1 1 1 0 0 1 1 0 1 0 0 1]
</code></pre>
<p>That is the process for a single update of our cellular automata.</p>
<p>To do many updates and record the state over time, we will create a function.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">CA_run</span><span class="p">(</span><span class="n">initial_state</span><span class="p">,</span> <span class="n">n_steps</span><span class="p">,</span> <span class="n">rule_number</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">rule_string</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">binary_repr</span><span class="p">(</span><span class="n">rule_number</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">rule</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="nb">int</span><span class="p">(</span><span class="n">bit</span><span class="p">)</span> <span class="k">for</span> <span class="n">bit</span> <span class="ow">in</span> <span class="n">rule_string</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">m_cells</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">initial_state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">CA_run</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">n_steps</span><span class="p">,</span> <span class="n">m_cells</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">CA_run</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">initial_state</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">step</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n_steps</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">all_triplets</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">stack</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="n">np</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="n">CA_run</span><span class="p">[</span><span class="n">step</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="p">:],</span> <span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                <span class="n">CA_run</span><span class="p">[</span><span class="n">step</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="p">:],</span>
</span></span><span class="line"><span class="cl">                <span class="n">np</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="n">CA_run</span><span class="p">[</span><span class="n">step</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="p">:],</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">CA_run</span><span class="p">[</span><span class="n">step</span><span class="p">,</span> <span class="p">:]</span> <span class="o">=</span> <span class="n">rule</span><span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">apply_along_axis</span><span class="p">(</span><span class="n">rule_index</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">all_triplets</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">CA_run</span></span></span></code></pre>
</div>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">initial</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="n">CA_run</span><span class="p">(</span><span class="n">initial</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span></span></span></code></pre>
</div>
<pre><code>[[0. 1. 0. 0. 0. 1. 0. 0. 0. 1. 0. 0. 0. 0. 1. 0. 1. 1. 1. 0.]
 [1. 1. 1. 0. 1. 1. 1. 0. 1. 1. 1. 0. 0. 1. 1. 0. 1. 0. 0. 1.]
 [0. 0. 0. 0. 1. 0. 0. 0. 1. 0. 0. 1. 1. 1. 0. 0. 1. 1. 1. 1.]
 [1. 0. 0. 1. 1. 1. 0. 1. 1. 1. 1. 1. 0. 0. 1. 1. 1. 0. 0. 0.]
 [1. 1. 1. 1. 0. 0. 0. 1. 0. 0. 0. 0. 1. 1. 1. 0. 0. 1. 0. 1.]
 [0. 0. 0. 0. 1. 0. 1. 1. 1. 0. 0. 1. 1. 0. 0. 1. 1. 1. 0. 1.]
 [1. 0. 0. 1. 1. 0. 1. 0. 0. 1. 1. 1. 0. 1. 1. 1. 0. 0. 0. 1.]
 [0. 1. 1. 1. 0. 0. 1. 1. 1. 1. 0. 0. 0. 1. 0. 0. 1. 0. 1. 1.]
 [0. 1. 0. 0. 1. 1. 1. 0. 0. 0. 1. 0. 1. 1. 1. 1. 1. 0. 1. 0.]
 [1. 1. 1. 1. 1. 0. 0. 1. 0. 1. 1. 0. 1. 0. 0. 0. 0. 0. 1. 1.]]
</code></pre>
<h2 id="lets-get-visual">Let&rsquo;s Get Visual<a class="headerlink" href="#lets-get-visual" title="Link to this heading">#</a></h2>
<p>For larger simulations, interesting patterns start to emerge. To visualize our simulation results we will use the <code>ax.matshow</code> function.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s2">&#34;image.cmap&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;binary&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">RandomState</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="n">CA_run</span><span class="p">(</span><span class="n">rng</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">300</span><span class="p">),</span> <span class="mi">150</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="mi">9</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">matshow</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/elementary-cellular-automata/output_18_0.png" alt="png"></p>
<h2 id="learning-the-rules">Learning the Rules<a class="headerlink" href="#learning-the-rules" title="Link to this heading">#</a></h2>
<p>With the code set up to produce the simulation, we can now start to explore the properties of these different rules. Wolfram separated the rules into four classes which are outlined below.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">plot_CA_class</span><span class="p">(</span><span class="n">rule_list</span><span class="p">,</span> <span class="n">class_label</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">RandomState</span><span class="p">(</span><span class="n">seed</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="p">,</span> <span class="n">axs</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">rule_list</span><span class="p">),</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">3.5</span><span class="p">),</span> <span class="n">constrained_layout</span><span class="o">=</span><span class="kc">True</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">initial</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">ax</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">axs</span><span class="o">.</span><span class="n">ravel</span><span class="p">()):</span>
</span></span><span class="line"><span class="cl">        <span class="n">data</span> <span class="o">=</span> <span class="n">CA_run</span><span class="p">(</span><span class="n">initial</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="n">rule_list</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Rule </span><span class="si">{</span><span class="n">rule_list</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">matshow</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="o">.</span><span class="n">suptitle</span><span class="p">(</span><span class="n">class_label</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">16</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span></span></span></code></pre>
</div>
<h3 id="class-one">Class One<a class="headerlink" href="#class-one" title="Link to this heading">#</a></h3>
<p>Cellular automata which rapidly converge to a uniform state</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">_</span> <span class="o">=</span> <span class="n">plot_CA_class</span><span class="p">([</span><span class="mi">4</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">172</span><span class="p">],</span> <span class="s2">&#34;Class One&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/elementary-cellular-automata/output_22_0.png" alt="png"></p>
<h3 id="class-two">Class Two<a class="headerlink" href="#class-two" title="Link to this heading">#</a></h3>
<p>Cellular automata which rapidly converge to a repetitive or stable state</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">_</span> <span class="o">=</span> <span class="n">plot_CA_class</span><span class="p">([</span><span class="mi">50</span><span class="p">,</span> <span class="mi">108</span><span class="p">,</span> <span class="mi">173</span><span class="p">],</span> <span class="s2">&#34;Class Two&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/elementary-cellular-automata/output_24_0.png" alt="png"></p>
<h3 id="class-three">Class Three<a class="headerlink" href="#class-three" title="Link to this heading">#</a></h3>
<p>Cellular automata which appear to remain in a random state</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">_</span> <span class="o">=</span> <span class="n">plot_CA_class</span><span class="p">([</span><span class="mi">60</span><span class="p">,</span> <span class="mi">106</span><span class="p">,</span> <span class="mi">150</span><span class="p">],</span> <span class="s2">&#34;Class Three&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/elementary-cellular-automata/output_26_0.png" alt="png"></p>
<h3 id="class-four">Class Four<a class="headerlink" href="#class-four" title="Link to this heading">#</a></h3>
<p>Cellular automata which form areas of repetitive or stable states, but also form structures that interact with each other in complicated ways.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">_</span> <span class="o">=</span> <span class="n">plot_CA_class</span><span class="p">([</span><span class="mi">54</span><span class="p">,</span> <span class="mi">62</span><span class="p">,</span> <span class="mi">110</span><span class="p">],</span> <span class="s2">&#34;Class Four&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/elementary-cellular-automata/output_28_0.png" alt="png"></p>
<p>Amazingly, the interacting structures which emerge from rule 110 has been shown to be capable of <a href="https://en.wikipedia.org/wiki/Turing_machine">universal computation</a>.</p>
<p>In all the examples above a random initial state was used, but another interesting case is when a single 1 is initialized with all other values set to zero.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">initial</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="mi">300</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">initial</span><span class="p">[</span><span class="mi">300</span> <span class="o">//</span> <span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="n">CA_run</span><span class="p">(</span><span class="n">initial</span><span class="p">,</span> <span class="mi">150</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">matshow</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/elementary-cellular-automata/output_31_0.png" alt="png"></p>
<p>For certain rules, the emergent structures interact in chaotic and interesting ways.</p>
<p>I hope you enjoyed this brief look into the world of elementary cellular automata, and are inspired to make some pretty pictures of your own.</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Animate Your Own Fractals in Python with Matplotlib]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/animated-fractals/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/animated-polar-plot/?utm_source=atom_feed" rel="related" type="text/html" title="Animated polar plot with oceanographic data" />
                <link href="https://blog.scientific-python.org/matplotlib/emoji-mosaic-art/?utm_source=atom_feed" rel="related" type="text/html" title="Emoji Mosaic Art" />
                <link href="https://blog.scientific-python.org/matplotlib/draw-all-graphs-of-n-nodes/?utm_source=atom_feed" rel="related" type="text/html" title="Draw all graphs of N nodes" />
                <link href="https://blog.scientific-python.org/matplotlib/matplotlib-cyberpunk-style/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib Cyberpunk Style" />
                <link href="https://blog.scientific-python.org/matplotlib/mpl-for-making-diagrams/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib for Making Diagrams" />
            
                <id>https://blog.scientific-python.org/matplotlib/animated-fractals/</id>
            
            
            <published>2020-07-04T00:06:36+02:00</published>
            <updated>2020-07-04T00:06:36+02:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Discover the bizarre geometry of the fractals and learn how to make an animated visualization of these marvels using Python and the Matplotlib&rsquo;s Animation API.</blockquote><p>Imagine zooming an image over and over and never go out of finer details. It may sound bizarre but the mathematical
concept of <a href="https://en.wikipedia.org/wiki/Fractal">fractals</a> opens the realm towards this intricating infinity. This
strange geometry exhibits the same or similar patterns irrespectively of the scale. We can see one fractal example
in the image above.</p>
<p>The <em>fractals</em> may seem difficult to understand due to their peculiarity, but that&rsquo;s not the case. As Benoit Mandelbrot,
one of the founding fathers of the fractal geometry said in his legendary
<a href="https://www.ted.com/talks/benoit_mandelbrot_fractals_and_the_art_of_roughness?language=en">TED Talk</a>:</p>
<blockquote>
<p>A surprising aspect is that the rules of this geometry are extremely short. You crank the formulas several times and
at the end, you get things like this (pointing to a stunning plot)</p>
<p>&ndash; <cite>Benoit Mandelbrot</cite></p>
</blockquote>
<p>In this tutorial blog post, we will see how to construct fractals in Python and animate them using the amazing
<em>Matplotlib&rsquo;s</em> Animation API. First, we will demonstrate the convergence of the <em>Mandelbrot Set</em> with an
enticing animation. In the second part, we will analyze one interesting property of the <em>Julia Set</em>. Stay tuned!</p>
<h1 id="intuition">Intuition<a class="headerlink" href="#intuition" title="Link to this heading">#</a></h1>
<p>We all have a common sense of the concept of similarity. We say two objects are similar to each other if they share
some common patterns.</p>
<p>This notion is not only limited to a comparison of two different objects. We can also compare different parts of the
same object. For instance, a leaf. We know very well that the left side matches exactly the right side, i.e. the leaf
is symmetrical.</p>
<p>In mathematics, this phenomenon is known as <a href="https://en.wikipedia.org/wiki/Self-similarity">self-similarity</a>. It means
a given object is similar (completely or to some extent) to some smaller part of itself. One remarkable example is the
<a href="https://isquared.digital/visualizations/2020-06-15-koch-curve/">An orange Koch Snowflake. It has 6 bulges which themselves have 3 sub-bulges. These sub-bulges have another 3 sub-sub bulges. </a> as shown in the image below:</p>
<p><img src="/matplotlib/animated-fractals/snowflake.png" alt="Koch Snowflake"></p>
<p>We can infinitely magnify some part of it and the same pattern will repeat over and over again. This is how fractal
geometry is defined.</p>
<h1 id="animated-mandelbrot-set">Animated Mandelbrot Set<a class="headerlink" href="#animated-mandelbrot-set" title="Link to this heading">#</a></h1>
<p><a href="https://en.wikipedia.org/wiki/Mandelbrot_set">Mandelbrot Set</a> is defined over the set of <em>complex numbers</em>. It consists
of all complex numbers <strong>c</strong>, such that the sequence <strong>zᵢ₊ᵢ = zᵢ² + c, z₀ = 0</strong> is bounded. It means, after a certain
number of iterations the absolute value must not exceed a given limit. At first sight, it might
seem odd and simple, but in fact, it has some mind-blowing properties.</p>
<p>The <em>Python</em> implementation is quite straightforward, as given in the code snippet below:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">mandelbrot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">threshold</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Calculates whether the number c = x + i*y belongs to the
</span></span></span><span class="line"><span class="cl"><span class="s2">    Mandelbrot set. In order to belong, the sequence z[i + 1] = z[i]**2 + c
</span></span></span><span class="line"><span class="cl"><span class="s2">    must not diverge after &#39;threshold&#39; number of steps. The sequence diverges
</span></span></span><span class="line"><span class="cl"><span class="s2">    if the absolute value of z[i+1] is greater than 4.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">    :param float x: the x component of the initial complex number
</span></span></span><span class="line"><span class="cl"><span class="s2">    :param float y: the y component of the initial complex number
</span></span></span><span class="line"><span class="cl"><span class="s2">    :param int threshold: the number of iterations to considered it converged
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># initial conditions</span>
</span></span><span class="line"><span class="cl">    <span class="n">c</span> <span class="o">=</span> <span class="nb">complex</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="nb">complex</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">threshold</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">z</span> <span class="o">=</span> <span class="n">z</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">c</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mf">4.0</span><span class="p">:</span>  <span class="c1"># it diverged</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">i</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">threshold</span> <span class="o">-</span> <span class="mi">1</span>  <span class="c1"># it didn&#39;t diverge</span></span></span></code></pre>
</div>
<p>As we can see, we set the maximum number of iterations encoded in the variable <code>threshold</code>. If the magnitude of the
sequence at some iteration exceeds <strong>4</strong>, we consider it as diverged (<strong>c</strong> does not belong to the set) and return the
iteration number at which this occurred. If this never happens (<strong>c</strong> belongs to the set), we return the maximum
number of iterations.</p>
<p>We can use the information about the number of iterations before the sequence diverges. All we have to do
is to associate this number to a color relative to the maximum number of loops. Thus, for all complex numbers
<strong>c</strong> in some lattice of the complex plane, we can make a nice animation of the convergence process as a function
of the maximum allowed iterations.</p>
<p>One particular and interesting area is the <em>3x3</em> lattice starting at position -2 and -1.5 for the <em>real</em> and
<em>imaginary</em> axis respectively. We can observe the process of convergence as the number of allowed iterations increases.
This is easily achieved using the <em>Matplotlib&rsquo;s</em> Animation API, as shown with the following code:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.animation</span> <span class="k">as</span> <span class="nn">animation</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">x_start</span><span class="p">,</span> <span class="n">y_start</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.5</span>  <span class="c1"># an interesting region starts here</span>
</span></span><span class="line"><span class="cl"><span class="n">width</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span>  <span class="c1"># for 3 units up and right</span>
</span></span><span class="line"><span class="cl"><span class="n">density_per_unit</span> <span class="o">=</span> <span class="mi">250</span>  <span class="c1"># how many pixles per unit</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># real and imaginary axis</span>
</span></span><span class="line"><span class="cl"><span class="n">re</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">x_start</span><span class="p">,</span> <span class="n">x_start</span> <span class="o">+</span> <span class="n">width</span><span class="p">,</span> <span class="n">width</span> <span class="o">*</span> <span class="n">density_per_unit</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">im</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">y_start</span><span class="p">,</span> <span class="n">y_start</span> <span class="o">+</span> <span class="n">height</span><span class="p">,</span> <span class="n">height</span> <span class="o">*</span> <span class="n">density_per_unit</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>  <span class="c1"># instantiate a figure to draw</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">axes</span><span class="p">()</span>  <span class="c1"># create an axes object</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">animate</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>  <span class="c1"># clear axes object</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_xticks</span><span class="p">([],</span> <span class="p">[])</span>  <span class="c1"># clear x-axis ticks</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_yticks</span><span class="p">([],</span> <span class="p">[])</span>  <span class="c1"># clear y-axis ticks</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">empty</span><span class="p">((</span><span class="nb">len</span><span class="p">(</span><span class="n">re</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">im</span><span class="p">)))</span>  <span class="c1"># re-initialize the array-like image</span>
</span></span><span class="line"><span class="cl">    <span class="n">threshold</span> <span class="o">=</span> <span class="nb">round</span><span class="p">(</span><span class="mf">1.15</span> <span class="o">**</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span>  <span class="c1"># calculate the current threshold</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># iterations for the current threshold</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">re</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">im</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">            <span class="n">X</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">mandelbrot</span><span class="p">(</span><span class="n">re</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">im</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">threshold</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># associate colors to the iterations with an interpolation</span>
</span></span><span class="line"><span class="cl">    <span class="n">img</span> <span class="o">=</span> <span class="n">ax</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">X</span><span class="o">.</span><span class="n">T</span><span class="p">,</span> <span class="n">interpolation</span><span class="o">=</span><span class="s2">&#34;bicubic&#34;</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s2">&#34;magma&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[</span><span class="n">img</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">anim</span> <span class="o">=</span> <span class="n">animation</span><span class="o">.</span><span class="n">FuncAnimation</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">animate</span><span class="p">,</span> <span class="n">frames</span><span class="o">=</span><span class="mi">45</span><span class="p">,</span> <span class="n">interval</span><span class="o">=</span><span class="mi">120</span><span class="p">,</span> <span class="n">blit</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">anim</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s2">&#34;mandelbrot.gif&#34;</span><span class="p">,</span> <span class="n">writer</span><span class="o">=</span><span class="s2">&#34;imagemagick&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p>We make animations in <em>Matplotlib</em> using the <code>FuncAnimation</code> function from the <em>Animation</em> API. We need to specify
the <code>figure</code> on which we draw a predefined number of consecutive <code>frames</code>. A predetermined <code>interval</code> expressed in
milliseconds defines the delay between the frames.</p>
<p>In this context, the <code>animate</code> function plays a central role, where the input argument is the frame number, starting
from 0. It means, in order to animate we always have to think in terms of frames. Hence, we use the frame number
to calculate the variable <code>threshold</code> which is the maximum number of allowed iterations.</p>
<p>To represent our lattice we instantiate two arrays <code>re</code> and <code>im</code>: the former for the values on the <em>real</em> axis
and the latter for the values on the <em>imaginary</em> axis. The number of elements in these two arrays is defined by
the variable <code>density_per_unit</code> which defines the number of samples per unit step. The higher it is, the better
quality we get, but at a cost of heavier computation.</p>
<p>Now, depending on the current <code>threshold</code>, for every complex number <strong>c</strong> in our lattice, we calculate the number of
iterations before the sequence <strong>zᵢ₊ᵢ = zᵢ² + c, z₀ = 0</strong> diverges. We save them in an initially empty matrix called <code>X</code>.
In the end, we <em>interpolate</em> the values in <code>X</code> and assign them a color drawn from a prearranged <em>colormap</em>.</p>
<p>After cranking the <code>animate</code> function multiple times we get a stunning animation as depicted below:</p>
<p><img src="/matplotlib/animated-fractals/mandelbrot.gif" alt="Mandelbrot set animation. The first few frames only show a few outlines of the Mandelbrot shape. The middle frames show a more defined shape. The last few frames show the characteristic Mandelbrot shape in a very clear way."></p>
<h1 id="animated-julia-set">Animated Julia Set<a class="headerlink" href="#animated-julia-set" title="Link to this heading">#</a></h1>
<p>The <a href="https://en.wikipedia.org/wiki/Julia_set">Julia Set</a> is quite similar to the <em>Mandelbrot Set</em>. Instead of setting
<strong>z₀ = 0</strong> and testing whether for some complex number <strong>c = x + i*y</strong> the sequence <strong>zᵢ₊ᵢ = zᵢ² + c</strong> is bounded, we
switch the roles a bit. We fix the value for <strong>c</strong>, we set an arbitrary initial condition <strong>z₀ = x + i*y</strong>, and we
observe the convergence of the sequence. The <em>Python</em> implementation is given below:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">julia_quadratic</span><span class="p">(</span><span class="n">zx</span><span class="p">,</span> <span class="n">zy</span><span class="p">,</span> <span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">,</span> <span class="n">threshold</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Calculates whether the number z[0] = zx + i*zy with a constant c = x + i*y
</span></span></span><span class="line"><span class="cl"><span class="s2">    belongs to the Julia set. In order to belong, the sequence
</span></span></span><span class="line"><span class="cl"><span class="s2">    z[i + 1] = z[i]**2 + c, must not diverge after &#39;threshold&#39; number of steps.
</span></span></span><span class="line"><span class="cl"><span class="s2">    The sequence diverges if the absolute value of z[i+1] is greater than 4.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">    :param float zx: the x component of z[0]
</span></span></span><span class="line"><span class="cl"><span class="s2">    :param float zy: the y component of z[0]
</span></span></span><span class="line"><span class="cl"><span class="s2">    :param float cx: the x component of the constant c
</span></span></span><span class="line"><span class="cl"><span class="s2">    :param float cy: the y component of the constant c
</span></span></span><span class="line"><span class="cl"><span class="s2">    :param int threshold: the number of iterations to considered it converged
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># initial conditions</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="nb">complex</span><span class="p">(</span><span class="n">zx</span><span class="p">,</span> <span class="n">zy</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">c</span> <span class="o">=</span> <span class="nb">complex</span><span class="p">(</span><span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">threshold</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">z</span> <span class="o">=</span> <span class="n">z</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">c</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mf">4.0</span><span class="p">:</span>  <span class="c1"># it diverged</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">i</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">threshold</span> <span class="o">-</span> <span class="mi">1</span>  <span class="c1"># it didn&#39;t diverge</span></span></span></code></pre>
</div>
<p>Obviously, the setup is quite similar as the <em>Mandelbrot Set</em> implementation. The maximum number of iterations is
denoted as <code>threshold</code>. If the magnitude of the sequence is never greater than <strong>4</strong>, the number <strong>z₀</strong> belongs to
the <em>Julia Set</em> and vice-versa.</p>
<p>The number <strong>c</strong> is giving us the freedom to analyze its impact on the convergence of the sequence, given that the
number of maximum iterations is fixed. One interesting range of values for <strong>c</strong> is for <strong>c = r cos α + i × r sin α</strong>
such that <strong>r=0.7885</strong> and <strong>α ∈ [0, 2π]</strong>.</p>
<p>The best possible way to make this analysis is to create an animated visualization as the number <strong>c</strong> changes.
This <a href="https://isquared.digital/blog/2020-02-08-interactive-dataviz/">ameliorates our visual perception</a> and
understanding of such abstract phenomena in a captivating manner. To do so, we use the Matplotlib&rsquo;s <em>Animation API</em>, as
demonstrated in the code below:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.animation</span> <span class="k">as</span> <span class="nn">animation</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">x_start</span><span class="p">,</span> <span class="n">y_start</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="o">-</span><span class="mi">2</span>  <span class="c1"># an interesting region starts here</span>
</span></span><span class="line"><span class="cl"><span class="n">width</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span>  <span class="c1"># for 4 units up and right</span>
</span></span><span class="line"><span class="cl"><span class="n">density_per_unit</span> <span class="o">=</span> <span class="mi">200</span>  <span class="c1"># how many pixles per unit</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># real and imaginary axis</span>
</span></span><span class="line"><span class="cl"><span class="n">re</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">x_start</span><span class="p">,</span> <span class="n">x_start</span> <span class="o">+</span> <span class="n">width</span><span class="p">,</span> <span class="n">width</span> <span class="o">*</span> <span class="n">density_per_unit</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">im</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="n">y_start</span><span class="p">,</span> <span class="n">y_start</span> <span class="o">+</span> <span class="n">height</span><span class="p">,</span> <span class="n">height</span> <span class="o">*</span> <span class="n">density_per_unit</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">threshold</span> <span class="o">=</span> <span class="mi">20</span>  <span class="c1"># max allowed iterations</span>
</span></span><span class="line"><span class="cl"><span class="n">frames</span> <span class="o">=</span> <span class="mi">100</span>  <span class="c1"># number of frames in the animation</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># we represent c as c = r*cos(a) + i*r*sin(a) = r*e^{i*a}</span>
</span></span><span class="line"><span class="cl"><span class="n">r</span> <span class="o">=</span> <span class="mf">0.7885</span>
</span></span><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span><span class="p">,</span> <span class="n">frames</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>  <span class="c1"># instantiate a figure to draw</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">axes</span><span class="p">()</span>  <span class="c1"># create an axes object</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">animate</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>  <span class="c1"># clear axes object</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_xticks</span><span class="p">([],</span> <span class="p">[])</span>  <span class="c1"># clear x-axis ticks</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_yticks</span><span class="p">([],</span> <span class="p">[])</span>  <span class="c1"># clear y-axis ticks</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">empty</span><span class="p">((</span><span class="nb">len</span><span class="p">(</span><span class="n">re</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">im</span><span class="p">)))</span>  <span class="c1"># the initial array-like image</span>
</span></span><span class="line"><span class="cl">    <span class="n">cx</span><span class="p">,</span> <span class="n">cy</span> <span class="o">=</span> <span class="n">r</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span> <span class="n">r</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>  <span class="c1"># the initial c number</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># iterations for the given threshold</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">re</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">im</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">            <span class="n">X</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">julia_quadratic</span><span class="p">(</span><span class="n">re</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">im</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">cx</span><span class="p">,</span> <span class="n">cy</span><span class="p">,</span> <span class="n">threshold</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">img</span> <span class="o">=</span> <span class="n">ax</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">X</span><span class="o">.</span><span class="n">T</span><span class="p">,</span> <span class="n">interpolation</span><span class="o">=</span><span class="s2">&#34;bicubic&#34;</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s2">&#34;magma&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[</span><span class="n">img</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">anim</span> <span class="o">=</span> <span class="n">animation</span><span class="o">.</span><span class="n">FuncAnimation</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">animate</span><span class="p">,</span> <span class="n">frames</span><span class="o">=</span><span class="n">frames</span><span class="p">,</span> <span class="n">interval</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">blit</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">anim</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s2">&#34;julia_set.gif&#34;</span><span class="p">,</span> <span class="n">writer</span><span class="o">=</span><span class="s2">&#34;imagemagick&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p>The logic in the <code>animate</code> function is very similar to the previous example. We update the number <strong>c</strong> as a function
of the frame number. Based on that we estimate the convergence of all complex numbers in the defined lattice, given the
fixed <code>threshold</code> of allowed iterations. Same as before, we save the results in an initially empty matrix <code>X</code> and
associate them to a color relative to the maximum number of iterations. The resulting animation is illustrated below:</p>
<p><img src="/matplotlib/animated-fractals/julia_set.gif" alt="Julia Set Animation"></p>
<h1 id="summary">Summary<a class="headerlink" href="#summary" title="Link to this heading">#</a></h1>
<p>The fractals are really mind-gobbling structures as we saw during this blog. First, we gave a general intuition
of the fractal geometry. Then, we observed two types of fractals: the <em>Mandelbrot</em> and <em>Julia</em> sets. We implemented
them in Python and made interesting animated visualizations of their properties.</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Animated polar plot with oceanographic data]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/animated-polar-plot/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/emoji-mosaic-art/?utm_source=atom_feed" rel="related" type="text/html" title="Emoji Mosaic Art" />
                <link href="https://blog.scientific-python.org/matplotlib/draw-all-graphs-of-n-nodes/?utm_source=atom_feed" rel="related" type="text/html" title="Draw all graphs of N nodes" />
                <link href="https://blog.scientific-python.org/matplotlib/matplotlib-cyberpunk-style/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib Cyberpunk Style" />
                <link href="https://blog.scientific-python.org/matplotlib/mpl-for-making-diagrams/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib for Making Diagrams" />
                <link href="https://blog.scientific-python.org/matplotlib/create-ridgeplots-in-matplotlib/?utm_source=atom_feed" rel="related" type="text/html" title="Create Ridgeplots in Matplotlib" />
            
                <id>https://blog.scientific-python.org/matplotlib/animated-polar-plot/</id>
            
            
            <published>2020-06-12T09:56:36+02:00</published>
            <updated>2020-06-12T09:56:36+02:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>This post describes how to animate some oceanographic measurements in a tweaked polar plot</blockquote><p>The <strong>ocean</strong> is a key component of the Earth climate system. It thus needs a continuous real-time monitoring to help scientists better understand its dynamic and predict its evolution. All around the world, oceanographers have managed to join their efforts and set up a <a href="https://www.goosocean.org">Global Ocean Observing System</a> among which <a href="http://www.argo.ucsd.edu/"><strong>Argo</strong></a> is a key component. Argo is a global network of nearly 4000 autonomous probes or floats measuring pressure, temperature and salinity from the surface to 2000m depth every 10 days. The localisation of these floats is nearly random between the 60th parallels (see live coverage <a href="http://collab.umr-lops.fr/app/divaa/">here</a>). All data are collected by satellite in real-time, processed by several data centers and finally merged in a single dataset (collecting more than 2 millions of vertical profiles data) made freely available to anyone.</p>
<p>In this particular case, we want to plot temperature (surface and 1000m deep) data measured by those floats, for the period 2010-2020 and for the Mediterranean sea. We want this plot to be circular and animated, now you start to get the title of this post: <strong>Animated polar plot</strong>.</p>
<p>First we need some data to work with. To retrieve our temperature values from Argo, we use <a href="https://argopy.readthedocs.io"><strong>Argopy</strong></a>, which is a Python library that aims to ease Argo data access, manipulation and visualization for standard users, as well as Argo experts and operators. Argopy returns <a href="http://xarray.pydata.org">xarray</a> dataset objects, which make our analysis much easier.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">argopy</span> <span class="kn">import</span> <span class="n">DataFetcher</span> <span class="k">as</span> <span class="n">ArgoDataFetcher</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">argo_loader</span> <span class="o">=</span> <span class="n">ArgoDataFetcher</span><span class="p">(</span><span class="n">cache</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Query surface and 1000m temp in Med sea with argopy</span>
</span></span><span class="line"><span class="cl"><span class="n">df1</span> <span class="o">=</span> <span class="n">argo_loader</span><span class="o">.</span><span class="n">region</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="o">-</span><span class="mf">1.2</span><span class="p">,</span> <span class="mf">29.0</span><span class="p">,</span> <span class="mf">28.0</span><span class="p">,</span> <span class="mf">46.0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">10.0</span><span class="p">,</span> <span class="s2">&#34;2009-12&#34;</span><span class="p">,</span> <span class="s2">&#34;2020-01&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span><span class="o">.</span><span class="n">to_xarray</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">df2</span> <span class="o">=</span> <span class="n">argo_loader</span><span class="o">.</span><span class="n">region</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="o">-</span><span class="mf">1.2</span><span class="p">,</span> <span class="mf">29.0</span><span class="p">,</span> <span class="mf">28.0</span><span class="p">,</span> <span class="mf">46.0</span><span class="p">,</span> <span class="mf">975.0</span><span class="p">,</span> <span class="mf">1025.0</span><span class="p">,</span> <span class="s2">&#34;2009-12&#34;</span><span class="p">,</span> <span class="s2">&#34;2020-01&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span><span class="o">.</span><span class="n">to_xarray</span><span class="p">()</span></span></span></code></pre>
</div>
<p>Here we create some arrays we&rsquo;ll use for plotting, we set up a date array and extract day of the year and year itself that will be useful. Then to build our temperature array, we use xarray very useful methods : <code>where()</code> and <code>mean()</code>. Then we build a pandas Dataframe, because it&rsquo;s prettier!</p>

<div class="highlight">
  <pre># Weekly date array
daterange = np.arange(&#34;2010-01-01&#34;, &#34;2020-01-03&#34;, dtype=&#34;datetime64[7D]&#34;)
dayoftheyear = pd.DatetimeIndex(
    np.array(daterange, dtype=&#34;datetime64[D]&#34;) &#43; 3
).dayofyear  # middle of the week
activeyear = pd.DatetimeIndex(
    np.array(daterange, dtype=&#34;datetime64[D]&#34;) &#43; 3
).year  # extract year

# Init final arrays
tsurf = np.zeros(len(daterange))
t1000 = np.zeros(len(daterange))

# Filling arrays
for i in range(len(daterange)):
    i1 = (df1[&#34;TIME&#34;] &gt;= daterange[i]) &amp; (df1[&#34;TIME&#34;] &lt; daterange[i] &#43; 7)
    i2 = (df2[&#34;TIME&#34;] &gt;= daterange[i]) &amp; (df2[&#34;TIME&#34;] &lt; daterange[i] &#43; 7)
    tsurf[i] = df1.where(i1, drop=True)[&#34;TEMP&#34;].mean().values
    t1000[i] = df2.where(i2, drop=True)[&#34;TEMP&#34;].mean().values

# Creating dataframe
d = {&#34;date&#34;: np.array(daterange, dtype=&#34;datetime64[D]&#34;), &#34;tsurf&#34;: tsurf, &#34;t1000&#34;: t1000}
ndf = pd.DataFrame(data=d)
ndf.head()</pre>
</div>

<p>This produces:</p>

<div class="highlight">
  <pre>        date  tsurf  t1000
0 2009-12-31    0.0    0.0
1 2010-01-07    0.0    0.0
2 2010-01-14    0.0    0.0
3 2010-01-21    0.0    0.0
4 2010-01-28    0.0    0.0</pre>
</div>

<p>Then it&rsquo;s time to plot, for that we first need to import what we need, and set some useful variables.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s2">&#34;xtick.major.pad&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;17&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s2">&#34;axes.axisbelow&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl"><span class="n">matplotlib</span><span class="o">.</span><span class="n">rc</span><span class="p">(</span><span class="s2">&#34;axes&#34;</span><span class="p">,</span> <span class="n">edgecolor</span><span class="o">=</span><span class="s2">&#34;w&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib.lines</span> <span class="kn">import</span> <span class="n">Line2D</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib.animation</span> <span class="kn">import</span> <span class="n">FuncAnimation</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">IPython.display</span> <span class="kn">import</span> <span class="n">HTML</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">big_angle</span> <span class="o">=</span> <span class="mi">360</span> <span class="o">/</span> <span class="mi">12</span>  <span class="c1"># How we split our polar space</span>
</span></span><span class="line"><span class="cl"><span class="n">date_angle</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">((</span><span class="mi">360</span> <span class="o">/</span> <span class="mi">365</span><span class="p">)</span> <span class="o">*</span> <span class="n">dayoftheyear</span><span class="p">)</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mi">180</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>  <span class="c1"># For a day, a corresponding angle</span>
</span></span><span class="line"><span class="cl"><span class="c1"># inner and outer ring limit values</span>
</span></span><span class="line"><span class="cl"><span class="n">inner</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="n">outer</span> <span class="o">=</span> <span class="mi">30</span>
</span></span><span class="line"><span class="cl"><span class="c1"># setting our color values</span>
</span></span><span class="line"><span class="cl"><span class="n">ocean_color</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;#ff7f50&#34;</span><span class="p">,</span> <span class="s2">&#34;#004752&#34;</span><span class="p">]</span></span></span></code></pre>
</div>
<p>Now we want to make our axes like we want, for that we build a function <code>dress_axes</code> that will be called during the animation process. Here we plot some bars with an offset (combination of <code>bottom</code> and <code>ylim</code> after). Those bars are actually our background, and the offset allows us to plot a legend in the middle of the plot.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">dress_axes</span><span class="p">(</span><span class="n">ax</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_facecolor</span><span class="p">(</span><span class="s2">&#34;w&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_theta_zero_location</span><span class="p">(</span><span class="s2">&#34;N&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_theta_direction</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Here is how we position the months labels</span>
</span></span><span class="line"><span class="cl">    <span class="n">middles</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="n">big_angle</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">360</span><span class="p">,</span> <span class="n">big_angle</span><span class="p">)</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mi">180</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_xticks</span><span class="p">(</span><span class="n">middles</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_xticklabels</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;January&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;February&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;March&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;April&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;May&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;June&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;July&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;August&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;September&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;October&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;November&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;December&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_yticks</span><span class="p">([</span><span class="mi">15</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">25</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_yticklabels</span><span class="p">([</span><span class="s2">&#34;15°C&#34;</span><span class="p">,</span> <span class="s2">&#34;20°C&#34;</span><span class="p">,</span> <span class="s2">&#34;25°C&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Changing radial ticks angle</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_rlabel_position</span><span class="p">(</span><span class="mi">359</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">tick_params</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s2">&#34;both&#34;</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;w&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="s2">&#34;x&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">plt</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="s2">&#34;y&#34;</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;w&#34;</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s2">&#34;:&#34;</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Here is the bar plot that we use as background</span>
</span></span><span class="line"><span class="cl">    <span class="n">bars</span> <span class="o">=</span> <span class="n">ax</span><span class="o">.</span><span class="n">bar</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">middles</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">outer</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">width</span><span class="o">=</span><span class="n">big_angle</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mi">180</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">bottom</span><span class="o">=</span><span class="n">inner</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="s2">&#34;lightgray&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">edgecolor</span><span class="o">=</span><span class="s2">&#34;w&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">zorder</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">plt</span><span class="o">.</span><span class="n">ylim</span><span class="p">([</span><span class="mi">2</span><span class="p">,</span> <span class="n">outer</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Custom legend</span>
</span></span><span class="line"><span class="cl">    <span class="n">legend_elements</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">Line2D</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="n">marker</span><span class="o">=</span><span class="s2">&#34;o&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">color</span><span class="o">=</span><span class="s2">&#34;w&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">label</span><span class="o">=</span><span class="s2">&#34;Surface&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">markerfacecolor</span><span class="o">=</span><span class="n">ocean_color</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="n">markersize</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="n">Line2D</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="n">marker</span><span class="o">=</span><span class="s2">&#34;o&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">color</span><span class="o">=</span><span class="s2">&#34;w&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">label</span><span class="o">=</span><span class="s2">&#34;1000m&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">markerfacecolor</span><span class="o">=</span><span class="n">ocean_color</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="n">markersize</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">legend</span><span class="p">(</span><span class="n">handles</span><span class="o">=</span><span class="n">legend_elements</span><span class="p">,</span> <span class="n">loc</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">13</span><span class="p">,</span> <span class="n">frameon</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Main title for the figure</span>
</span></span><span class="line"><span class="cl">    <span class="n">plt</span><span class="o">.</span><span class="n">suptitle</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Mediterranean temperature from Argo profiles&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">fontsize</span><span class="o">=</span><span class="mi">16</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">horizontalalignment</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span></span></span></code></pre>
</div>
<p>From there we can plot the frame of our plot.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">111</span><span class="p">,</span> <span class="n">polar</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">dress_axes</span><span class="p">(</span><span class="n">ax</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/animated-polar-plot/axes_empty.png" alt="axesFrame"></p>
<p>Then it&rsquo;s finally time to plot our data. Since we want to animated the plot, we&rsquo;ll build a function that will be called in <code>FuncAnimation</code> later on. Since the state of the plot changes on every time stamp, we have to redress the axes for each frame, easy with our <code>dress_axes</code> function. Then we plot our temperature data using basic <code>plot()</code>: thin lines for historical measurements, thicker lines for the current year.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">draw_data</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Clear</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">cla</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Redressing axes</span>
</span></span><span class="line"><span class="cl">    <span class="n">dress_axes</span><span class="p">(</span><span class="n">ax</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Limit between thin lines and thick line, this is current date minus 51 weeks basically.</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># why 51 and not 52 ? That create a small gap before the current date, which is prettier</span>
</span></span><span class="line"><span class="cl">    <span class="n">i0</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">max</span><span class="p">([</span><span class="n">i</span> <span class="o">-</span> <span class="mi">51</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">date_angle</span><span class="p">[</span><span class="n">i0</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">ndf</span><span class="p">[</span><span class="s2">&#34;tsurf&#34;</span><span class="p">][</span><span class="n">i0</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;-&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="n">ocean_color</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">alpha</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">linewidth</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">date_angle</span><span class="p">[</span><span class="mi">0</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">ndf</span><span class="p">[</span><span class="s2">&#34;tsurf&#34;</span><span class="p">][</span><span class="mi">0</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;-&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="n">ocean_color</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">linewidth</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">date_angle</span><span class="p">[</span><span class="n">i0</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">ndf</span><span class="p">[</span><span class="s2">&#34;t1000&#34;</span><span class="p">][</span><span class="n">i0</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;-&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="n">ocean_color</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">alpha</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">linewidth</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">date_angle</span><span class="p">[</span><span class="mi">0</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">ndf</span><span class="p">[</span><span class="s2">&#34;t1000&#34;</span><span class="p">][</span><span class="mi">0</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;-&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="n">ocean_color</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">linewidth</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Plotting a line to spot the current date easily</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">date_angle</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">date_angle</span><span class="p">[</span><span class="n">i</span><span class="p">]],</span> <span class="p">[</span><span class="n">inner</span><span class="p">,</span> <span class="n">outer</span><span class="p">],</span> <span class="s2">&#34;k-&#34;</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Display the current year as a title, just beneath the suptitle</span>
</span></span><span class="line"><span class="cl">    <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">activeyear</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">16</span><span class="p">,</span> <span class="n">horizontalalignment</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Test it</span>
</span></span><span class="line"><span class="cl"><span class="n">draw_data</span><span class="p">(</span><span class="mi">322</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/animated-polar-plot/thumbnail.png" alt="oneplot"></p>
<p>Finally it&rsquo;s time to animate, using <code>FuncAnimation</code>. Then we save it as a mp4 file or we display it in our notebook with <code>HTML(anim.to_html5_video())</code>.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">anim</span> <span class="o">=</span> <span class="n">FuncAnimation</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="p">,</span> <span class="n">draw_data</span><span class="p">,</span> <span class="n">interval</span><span class="o">=</span><span class="mi">40</span><span class="p">,</span> <span class="n">frames</span><span class="o">=</span><span class="nb">len</span><span class="p">(</span><span class="n">daterange</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">repeat</span><span class="o">=</span><span class="kc">False</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># anim.save(&#39;ArgopyUseCase_MedTempAnimation.mp4&#39;)</span>
</span></span><span class="line"><span class="cl"><span class="n">HTML</span><span class="p">(</span><span class="n">anim</span><span class="o">.</span><span class="n">to_html5_video</span><span class="p">())</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/animated-polar-plot/animatedpolar.gif" alt="animation"></p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Emoji Mosaic Art]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/emoji-mosaic-art/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/draw-all-graphs-of-n-nodes/?utm_source=atom_feed" rel="related" type="text/html" title="Draw all graphs of N nodes" />
                <link href="https://blog.scientific-python.org/matplotlib/matplotlib-cyberpunk-style/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib Cyberpunk Style" />
                <link href="https://blog.scientific-python.org/matplotlib/mpl-for-making-diagrams/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib for Making Diagrams" />
                <link href="https://blog.scientific-python.org/matplotlib/create-ridgeplots-in-matplotlib/?utm_source=atom_feed" rel="related" type="text/html" title="Create Ridgeplots in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/create-a-tesla-cybertruck-that-drives/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Tesla Cybertruck That Drives" />
            
                <id>https://blog.scientific-python.org/matplotlib/emoji-mosaic-art/</id>
            
            
            <published>2020-05-24T19:11:01+05:30</published>
            <updated>2020-05-24T19:11:01+05:30</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Applied image manipulation to create procedural art.</blockquote><p>A while back, I came across this cool <a href="https://github.com/willdady/emosaic">repository</a> to create emoji-art from images. I wanted to use it to transform my mundane Facebook profile picture to something more snazzy. The only trouble? It was written in Rust.</p>
<p>So instead of going through the process of installing Rust, I decided to take the easy route and spin up some code to do the same in Python using <a href="https://matplotlib.org/">matplotlib</a>.</p>
<p><del>Because that&rsquo;s what anyone sane would do, right?</del></p>
<p>In this post, I&rsquo;ll try to explain my process as we attempt to recreate similar mosaics as this one below. I&rsquo;ve aimed this post at people who&rsquo;ve worked with <em>some</em> sort of image data before; but really, anyone can follow along.</p>
<p><img src="/matplotlib/emoji-mosaic-art/warhol.png" alt="Emoji mosaic by Will Dady based on Andy Warhol’s Multiple Marilyns."></p>
<h2 id="packages">Packages<a class="headerlink" href="#packages" title="Link to this heading">#</a></h2>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">tqdm</span> <span class="kn">import</span> <span class="n">tqdm</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">scipy</span> <span class="kn">import</span> <span class="n">spatial</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib</span> <span class="kn">import</span> <span class="n">cm</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">scipy</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Matplotlib:</span><span class="si">{</span><span class="n">matplotlib</span><span class="o">.</span><span class="n">__version__</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Numpy:</span><span class="si">{</span><span class="n">np</span><span class="o">.</span><span class="n">__version__</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Scipy: </span><span class="si">{</span><span class="n">scipy</span><span class="o">.</span><span class="n">__version__</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">## Matplotlib: &#39;3.2.1&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1">## Numpy: &#39;1.18.1&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1">## Scipy: &#39;1.4.1&#39;</span></span></span></code></pre>
</div>
<p>Let&rsquo;s read in our image:</p>

<div class="highlight">
  <pre>img = plt.imread(r&#34;naomi_32.png&#34;, 1)
dim = img.shape[0] ##we&#39;ll need this later
plt.imshow(img)</pre>
</div>

<p><img src="/matplotlib/emoji-mosaic-art/save_100.png" alt="Naomi Watts Cannes (2014) Licensed under Creative Commons attributed to Georges Biard"></p>
<p><strong>Note</strong>: <em>The image displayed above is 100x100 but we&rsquo;ll use a 32x32 from here on since that&rsquo;s gonna suffice all our needs.</em></p>
<p>So really, what <em>is</em> an image? To numpy and matplotlib (and for almost every image processing library out there), it is, essentially, just a matrix (say A), where every individual pixel (p) is an element of A. If it&rsquo;s a grayscale image, every pixel (p) is just a single number (or a scalar) - in the range [0,1] if float, or [0,255] if integer. If it&rsquo;s not grayscale - like in our case - every pixel is a vector of either dimension 3 - <strong>Red</strong> (R), <strong>Green</strong> (G), and <strong>Blue</strong> (B), or dimension 4 - RGBA (A stands for <strong>Alpha</strong>, which is basically transparency).</p>
<p>If anything is unclear so far, I&rsquo;d strongly suggest going through a post like <a href="https://matplotlib.org/3.1.1/tutorials/introductory/images.html">this</a> or <a href="http://scipy-lectures.org/advanced/image_processing/">this</a>. Knowing that an image can be represented as a matrix (or a <code>numpy array</code>) greatly helps us as almost every transformation of the image can be represented in terms of matrix maths.</p>
<p>To prove my point, let&rsquo;s look at <code>img</code> a little.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1">## Let&#39;s check the type of img</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">img</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &lt;class &#39;numpy.ndarray&#39;&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">## The shape of the array img</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">img</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># (32, 32, 4)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">## The value of the first pixel of img</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">img</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [128 144 117 255]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">## Let&#39;s view the color of the first pixel</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">color</span> <span class="o">=</span> <span class="n">img</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="mf">255.0</span>  <span class="c1">##RGBA only accepts values in the 0-1 range</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">fill</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="n">color</span><span class="p">)</span></span></span></code></pre>
</div>
<p>That should give you a square filled with the color of the first pixel of <code>img</code>.</p>
<p><img src="/matplotlib/emoji-mosaic-art/first_pixel.png" alt="img[0][0]" title="The first pixel of the image we read in"></p>
<h2 id="methodology">Methodology<a class="headerlink" href="#methodology" title="Link to this heading">#</a></h2>
<p>We want to go from a plain image to an image full of emojis - or in other words, <strong>an image of images</strong>. Essentially, we&rsquo;re going to replace all pixels with emojis. However, to ensure that our new emoji-image looks like the original image and not just random smiley faces, the trick is to make sure that <em>every pixel is replaced my an emoji which has similar color to that pixel</em>. That&rsquo;s what gives the result the look of a mosaic.</p>
<p>&lsquo;Similar&rsquo; really just means that the <strong>mean</strong> (median is also worth trying) color of the emoji should be close to the pixel it replaces.</p>
<p>So how do you find the mean color of an entire image? Easy. We just take all the RGBA arrays and average the Rs together, and then the Gs together, and then the Bs together, and then the As together (the As, by the way, are just all 1 in our case, so the mean is also going to be 1). Here&rsquo;s that idea expressed formally:</p>
<p>\[ (r, g, b){\mu}=\left(\frac{\left(r{1}+r_{2}+\ldots+r_{N}\right)}{N}, \frac{\left(g_{1}+g_{2}+\ldots+g_{N}\right)}{N}, \frac{\left(b_{1}+b_{2}+\ldots+b_{N}\right)}{N}\right) \]</p>
<p>The resulting color would be single array of RGBA values: \[ [r_{\mu}, g_{\mu}, b_{\mu}, 1] \]</p>
<p>So now our steps become somewhat like this:</p>
<p><strong>Part I</strong> - Get emoji matches</p>
<ol>
<li>Find a bunch of emojis.</li>
<li>Find the mean of the emojis.</li>
<li>For each pixel in the image, find the emoji closest to it (wrt color), and replace pixel with that emoji (say, E).</li>
</ol>
<p><strong>Part II</strong> - Reshape emojis to image</p>
<ol>
<li>Reshape the flattened array of all Es back to the shape of our image.</li>
<li>Concatenate all emojis into a single array (reduce dimensions).</li>
</ol>
<p>That&rsquo;s pretty much it!</p>
<h3 id="step-i1---our-emoji-bank">Step I.1 - Our Emoji bank<a class="headerlink" href="#step-i1---our-emoji-bank" title="Link to this heading">#</a></h3>
<p>I took care of this for you beforehand with a bit of BeautifulSoup and requests magic. Our emoji collection is a numpy array of shape <code>1506, 16, 16, 4</code> - that&rsquo;s 1506 emojis with each being a 16x16 array of RGBA values. You can find it <a href="https://github.com/sharmaabhishekk/emoji-mosaic-mpl">here</a>.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">emoji_array</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s2">&#34;emojis_16.npy&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">emoji_array</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">## 1506, 16, 16, 4</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">##plt.imshow(emoji_array[0]) ##to view the first emoji</span></span></span></code></pre>
</div>
<h3 id="step-i2---calculate-the-mean-rgba-value-of-all-emojis">Step I.2 - Calculate the mean RGBA value of all emojis.<a class="headerlink" href="#step-i2---calculate-the-mean-rgba-value-of-all-emojis" title="Link to this heading">#</a></h3>
<p>We&rsquo;ve seen the formula above; here&rsquo;s the numpy code for it. We&rsquo;re gonna iterate over all all the 1506 emojis and create an array <code>emoji_mean_array</code> out of them.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">emoji_mean_array</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="n">ar</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="k">for</span> <span class="n">ar</span> <span class="ow">in</span> <span class="n">emoji_array</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>  <span class="c1">##`np.median(ar, axis=(0,1))` for median instead of mean</span></span></span></code></pre>
</div>
<h3 id="step-i3---finding-closest-emoji-match-for-all-pixels">Step I.3 - finding closest emoji match for all pixels<a class="headerlink" href="#step-i3---finding-closest-emoji-match-for-all-pixels" title="Link to this heading">#</a></h3>
<p>The easiest way to do that would be use Scipy&rsquo;s <strong><code>KDTree</code></strong> to create a <code>tree</code> object of all average RGBA values we calculated in #2. This enables us to perform fast lookup for every pixel using the <code>query</code> method. Here&rsquo;s how the code for that looks -</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">tree</span> <span class="o">=</span> <span class="n">spatial</span><span class="o">.</span><span class="n">KDTree</span><span class="p">(</span><span class="n">emoji_mean_array</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">indices</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">flattened_img</span> <span class="o">=</span> <span class="n">img</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">img</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>  <span class="c1">##shape = [1024, 16, 16, 4]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">pixel</span> <span class="ow">in</span> <span class="n">tqdm</span><span class="p">(</span><span class="n">flattened_img</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s2">&#34;Matching emojis&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">_</span><span class="p">,</span> <span class="n">index</span> <span class="o">=</span> <span class="n">tree</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">pixel</span><span class="p">)</span>  <span class="c1">##returns distance and index of closest match.</span>
</span></span><span class="line"><span class="cl">    <span class="n">indices</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">index</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">emoji_matches</span> <span class="o">=</span> <span class="n">emoji_array</span><span class="p">[</span><span class="n">indices</span><span class="p">]</span>  <span class="c1">##our emoji_matches</span></span></span></code></pre>
</div>
<h3 id="step-ii1">Step II.1<a class="headerlink" href="#step-ii1" title="Link to this heading">#</a></h3>
<p>The final step is to reshape the array a little more to enable us to plot it using the imshow function. As you can see above, to loop over the pixels we had to flatten the image out into the <code>flattened_img</code>. Now we have to sort of un-flatten it back; to make sure it&rsquo;s back in the form of an image. Fortunately, using numpy&rsquo;s <code>reshape</code> function makes this easy.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">resized_ar</span> <span class="o">=</span> <span class="n">emoji_matches</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">dim</span><span class="p">,</span> <span class="n">dim</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>  <span class="c1">##dim is what we got earlier when we read in the image</span></span></span></code></pre>
</div>
<h3 id="step-ii2">Step II.2<a class="headerlink" href="#step-ii2" title="Link to this heading">#</a></h3>
<p>The last bit is the trickiest. The problem with the output we&rsquo;ve got so far is that it&rsquo;s too nested. Or in simpler terms, what we have is a image where every individual pixel is itself an image. That&rsquo;s all fine but it&rsquo;s not valid input for imshow and if we try to pass it in, it tells us exactly that.</p>

<div class="highlight">
  <pre>TypeError: Invalid shape (32, 32, 16, 16, 4) for image data</pre>
</div>

<p>To grasp our problem intuitively, think about it this way. What we have right now are lots of images like these:</p>
<p><img src="/matplotlib/emoji-mosaic-art/chopped_face.png" alt="“Chopped raccoon img”" title="Image from Scipy under BSD License"></p>
<p>What we want is to merge them all together. Like so:</p>
<p><img src="/matplotlib/emoji-mosaic-art/rejoined_face.png" alt="“Rejoined raccoon img”"></p>
<p>To think about it slightly more technically, what we have right now is a <em>five</em> dimensional array. What we need is to rehshape it in such a way that it&rsquo;s - at maximum - <em>three</em> dimensional. However, it&rsquo;s not as easy as a simple <code>np.reshape</code> (I&rsquo;d suggest you go ahead and try that anyway).</p>
<p>Don&rsquo;t worry though, we have Stack Overflow to the rescue! This excellent <a href="https://stackoverflow.com/questions/52730668/concatenating-multiple-images-into-one/52733370#52733370">answer</a> does exactly that. You don&rsquo;t have to go through it, I have copied the relevant code in here.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">np_block_2D</span><span class="p">(</span><span class="n">chops</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Converts list of chopped images to one single image&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">block</span><span class="p">([[[</span><span class="n">x</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">row</span><span class="p">]</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">chops</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">final_img</span> <span class="o">=</span> <span class="n">np_block_2D</span><span class="p">(</span><span class="n">resized_ar</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">final_img</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">## (512, 512, 4)</span></span></span></code></pre>
</div>
<p>The shape looks correct enough. Let&rsquo;s try to plot it.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">final_img</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/emoji-mosaic-art/final_image.png" alt="“Emoji Mosaic final_img”"></p>
<p><strong>Et Voilà</strong></p>
<p>Of course, the result looks a little <em>meh</em> but that&rsquo;s because we only used 32x32 emojis. Here&rsquo;s what the same code would do with 10000 emojis (100x100).</p>
<p><img src="/matplotlib/emoji-mosaic-art/final_image_100.png" alt="“Emoji Mosaic full_size”"></p>
<p>Better?</p>
<p>Now, let&rsquo;s try and create nine of these emoji-images and grid them together.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">canvas</span><span class="p">(</span><span class="n">gray_scale_img</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Plot a 3x3 matrix of the images using different colormaps
</span></span></span><span class="line"><span class="cl"><span class="s2">        param gray_scale_img: a square gray_scale_image
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="p">,</span> <span class="n">axes</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">nrows</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">ncols</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="mi">8</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">axes</span> <span class="o">=</span> <span class="n">axes</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">cmaps</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;BuPu_r&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;bone&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;CMRmap&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;magma&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;afmhot&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;ocean&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;inferno&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;PuRd_r&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;gist_gray&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">cmap</span><span class="p">,</span> <span class="n">ax</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">cmaps</span><span class="p">,</span> <span class="n">axes</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">cmapper</span> <span class="o">=</span> <span class="n">cm</span><span class="o">.</span><span class="n">get_cmap</span><span class="p">(</span><span class="n">cmap</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">rgba_image</span> <span class="o">=</span> <span class="n">cmapper</span><span class="p">(</span><span class="n">gray_scale_img</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">single_plot</span><span class="p">(</span><span class="n">rgba_image</span><span class="p">,</span> <span class="n">ax</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># ax.imshow(rgba_image) ##try this if you just want to plot the plain image in different color spaces, comment the single_plot call above</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">set_axis_off</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">plt</span><span class="o">.</span><span class="n">subplots_adjust</span><span class="p">(</span><span class="n">hspace</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">wspace</span><span class="o">=-</span><span class="mf">0.2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">fig</span><span class="p">,</span> <span class="n">axes</span></span></span></code></pre>
</div>
<p>The code does mostly the same stuff as before. To get the different colours, I used a simple hack. I first converted the image to grayscale and then used 9 different colormaps on it. Then I used the RGB values returned by the colormap to get the absolute values for our new input image. After that, the only part left is to just feed the new input image through the pipeline we&rsquo;ve discussed so far and that gives us our emoji-image.</p>
<p>Here&rsquo;s what that looks like:</p>
<p><img src="/matplotlib/emoji-mosaic-art/final_3x3_tile.png" alt="“Emoji Mosaic 3x3_grid”"></p>
<p><em>Pretty</em></p>
<h2 id="conclusion">Conclusion<a class="headerlink" href="#conclusion" title="Link to this heading">#</a></h2>
<p>Some final thoughts to wrap this up.</p>
<ul>
<li>
<p>I&rsquo;m not sure if my way to get different colours using different cmaps is what people usually do. I&rsquo;m almost certain there&rsquo;s a better way and if you know one, please submit a PR to the repo (link below).</p>
</li>
<li>
<p>Iterating over every pixel is not really the best idea. We got away with it since it&rsquo;s just 1024 (32x32) pixels but for images with higher resolution, we&rsquo;d have to either iterate over grids of images at once (say a 3x3 or 2x2 window) or resize the image itself to a more workable shape. I prefer the latter since that way we can also just resize it to a square shape in the same call which also has the additional advantage of fitting in nicely in our 3x3 mosaic. I&rsquo;ll leave the readers to work that out themselves using numpy (and, no, please don&rsquo;t use <code>cv2.resize</code>).</p>
</li>
<li>
<p>The <code>KDTree</code> was not part of my initial code. Initially, I&rsquo;d just looped over every emoji for every pixel and then calculated the Euclidean distance (using <code>np.linalg.norm(a-b)</code>). As you can probably imagine, the nested loop in there slowed down the code tremendously - even a 32x32 emoji-image took around 10 minutes to run - right now the same code takes ~19 seconds. Guess that&rsquo;s the power of vectorization for you all.</p>
</li>
<li>
<p>It&rsquo;s worth messing around with median instead of mean to get the RGBA values of the emojis. Most emojis are circular in shape and hence there&rsquo;s a lot of space left outside the area of the circular region which sort of waters down the average color in turn watering down the end result. Considering the median might sort out this problem for some images which aren&rsquo;t very rich.</p>
</li>
<li>
<p>While I&rsquo;ve tried to go in a linear manner with (what I hope was) a good mix of explanation and code, I&rsquo;d strongly suggest looking at the full code in the repository <a href="https://github.com/sharmaabhishekk/emoji-mosaic-mpl">here</a> in case you feel like I sprung anything on you.</p>
</li>
</ul>
<hr>
<p>I hope you enjoyed this post and learned something from it. If you have any feedback, criticism, questions, please feel free to DM me on <a href="https://twitter.com/abhisheksh_98">Twitter</a> or email me (preferably the former since I&rsquo;m almost always on there). Thank you, and take care!</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="art" label="art" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Draw all graphs of N nodes]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/draw-all-graphs-of-n-nodes/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/matplotlib-cyberpunk-style/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib Cyberpunk Style" />
                <link href="https://blog.scientific-python.org/matplotlib/mpl-for-making-diagrams/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib for Making Diagrams" />
                <link href="https://blog.scientific-python.org/matplotlib/create-ridgeplots-in-matplotlib/?utm_source=atom_feed" rel="related" type="text/html" title="Create Ridgeplots in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/create-a-tesla-cybertruck-that-drives/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Tesla Cybertruck That Drives" />
                <link href="https://blog.scientific-python.org/matplotlib/an-inquiry-into-matplotlib-figures/?utm_source=atom_feed" rel="related" type="text/html" title="An Inquiry Into Matplotlib&#39;s Figures" />
            
                <id>https://blog.scientific-python.org/matplotlib/draw-all-graphs-of-n-nodes/</id>
            
            
            <published>2020-05-07T09:05:32+01:00</published>
            <updated>2020-05-07T09:05:32+01:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>A fun project about drawing all possible differently-looking (not isomorphic) graphs of N nodes.</blockquote><p>The other day I was homeschooling my kids, and they asked me: &ldquo;Daddy, can you draw us all possible non-isomorphic graphs of 3 nodes&rdquo;? Or maybe I asked them that? Either way, we happily drew all possible graphs of 3 nodes, but already for 4 nodes it got hard, and for 5 nodes - <a href="https://www.graphclasses.org/smallgraphs.html#nodes5">plain impossible</a>!</p>
<p>So I thought: let me try to write a brute-force program to do it! I spent a few hours sketching some smart dynamic programming solution to generate these graphs, and went nowhere, as apparently the <a href="http://www.cs.columbia.edu/~cs4205/files/CM9.pdf">problem is quite hard</a>. I gave up, and decided to go with a naive approach:</p>
<ol>
<li>Generate all graphs of N nodes, even if some of them look the same (are isomorphic). For \(N\) nodes, there are \(\frac{N(N-1)}{2}\) potential edges to connect these nodes, so it&rsquo;s like generating a bunch of binary numbers. Simple!</li>
<li>Write a program to tell if two graphs are isomorphic, then remove all duplicates, unworthy of being presented in the final picture.</li>
</ol>
<p>This strategy seemed more reasonable, but writing a &ldquo;graph-comparator&rdquo; still felt like a cumbersome task, and more importantly, this part would itself be slow, as I&rsquo;d still have to go through a whole tree of options for every graph comparison. So after some more head-scratching, I decided to simplify it even further, and use the fact that these days the memory is cheap:</p>
<ol>
<li>Generate all possible graphs (some of them totally isomorphic, meaning that they would look as a repetition if plotted on a figure)</li>
<li>For each graph, generate its &ldquo;description&rdquo; (like an <a href="https://en.wikipedia.org/wiki/Adjacency_matrix">adjacency matrix</a>, of an edge list), and check if a graph with this description is already on the list. If yes, skip it, we got its portrait already!</li>
<li>If however the graph is unique, include it in the picture, and also generate all possible &ldquo;descriptions&rdquo; of it, up to node permutation, and add them to the hash table. To make sure no other graph of this particular shape would ever be included in our pretty picture again.</li>
</ol>
<p>For the first task, I went with the edge list, which made the task identical to <a href="https://www.geeksforgeeks.org/generate-all-the-binary-strings-of-n-bits/">generating all binary numbers</a> of length \(\frac{N(N-1)}{2}\) with a recursive function, except instead of writing zeroes you skip edges, and instead of writing ones, you include them. Below is the function that does the trick, and has an additional bonus of listing all edges in a neat orderly way. For every edge \(i \rightarrow j\) we can be sure that \(i\) is lower than \(j\), and also that edges are sorted as words in a dictionary. Which is good, as it restricts the set of possible descriptions a bit, which will simplify our life later.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">make_graphs</span><span class="p">(</span><span class="n">n</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Make a graph recursively, by either including, or skipping each edge.
</span></span></span><span class="line"><span class="cl"><span class="s2">    Edges are given in lexicographical order by construction.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">i</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>  <span class="c1"># First call</span>
</span></span><span class="line"><span class="cl">        <span class="n">out</span> <span class="o">=</span> <span class="p">[[(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span> <span class="o">+</span> <span class="n">r</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">make_graphs</span><span class="p">(</span><span class="n">n</span><span class="o">=</span><span class="n">n</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">out</span> <span class="o">+=</span> <span class="p">[[(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)]</span> <span class="o">+</span> <span class="n">r</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">make_graphs</span><span class="p">(</span><span class="n">n</span><span class="o">=</span><span class="n">n</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">        <span class="n">out</span> <span class="o">+=</span> <span class="p">[</span><span class="n">r</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">make_graphs</span><span class="p">(</span><span class="n">n</span><span class="o">=</span><span class="n">n</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">out</span> <span class="o">=</span> <span class="n">make_graphs</span><span class="p">(</span><span class="n">n</span><span class="o">=</span><span class="n">n</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">j</span><span class="o">=</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">out</span> <span class="o">=</span> <span class="p">[[]]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">out</span></span></span></code></pre>
</div>
<p>If you run this function for a small number of nodes (say, \(N=3\)), you can see how it generates all possible graph topologies, but that some of the descriptions would actually lead to identical pictures, if drawn (graphs 2 and 3 in the list below).</p>

<div class="highlight">
  <pre>[(0, 1), (0, 2), (1, 2)]
[(0, 1), (0, 2)]
[(0, 1), (1, 2)]
[(0, 1)]</pre>
</div>

<p>Also, while building a graph from edges means that we&rsquo;ll never get lonely unconnected points, we can get graphs that are smaller than \(n\) nodes (the last graph in the list above), or graphs that have unconnected parts. It is impossible for \(n=3\), but starting with \(n=4\) we would get things like <code>[(0,1), (2,3)]</code>, which is technically a graph, but you cannot exactly wear it as a piece of jewelry, as it would fall apart. So at this point I decided to only visualize fully connected graphs of exactly \(n\) vertices.</p>
<p>To continue with the plan, we now need to make a function that for every graph would generate a family of its &ldquo;alternative representations&rdquo; (given the constraints of our generator), to make sure duplicates would not slip under the radar. First we need a permutation function, to permute the nodes (you could also use a built-in function in <code>numpy</code>, but coding this one from scratch is always fun, isn&rsquo;t it?). Here&rsquo;s the permutation generator:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">perm</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;All permutations of n elements.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">s</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">perm</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">s</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[[]]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">p</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">s</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">perm</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">([</span><span class="n">k</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">s</span> <span class="k">if</span> <span class="n">k</span> <span class="o">!=</span> <span class="n">i</span><span class="p">]))]</span></span></span></code></pre>
</div>
<p>Now, for any given graph description, we can permute its nodes, sort the \(i,j\) within each edge, sort the edges themselves, remove duplicate alt-descriptions, and remember the list of potential impostors:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">permute</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Create a set of all possible isomorphic codes for a graph,
</span></span></span><span class="line"><span class="cl"><span class="s2">    as nice hashable tuples. All edges are i&lt;j, and sorted lexicographically.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ps</span> <span class="o">=</span> <span class="n">perm</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">out</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([])</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">ps</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">out</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nb">tuple</span><span class="p">(</span><span class="nb">sorted</span><span class="p">([(</span><span class="n">p</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">p</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="k">if</span> <span class="n">p</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">p</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="k">else</span> <span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="n">j</span><span class="p">],</span> <span class="n">p</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">g</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">out</span><span class="p">)</span></span></span></code></pre>
</div>
<p>Say, for an input description of <code>[(0, 1), (0, 2)]</code>, the function above returns three &ldquo;synonyms&rdquo;:</p>

<div class="highlight">
  <pre>((0, 1), (1, 2))
((0, 1), (0, 2))
((0, 2), (1, 2))</pre>
</div>

<p>I suspect there should be a neater way to code that, to avoid using the <code>list → set → list</code> pipeline to get rid of duplicates, but hey, it works!</p>
<p>At this point, the only thing that&rsquo;s missing is the function to check whether the graph comes in one piece, which happens to be a famous and neat algorithm called the &ldquo;<a href="https://en.wikipedia.org/wiki/Disjoint-set_data_structure">Union-Find</a>&rdquo;. I won&rsquo;t describe it here in detail, but in short, it goes though all edges and connects nodes to each other in a special way; then counts how many separate connected components (like, chunks of the graph) remain in the end. If all nodes are in one chunk, we like it. If not, I don&rsquo;t want to see it in my pictures!</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">connected</span><span class="p">(</span><span class="n">g</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Check if the graph is fully connected, with Union-Find.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">nodes</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="n">i</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">e</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="n">roots</span> <span class="o">=</span> <span class="p">{</span><span class="n">node</span><span class="p">:</span> <span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">nodes</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">_root</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">depth</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">node</span> <span class="o">==</span> <span class="n">roots</span><span class="p">[</span><span class="n">node</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">depth</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">_root</span><span class="p">(</span><span class="n">roots</span><span class="p">[</span><span class="n">node</span><span class="p">],</span> <span class="n">depth</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">g</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">ri</span><span class="p">,</span> <span class="n">di</span> <span class="o">=</span> <span class="n">_root</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">rj</span><span class="p">,</span> <span class="n">dj</span> <span class="o">=</span> <span class="n">_root</span><span class="p">(</span><span class="n">j</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">ri</span> <span class="o">==</span> <span class="n">rj</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">di</span> <span class="o">&lt;=</span> <span class="n">dj</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">roots</span><span class="p">[</span><span class="n">ri</span><span class="p">]</span> <span class="o">=</span> <span class="n">rj</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">roots</span><span class="p">[</span><span class="n">rj</span><span class="p">]</span> <span class="o">=</span> <span class="n">ri</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="nb">set</span><span class="p">([</span><span class="n">_root</span><span class="p">(</span><span class="n">node</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">nodes</span><span class="p">]))</span> <span class="o">==</span> <span class="mi">1</span></span></span></code></pre>
</div>
<p>Now we can finally generate the &ldquo;overkill&rdquo; list of graphs, filter it, and plot the pics:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">filter</span><span class="p">(</span><span class="n">gs</span><span class="p">,</span> <span class="n">target_nv</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Filter all improper graphs: those with not enough nodes,
</span></span></span><span class="line"><span class="cl"><span class="s2">    those not fully connected, and those isomorphic to previously considered.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mem</span> <span class="o">=</span> <span class="nb">set</span><span class="p">({})</span>
</span></span><span class="line"><span class="cl">    <span class="n">gs2</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">g</span> <span class="ow">in</span> <span class="n">gs</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">nv</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="nb">set</span><span class="p">([</span><span class="n">i</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">e</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">nv</span> <span class="o">!=</span> <span class="n">target_nv</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">connected</span><span class="p">(</span><span class="n">g</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">mem</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">gs2</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">g</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">mem</span> <span class="o">|=</span> <span class="nb">set</span><span class="p">(</span><span class="n">permute</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">target_nv</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">gs2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Main body</span>
</span></span><span class="line"><span class="cl"><span class="n">NV</span> <span class="o">=</span> <span class="mi">6</span>
</span></span><span class="line"><span class="cl"><span class="n">gs</span> <span class="o">=</span> <span class="n">make_graphs</span><span class="p">(</span><span class="n">NV</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">gs</span> <span class="o">=</span> <span class="nb">filter</span><span class="p">(</span><span class="n">gs</span><span class="p">,</span> <span class="n">NV</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">plot_graphs</span><span class="p">(</span><span class="n">gs</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="mi">14</span><span class="p">,</span> <span class="n">dotsize</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span></span></span></code></pre>
</div>
<p>For plotting the graphs I wrote a small wrapper for the MatPlotLib-based NetworkX visualizer, splitting the figure into lots of tiny little facets using Matplotlib <code>subplot</code> command. &ldquo;Kamada-Kawai&rdquo; layout below is a <a href="https://en.wikipedia.org/wiki/Force-directed_graph_drawing">popular and fast version of a spring-based layout</a>, that makes the graphs look really nice.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">plot_graphs</span><span class="p">(</span><span class="n">graphs</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="mi">14</span><span class="p">,</span> <span class="n">dotsize</span><span class="o">=</span><span class="mi">20</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Utility to plot a lot of graphs from an array of graphs.
</span></span></span><span class="line"><span class="cl"><span class="s2">    Each graphs is a list of edges; each edge is a tuple.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">graphs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="n">figsize</span><span class="p">,</span> <span class="n">figsize</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="o">.</span><span class="n">patch</span><span class="o">.</span><span class="n">set_facecolor</span><span class="p">(</span><span class="s2">&#34;white&#34;</span><span class="p">)</span>  <span class="c1"># To make copying possible (white background)</span>
</span></span><span class="line"><span class="cl">    <span class="n">k</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">n</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">plt</span><span class="o">.</span><span class="n">subplot</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">g</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">Graph</span><span class="p">()</span>  <span class="c1"># Generate a Networkx object</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">graphs</span><span class="p">[</span><span class="n">i</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">            <span class="n">g</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">nx</span><span class="o">.</span><span class="n">draw_kamada_kawai</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="n">dotsize</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p>Here are the results. To build the anticipation, let&rsquo;s start with something trivial: all graphs of 3 nodes:</p>
<p><img src="/matplotlib/draw-all-graphs-of-n-nodes/3nodes.png" alt="Two non isomorphic graphs with 3 nodes, the first graph connects all 3 nodes and creates a triangle. The second graph is a path graph with 3 nodes connected as a single path."></p>
<p>All graphs of 4 nodes:</p>
<p><img src="/matplotlib/draw-all-graphs-of-n-nodes/4nodes.png" alt="All six possible non isomorphic graphs with 4 nodes. The first graph is a complete graph with all 4 nodes connected to each other. The second one is a complete graph with one edge removed. The third graph is a triangle graph with one node attached with one of the nodes in the graph. The fourth graph is a star graph, with one central node connected to the other 3 nodes. The fifth one is a graph where the edges form a square. The sixth one is a path graph which connects all 4 nodes as a single path."></p>
<p>All graphs of 5 nodes:</p>
<p><img src="/matplotlib/draw-all-graphs-of-n-nodes/5nodes.png" alt="All 21 possibilities of non isomorphic graphs with 5 nodes. The different graphs show multiple possible structures from a complete graph of 5 nodes to a path graph of 5 nodes. Other structures present in this collection of graphs show a pentagon shaped graph, a star graph and others."></p>
<p>Generating figures above is of course all instantaneous on a decent computer, but for 6 nodes (below) it takes a few seconds:</p>
<p><img src="/matplotlib/draw-all-graphs-of-n-nodes/6nodes.png" alt="All 112 possibilities of non isomorphic graphs with 6 nodes. The different graphs show multiple possible structures from a complete graph of 6 nodes to a path graph of 6 nodes. Other structures present in this collection of graphs show a hexagon shaped graph, a star graph, two complete graphs with 4 nodes stacked on top of each other with the two complete 4 graphs sharing an edge and 107 other structures!"></p>
<p>For 7 nodes (below) it takes about 5-10 minutes. It&rsquo;s easy to see why: the brute-force approach generates all \(2^{\frac{n(n-1)}{2}}\) possible graphs, which means that the number of operations grows exponentially! Every increase of \(n\) by one, gives us \(n-1\) new edges to consider, which means that the time to run the program increases by \(~2^{n-1}\). For \(n=7\) it brought me from seconds to minutes, for \(n=8\) it would have shifted me from minutes to hours, and for \(n=9\), from hours, to months of computation. Isn&rsquo;t it fun? We are all specialists in exponential growth these days, so here you are :)</p>
<p><img src="/matplotlib/draw-all-graphs-of-n-nodes/7nodes.png" alt="ALL 853 possibilities of non isomorphic graphs with 7 nodes. The different graphs show multiple possible structures from a complete graph of 7 nodes to a path graph of 7 nodes. Other structures present in this collection show many star and kite-shaped graphs."></p>
<p>The code is available as a <a href="https://github.com/khakhalin/Sketches/blob/master/classic/generate_all_graphs.ipynb">Jupyter Notebook on my GitHub</a>. I hope you enjoyed the pictures, and the read! Which of those charms above would bring most luck? Which ones seem best for divination? Let me know what you think! :)</p>
<p>Contact me via <a href="https://twitter.com/ampanmdagaba">Twitter</a> or <a href="https://github.com/khakhalin">Github</a>.</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="graphs" label="graphs" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Matplotlib Cyberpunk Style]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/matplotlib-cyberpunk-style/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/mpl-for-making-diagrams/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib for Making Diagrams" />
                <link href="https://blog.scientific-python.org/matplotlib/create-ridgeplots-in-matplotlib/?utm_source=atom_feed" rel="related" type="text/html" title="Create Ridgeplots in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/create-a-tesla-cybertruck-that-drives/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Tesla Cybertruck That Drives" />
                <link href="https://blog.scientific-python.org/matplotlib/an-inquiry-into-matplotlib-figures/?utm_source=atom_feed" rel="related" type="text/html" title="An Inquiry Into Matplotlib&#39;s Figures" />
                <link href="https://blog.scientific-python.org/matplotlib/custom-3d-engine/?utm_source=atom_feed" rel="related" type="text/html" title="Custom 3D engine in Matplotlib" />
            
                <id>https://blog.scientific-python.org/matplotlib/matplotlib-cyberpunk-style/</id>
            
            
            <published>2020-03-27T20:26:07+01:00</published>
            <updated>2020-03-27T20:26:07+01:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Futuristic neon glow for your next data visualization</blockquote><p><img src="/matplotlib/matplotlib-cyberpunk-style/figures/5.png" alt="A line graph styled with a dark background and neon glowing lines in the style of Cyberpunk."></p>
<h2 id="1---the-basis">1 - The Basis<a class="headerlink" href="#1---the-basis" title="Link to this heading">#</a></h2>
<p>Let&rsquo;s make up some numbers, put them in a Pandas dataframe and plot them:</p>
<pre><code>import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'A': [1, 3, 9, 5, 2, 1, 1],
                   'B': [4, 5, 5, 7, 9, 8, 6]})

df.plot(marker='o')
plt.show()
</code></pre>
<p><img src="/matplotlib/matplotlib-cyberpunk-style/figures/1.png" alt="A simple chart consisted of two lines, one blue line, and one orange line. The lines are on a white background."></p>
<h2 id="2---the-darkness">2 - The Darkness<a class="headerlink" href="#2---the-darkness" title="Link to this heading">#</a></h2>
<p>Not bad, but somewhat ordinary. Let&rsquo;s customize it by using Seaborn&rsquo;s dark style, as well as changing background and font colors:</p>
<pre><code>plt.style.use(&quot;seaborn-dark&quot;)

for param in ['figure.facecolor', 'axes.facecolor', 'savefig.facecolor']:
    plt.rcParams[param] = '#212946'  # bluish dark grey

for param in ['text.color', 'axes.labelcolor', 'xtick.color', 'ytick.color']:
    plt.rcParams[param] = '0.9'  # very light grey

ax.grid(color='#2A3459')  # bluish dark grey, but slightly lighter than background
</code></pre>
<p><img src="/matplotlib/matplotlib-cyberpunk-style/figures/2.png" alt="A simple chart with a dark background consisted of two lines: A is the blue line and B is the orange line."></p>
<h2 id="3---the-light">3 - The Light<a class="headerlink" href="#3---the-light" title="Link to this heading">#</a></h2>
<p>It looks more interesting now, but we need our colors to shine more against the dark background:</p>
<pre><code>fig, ax = plt.subplots()
colors = [
    '#08F7FE',  # teal/cyan
    '#FE53BB',  # pink
    '#F5D300',  # yellow
    '#00ff41', # matrix green
]
df.plot(marker='o', ax=ax, color=colors)
</code></pre>
<p><img src="/matplotlib/matplotlib-cyberpunk-style/figures/3.png" alt="A simple chart with a dark background consisted of two lines: A is the blue line and B is the purple line."></p>
<h2 id="4---the-glow">4 - The Glow<a class="headerlink" href="#4---the-glow" title="Link to this heading">#</a></h2>
<p>Now, how to get that neon look? To make it shine, we <em>redraw the lines multiple times</em>, with low alpha value and slightly increasing linewidth. The overlap creates the glow effect.</p>
<pre><code>n_lines = 10
diff_linewidth = 1.05
alpha_value = 0.03

for n in range(1, n_lines+1):

    df.plot(marker='o',
            linewidth=2+(diff_linewidth*n),
            alpha=alpha_value,
            legend=False,
            ax=ax,
            color=colors)
</code></pre>
<p><img src="/matplotlib/matplotlib-cyberpunk-style/figures/4.png" alt="A simple chart with a dark background consisted of two lines: A is the blue line and B is the purple line.  However, they have a neon look and are both glowing."></p>
<h2 id="5---the-finish">5 - The Finish<a class="headerlink" href="#5---the-finish" title="Link to this heading">#</a></h2>
<p>For some more fine tuning, we color the area below the line (via <code>ax.fill_between</code>) and adjust the axis limits.</p>
<p>Here&rsquo;s the full code:</p>
<pre><code>import pandas as pd
import matplotlib.pyplot as plt


plt.style.use(&quot;dark_background&quot;)

for param in ['text.color', 'axes.labelcolor', 'xtick.color', 'ytick.color']:
    plt.rcParams[param] = '0.9'  # very light grey

for param in ['figure.facecolor', 'axes.facecolor', 'savefig.facecolor']:
    plt.rcParams[param] = '#212946'  # bluish dark grey

colors = [
    '#08F7FE',  # teal/cyan
    '#FE53BB',  # pink
    '#F5D300',  # yellow
    '#00ff41',  # matrix green
]


df = pd.DataFrame({'A': [1, 3, 9, 5, 2, 1, 1],
                   'B': [4, 5, 5, 7, 9, 8, 6]})

fig, ax = plt.subplots()

df.plot(marker='o', color=colors, ax=ax)

# Redraw the data with low alpha and slightly increased linewidth:
n_shades = 10
diff_linewidth = 1.05
alpha_value = 0.3 / n_shades

for n in range(1, n_shades+1):

    df.plot(marker='o',
            linewidth=2+(diff_linewidth*n),
            alpha=alpha_value,
            legend=False,
            ax=ax,
            color=colors)

# Color the areas below the lines:
for column, color in zip(df, colors):
    ax.fill_between(x=df.index,
                    y1=df[column].values,
                    y2=[0] * len(df),
                    color=color,
                    alpha=0.1)

ax.grid(color='#2A3459')

ax.set_xlim([ax.get_xlim()[0] - 0.2, ax.get_xlim()[1] + 0.2])  # to not have the markers cut off
ax.set_ylim(0)

plt.show()
</code></pre>
<p><img src="/matplotlib/matplotlib-cyberpunk-style/figures/5.png" alt="A simple chart with a dark background consisted of two lines: A is the blue line and B is the purple line. However they are neon, both glow, and the area below them glows as well."></p>
<p>If this helps you or if you have constructive criticism, I&rsquo;d be happy to hear about it! Please contact me via <a href="https://dhaitz.github.io">here</a> or <a href="https://twitter.com/d_haitz">here</a>. Thanks!</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Matplotlib for Making Diagrams]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/mpl-for-making-diagrams/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/create-ridgeplots-in-matplotlib/?utm_source=atom_feed" rel="related" type="text/html" title="Create Ridgeplots in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/create-a-tesla-cybertruck-that-drives/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Tesla Cybertruck That Drives" />
                <link href="https://blog.scientific-python.org/matplotlib/an-inquiry-into-matplotlib-figures/?utm_source=atom_feed" rel="related" type="text/html" title="An Inquiry Into Matplotlib&#39;s Figures" />
                <link href="https://blog.scientific-python.org/matplotlib/custom-3d-engine/?utm_source=atom_feed" rel="related" type="text/html" title="Custom 3D engine in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/warming-stripes/?utm_source=atom_feed" rel="related" type="text/html" title="Creating the Warming Stripes in Matplotlib" />
            
                <id>https://blog.scientific-python.org/matplotlib/mpl-for-making-diagrams/</id>
            
            
            <published>2020-02-19T12:57:07-05:00</published>
            <updated>2020-02-19T12:57:07-05:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>How to use Matplotlib to make diagrams.</blockquote><h1 id="matplotlib-for-diagrams">Matplotlib for diagrams<a class="headerlink" href="#matplotlib-for-diagrams" title="Link to this heading">#</a></h1>
<p>This is my first post for the Matplotlib blog so I wanted to lead
with an example of what I most love about it:
How much control Matplotlib gives you.
I like to use it as a programmable drawing tool that happens
to be good at plotting data.</p>
<p>The default layout for Matplotlib works great for a lot of things,
but sometimes you want to exert
more control. Sometimes you want to treat your figure window as
a blank canvas and create diagrams
to communicate your ideas. Here, we will walk through the process
for setting this up. Most of these tricks are detailed in
<a href="https://e2eml.school/matplotlib_framing.html">this cheat sheet for laying out plots</a>.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span></span></span></code></pre>
</div>
<p>The first step is to choose the size of your canvas.</p>
<p>(Just a heads up, I love the metaphor
of the canvas, so that&rsquo;s how I am using the term here.
The Canvas object is a very specific
thing in the Matplotlib code base. That&rsquo;s not what I&rsquo;m referring to.)</p>
<p>I&rsquo;m planning to make a diagram that is 16 centimeters wide
and 9 centimeters high.
This will fit comfortably on a piece of A4 or US Letter paper
and will be almost twice as wide as it is high.
It also scales up nicely to fit on a wide-format slide presentation.</p>
<p>The <code>plt.figure()</code> function accepts a <code>figsize</code> argument,
a tuple of <code>(width, height)</code> in <strong>inches</strong>.
To convert from centimeters, we&rsquo;ll divide by 2.54.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig_width</span> <span class="o">=</span> <span class="mi">16</span>  <span class="c1"># cm</span>
</span></span><span class="line"><span class="cl"><span class="n">fig_height</span> <span class="o">=</span> <span class="mi">9</span>  <span class="c1"># cm</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="n">fig_width</span> <span class="o">/</span> <span class="mf">2.54</span><span class="p">,</span> <span class="n">fig_height</span> <span class="o">/</span> <span class="mf">2.54</span><span class="p">))</span></span></span></code></pre>
</div>
<p>The next step is to add an Axes object that we can draw on.
By default, Matplotlib will size and place the Axes to leave
a little border and room for x- and y-axis labels. However, we don&rsquo;t
want that this time around. We want our Axes to extend right up
to the edge of the Figure.</p>
<p>The <code>add_axes()</code> function lets us specify exactly where to place
our new Axes and how big to make it. It accepts a tuple of the format
<code>(left, bottom, width, height)</code>. The coordinate frame of the Figure
is always (0, 0) at the bottom left corner and (1, 1) at the upper right,
no matter what size of Figure you are working with. Positions, widths,
and heights all become fractions of the total width and height of the Figure.</p>
<p>To fill the Figure with our Axes entirely, we specify a left position of 0,
a bottom position of 0, a width of 1, and a height of 1.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span></span></span></code></pre>
</div>
<p>To make our diagram creation easier, we can set the axis limits so that
one unit in the figure equals one centimeter. This grants us
an intuitive way to control the size of objects in the diagram.
A circle with a radius of 2 will be drawn as a circle (not an ellipse)
in the final image and have a radius of 2 cm.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">fig_width</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">fig_height</span><span class="p">)</span></span></span></code></pre>
</div>
<p>We can also do away with the automatically generated ticks
and tick labels with this pair of calls.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">tick_params</span><span class="p">(</span><span class="n">bottom</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">top</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">left</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">right</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">tick_params</span><span class="p">(</span><span class="n">labelbottom</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">labeltop</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">labelleft</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">labelright</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span></span></span></code></pre>
</div>
<p>At this point we have a big blank space of exactly the right size and shape.
Now we can begin building our diagram. The foundation of the image will be
the background color. White is fine, but sometimes it&rsquo;s fun to mix it up.
<a href="https://e2eml.school/matplotlib_lines.html#color">Here are some ideas</a>
to get you started.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_facecolor</span><span class="p">(</span><span class="s2">&#34;antiquewhite&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p>We can also add a border to the diagram to visually set it apart.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;top&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_color</span><span class="p">(</span><span class="s2">&#34;midnightblue&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;bottom&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_color</span><span class="p">(</span><span class="s2">&#34;midnightblue&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;left&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_color</span><span class="p">(</span><span class="s2">&#34;midnightblue&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;right&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_color</span><span class="p">(</span><span class="s2">&#34;midnightblue&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;top&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;bottom&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;left&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;right&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span></span></span></code></pre>
</div>
<p>Now we have a foundation and background in place
and we&rsquo;re finally ready to start drawing.
You have complete freedom to
<a href="https://e2eml.school/matplotlib_lines.html">draw curves and shapes</a>,
<a href="https://e2eml.school/matplotlib_points.html">place points</a>,
and <a href="https://e2eml.school/matplotlib_text.html">add text</a>
of any variety within our 16 x 9 garden walls.</p>
<p>Then when you&rsquo;re done, the last step is to save the figure out as a
<code>.png</code> file. In this format it can be imported to and added to whatever
document or presentation you&rsquo;re working on</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s2">&#34;blank_diagram.png&#34;</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">300</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/mpl-for-making-diagrams/blank_diagram.png" alt="Blank diagram example."></p>
<p>If you&rsquo;re making a collection of diagrams,
you can make a convenient template for your blank canvas.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">blank_diagram</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig_width</span><span class="o">=</span><span class="mi">16</span><span class="p">,</span> <span class="n">fig_height</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">bg_color</span><span class="o">=</span><span class="s2">&#34;antiquewhite&#34;</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;midnightblue&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="n">fig_width</span> <span class="o">/</span> <span class="mf">2.54</span><span class="p">,</span> <span class="n">fig_height</span> <span class="o">/</span> <span class="mf">2.54</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">fig_width</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">fig_height</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_facecolor</span><span class="p">(</span><span class="n">bg_color</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">tick_params</span><span class="p">(</span><span class="n">bottom</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">top</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">left</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">right</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">tick_params</span><span class="p">(</span><span class="n">labelbottom</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">labeltop</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">labelleft</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">labelright</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;top&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_color</span><span class="p">(</span><span class="n">color</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;bottom&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_color</span><span class="p">(</span><span class="n">color</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;left&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_color</span><span class="p">(</span><span class="n">color</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;right&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_color</span><span class="p">(</span><span class="n">color</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;top&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;bottom&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;left&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">spines</span><span class="p">[</span><span class="s2">&#34;right&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">set_linewidth</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">fig</span><span class="p">,</span> <span class="n">ax</span></span></span></code></pre>
</div>
<p>Then you can take that canvas and add arbitrary text, shapes, and lines.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">blank_diagram</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">x0</span> <span class="ow">in</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="o">-</span><span class="mi">3</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="n">x0</span><span class="p">,</span> <span class="n">x0</span> <span class="o">+</span> <span class="mi">3</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">9</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s2">&#34;stripes.png&#34;</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">300</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/mpl-for-making-diagrams/stripes.png" alt="White rectangle with black stripes."></p>
<p>Or more intricately:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">blank_diagram</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">centers</span> <span class="o">=</span> <span class="p">[(</span><span class="mf">3.5</span><span class="p">,</span> <span class="mf">6.5</span><span class="p">),</span> <span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mf">6.5</span><span class="p">),</span> <span class="p">(</span><span class="mf">12.5</span><span class="p">,</span> <span class="mf">6.5</span><span class="p">),</span> <span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl"><span class="n">radii</span> <span class="o">=</span> <span class="mf">1.5</span>
</span></span><span class="line"><span class="cl"><span class="n">texts</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s2">&#34;My roommate&#34;</span><span class="p">,</span> <span class="s2">&#34;is a Philistine&#34;</span><span class="p">,</span> <span class="s2">&#34;and a boor&#34;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s2">&#34;My roommate&#34;</span><span class="p">,</span> <span class="s2">&#34;ate the last&#34;</span><span class="p">,</span> <span class="s2">&#34;of the&#34;</span><span class="p">,</span> <span class="s2">&#34;cold cereal&#34;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s2">&#34;I am really&#34;</span><span class="p">,</span> <span class="s2">&#34;really hungy&#34;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s2">&#34;I&#39;m annoyed&#34;</span><span class="p">,</span> <span class="s2">&#34;at my roommate&#34;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Draw circles with text in the center</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">center</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">centers</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">center</span>
</span></span><span class="line"><span class="cl">    <span class="n">theta</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="o">+</span> <span class="n">radii</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="n">y</span> <span class="o">+</span> <span class="n">radii</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="s2">&#34;midnightblue&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">y</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">texts</span><span class="p">[</span><span class="n">i</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">horizontalalignment</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">verticalalignment</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="s2">&#34;midnightblue&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Draw arrows connecting them</span>
</span></span><span class="line"><span class="cl"><span class="c1"># https://e2eml.school/matplotlib_text.html#annotate</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">centers</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">radii</span><span class="p">,</span> <span class="n">centers</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">centers</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">radii</span><span class="p">,</span> <span class="n">centers</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">arrowstyle</span><span class="o">=</span><span class="s2">&#34;-|&gt;&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">centers</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">radii</span><span class="p">,</span> <span class="n">centers</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">1</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">centers</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">radii</span><span class="p">,</span> <span class="n">centers</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">arrowstyle</span><span class="o">=</span><span class="s2">&#34;-|&gt;&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">centers</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">radii</span><span class="p">,</span> <span class="n">centers</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">radii</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">centers</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">radii</span><span class="p">,</span> <span class="n">centers</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">radii</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">arrowstyle</span><span class="o">=</span><span class="s2">&#34;-|&gt;&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">centers</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">radii</span><span class="p">,</span> <span class="n">centers</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">radii</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">centers</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">radii</span><span class="p">,</span> <span class="n">centers</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">radii</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">arrowprops</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">arrowstyle</span><span class="o">=</span><span class="s2">&#34;-|&gt;&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s2">&#34;causal.png&#34;</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">300</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/mpl-for-making-diagrams/causal.png" alt="A joke flow chart. The top level goes from left to right, and then both left and right edges lead to the bottom level. The top level is: 1. My roommate is a Philistine and a boor. 2. My roommate ate the last of the cold cereal. 3. I am really really hungry. The bottom level is: I’m annoyed at my roommate."></p>
<p>Once you get started on this path, you can start making
extravagantly annotated plots. It can elevate your data
presentations to true storytelling.</p>
<p>Happy diagram building!</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Create Ridgeplots in Matplotlib]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/create-ridgeplots-in-matplotlib/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/create-a-tesla-cybertruck-that-drives/?utm_source=atom_feed" rel="related" type="text/html" title="Create a Tesla Cybertruck That Drives" />
                <link href="https://blog.scientific-python.org/matplotlib/an-inquiry-into-matplotlib-figures/?utm_source=atom_feed" rel="related" type="text/html" title="An Inquiry Into Matplotlib&#39;s Figures" />
                <link href="https://blog.scientific-python.org/matplotlib/custom-3d-engine/?utm_source=atom_feed" rel="related" type="text/html" title="Custom 3D engine in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/warming-stripes/?utm_source=atom_feed" rel="related" type="text/html" title="Creating the Warming Stripes in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/matplotlib-in-data-driven-seo/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib in Data Driven SEO" />
            
                <id>https://blog.scientific-python.org/matplotlib/create-ridgeplots-in-matplotlib/</id>
            
            
            <published>2020-02-15T09:50:16+01:00</published>
            <updated>2020-02-15T09:50:16+01:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>This post details how to leverage gridspec to create ridgeplots in Matplotlib</blockquote><h1 id="introduction">Introduction<a class="headerlink" href="#introduction" title="Link to this heading">#</a></h1>
<p>This post will outline how we can leverage <a href="https://matplotlib.org/3.1.3/api/_as_gen/matplotlib.gridspec.GridSpec.html">gridspec</a> to create ridgeplots in Matplotlib. While this is a relatively straightforward tutorial, some experience working with sklearn would be beneficial. Naturally it being a <em>vast</em> undertaking, this will not be an sklearn tutorial, those interested can read through the docs <a href="https://scikit-learn.org/stable/user_guide.html">here</a>. However, I will use its <code>KernelDensity</code> module from <code>sklearn.neighbors</code>.</p>
<!--
# Contents
  - [Packages](#packages)
  - [Data](#data)
  - [GridSpec](gs1)
  - [Kernel Density Estimation](#kde)
  - [Overlapping Axes Objects](#gs2)
  - [Complete Snippet](#snippet)
 -->
<h3 id="packages">Packages <a id="packages"></a><a class="headerlink" href="#packages" title="Link to this heading">#</a></h3>

<div class="highlight">
  <pre>import pandas as pd
import numpy as np
from sklearn.neighbors import KernelDensity

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.gridspec as grid_spec</pre>
</div>

<h3 id="data">Data <a id="data"></a><a class="headerlink" href="#data" title="Link to this heading">#</a></h3>
<p>I&rsquo;ll be using some mock data I created. You can grab the dataset from GitHub <a href="https://github.com/petermckeever/mock-data/blob/master/datasets/mock-european-test-results.csv">here</a> if you want to play along. The data looks at aptitude test scores broken down by country, age, and sex.</p>

<div class="highlight">
  <pre>data = pd.read_csv(&#34;mock-european-test-results.csv&#34;)</pre>
</div>

<table>
  <thead>
      <tr>
          <th>country</th>
          <th>age</th>
          <th>sex</th>
          <th>score</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Italy</td>
          <td>21</td>
          <td>female</td>
          <td>0.77</td>
      </tr>
      <tr>
          <td>Spain</td>
          <td>20</td>
          <td>female</td>
          <td>0.87</td>
      </tr>
      <tr>
          <td>Italy</td>
          <td>24</td>
          <td>female</td>
          <td>0.39</td>
      </tr>
      <tr>
          <td>United Kingdom</td>
          <td>20</td>
          <td>female</td>
          <td>0.70</td>
      </tr>
      <tr>
          <td>Germany</td>
          <td>20</td>
          <td>male</td>
          <td>0.25</td>
      </tr>
      <tr>
          <td>&hellip;</td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
  </tbody>
</table>
<h3 id="gridspec">GridSpec <a id="gs1"></a><a class="headerlink" href="#gridspec" title="Link to this heading">#</a></h3>
<p>GridSpec is a Matplotlib module that allows us easy creation of subplots. We can control the number of subplots, the positions, the height, width, and spacing between each. As a basic example, let&rsquo;s create a quick template. The key parameters we&rsquo;ll be focusing on are <code>nrows</code>, <code>ncols</code>, and <code>width_ratios</code>.</p>
<p><code>nrows</code>and <code>ncols</code> divide our figure into areas we can add axes to. <code>width_ratios</code>controls the width of each of our columns. If we create something like <code>GridSpec(2,2,width_ratios=[2,1])</code>, we are subsetting our figure into 2 rows, 2 columns, and setting our width ratio to 2:1, i.e., that the first column will take up two times the width of the figure.</p>
<p>What&rsquo;s great about GridSpec is that now we have created those subsets, we are not <em>bound</em> to them, as we will see below.</p>
<p><strong>Note</strong>: I am using my own theme, so plots will look different. Creating custom themes is outside the scope of this tutorial (but I may write one in the future).</p>

<div class="highlight">
  <pre>gs = (grid_spec.GridSpec(2,2,width_ratios=[2,1]))

fig = plt.figure(figsize=(8,6))

ax = fig.add_subplot(gs[0:1,0])
ax1 = fig.add_subplot(gs[1:,0])
ax2 = fig.add_subplot(gs[0:,1:])

ax_objs = [ax,ax1,ax2]
n = [&#34;&#34;,1,2]

i = 0
for ax_obj in ax_objs:
    ax_obj.text(0.5,0.5,&#34;ax{}&#34;.format(n[i]),
                ha=&#34;center&#34;,color=&#34;red&#34;,
                fontweight=&#34;bold&#34;,size=20)
    i &#43;= 1

plt.show()</pre>
</div>

<p><img src="/matplotlib/create-ridgeplots-in-matplotlib/basic_template.png" alt="This is a chart with 3 subplot labeled ax, ax1, and ax2. It was created using GridSpec."></p>
<p>I won&rsquo;t get into more detail about what everything does here. If you are interested in learning more about figures, axes, and gridspec, Akash Palrecha has <a href="../an-inquiry-into-matplotlib-figures/">written a very nice guide here</a>.</p>
<h3 id="kernel-density-estimation">Kernel Density Estimation <a id="kde"></a><a class="headerlink" href="#kernel-density-estimation" title="Link to this heading">#</a></h3>
<p>We have a couple of options here. The easiest by far is to stick with the pipes built into pandas. All that&rsquo;s needed is to select the column and add <code>plot.kde</code>. This defaults to a Scott bandwidth method, but you can choose a Silverman method, or add your own. Let&rsquo;s use GridSpec again to plot the distribution for each country. First we&rsquo;ll grab the unique country names and create a list of colors.</p>

<div class="highlight">
  <pre>countries = [x for x in np.unique(data.country)]
colors = [&#39;#0000ff&#39;, &#39;#3300cc&#39;, &#39;#660099&#39;, &#39;#990066&#39;, &#39;#cc0033&#39;, &#39;#ff0000&#39;]</pre>
</div>

<p>Next we&rsquo;ll loop through each country and color to plot our data. Unlike the above we will not explicitly declare how many rows we want to plot. The reason for this is to make our code more dynamic. If we set a specific number of rows and specific number of axes objects, we&rsquo;re creating inefficient code. This is a bit of an aside, but when creating visualizations, you should always aim to reduce and reuse. By reduce, we specifically mean lessening the number of variables we are declaring and the unnecessary code associated with that. We are plotting data for six countries, what happens if we get data for 20 countries? That&rsquo;s a lot of additional code. Related, by not explicitly declaring those variables we make our code adaptable and ready to be scripted to automatically create new plots when new data of the same kind becomes available.</p>

<div class="highlight">
  <pre>gs = (grid_spec.GridSpec(len(countries),1))

fig = plt.figure(figsize=(8,6))

i = 0

#creating empty list
ax_objs = []

for country in countries:
    # creating new axes object and appending to ax_objs
    ax_objs.append(fig.add_subplot(gs[i:i&#43;1, 0:]))

    # plotting the distribution
    plot = (data[data.country == country]
            .score.plot.kde(ax=ax_objs[-1],color=&#34;#f0f0f0&#34;, lw=0.5)
           )

    # grabbing x and y data from the kde plot
    x = plot.get_children()[0]._x
    y = plot.get_children()[0]._y

    # filling the space beneath the distribution
    ax_objs[-1].fill_between(x,y,color=colors[i])

    # setting uniform x and y lims
    ax_objs[-1].set_xlim(0, 1)
    ax_objs[-1].set_ylim(0,2.2)

    i &#43;= 1

plt.tight_layout()
plt.show()</pre>
</div>

<p><img src="/matplotlib/create-ridgeplots-in-matplotlib/grid_spec_distro.png" alt="6 kernel density estimate (KDE) charts, each with different shades ranging from blue to blood red."></p>
<p>We&rsquo;re not quite at ridge plots yet, but let&rsquo;s look at what&rsquo;s going on here. You&rsquo;ll notice instead of setting an explicit number of rows, we&rsquo;ve set it to the length of our countries list - <code>gs = (grid_spec.GridSpec(len(countries),1))</code>. This gives us flexibility for future plotting with the ability to plot more or less countries without needing to adjust the code.</p>
<p>Just after the for loop we create each axes object: <code>ax_objs.append(fig.add_subplot(gs[i:i+1, 0:]))</code>. Before the loop we declared <code>i = 0</code>. Here we are saying create axes object from row 0 to 1, the next time the loop runs it creates an axes object from row 1 to 2, then 2 to 3, 3 to 4, and so on.</p>
<p>Following this we can use <code>ax_objs[-1]</code> to access the last created axes object to use as our plotting area.</p>
<p>Next, we create the kde plot. We declare this as a variable so we can retrieve the x and y values to use in the <code>fill_between</code> that follows.</p>
<h3 id="overlapping-axes-objects">Overlapping Axes Objects <a id="gs2"></a><a class="headerlink" href="#overlapping-axes-objects" title="Link to this heading">#</a></h3>
<p>Once again using GridSpec, we can adjust the spacing between each of the subplots. We can do this by adding one line outside of the loop before <code>plt.tight_layout()</code>The exact value will depend on your distribution so feel free to play around with the exact value:</p>

<div class="highlight">
  <pre>gs.update(hspace= -0.5)</pre>
</div>

<p><img src="/matplotlib/create-ridgeplots-in-matplotlib/grid_spec_distro_overlap_1.png" alt="6 kernel density estimate (KDE) charts, each with different shades ranging from blue to blood red. However, the y axis object are overlapping."></p>
<p>Now our axes objects are overlapping! Great-ish. Each axes object is hiding the one layered below it. We <em>could</em> just add <code>ax_objs[-1].axis(&quot;off&quot;)</code> to our for loop, but if we do that we will lose our xticklabels. Instead we will create a variable to access the background of each axes object, and we will loop through each line of the border (spine) to turn them off. As we <em>only</em> need the xticklabels for the final plot, we will add an if statement to handle that. We will also add in our country labels here. In our for loop we add:</p>

<div class="highlight">
  <pre># make background transparent
rect = ax_objs[-1].patch
rect.set_alpha(0)

# remove borders, axis ticks, and labels
ax_objs[-1].set_yticklabels([])
ax_objs[-1].set_ylabel(&#39;&#39;)

if i == len(countries)-1:
    pass
else:
    ax_objs[-1].set_xticklabels([])

spines = [&#34;top&#34;,&#34;right&#34;,&#34;left&#34;,&#34;bottom&#34;]
for s in spines:
    ax_objs[-1].spines[s].set_visible(False)

country = country.replace(&#34; &#34;,&#34;\n&#34;)
ax_objs[-1].text(-0.02,0,country,fontweight=&#34;bold&#34;,fontsize=14,ha=&#34;center&#34;)</pre>
</div>

<p><img src="/matplotlib/create-ridgeplots-in-matplotlib/grid_spec_distro_overlap_2.png" alt="6 kernel density estimate (KDE) charts each representing 6 countries. France is blue, Germany is dark blue, Ireland is purple, Italy is a lighter shade of purple, Spain is red, and the United Kingdom is blood red.  The x-axis shows the distribution of children in each county listed."></p>
<p>As an alternative to the above, we can use the <code>KernelDensity</code> module from <code>sklearn.neighbors</code> to create our distribution. This gives us a bit more control over our bandwidth. The method here is taken from Jake VanderPlas&rsquo;s fantastic <em>Python Data Science Handbook</em>, you can read his full excerpt <a href="https://jakevdp.github.io/PythonDataScienceHandbook/05.13-kernel-density-estimation.html">here</a>. We can reuse most of the above code, but need to make a couple of changes. Rather than repeat myself, I&rsquo;ll add the full snippet here and you can see the changes and minor additions (added title, label to xaxis).</p>
<h3 id="complete-plot-snippet">Complete Plot Snippet <a id="snippet"></a><a class="headerlink" href="#complete-plot-snippet" title="Link to this heading">#</a></h3>

<div class="highlight">
  <pre>countries = [x for x in np.unique(data.country)]
colors = [&#39;#0000ff&#39;, &#39;#3300cc&#39;, &#39;#660099&#39;, &#39;#990066&#39;, &#39;#cc0033&#39;, &#39;#ff0000&#39;]

gs = grid_spec.GridSpec(len(countries),1)
fig = plt.figure(figsize=(16,9))

i = 0

ax_objs = []
for country in countries:
    country = countries[i]
    x = np.array(data[data.country == country].score)
    x_d = np.linspace(0,1, 1000)

    kde = KernelDensity(bandwidth=0.03, kernel=&#39;gaussian&#39;)
    kde.fit(x[:, None])

    logprob = kde.score_samples(x_d[:, None])

    # creating new axes object
    ax_objs.append(fig.add_subplot(gs[i:i&#43;1, 0:]))

    # plotting the distribution
    ax_objs[-1].plot(x_d, np.exp(logprob),color=&#34;#f0f0f0&#34;,lw=1)
    ax_objs[-1].fill_between(x_d, np.exp(logprob), alpha=1,color=colors[i])


    # setting uniform x and y lims
    ax_objs[-1].set_xlim(0,1)
    ax_objs[-1].set_ylim(0,2.5)

    # make background transparent
    rect = ax_objs[-1].patch
    rect.set_alpha(0)

    # remove borders, axis ticks, and labels
    ax_objs[-1].set_yticklabels([])

    if i == len(countries)-1:
        ax_objs[-1].set_xlabel(&#34;Test Score&#34;, fontsize=16,fontweight=&#34;bold&#34;)
    else:
        ax_objs[-1].set_xticklabels([])

    spines = [&#34;top&#34;,&#34;right&#34;,&#34;left&#34;,&#34;bottom&#34;]
    for s in spines:
        ax_objs[-1].spines[s].set_visible(False)

    adj_country = country.replace(&#34; &#34;,&#34;\n&#34;)
    ax_objs[-1].text(-0.02,0,adj_country,fontweight=&#34;bold&#34;,fontsize=14,ha=&#34;right&#34;)


    i &#43;= 1

gs.update(hspace=-0.7)

fig.text(0.07,0.85,&#34;Distribution of Aptitude Test Results from 18 – 24 year-olds&#34;,fontsize=20)

plt.tight_layout()
plt.show()</pre>
</div>

<p><img src="/matplotlib/create-ridgeplots-in-matplotlib/grid_spec_distro_overlap_3.png" alt="6 kernel density estimate (KDE) charts each representing 6 countries. France is blue, Germany is dark blue, Ireland is purple, Italy is a lighter shade of purple, Spain is red, and the United Kingdom is blood red.  The x-axis shows the distribution of aptitude test results from 18 to 24 years old in each county listed."></p>
<p>I&rsquo;ll finish this off with a little project to put the above code into practice. The data provided also contains information on whether the test taker was male or female. Using the above code as a template, see how you get on creating something like this:</p>
<p><img src="/matplotlib/create-ridgeplots-in-matplotlib/split_ridges.png" alt="Each of two sets of six kernel density estimate (KDE) charts shows six different countries. France is blue, Germany is dark blue, Ireland is purple, Italy is a lighter shade of purple, Spain is red, and the United Kingdom is blood red. The x-axis displays the distribution of 18 to 24 year olds’ aptitude test scores in each county presented. The distribution of the results of the aptitude test among boys aged 18 to 24 in each county is shown on one of the two 6-kennel charts, while the distribution of females is shown on the other."></p>
<p>For those more ambitious, this could be turned into a split violin plot with males on one side and females on the other. Is there a way to combine the ridge and violin plot?</p>
<p>I&rsquo;d love to see what people come back with so if you do create something, send it to me on twitter <a href="http://twitter.com/petermckeever">here</a>!</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Create a Tesla Cybertruck That Drives]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/create-a-tesla-cybertruck-that-drives/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/an-inquiry-into-matplotlib-figures/?utm_source=atom_feed" rel="related" type="text/html" title="An Inquiry Into Matplotlib&#39;s Figures" />
                <link href="https://blog.scientific-python.org/matplotlib/custom-3d-engine/?utm_source=atom_feed" rel="related" type="text/html" title="Custom 3D engine in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/warming-stripes/?utm_source=atom_feed" rel="related" type="text/html" title="Creating the Warming Stripes in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/matplotlib-in-data-driven-seo/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib in Data Driven SEO" />
                <link href="https://blog.scientific-python.org/matplotlib/using-matplotlib-to-advocate-for-postdocs/?utm_source=atom_feed" rel="related" type="text/html" title="Using Matplotlib to Advocate for Postdocs" />
            
                <id>https://blog.scientific-python.org/matplotlib/create-a-tesla-cybertruck-that-drives/</id>
            
            
            <published>2020-01-12T13:35:34-05:00</published>
            <updated>2020-01-12T13:35:34-05:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Learn how to create a Tesla Cybertruck with Matplotlib that drives via animation.</blockquote><p>My name is <a href="https://wwww.twitter.com/tedpetrou">Ted Petrou</a>, founder of <a href="https://www.dunderdata.com">Dunder Data</a>, and in this tutorial you will learn how to create the new <a href="https://www.tesla.com/cybertruck">Tesla Cybertruck</a> using Matplotlib. I was inspired by the image below which was originally created by <a href="https://twitter.com/lynnandtonic/status/1197989912970067969?lang=en">Lynn Fisher</a> (without Matplotlib).</p>
<p>Before going into detail, let&rsquo;s jump to the results. Here is the completed recreation of the Tesla Cybertruck that drives off the screen.</p>
<video width="700" height="500" controls>
  <source src="tesla_animate.mp4" type="video/mp4">
</video>
<h2 id="tutorial">Tutorial<a class="headerlink" href="#tutorial" title="Link to this heading">#</a></h2>
<p>A tutorial now follows containing all the steps that creates a Tesla Cybertruck that drives. It covers the following topics:</p>
<ul>
<li>Figure and Axes setup</li>
<li>Adding shapes</li>
<li>Color gradients</li>
<li>Animation</li>
</ul>
<p>Understanding these topics should give you enough to start animating your own figures in Matplotlib. This tutorial is not suited for those with no Matplotlib experience. You need to understand the relationship between the Figure and Axes and how to use the object-oriented interface of Matplotlib.</p>
<h3 id="figure-and-axes-setup">Figure and Axes setup<a class="headerlink" href="#figure-and-axes-setup" title="Link to this heading">#</a></h3>
<p>We first create a Matplotlib Figure without any Axes (the plotting surface). The function <code>create_axes</code> adds an Axes to the Figure, sets the x-limits to be twice the y-limits (to match the ratio of the figure dimensions (16 x 8)), fills in the background with two different dark colors using <code>fill_between</code>, and adds grid lines to make it easier to plot the objects in the exact place you desire. Set the <code>draft</code> parameter to <code>False</code> when you want to remove the grid lines, tick marks, and tick labels.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">Figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="mi">8</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">create_axes</span><span class="p">(</span><span class="n">draft</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">fill_between</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="n">y1</span><span class="o">=</span><span class="mf">0.36</span><span class="p">,</span> <span class="n">y2</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">fill_between</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="n">y1</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">y2</span><span class="o">=</span><span class="mf">0.36</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#101115&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">draft</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">grid</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s2">&#34;off&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">create_axes</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/create-a-tesla-cybertruck-that-drives/output_4_0.png" alt="png"></p>
<h3 id="shapes-in-matplotlib">Shapes in Matplotlib<a class="headerlink" href="#shapes-in-matplotlib" title="Link to this heading">#</a></h3>
<p>Most of the Cybertruck is composed of shapes (patches in Matplotlib terminology) - circles, rectangles, and polygons. These shapes are available in the patches Matplotlib module. After importing, we instantiate single instances of these patches and then call the <code>add_patch</code> method to add the patch to the Axes.</p>
<p>For the Cybertruck, I used three patches, <code>Polygon</code>, <code>Rectangle</code>, and <code>Circle</code>. They each have different parameters available in their constructor. I first constructed the body of the car as four polygons. Two other polygons were used for the rims. Each polygon is provided a list of x, y coordinates where the corner points are located. Matplotlib connects all the points in the order given and fills it in with the provided color.</p>
<p>Notice how the Axes is retrieved as the first line of the function. This is used throughout the tutorial.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib.patches</span> <span class="kn">import</span> <span class="n">Polygon</span><span class="p">,</span> <span class="n">Rectangle</span><span class="p">,</span> <span class="n">Circle</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">create_body</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">axes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">top</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">([[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">0.66</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.6</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">]],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#DCDCDC&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">windows</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[[</span><span class="mf">0.74</span><span class="p">,</span> <span class="mf">0.54</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">0.64</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.26</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.262</span><span class="p">,</span> <span class="mf">0.57</span><span class="p">]],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">windows_bottom</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[[</span><span class="mf">0.8</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">0.635</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.255</span><span class="p">,</span> <span class="mf">0.597</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.255</span><span class="p">,</span> <span class="mf">0.585</span><span class="p">]],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#474747&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">base</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.445</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.67</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.78</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.84</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.3</span><span class="p">,</span> <span class="mf">0.423</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.36</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.44</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.52</span><span class="p">,</span> <span class="mf">0.43</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.58</span><span class="p">,</span> <span class="mf">0.44</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.6</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#1E2329&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">left_rim</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.445</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.67</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.78</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.84</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.824</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.77</span><span class="p">,</span> <span class="mf">0.49</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.674</span><span class="p">,</span> <span class="mf">0.49</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">0.633</span><span class="p">,</span> <span class="mf">0.445</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#373E48&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">right_rim</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.3</span><span class="p">,</span> <span class="mf">0.423</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.36</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.44</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.52</span><span class="p">,</span> <span class="mf">0.43</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.504</span><span class="p">,</span> <span class="mf">0.43</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.436</span><span class="p">,</span> <span class="mf">0.498</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.364</span><span class="p">,</span> <span class="mf">0.498</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="mf">1.312</span><span class="p">,</span> <span class="mf">0.423</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#4D586A&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">top</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">windows</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">windows_bottom</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">base</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">left_rim</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">right_rim</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">create_body</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/create-a-tesla-cybertruck-that-drives/output_6_0.png" alt="png"></p>
<h4 id="tires">Tires<a class="headerlink" href="#tires" title="Link to this heading">#</a></h4>
<p>I used three <code>Circle</code> patches for each of the tires. You must provide the center and radius. For the innermost circles (the &ldquo;spokes&rdquo;), I&rsquo;ve set the <code>zorder</code> to 99. The <code>zorder</code> determines the order of how plotting objects are layered on top of each other. The higher the number, the higher up on the stack of layers the object will be plotted. During the next step, we will draw some rectangles through the tires and they need to be plotted underneath these spokes.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">create_tires</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">axes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">left_tire</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">0.724</span><span class="p">,</span> <span class="mf">0.39</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.075</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#202328&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">right_tire</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">1.404</span><span class="p">,</span> <span class="mf">0.39</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.075</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#202328&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">left_inner_tire</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">0.724</span><span class="p">,</span> <span class="mf">0.39</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.052</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#15191C&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">right_inner_tire</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">1.404</span><span class="p">,</span> <span class="mf">0.39</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.052</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#15191C&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">left_spoke</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">0.724</span><span class="p">,</span> <span class="mf">0.39</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.019</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#202328&#34;</span><span class="p">,</span> <span class="n">zorder</span><span class="o">=</span><span class="mi">99</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">right_spoke</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">1.404</span><span class="p">,</span> <span class="mf">0.39</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.019</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#202328&#34;</span><span class="p">,</span> <span class="n">zorder</span><span class="o">=</span><span class="mi">99</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">left_inner_spoke</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">0.724</span><span class="p">,</span> <span class="mf">0.39</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.011</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#131418&#34;</span><span class="p">,</span> <span class="n">zorder</span><span class="o">=</span><span class="mi">99</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">right_inner_spoke</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">1.404</span><span class="p">,</span> <span class="mf">0.39</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.011</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#131418&#34;</span><span class="p">,</span> <span class="n">zorder</span><span class="o">=</span><span class="mi">99</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">left_tire</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">right_tire</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">left_inner_tire</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">right_inner_tire</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">left_spoke</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">right_spoke</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">left_inner_spoke</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">right_inner_spoke</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">create_tires</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/create-a-tesla-cybertruck-that-drives/output_8_0.png" alt="png"></p>
<h4 id="axles">Axles<a class="headerlink" href="#axles" title="Link to this heading">#</a></h4>
<p>I used the <code>Rectangle</code> patch to represent the two &lsquo;axles&rsquo; (this isn&rsquo;t the correct term, but you&rsquo;ll see what I mean) going through the tires. You must provide a coordinate for the lower left corner, a width, and a height. You can also provide it an angle (in degrees) to control its orientation. Notice that they go under the spokes plotted from above. This is due to their lower <code>zorder</code>.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">create_axles</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">axes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">left_left_axle</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="mf">0.687</span><span class="p">,</span> <span class="mf">0.427</span><span class="p">),</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.104</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="mf">0.005</span><span class="p">,</span> <span class="n">angle</span><span class="o">=</span><span class="mi">315</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#202328&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">left_right_axle</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="mf">0.761</span><span class="p">,</span> <span class="mf">0.427</span><span class="p">),</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.104</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="mf">0.005</span><span class="p">,</span> <span class="n">angle</span><span class="o">=</span><span class="mi">225</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#202328&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">right_left_axle</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="mf">1.367</span><span class="p">,</span> <span class="mf">0.427</span><span class="p">),</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.104</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="mf">0.005</span><span class="p">,</span> <span class="n">angle</span><span class="o">=</span><span class="mi">315</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#202328&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">right_right_axle</span> <span class="o">=</span> <span class="n">Rectangle</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="mf">1.441</span><span class="p">,</span> <span class="mf">0.427</span><span class="p">),</span> <span class="n">width</span><span class="o">=</span><span class="mf">0.104</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="mf">0.005</span><span class="p">,</span> <span class="n">angle</span><span class="o">=</span><span class="mi">225</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#202328&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">left_left_axle</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">left_right_axle</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">right_left_axle</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">right_right_axle</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">create_axles</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/create-a-tesla-cybertruck-that-drives/output_10_0.png" alt="png"></p>
<h4 id="other-details">Other details<a class="headerlink" href="#other-details" title="Link to this heading">#</a></h4>
<p>The front bumper, head light, tail light, door and window lines are added below. I used regular Matplotlib lines for some of these. Those lines are not patches and get added directly to the Axes without any other additional method.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">create_other_details</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">axes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># other details</span>
</span></span><span class="line"><span class="cl">    <span class="n">front</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.597</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.589</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.589</span><span class="p">,</span> <span class="mf">0.445</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.445</span><span class="p">]],</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#26272d&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">front_bottom</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.438</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.58</span><span class="p">,</span> <span class="mf">0.438</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.58</span><span class="p">,</span> <span class="mf">0.423</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.423</span><span class="p">]],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#26272d&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">head_light</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.597</span><span class="p">,</span> <span class="mf">0.51</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.589</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.589</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.62</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">]],</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span><span class="o">=</span><span class="s2">&#34;aqua&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">step</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[[</span><span class="mf">0.84</span><span class="p">,</span> <span class="mf">0.39</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.84</span><span class="p">,</span> <span class="mf">0.394</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.3</span><span class="p">,</span> <span class="mf">0.397</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.3</span><span class="p">,</span> <span class="mf">0.393</span><span class="p">]],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;#1E2329&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># doors</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mf">0.84</span><span class="p">,</span> <span class="mf">0.84</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.42</span><span class="p">,</span> <span class="mf">0.523</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mf">1.02</span><span class="p">,</span> <span class="mf">1.04</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.42</span><span class="p">,</span> <span class="mf">0.53</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mf">1.26</span><span class="p">,</span> <span class="mf">1.26</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.42</span><span class="p">,</span> <span class="mf">0.54</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mf">0.84</span><span class="p">,</span> <span class="mf">0.85</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.523</span><span class="p">,</span> <span class="mf">0.547</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mf">1.04</span><span class="p">,</span> <span class="mf">1.04</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.53</span><span class="p">,</span> <span class="mf">0.557</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mf">1.26</span><span class="p">,</span> <span class="mf">1.26</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.54</span><span class="p">,</span> <span class="mf">0.57</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># window lines</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mf">0.87</span><span class="p">,</span> <span class="mf">0.88</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.56</span><span class="p">,</span> <span class="mf">0.59</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">([</span><span class="mf">1.03</span><span class="p">,</span> <span class="mf">1.04</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.56</span><span class="p">,</span> <span class="mf">0.63</span><span class="p">],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;black&#34;</span><span class="p">,</span> <span class="n">lw</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># tail light</span>
</span></span><span class="line"><span class="cl">    <span class="n">tail_light</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">1.6</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.007</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;red&#34;</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.6</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tail_light_center</span> <span class="o">=</span> <span class="n">Circle</span><span class="p">((</span><span class="mf">1.6</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">),</span> <span class="n">radius</span><span class="o">=</span><span class="mf">0.003</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;yellow&#34;</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.6</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tail_light_up</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[[</span><span class="mf">1.597</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.6</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.603</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">]],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;red&#34;</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.4</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tail_light_right</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[[</span><span class="mf">1.6</span><span class="p">,</span> <span class="mf">0.563</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.64</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.6</span><span class="p">,</span> <span class="mf">0.557</span><span class="p">]],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;red&#34;</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.4</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tail_light_down</span> <span class="o">=</span> <span class="n">Polygon</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[[</span><span class="mf">1.597</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.6</span><span class="p">,</span> <span class="mf">0.52</span><span class="p">],</span> <span class="p">[</span><span class="mf">1.603</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">]],</span> <span class="n">color</span><span class="o">=</span><span class="s2">&#34;red&#34;</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.4</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">front</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">front_bottom</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">head_light</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">step</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">tail_light</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">tail_light_center</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">tail_light_up</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">tail_light_right</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">add_patch</span><span class="p">(</span><span class="n">tail_light_down</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">create_other_details</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/create-a-tesla-cybertruck-that-drives/output_12_0.png" alt="png"></p>
<h4 id="color-gradients-for-the-head-light-beam">Color gradients for the head light beam<a class="headerlink" href="#color-gradients-for-the-head-light-beam" title="Link to this heading">#</a></h4>
<p>The head light beam has a distinct color gradient that dissipates into the night sky. This is challenging to complete. I found an <a href="https://wwww.twitter.com/tedpetrou">excellent answer on Stack Overflow from user Joe Kington</a> on how to do this. We begin by using the <code>imshow</code> function which creates images from 3-dimensional arrays. Our image will simply be a rectangle of colors.</p>
<p>We create a 1 x 100 x 4 array that represents 1 row by 100 columns of points of RGBA (red, green, blue, alpha) values. Every point is given the same red, green, and blue values of (0, 1, 1) which represents the color &lsquo;aqua&rsquo;. The alpha value represents opacity and ranges between 0 and 1 with 0 being completely transparent (invisible) and 1 being opaque. We would like the opacity to decrease as the light extends further from the head light (that is further to the left). The NumPy <code>linspace</code> function is used to create an array of 100 numbers increasing linearly from 0 to 1. This array will be set as the alpha values.</p>
<p>The <code>extent</code> parameter defines the rectangular region where the image will be shown. The four values correspond to xmin, xmax, ymin, and ymax. The 100 alpha values will be mapped to this region beginning from the left. The array of alphas begins at 0, which means that the very left of this rectangular region will be transparent. The opacity will increase moving to the right-side of the rectangle where it eventually reaches 1.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.colors</span> <span class="k">as</span> <span class="nn">mcolors</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">create_headlight_beam</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">axes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">empty</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">float</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">rgb</span> <span class="o">=</span> <span class="n">mcolors</span><span class="o">.</span><span class="n">colorConverter</span><span class="o">.</span><span class="n">to_rgb</span><span class="p">(</span><span class="s2">&#34;aqua&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">alphas</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span><span class="p">[:,</span> <span class="p">:,</span> <span class="p">:</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">rgb</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span><span class="p">[:,</span> <span class="p">:,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">alphas</span>
</span></span><span class="line"><span class="cl">    <span class="n">im</span> <span class="o">=</span> <span class="n">ax</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">z</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.589</span><span class="p">,</span> <span class="mf">0.501</span><span class="p">,</span> <span class="mf">0.505</span><span class="p">],</span> <span class="n">zorder</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">create_headlight_beam</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/create-a-tesla-cybertruck-that-drives/output_14_0.png" alt="png"></p>
<h4 id="headlight-cloud">Headlight Cloud<a class="headerlink" href="#headlight-cloud" title="Link to this heading">#</a></h4>
<p>The cloud of points surrounding the headlight beam is even more challenging to complete. This time, a 100 x 100 grid of points was used to control the opacity. The opacity is directly proportional to the vertical distance from the center beam. Additionally, if a point was outside of the diagonal of the rectangle defined by <code>extent</code>, its opacity was set to 0.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">create_headlight_cloud</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">axes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">z2</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">empty</span><span class="p">((</span><span class="mi">100</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">float</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">rgb</span> <span class="o">=</span> <span class="n">mcolors</span><span class="o">.</span><span class="n">colorConverter</span><span class="o">.</span><span class="n">to_rgb</span><span class="p">(</span><span class="s2">&#34;aqua&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">z2</span><span class="p">[:,</span> <span class="p">:,</span> <span class="p">:</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="n">rgb</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">abs</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mi">100</span><span class="p">))):</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">x</span> <span class="o">*</span> <span class="mf">0.2</span> <span class="o">&gt;</span> <span class="n">y</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">z2</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="p">(</span><span class="n">y</span> <span class="o">+</span> <span class="mf">0.8</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">z2</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="n">im2</span> <span class="o">=</span> <span class="n">ax</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">z2</span><span class="p">,</span> <span class="n">extent</span><span class="o">=</span><span class="p">[</span><span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.65</span><span class="p">,</span> <span class="mf">0.45</span><span class="p">,</span> <span class="mf">0.55</span><span class="p">],</span> <span class="n">zorder</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">create_headlight_cloud</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/create-a-tesla-cybertruck-that-drives/output_16_0.png" alt="png"></p>
<h3 id="creating-a-function-to-draw-the-car">Creating a Function to Draw the Car<a class="headerlink" href="#creating-a-function-to-draw-the-car" title="Link to this heading">#</a></h3>
<p>All of our work from above can be placed in a single function that draws the car. This will be used when initializing our animation. Notice, that the first line of the function clears the Figure, which removes our Axes. If we don&rsquo;t clear the Figure, then we will keep adding more and more Axes each time this function is called. Since this is our final product, we set <code>draft</code> to <code>False</code>.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">draw_car</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_axes</span><span class="p">(</span><span class="n">draft</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_body</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_tires</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_axles</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_other_details</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_headlight_beam</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_headlight_beam</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">draw_car</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/create-a-tesla-cybertruck-that-drives/output_18_0.png" alt="png"></p>
<h2 id="animation">Animation<a class="headerlink" href="#animation" title="Link to this heading">#</a></h2>
<p>Animation in Matplotlib is fairly straightforward. You must create a function that updates the position of the objects in your figure for each frame. This function is called repeatedly for each frame.</p>
<p>In the <code>update</code> function below, we loop through each patch, line, and image in our Axes and reduce the x-value of each plotted object by .015. This has the effect of moving the truck to the left. The trickiest part was changing the x and y values for the rectangular tire &lsquo;axles&rsquo; so that it appeared that the tires were rotating. Some basic trigonometry helps calculate this.</p>
<p>Implicitly, Matplotlib passes the update function the frame number as an integer as the first argument. We accept this input as the parameter <code>frame_number</code>. We only use it in one place, and that is to do nothing during the first frame.</p>
<p>Finally, the <code>FuncAnimation</code> class from the animation module is used to construct the animation. We provide it our original Figure, the function to update the Figure (<code>update</code>), a function to initialize the Figure (<code>draw_car</code>), the total number of frames, and any extra arguments used during update (<code>fargs</code>).</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib.animation</span> <span class="kn">import</span> <span class="n">FuncAnimation</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="n">frame_number</span><span class="p">,</span> <span class="n">x_delta</span><span class="p">,</span> <span class="n">radius</span><span class="p">,</span> <span class="n">angle</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">frame_number</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">axes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">patch</span> <span class="ow">in</span> <span class="n">ax</span><span class="o">.</span><span class="n">patches</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">patch</span><span class="p">,</span> <span class="n">Polygon</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">arr</span> <span class="o">=</span> <span class="n">patch</span><span class="o">.</span><span class="n">get_xy</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="n">arr</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">-=</span> <span class="n">x_delta</span>
</span></span><span class="line"><span class="cl">        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">patch</span><span class="p">,</span> <span class="n">Circle</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">patch</span><span class="o">.</span><span class="n">get_center</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="n">patch</span><span class="o">.</span><span class="n">set_center</span><span class="p">((</span><span class="n">x</span> <span class="o">-</span> <span class="n">x_delta</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">patch</span><span class="p">,</span> <span class="n">Rectangle</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">xd_old</span> <span class="o">=</span> <span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">patch</span><span class="o">.</span><span class="n">angle</span> <span class="o">/</span> <span class="mi">180</span><span class="p">)</span> <span class="o">*</span> <span class="n">radius</span>
</span></span><span class="line"><span class="cl">            <span class="n">yd_old</span> <span class="o">=</span> <span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">patch</span><span class="o">.</span><span class="n">angle</span> <span class="o">/</span> <span class="mi">180</span><span class="p">)</span> <span class="o">*</span> <span class="n">radius</span>
</span></span><span class="line"><span class="cl">            <span class="n">patch</span><span class="o">.</span><span class="n">angle</span> <span class="o">+=</span> <span class="n">angle</span>
</span></span><span class="line"><span class="cl">            <span class="n">xd</span> <span class="o">=</span> <span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">patch</span><span class="o">.</span><span class="n">angle</span> <span class="o">/</span> <span class="mi">180</span><span class="p">)</span> <span class="o">*</span> <span class="n">radius</span>
</span></span><span class="line"><span class="cl">            <span class="n">yd</span> <span class="o">=</span> <span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">pi</span> <span class="o">*</span> <span class="n">patch</span><span class="o">.</span><span class="n">angle</span> <span class="o">/</span> <span class="mi">180</span><span class="p">)</span> <span class="o">*</span> <span class="n">radius</span>
</span></span><span class="line"><span class="cl">            <span class="n">x</span> <span class="o">=</span> <span class="n">patch</span><span class="o">.</span><span class="n">get_x</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="n">y</span> <span class="o">=</span> <span class="n">patch</span><span class="o">.</span><span class="n">get_y</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="n">x_new</span> <span class="o">=</span> <span class="n">x</span> <span class="o">-</span> <span class="n">x_delta</span> <span class="o">+</span> <span class="n">xd</span> <span class="o">-</span> <span class="n">xd_old</span>
</span></span><span class="line"><span class="cl">            <span class="n">y_new</span> <span class="o">=</span> <span class="n">y</span> <span class="o">+</span> <span class="n">yd</span> <span class="o">-</span> <span class="n">yd_old</span>
</span></span><span class="line"><span class="cl">            <span class="n">patch</span><span class="o">.</span><span class="n">set_x</span><span class="p">(</span><span class="n">x_new</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">patch</span><span class="o">.</span><span class="n">set_y</span><span class="p">(</span><span class="n">y_new</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">ax</span><span class="o">.</span><span class="n">lines</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">xdata</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">get_xdata</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">line</span><span class="o">.</span><span class="n">set_xdata</span><span class="p">(</span><span class="n">xdata</span> <span class="o">-</span> <span class="n">x_delta</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">image</span> <span class="ow">in</span> <span class="n">ax</span><span class="o">.</span><span class="n">images</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">extent</span> <span class="o">=</span> <span class="n">image</span><span class="o">.</span><span class="n">get_extent</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">extent</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-=</span> <span class="n">x_delta</span>
</span></span><span class="line"><span class="cl">        <span class="n">extent</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-=</span> <span class="n">x_delta</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">animation</span> <span class="o">=</span> <span class="n">FuncAnimation</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="p">,</span> <span class="n">update</span><span class="p">,</span> <span class="n">init_func</span><span class="o">=</span><span class="n">draw_car</span><span class="p">,</span> <span class="n">frames</span><span class="o">=</span><span class="mi">110</span><span class="p">,</span> <span class="n">repeat</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">fargs</span><span class="o">=</span><span class="p">(</span><span class="mf">0.015</span><span class="p">,</span> <span class="mf">0.052</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre>
</div>
<h3 id="save-animation">Save animation<a class="headerlink" href="#save-animation" title="Link to this heading">#</a></h3>
<p>Finally, we can save the animation as an mp4 file (you must have ffmpeg installed for this to work). We set the frames-per-second (<code>fps</code>) to 30. From above, the total number of frames is 110 (enough to move the truck off the screen) so the video will last nearly four seconds (110 / 30).</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">animation</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s2">&#34;tesla_animate.mp4&#34;</span><span class="p">,</span> <span class="n">fps</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">bitrate</span><span class="o">=</span><span class="mi">3000</span><span class="p">)</span></span></span></code></pre>
</div>
<video width="700" height="500" controls>
  <source src="tesla_animate.mp4" type="video/mp4">
</video>
<h2 id="continue-animating">Continue Animating<a class="headerlink" href="#continue-animating" title="Link to this heading">#</a></h2>
<p>I encourage you to add more components to your Cybertruck animation to personalize the creation. I suggest encapsulating each addition with a function as done in this tutorial.</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[An Inquiry Into Matplotlib's Figures]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/an-inquiry-into-matplotlib-figures/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/custom-3d-engine/?utm_source=atom_feed" rel="related" type="text/html" title="Custom 3D engine in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/warming-stripes/?utm_source=atom_feed" rel="related" type="text/html" title="Creating the Warming Stripes in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/matplotlib-in-data-driven-seo/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib in Data Driven SEO" />
                <link href="https://blog.scientific-python.org/matplotlib/using-matplotlib-to-advocate-for-postdocs/?utm_source=atom_feed" rel="related" type="text/html" title="Using Matplotlib to Advocate for Postdocs" />
            
                <id>https://blog.scientific-python.org/matplotlib/an-inquiry-into-matplotlib-figures/</id>
            
            
            <published>2019-12-24T11:25:42+05:30</published>
            <updated>2019-12-24T11:25:42+05:30</updated>
            
            
            <content type="html"><![CDATA[<blockquote>This guide dives deep into the inner workings of Matplotlib&rsquo;s Figures, Axes, subplots and the very amazing GridSpec!</blockquote><h1 id="preliminaries">Preliminaries<a class="headerlink" href="#preliminaries" title="Link to this heading">#</a></h1>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib</span> <span class="k">as</span> <span class="nn">mpl</span></span></span></code></pre>
</div>
<blockquote>
<p>A Top-Down runnable Jupyter Notebook with the exact contents of this blog can be found <a href="https://gist.github.com/akashpalrecha/4652e98c9b2f3f1961637be001dc0239">here</a></p>
</blockquote>
<blockquote>
<p>An interactive version of this guide can be accessed on <a href="https://colab.research.google.com/drive/1SOgWPI9HckTQ0zm47Ma-gYCTucMccTxg">Google Colab</a></p>
</blockquote>
<h1 id="a-word-before-we-get-started">A word before we get started&hellip;<a class="headerlink" href="#a-word-before-we-get-started" title="Link to this heading">#</a></h1>
<hr>
<p>Although a beginner can follow along with this guide, it is primarily meant for people who have at least a basic knowledge of how Matplotlib&rsquo;s plotting functionality works.</p>
<p>Essentially, if you know how to take 2 NumPy arrays and plot them (using an appropriate type of graph) on 2 different axes in a single figure and give it basic styling, you&rsquo;re good to go for the purposes of this guide.</p>
<p>If you feel you need some introduction to basic Matplotlib plotting, here&rsquo;s a great guide that can help you get a feel for <a href="https://matplotlib.org/devdocs/gallery/subplots_axes_and_figures/subplots_demo.html">introductory plotting using Matplotlib</a></p>
<p>From here on, I will be assuming that you have gained sufficient knowledge to follow along this guide.</p>
<p>Also, in order to save everyone&rsquo;s time, I will keep my explanations short, terse and very much to the point, and sometimes leave it for the reader to interpret things (because that&rsquo;s what I&rsquo;ve done throughout this guide for myself anyway).</p>
<p>The primary driver in this whole exercise will be code and not text, and I encourage you to spin up a Jupyter notebook and type in and try out everything yourself to make the best use of this resource.</p>
<h2 id="what-this-guide-is-and-what-it-is-not">What this guide <em>is</em> and what it is <em>not</em>:<a class="headerlink" href="#what-this-guide-is-and-what-it-is-not" title="Link to this heading">#</a></h2>
<p>This is not a guide about how to beautifully plot different kinds of data using Matplotlib, the internet is more than full of such tutorials by people who can explain it way better than I can.</p>
<p>This article attempts to explain the workings of some of the foundations of any plot you create using Matplotlib.
We will mostly refrain from focusing on what data we are plotting and instead focus on the anatomy of our plots.</p>
<h1 id="setting-up">Setting up<a class="headerlink" href="#setting-up" title="Link to this heading">#</a></h1>
<p>Matplotlib has many styles available, we can see the available options using:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">available</span></span></span></code></pre>
</div>
<pre><code>['seaborn-dark',
 'seaborn-darkgrid',
 'seaborn-ticks',
 'fivethirtyeight',
 'seaborn-whitegrid',
 'classic',
 '_classic_test',
 'fast',
 'seaborn-talk',
 'seaborn-dark-palette',
 'seaborn-bright',
 'seaborn-pastel',
 'grayscale',
 'seaborn-notebook',
 'ggplot',
 'seaborn-colorblind',
 'seaborn-muted',
 'seaborn',
 'Solarize_Light2',
 'seaborn-paper',
 'bmh',
 'tableau-colorblind10',
 'seaborn-white',
 'dark_background',
 'seaborn-poster',
 'seaborn-deep']
</code></pre>
<p>We shall use <code>seaborn</code>. This is done like so:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">&#34;seaborn&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p>Let&rsquo;s get started!</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># Creating some fake data for plotting</span>
</span></span><span class="line"><span class="cl"><span class="n">xs</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span><span class="p">,</span> <span class="mi">400</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ys</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">xs</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">xc</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span><span class="p">,</span> <span class="mi">600</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">yc</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">xc</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span></span></span></code></pre>
</div>
<h1 id="exploration">Exploration<a class="headerlink" href="#exploration" title="Link to this heading">#</a></h1>
<p>The usual way to create a plot using Matplotlib goes somewhat like this:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="mi">8</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># `Fig` is short for Figure. `ax` is short for Axes.</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xc</span><span class="p">,</span> <span class="n">yc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xc</span><span class="p">,</span> <span class="n">yc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s2">&#34;Basic plotting using Matplotlib&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_14_0.png" alt="png"></p>
<p>Our goal today is to take apart the previous snippet of code and understand all of the underlying building blocks well enough so that we can use them separately and in a much more powerful way.</p>
<p>If you&rsquo;re a beginner like I was before writing this guide, let me assure you: this is all very simple stuff.</p>
<p>Going into <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html?highlight=subplots#matplotlib.pyplot.subplots"><code>plt.subplots</code></a> documentation (hit <code>Shift+Tab+Tab</code> in a Jupyter notebook) reveals some of the other Matplotlib internals that it uses in order to give us the <code>Figure</code> and it&rsquo;s <code>Axes</code>.</p>
<p>These include :<br></p>
<ol>
<li><code>plt.subplot</code></li>
<li><code>plt.figure</code></li>
<li><code>mpl.figure.Figure</code></li>
<li><code>mpl.figure.Figure.add_subplot</code></li>
<li><code>mpl.gridspec.GridSpec</code></li>
<li><code>mpl.axes.Axes</code></li>
</ol>
<p>Let&rsquo;s try and figure out what these functions / classes do.</p>
<h1 id="what-is-a-figure-and-what-are-axes">What is a <code>Figure</code>? And what are <code>Axes</code>?<a class="headerlink" href="#what-is-a-figure-and-what-are-axes" title="Link to this heading">#</a></h1>
<p>A <a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.figure.html?highlight=figure#matplotlib.pyplot.figure"><code>Figure</code></a> in Matplotlib is simply your main (imaginary) canvas. This is where you will be doing all your plotting / drawing / putting images and what not. This is the central object with which you will always be interacting. A figure has a size defined for it at the time of creation.</p>
<p>You can define a figure like so (both statements are equivalent):</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">figure</span><span class="o">.</span><span class="n">Figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># OR</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span></span></span></code></pre>
</div>
<p>Notice the word <em>imaginary</em> above. What this means is that a Figure by itself does not have any place for you to plot. You need to attach/add an <a href="https://matplotlib.org/api/axes_api.html?highlight=matplotlib.axes.axes#matplotlib.axes.Axes"><code>Axes</code></a> to it to do any kind of plotting. You can put as many <code>Axes</code> objects as you want inside of any <code>Figure</code> you have created.</p>
<p>An <code>Axes</code>:</p>
<ol>
<li>Has a space (like a blank Page) where you can draw/plot data.</li>
<li>A parent <code>Figure</code></li>
<li>Has properties stating where it will be placed inside it&rsquo;s parent <code>Figure</code>.</li>
<li>Has methods to draw/plot different kinds of data in different ways and add custom styles.</li>
</ol>
<p>You can create an <code>Axes</code> like so (both statements are equivalent):</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">ax1</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">axes</span><span class="o">.</span><span class="n">Axes</span><span class="p">(</span><span class="n">fig</span><span class="o">=</span><span class="n">fig</span><span class="p">,</span> <span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">],</span> <span class="n">facecolor</span><span class="o">=</span><span class="s2">&#34;red&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># OR</span>
</span></span><span class="line"><span class="cl"><span class="n">ax1</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">Axes</span><span class="p">(</span><span class="n">fig</span><span class="o">=</span><span class="n">fig</span><span class="p">,</span> <span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">],</span> <span class="n">facecolor</span><span class="o">=</span><span class="s2">&#34;red&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span></span></span></code></pre>
</div>
<p>The first parameter <code>fig</code> is simply a pointer to the parent <code>Figure</code> to which an Axes will belong.<br>
The second parameter <code>rect</code> has four numbers : <code>[left_position, bottom_position, height, width]</code> to define the position of the <code>Axes</code> inside the <code>Figure</code> and the height and width <em>with respect to the <code>Figure</code></em>. All these numbers are expressed in percentages.</p>
<p>A <code>Figure</code> simply holds a given number of <code>Axes</code> at any point of time</p>
<p>We will go into some of these design decisions in a few moments'</p>
<h1 id="recreating-pltsubplots-with-basic-matplotlib-functionality">Recreating <code>plt.subplots</code> with basic Matplotlib functionality<a class="headerlink" href="#recreating-pltsubplots-with-basic-matplotlib-functionality" title="Link to this heading">#</a></h1>
<p>We will try and recreate the below plot using Matplotlib primitives as a way to understand them better. We&rsquo;ll try and be a slightly creative by deviating a bit though.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s2">&#34;2x2 Grid&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<pre><code>Text(0.5, 0.98, '2x2 Grid')
</code></pre>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_20_1.png" alt="png"></p>
<h1 id="lets-create-our-first-plot-using-matplotlib-primitives">Let&rsquo;s create our first plot using Matplotlib primitives:<a class="headerlink" href="#lets-create-our-first-plot-using-matplotlib-primitives" title="Link to this heading">#</a></h1>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># We first need a figure, an imaginary canvas to put things on</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">Figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Let&#39;s start with two Axes with an arbitrary position and size</span>
</span></span><span class="line"><span class="cl"><span class="n">ax1</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">Axes</span><span class="p">(</span><span class="n">fig</span><span class="o">=</span><span class="n">fig</span><span class="p">,</span> <span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">],</span> <span class="n">facecolor</span><span class="o">=</span><span class="s2">&#34;red&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax2</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">Axes</span><span class="p">(</span><span class="n">fig</span><span class="o">=</span><span class="n">fig</span><span class="p">,</span> <span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">facecolor</span><span class="o">=</span><span class="s2">&#34;blue&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p>Now you need to add the <code>Axes</code> to <code>fig</code>. You should stop right here and think about why would there be a need to do this when <code>fig</code> is already a parent of <code>ax1</code> and <code>ax2</code>? Let&rsquo;s do this anyway and we&rsquo;ll go into the details afterwards.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">(</span><span class="n">ax2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">(</span><span class="n">ax1</span><span class="p">)</span></span></span></code></pre>
</div>
<pre><code>&lt;matplotlib.axes._axes.Axes at 0x1211dead0&gt;
</code></pre>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># As you can see the Axes are exactly where we specified.</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_25_0.png" alt="png"></p>
<p>That means you can do this now:</p>
<blockquote>
<p>Remark: Notice the <code>ax.reverse()</code> call in the snippet below. If I hadn&rsquo;t done that, the biggest plot would be placed in the end on top of every other plot and you would just see a single, blank &lsquo;cyan&rsquo; colored plot.</p>
</blockquote>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">sizes</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.02</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">50</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">50</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">sizes</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="mi">255</span><span class="p">)))[</span><span class="mi">2</span><span class="p">:]</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">color</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">color</span> <span class="o">=</span> <span class="s2">&#34;0&#34;</span> <span class="o">+</span> <span class="n">color</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span> <span class="o">=</span> <span class="s2">&#34;#99&#34;</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">color</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">plt</span><span class="o">.</span><span class="n">Axes</span><span class="p">(</span><span class="n">fig</span><span class="o">=</span><span class="n">fig</span><span class="p">,</span> <span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">sizes</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">sizes</span><span class="p">[</span><span class="n">i</span><span class="p">]],</span> <span class="n">facecolor</span><span class="o">=</span><span class="n">color</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">reverse</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">axes</span> <span class="ow">in</span> <span class="n">ax</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">(</span><span class="n">axes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_27_0.png" alt="png"></p>
<p>The above example demonstrates why it is important to decouple the process of creation of an <code>Axes</code> and actually putting it onto a <code>Figure</code>.</p>
<p>Also, you can remove an <code>Axes</code> from the canvas area of a <code>Figure</code> like so:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">delaxes</span><span class="p">(</span><span class="n">ax</span><span class="p">)</span></span></span></code></pre>
</div>
<p>This can be useful when you want to compare the same primary data (GDP) to several secondary data sources (education, spending, etc.) one by one (you&rsquo;ll need to add and delete each graph from the Figure in succession)<br>
I also encourage you to look into the documentation for <code>Figure</code> and <code>Axes</code> and glance over the several methods available to them. This will help you know what parts of the wheel you do not need to rebuild when you&rsquo;re working with these objects the next time.</p>
<h2 id="recreating-our-subplots-literally-from-scratch">Recreating our subplots literally from scratch<a class="headerlink" href="#recreating-our-subplots-literally-from-scratch" title="Link to this heading">#</a></h2>
<p>This should now make sense. We can now create our original <code>plt.subplots(2, 2)</code> example using the knowledge we have thus gained so far.<br>
(Although, this is definitely not the most convenient way to do this)</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">figure</span><span class="o">.</span><span class="n">Figure</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s2">&#34;Recreating plt.subplots(2, 2)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ax1</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">axes</span><span class="o">.</span><span class="n">Axes</span><span class="p">(</span><span class="n">fig</span><span class="o">=</span><span class="n">fig</span><span class="p">,</span> <span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax2</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">axes</span><span class="o">.</span><span class="n">Axes</span><span class="p">(</span><span class="n">fig</span><span class="o">=</span><span class="n">fig</span><span class="p">,</span> <span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax3</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">axes</span><span class="o">.</span><span class="n">Axes</span><span class="p">(</span><span class="n">fig</span><span class="o">=</span><span class="n">fig</span><span class="p">,</span> <span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax4</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">axes</span><span class="o">.</span><span class="n">Axes</span><span class="p">(</span><span class="n">fig</span><span class="o">=</span><span class="n">fig</span><span class="p">,</span> <span class="n">rect</span><span class="o">=</span><span class="p">[</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">,</span> <span class="mf">0.42</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">(</span><span class="n">ax1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">(</span><span class="n">ax2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">(</span><span class="n">ax3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">(</span><span class="n">ax4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_30_0.png" alt="png"></p>
<h2 id="using-gridspecgridspec">Using <code>gridspec.GridSpec</code><a class="headerlink" href="#using-gridspecgridspec" title="Link to this heading">#</a></h2>
<p>Docs : <a href="https://matplotlib.org/api/_as_gen/matplotlib.gridspec.GridSpec.html#matplotlib.gridspec.GridSpec">https://matplotlib.org/api/_as_gen/matplotlib.gridspec.GridSpec.html#matplotlib.gridspec.GridSpec</a></p>
<p><code>GridSpec</code> objects allow us more intuitive control over how our plot is exactly divided into subplots and what the size of each <code>Axes</code> is.<br>
You can essentially decide a <strong>Grid</strong> which all your <code>Axes</code> will conform to when laying themselves over.<br>
Once you define a grid, or <code>GridSpec</code> so to say, you can use that object to <em>generate</em> new <code>Axes</code> conforming to the grid which you can then add to your <code>Figure</code></p>
<p>Lets see how all of this works in code:</p>
<p>You can define a <code>GridSpec</code> object like so (both statements are equivalent):</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">gs</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">gridspec</span><span class="o">.</span><span class="n">GridSpec</span><span class="p">(</span><span class="n">nrows</span><span class="p">,</span> <span class="n">ncols</span><span class="p">,</span> <span class="n">width_ratios</span><span class="p">,</span> <span class="n">height_ratios</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># OR</span>
</span></span><span class="line"><span class="cl"><span class="n">gs</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">GridSpec</span><span class="p">(</span><span class="n">nrows</span><span class="p">,</span> <span class="n">ncols</span><span class="p">,</span> <span class="n">width_ratios</span><span class="p">,</span> <span class="n">height_ratios</span><span class="p">)</span></span></span></code></pre>
</div>
<p>More specifically:</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">gs</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">GridSpec</span><span class="p">(</span><span class="n">nrows</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">ncols</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">width_ratios</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="n">height_ratios</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span></span></span></code></pre>
</div>
<p><code>nrows</code> and <code>ncols</code> are pretty self explanatory. <code>width_ratios</code> determines the relative width of each column. <code>height_ratios</code> follows along the same lines.
The whole <code>grid</code> will always distribute itself using all the space available to it inside of a figure (things change up a bit when you have multiple <code>GridSpec</code> objects for a single figure, but that&rsquo;s for you to explore!). And inside of a <code>grid</code>, all the Axes will conform to the sizes and ratios defined already</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Taken from https://matplotlib.org/gallery/userdemo/demo_gridspec03.html#sphx-glr-gallery-userdemo-demo-gridspec03-py
</span></span></span><span class="line"><span class="cl"><span class="s2">    takes a figure and puts an &#39;axN&#39; label in the center of each Axes
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">ax</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">fig</span><span class="o">.</span><span class="n">axes</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">text</span><span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="s2">&#34;ax</span><span class="si">%d</span><span class="s2">&#34;</span> <span class="o">%</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="n">va</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s2">&#34;center&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ax</span><span class="o">.</span><span class="n">tick_params</span><span class="p">(</span><span class="n">labelbottom</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">labelleft</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span></span></span></code></pre>
</div>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># We will try and vary axis sizes here just to see what happens</span>
</span></span><span class="line"><span class="cl"><span class="n">gs</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">gridspec</span><span class="o">.</span><span class="n">GridSpec</span><span class="p">(</span><span class="n">nrows</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">ncols</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">width_ratios</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="n">height_ratios</span><span class="o">=</span><span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span></span></span></code></pre>
</div>
<pre><code>&lt;Figure size 576x396 with 0 Axes&gt;
</code></pre>
<p>You can pass <code>GridSpec</code> objects to a <code>Figure</code> to create subplots in your desired sizes and proportions like so :<br>
Notice how the sizes of the <code>Axes</code> relates to the ratios we defined when creating the Grid.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">ax1</span><span class="p">,</span> <span class="n">ax2</span><span class="p">,</span> <span class="n">ax3</span><span class="p">,</span> <span class="n">ax4</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">2</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">    <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">3</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_36_0.png" alt="png"></p>
<p>Doing the same thing in a simpler way</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">add_gs_to_fig</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">gs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Adds all `SubplotSpec`s in `gs` to `fig`&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">g</span> <span class="ow">in</span> <span class="n">gs</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">g</span><span class="p">)</span></span></span></code></pre>
</div>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">add_gs_to_fig</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">gs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_39_0.png" alt="png"></p>
<p>That means you can now do this:<br>
(Notice how the <code>Axes</code> sizes increase from top-left to bottom-right)</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">length</span> <span class="o">=</span> <span class="mi">6</span>
</span></span><span class="line"><span class="cl"><span class="n">gs</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">GridSpec</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">nrows</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">ncols</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">width_ratios</span><span class="o">=</span><span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="n">height_ratios</span><span class="o">=</span><span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">add_gs_to_fig</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">gs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">ax</span> <span class="ow">in</span> <span class="n">fig</span><span class="o">.</span><span class="n">axes</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">ax</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_41_0.png" alt="png"></p>
<h2 id="a-very-unexpected-observation-which-gives-us-yet-more-clarity-and-power">A very unexpected observation: (which gives us yet more clarity, and Power)<a class="headerlink" href="#a-very-unexpected-observation-which-gives-us-yet-more-clarity-and-power" title="Link to this heading">#</a></h2>
<p>Notice how after each print operation, different addresses get printed for each <code>gs</code> object.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span></span></span></code></pre>
</div>
<pre><code>(&lt;matplotlib.gridspec.SubplotSpec at 0x1282a9e50&gt;,
 &lt;matplotlib.gridspec.SubplotSpec at 0x12942add0&gt;,
 &lt;matplotlib.gridspec.SubplotSpec at 0x12942a750&gt;,
 &lt;matplotlib.gridspec.SubplotSpec at 0x12a727e10&gt;)
</code></pre>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span></span></span></code></pre>
</div>
<pre><code>(&lt;matplotlib.gridspec.SubplotSpec at 0x127d5c6d0&gt;,
 &lt;matplotlib.gridspec.SubplotSpec at 0x12b6d0b10&gt;,
 &lt;matplotlib.gridspec.SubplotSpec at 0x129fc6390&gt;,
 &lt;matplotlib.gridspec.SubplotSpec at 0x129fc6a50&gt;)
</code></pre>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span></span></span></code></pre>
</div>
<pre><code>&lt;matplotlib.gridspec.SubplotSpec object at 0x12951a610&gt; &lt;matplotlib.gridspec.SubplotSpec object at 0x12951a890&gt; &lt;matplotlib.gridspec.SubplotSpec object at 0x12951ac10&gt; &lt;matplotlib.gridspec.SubplotSpec object at 0x12951a150&gt;
</code></pre>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span></span></span></code></pre>
</div>
<pre><code>&lt;matplotlib.gridspec.SubplotSpec object at 0x128fad4d0&gt; &lt;matplotlib.gridspec.SubplotSpec object at 0x1291ebbd0&gt; &lt;matplotlib.gridspec.SubplotSpec object at 0x1294f9850&gt; &lt;matplotlib.gridspec.SubplotSpec object at 0x128106250&gt;
</code></pre>
<p><strong>Lets understand why this happens:</strong></p>
<p><em>Notice how a group of <code>gs</code> objects indexed into at the same time also produces just one object instead of multiple objects</em></p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">gs</span><span class="p">[:,</span> <span class="p">:],</span> <span class="n">gs</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># both output just one object each</span></span></span></code></pre>
</div>
<pre><code>(&lt;matplotlib.gridspec.SubplotSpec at 0x128116e50&gt;,
 &lt;matplotlib.gridspec.SubplotSpec at 0x128299290&gt;)
</code></pre>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># Lets try another `gs` object, this time a little more crowded</span>
</span></span><span class="line"><span class="cl"><span class="c1"># I chose the ratios randomly</span>
</span></span><span class="line"><span class="cl"><span class="n">gs</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">gridspec</span><span class="o">.</span><span class="n">GridSpec</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">nrows</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">ncols</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">width_ratios</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">height_ratios</span><span class="o">=</span><span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre>
</div>
<p><em>All these operations print just one object. What is going on here?</em></p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">gs</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">1</span><span class="p">:,</span> <span class="p">:</span><span class="mi">2</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">gs</span><span class="p">[:,</span> <span class="p">:])</span></span></span></code></pre>
</div>
<pre><code>&lt;matplotlib.gridspec.SubplotSpec object at 0x12a075fd0&gt;
&lt;matplotlib.gridspec.SubplotSpec object at 0x128cf0990&gt;
&lt;matplotlib.gridspec.SubplotSpec object at 0x12a075fd0&gt;
</code></pre>
<p>Let&rsquo;s try and add subplots to our <code>Figure</code> to <code>see</code> what&rsquo;s going on.<br>
We&rsquo;ll do a few different permutations to get an exact idea.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">ax1</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[:</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax2</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax3</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">:])</span>
</span></span><span class="line"><span class="cl"><span class="n">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_54_0.png" alt="png"></p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ax1 = fig.add_subplot(gs[:2, 0])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax2</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax3</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">:])</span>
</span></span><span class="line"><span class="cl"><span class="n">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_55_0.png" alt="png"></p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ax1 = fig.add_subplot(gs[:2, 0])</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ax2 = fig.add_subplot(gs[2, 0])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax3</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">:])</span>
</span></span><span class="line"><span class="cl"><span class="n">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_56_0.png" alt="png"></p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ax1 = fig.add_subplot(gs[:2, 0])</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ax2 = fig.add_subplot(gs[2, 0])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax3</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">:])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Notice the line below : You can overlay Axes using `GridSpec` too</span>
</span></span><span class="line"><span class="cl"><span class="n">ax4</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="n">gs</span><span class="p">[</span><span class="mi">2</span><span class="p">:,</span> <span class="mi">1</span><span class="p">:])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax4</span><span class="o">.</span><span class="n">set_facecolor</span><span class="p">(</span><span class="s2">&#34;orange&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_57_0.png" alt="png"></p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">add_gs_to_fig</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">gs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_58_0.png" alt="png"></p>
<p>Here&rsquo;s a bullet point summary of what this means:</p>
<ol>
<li><code>gs</code> can be used as a sort of a <code>factory</code> for different kinds of <code>Axes</code>.</li>
<li>You give this <code>factory</code> an order by indexing into particular areas of the <code>Grid</code>. It gives back a single <code>SubplotSpec</code> (check <code>type(gs[0]</code>) object that helps you create an <code>Axes</code> which has all of the area you indexed into combined into one unit.</li>
<li>Your <code>height</code> and <code>width</code> ratios for the indexed portion will determine the size of the <code>Axes</code> that gets generated.</li>
<li><code>Axes</code> will maintain relative proportions according to your <code>height</code> and <code>width</code> ratios always.</li>
<li>For all these reasons, I like <code>GridSpec</code>!</li>
</ol>
<p>This ability to create different grid variations that <code>GridSpec</code> provides is probably the reason for that anomaly we saw a while ago (printing different Addresses).</p>
<p>It creates new objects every time you index into it because it will be very troublesome to store all permutations of <code>SubplotSpec</code> objects into one group in memory (try and count permutations for a <code>GridSpec</code> of 10x10 and you&rsquo;ll know why)</p>
<hr>
<h2 id="now-lets-finally-create-pltsubplots22-once-again-using-gridspec">Now let&rsquo;s finally create <code>plt.subplots(2,2)</code> once again using GridSpec<a class="headerlink" href="#now-lets-finally-create-pltsubplots22-once-again-using-gridspec" title="Link to this heading">#</a></h2>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">gs</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">.</span><span class="n">gridspec</span><span class="o">.</span><span class="n">GridSpec</span><span class="p">(</span><span class="n">nrows</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">ncols</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">add_gs_to_fig</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">gs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">annotate_axes</span><span class="p">(</span><span class="n">fig</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">suptitle</span><span class="p">(</span><span class="s2">&#34;We&#39;re done!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;yayy&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<pre><code>yayy
</code></pre>
<p><img src="/matplotlib/an-inquiry-into-matplotlib-figures/output_61_1.png" alt="png"></p>
<h1 id="what-you-should-try">What you should try:<a class="headerlink" href="#what-you-should-try" title="Link to this heading">#</a></h1>
<hr>
<p>Here&rsquo;s a few things I think you should go ahead and explore:</p>
<ol>
<li>Multiple <code>GridSpec</code> objects for the Same Figure.</li>
<li>Deleting and adding <code>Axes</code> effectively and meaningfully.</li>
<li>All the methods available for <code>mpl.figure.Figure</code> and <code>mpl.axes.Axes</code> allowing us to manipulate their properties.</li>
<li>Kaggle Learn&rsquo;s Data visualization course is a great place to learn effective plotting using Python</li>
<li>Armed with knowledge, you will be able to use other plotting libraries such as <code>seaborn</code>, <code>plotly</code>, <code>pandas</code> and <code>altair</code> with much more flexibility (you can pass an <code>Axes</code> object to all their plotting functions). I encourage you to explore these libraries too.</li>
</ol>
<p>This is the first time I&rsquo;ve written any technical guide for the internet, it may not be as clean as tutorials generally are. But, I&rsquo;m open to all the constructive criticism that you may have for me (drop me an email on <a href="mailto:akashpalrecha@gmail.com">akashpalrecha@gmail.com</a>)</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Custom 3D engine in Matplotlib]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/custom-3d-engine/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/warming-stripes/?utm_source=atom_feed" rel="related" type="text/html" title="Creating the Warming Stripes in Matplotlib" />
                <link href="https://blog.scientific-python.org/matplotlib/matplotlib-in-data-driven-seo/?utm_source=atom_feed" rel="related" type="text/html" title="Matplotlib in Data Driven SEO" />
                <link href="https://blog.scientific-python.org/matplotlib/using-matplotlib-to-advocate-for-postdocs/?utm_source=atom_feed" rel="related" type="text/html" title="Using Matplotlib to Advocate for Postdocs" />
            
                <id>https://blog.scientific-python.org/matplotlib/custom-3d-engine/</id>
            
            
            <published>2019-12-18T09:05:32+01:00</published>
            <updated>2019-12-18T09:05:32+01:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>3D rendering is really easy once you&rsquo;ve understood a few concepts. To demonstrate that, we&rsquo;ll design a simple custom 3D engine that with 60 lines of Python and one Matplotlib call. That is, we&rsquo;ll render the bunny without using the 3D axis.</blockquote><p><img src="/matplotlib/custom-3d-engine/bunny.jpg" alt="A colourful outline of a bunny."></p>
<p>Matplotlib has a really nice <a href="https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html">3D
interface</a> with many
capabilities (and some limitations) that is quite popular among users. Yet, 3D
is still considered to be some kind of black magic for some users (or maybe
for the majority of users). I would thus like to explain in this post that 3D
rendering is really easy once you&rsquo;ve understood a few concepts. To demonstrate
that, we&rsquo;ll render the bunny above with 60 lines of Python and one Matplotlib
call. That is, without using the 3D axis.</p>
<p><strong>Advertisement</strong>: This post comes from an upcoming open access book on
scientific visualization using Python and Matplotlib. If you want to
support my work and have an early access to the book, go to
<a href="https://github.com/rougier/scientific-visualization-book">https://github.com/rougier/scientific-visualization-book</a>.</p>
<h1 id="loading-the-bunny">Loading the bunny<a class="headerlink" href="#loading-the-bunny" title="Link to this heading">#</a></h1>
<p>First things first, we need to load our model. We&rsquo;ll use a <a href="/matplotlib/custom-3d-engine/bunny.obj">simplified
version</a> of the <a href="https://en.wikipedia.org/wiki/Stanford_bunny">Stanford
bunny</a>. The file uses the
<a href="https://en.wikipedia.org/wiki/Wavefront_.obj_file">wavefront format</a> which is
one of the simplest format, so let&rsquo;s make a very simple (but error-prone)
loader that will just do the job for this post (and this model):</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">V</span><span class="p">,</span> <span class="n">F</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;bunny.obj&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">   <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">       <span class="k">if</span> <span class="n">line</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;#&#39;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">           <span class="k">continue</span>
</span></span><span class="line"><span class="cl">       <span class="n">values</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">       <span class="k">if</span> <span class="ow">not</span> <span class="n">values</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">           <span class="k">continue</span>
</span></span><span class="line"><span class="cl">       <span class="k">if</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;v&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">           <span class="n">V</span><span class="o">.</span><span class="n">append</span><span class="p">([</span><span class="nb">float</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">values</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="mi">4</span><span class="p">]])</span>
</span></span><span class="line"><span class="cl">       <span class="k">elif</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;f&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">           <span class="n">F</span><span class="o">.</span><span class="n">append</span><span class="p">([</span><span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">values</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="mi">4</span><span class="p">]])</span>
</span></span><span class="line"><span class="cl"><span class="n">V</span><span class="p">,</span> <span class="n">F</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">V</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">F</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span></span></span></code></pre>
</div>
<p><code>V</code> is now a set of vertices (3D points if you prefer) and <code>F</code> is a set of
faces (= triangles). Each triangle is described by 3 indices relatively to the
vertices array. Now, let&rsquo;s normalize the vertices such that the overall bunny
fits the unit box:</p>

<div class="highlight">
  <pre>V = (V-(V.max(0)&#43;V.min(0))/2)/max(V.max(0)-V.min(0))</pre>
</div>

<p>Now, we can have a first look at the model by getting only the x,y coordinates of the vertices and get rid of the z coordinate. To do this we can use the powerful
<a href="https://matplotlib.org/3.1.1/api/collections_api.html#matplotlib.collections.PolyCollection">PolyCollection</a>
object that allow to render efficiently a collection of non-regular
polygons. Since, we want to render a bunch of triangles, this is a perfect
match. So let&rsquo;s first extract the triangles and get rid of the <code>z</code> coordinate:</p>

<div class="highlight">
  <pre>T = V[F][...,:2]</pre>
</div>

<p>And we can now render it:</p>

<div class="highlight">
  <pre>fig = plt.figure(figsize=(6,6))
ax = fig.add_axes([0,0,1,1], xlim=[-1,&#43;1], ylim=[-1,&#43;1],
                  aspect=1, frameon=False)
collection = PolyCollection(T, closed=True, linewidth=0.1,
                            facecolor=&#34;None&#34;, edgecolor=&#34;black&#34;)
ax.add_collection(collection)
plt.show()</pre>
</div>

<p>You should obtain something like this (<a href="/matplotlib/custom-3d-engine/bunny-1.py">bunny-1.py</a>):</p>
<p><img src="/matplotlib/custom-3d-engine/bunny-1.png" alt="A black and white outline of a bunny facing left side."></p>
<h1 id="perspective-projection">Perspective Projection<a class="headerlink" href="#perspective-projection" title="Link to this heading">#</a></h1>
<p>The rendering we&rsquo;ve just made is actually an <a href="https://en.wikipedia.org/wiki/Orthographic_projection">orthographic
projection</a> while the
top bunny uses a <a href="https://en.wikipedia.org/wiki/3D_projection#Perspective_projection">perspective projection</a>:</p>
<p><img src="/matplotlib/custom-3d-engine/projections.png" alt="Difference in perspective projection and orthographic projection. The near clip plane appears smaller in the perspective projective than in the orthographic projection."></p>
<p>In both cases, the proper way of defining a projection is first to define a
viewing volume, that is, the volume in the 3D space we want to render on the
screen. To do that, we need to consider 6 clipping planes (left, right, top,
bottom, far, near) that enclose the viewing volume (frustum) relatively to the
camera. If we define a camera position and a viewing direction, each plane can
be described by a single scalar. Once we have this viewing volume, we can
project onto the screen using either the orthographic or the perspective
projection.</p>
<p>Fortunately for us, these projections are quite well known and can be expressed
using 4x4 matrices:</p>

<div class="highlight">
  <pre>def frustum(left, right, bottom, top, znear, zfar):
    M = np.zeros((4, 4), dtype=np.float32)
    M[0, 0] = &#43;2.0 * znear / (right - left)
    M[1, 1] = &#43;2.0 * znear / (top - bottom)
    M[2, 2] = -(zfar &#43; znear) / (zfar - znear)
    M[0, 2] = (right &#43; left) / (right - left)
    M[2, 1] = (top &#43; bottom) / (top - bottom)
    M[2, 3] = -2.0 * znear * zfar / (zfar - znear)
    M[3, 2] = -1.0
    return M

def perspective(fovy, aspect, znear, zfar):
    h = np.tan(0.5*radians(fovy)) * znear
    w = h * aspect
    return frustum(-w, w, -h, h, znear, zfar)</pre>
</div>

<p>For the perspective projection, we also need to specify the aperture angle that
(more or less) sets the size of the near plane relatively to the far
plane. Consequently, for high apertures, you&rsquo;ll get a lot of &ldquo;deformations&rdquo;.</p>
<p>However, if you look at the two functions above, you&rsquo;ll realize they return 4x4
matrices while our coordinates are 3D. How to use these matrices then ? The
answer is <a href="https://en.wikipedia.org/wiki/Homogeneous_coordinates">homogeneous
coordinates</a>. To make
a long story short, homogeneous coordinates are best to deal with transformation
and projections in 3D. In our case, because we&rsquo;re dealing with vertices (and
not vectors), we only need to add 1 as the fourth coordinate (<code>w</code>) to all our
vertices. Then we can apply the perspective transformation using the dot
product.</p>

<div class="highlight">
  <pre>V = np.c_[V, np.ones(len(V))] @ perspective(25,1,1,100).T</pre>
</div>

<p>Last step, we need to re-normalize the homogeneous coordinates. This means we
divide each transformed vertices with the last component (<code>w</code>) such as to
always have <code>w</code>=1 for each vertices.</p>

<div class="highlight">
  <pre>V /= V[:,3].reshape(-1,1)</pre>
</div>

<p>Now we can display the result again (<a href="/matplotlib/custom-3d-engine/bunny-2.py">bunny-2.py</a>):</p>
<p><img src="/matplotlib/custom-3d-engine/bunny-2.png" alt=""></p>
<p>Oh, weird result. What&rsquo;s wrong? What is wrong is that the camera is actually
inside the bunny. To have a proper rendering, we need to move the bunny away
from the camera or move the camera away from the bunny. Let&rsquo;s do the latter. The
camera is currently positioned at (0,0,0) and looking up in the z direction
(because of the frustum transformation). We thus need to move the camera away a
little bit in the z negative direction and <strong>before the perspective
transformation</strong>:</p>

<div class="highlight">
  <pre>V = V - (0,0,3.5)
V = np.c_[V, np.ones(len(V))] @ perspective(25,1,1,100).T
V /= V[:,3].reshape(-1,1)</pre>
</div>

<p>An now you should obtain (<a href="/matplotlib/custom-3d-engine/bunny-3.py">bunny-3.py</a>):</p>
<p><img src="/matplotlib/custom-3d-engine/bunny-3.png" alt=""></p>
<h1 id="model-view-projection-mvp">Model, view, projection (MVP)<a class="headerlink" href="#model-view-projection-mvp" title="Link to this heading">#</a></h1>
<p>It might be not obvious, but the last rendering is actually a perspective
transformation. To make it more obvious, we&rsquo;ll rotate the bunny around. To do
that, we need some rotation matrices (4x4) and we can as well define the
translation matrix in the meantime:</p>

<div class="highlight">
  <pre>def translate(x, y, z):
    return np.array([[1, 0, 0, x],
                     [0, 1, 0, y],
                     [0, 0, 1, z],
                     [0, 0, 0, 1]], dtype=float)

def xrotate(theta):
    t = np.pi * theta / 180
    c, s = np.cos(t), np.sin(t)
    return np.array([[1, 0,  0, 0],
                     [0, c, -s, 0],
                     [0, s,  c, 0],
                     [0, 0,  0, 1]], dtype=float)

def yrotate(theta):
    t = np.pi * theta / 180
    c, s = np.cos(t), np.sin(t)
    return  np.array([[ c, 0, s, 0],
                      [ 0, 1, 0, 0],
                      [-s, 0, c, 0],
                      [ 0, 0, 0, 1]], dtype=float)</pre>
</div>

<p>We&rsquo;ll now decompose the transformations we want to apply in term of model
(local transformations), view (global transformations) and projection such that
we can compute a global MVP matrix that will do everything at once:</p>

<div class="highlight">
  <pre>model = xrotate(20) @ yrotate(45)
view  = translate(0,0,-3.5)
proj  = perspective(25, 1, 1, 100)
MVP   = proj  @ view  @ model</pre>
</div>

<p>and we now write:</p>

<div class="highlight">
  <pre>V = np.c_[V, np.ones(len(V))] @ MVP.T
V /= V[:,3].reshape(-1,1)</pre>
</div>

<p>You should obtain (<a href="/matplotlib/custom-3d-engine/bunny-4.py">bunny-4.py</a>):</p>
<p><img src="/matplotlib/custom-3d-engine/bunny-4.png" alt=""></p>
<p>Let&rsquo;s now play a bit with the aperture such that you can see the difference.
Note that we also have to adapt the distance to the camera in order for the bunnies to have the same apparent size (<a href="/matplotlib/custom-3d-engine/bunny-5.py">bunny-5.py</a>):</p>
<p><img src="/matplotlib/custom-3d-engine/bunny-5.png" alt=""></p>
<h1 id="depth-sorting">Depth sorting<a class="headerlink" href="#depth-sorting" title="Link to this heading">#</a></h1>
<p>Let&rsquo;s try now to fill the triangles (<a href="/matplotlib/custom-3d-engine/bunny-6.py">bunny-6.py</a>):</p>
<p><img src="/matplotlib/custom-3d-engine/bunny-6.png" alt=""></p>
<p>As you can see, the result is &ldquo;interesting&rdquo; and totally wrong. The problem is
that the PolyCollection will draw the triangles in the order they are given
while we would like to have them from back to front. This means we need to sort
them according to their depth. The good news is that we already computed this
information when we applied the MVP transformation. It is stored in the new z
coordinates. However, these z values are vertices based while we need to sort
the triangles. We&rsquo;ll thus take the mean z value as being representative of the
depth of a triangle. If triangles are relatively small and do not intersect,
this works beautifully:</p>

<div class="highlight">
  <pre>T =  V[:,:,:2]
Z = -V[:,:,2].mean(axis=1)
I = np.argsort(Z)
T = T[I,:]</pre>
</div>

<p>And now everything is rendered right (<a href="/matplotlib/custom-3d-engine/bunny-7.py">bunny-7.py</a>):</p>
<p><img src="/matplotlib/custom-3d-engine/bunny-7.png" alt=""></p>
<p>Let&rsquo;s add some colors using the depth buffer. We&rsquo;ll color each triangle
according to it depth. The beauty of the PolyCollection object is that you can
specify the color of each of the triangle using a NumPy array, so let&rsquo;s just do
that:</p>

<div class="highlight">
  <pre>zmin, zmax = Z.min(), Z.max()
Z = (Z-zmin)/(zmax-zmin)
C = plt.get_cmap(&#34;magma&#34;)(Z)
I = np.argsort(Z)
T, C = T[I,:], C[I,:]</pre>
</div>

<p>And now everything is rendered right (<a href="/matplotlib/custom-3d-engine/bunny-8.py">bunny-8.py</a>):</p>
<p><img src="/matplotlib/custom-3d-engine/bunny-8.png" alt=""></p>
<p>The final script is 57 lines (but hardly readable):</p>

<div class="highlight">
  <pre>import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection

def frustum(left, right, bottom, top, znear, zfar):
    M = np.zeros((4, 4), dtype=np.float32)
    M[0, 0] = &#43;2.0 * znear / (right - left)
    M[1, 1] = &#43;2.0 * znear / (top - bottom)
    M[2, 2] = -(zfar &#43; znear) / (zfar - znear)
    M[0, 2] = (right &#43; left) / (right - left)
    M[2, 1] = (top &#43; bottom) / (top - bottom)
    M[2, 3] = -2.0 * znear * zfar / (zfar - znear)
    M[3, 2] = -1.0
    return M
def perspective(fovy, aspect, znear, zfar):
    h = np.tan(0.5*np.radians(fovy)) * znear
    w = h * aspect
    return frustum(-w, w, -h, h, znear, zfar)
def translate(x, y, z):
    return np.array([[1, 0, 0, x], [0, 1, 0, y],
                     [0, 0, 1, z], [0, 0, 0, 1]], dtype=float)
def xrotate(theta):
    t = np.pi * theta / 180
    c, s = np.cos(t), np.sin(t)
    return np.array([[1, 0,  0, 0], [0, c, -s, 0],
                     [0, s,  c, 0], [0, 0,  0, 1]], dtype=float)
def yrotate(theta):
    t = np.pi * theta / 180
    c, s = np.cos(t), np.sin(t)
    return  np.array([[ c, 0, s, 0], [ 0, 1, 0, 0],
                      [-s, 0, c, 0], [ 0, 0, 0, 1]], dtype=float)
V, F = [], []
with open(&#34;bunny.obj&#34;) as f:
    for line in f.readlines():
        if line.startswith(&#39;#&#39;):  continue
        values = line.split()
        if not values:            continue
        if values[0] == &#39;v&#39;:      V.append([float(x) for x in values[1:4]])
        elif values[0] == &#39;f&#39; :   F.append([int(x) for x in values[1:4]])
V, F = np.array(V), np.array(F)-1
V = (V-(V.max(0)&#43;V.min(0))/2) / max(V.max(0)-V.min(0))
MVP = perspective(25,1,1,100) @ translate(0,0,-3.5) @ xrotate(20) @ yrotate(45)
V = np.c_[V, np.ones(len(V))]  @ MVP.T
V /= V[:,3].reshape(-1,1)
V = V[F]
T =  V[:,:,:2]
Z = -V[:,:,2].mean(axis=1)
zmin, zmax = Z.min(), Z.max()
Z = (Z-zmin)/(zmax-zmin)
C = plt.get_cmap(&#34;magma&#34;)(Z)
I = np.argsort(Z)
T, C = T[I,:], C[I,:]
fig = plt.figure(figsize=(6,6))
ax = fig.add_axes([0,0,1,1], xlim=[-1,&#43;1], ylim=[-1,&#43;1], aspect=1, frameon=False)
collection = PolyCollection(T, closed=True, linewidth=0.1, facecolor=C, edgecolor=&#34;black&#34;)
ax.add_collection(collection)
plt.show()</pre>
</div>

<p>Now it&rsquo;s your turn to play. Starting from this simple script, you can achieve
interesting results:</p>
<p><img src="/matplotlib/custom-3d-engine/checkered-sphere.png" alt="">
<img src="/matplotlib/custom-3d-engine/platonic-solids.png" alt="">
<img src="/matplotlib/custom-3d-engine/surf.png" alt="">
<img src="/matplotlib/custom-3d-engine/bar.png" alt="">
<img src="/matplotlib/custom-3d-engine/contour.png" alt=""></p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="3d" label="3D" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Creating the Warming Stripes in Matplotlib]]></title>
            <link href="https://blog.scientific-python.org/matplotlib/warming-stripes/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://blog.scientific-python.org/matplotlib/using-matplotlib-to-advocate-for-postdocs/?utm_source=atom_feed" rel="related" type="text/html" title="Using Matplotlib to Advocate for Postdocs" />
            
                <id>https://blog.scientific-python.org/matplotlib/warming-stripes/</id>
            
            
            <published>2019-11-11T09:21:28+01:00</published>
            <updated>2019-11-11T09:21:28+01:00</updated>
            
            
            <content type="html"><![CDATA[<blockquote>Ed Hawkins made this impressively simple plot to show how global temperatures have risen since 1880. Here is how to recreate it using Matplotlib.</blockquote><p><img src="/matplotlib/warming-stripes/warming-stripes.png" alt="A horizontal bar divided into stripes with colors ranging from white to shades of blue and shades of red. There is a clear tendency of shades of blue on the left side of the bar, and shades of red on the right side of the bar."></p>
<p>Earth&rsquo;s temperatures are rising and nothing shows this in a simpler,
more approachable graphic than the “Warming Stripes”.
Introduced by Prof. Ed Hawkins they show the temperatures either for
the global average or for your region as colored bars from blue to red for the last 170 years, available at <a href="https://showyourstripes.info">#ShowYourStripes</a>.</p>
<p>The stripes have since become the logo of the <a href="https://scientistsforfuture.org">Scientists for Future</a>.
Here is how you can recreate this yourself using Matplotlib.</p>
<p>We are going to use the <a href="https://www.metoffice.gov.uk/hadobs/hadcrut4/index.html">HadCRUT4</a> dataset, published by the Met Office.
It uses combined sea and land surface temperatures.
The dataset used for the warming stripes is the annual global average.</p>
<p>First, let&rsquo;s import everything we are going to use.
The plot will consist of a bar for each year, colored using a custom
color map.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib.patches</span> <span class="kn">import</span> <span class="n">Rectangle</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib.collections</span> <span class="kn">import</span> <span class="n">PatchCollection</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">matplotlib.colors</span> <span class="kn">import</span> <span class="n">ListedColormap</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span></span></span></code></pre>
</div>
<p>Then we define our time limits, our reference period for
the neutral color and the range around it for maximum saturation.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">FIRST</span> <span class="o">=</span> <span class="mi">1850</span>
</span></span><span class="line"><span class="cl"><span class="n">LAST</span> <span class="o">=</span> <span class="mi">2018</span>  <span class="c1"># inclusive</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Reference period for the center of the color scale</span>
</span></span><span class="line"><span class="cl"><span class="n">FIRST_REFERENCE</span> <span class="o">=</span> <span class="mi">1971</span>
</span></span><span class="line"><span class="cl"><span class="n">LAST_REFERENCE</span> <span class="o">=</span> <span class="mi">2000</span>
</span></span><span class="line"><span class="cl"><span class="n">LIM</span> <span class="o">=</span> <span class="mf">0.7</span>  <span class="c1"># degrees</span></span></span></code></pre>
</div>
<p>Here we use pandas to read the fixed width text file, only the
first two columns, which are the year and the deviation from the
mean from 1961 to 1990.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># data from</span>
</span></span><span class="line"><span class="cl"><span class="c1"># https://www.metoffice.gov.uk/hadobs/hadcrut4/data/current/time_series/HadCRUT.4.6.0.0.annual_ns_avg.txt</span>
</span></span><span class="line"><span class="cl"><span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_fwf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;HadCRUT.4.6.0.0.annual_ns_avg.txt&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">index_col</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">usecols</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">names</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;year&#34;</span><span class="p">,</span> <span class="s2">&#34;anomaly&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">header</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">anomaly</span> <span class="o">=</span> <span class="n">df</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">FIRST</span><span class="p">:</span><span class="n">LAST</span><span class="p">,</span> <span class="s2">&#34;anomaly&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">dropna</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">reference</span> <span class="o">=</span> <span class="n">anomaly</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">FIRST_REFERENCE</span><span class="p">:</span><span class="n">LAST_REFERENCE</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span></span></span></code></pre>
</div>
<p>This is our custom colormap, we could also use one of
the <a href="https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html">colormaps</a> that come with <code>matplotlib</code>, e.g. <code>coolwarm</code> or <code>RdBu</code>.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># the colors in this colormap come from http://colorbrewer2.org</span>
</span></span><span class="line"><span class="cl"><span class="c1"># the 8 more saturated colors from the 9 blues / 9 reds</span>
</span></span><span class="line"><span class="cl"><span class="n">cmap</span> <span class="o">=</span> <span class="n">ListedColormap</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#08306b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#08519c&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#2171b5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#4292c6&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#6baed6&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#9ecae1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#c6dbef&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#deebf7&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#fee0d2&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#fcbba1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#fc9272&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#fb6a4a&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#ef3b2c&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#cb181d&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#a50f15&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;#67000d&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre>
</div>
<p>We create a figure with a single axes object that fills the full area
of the figure and does not have any axis ticks or labels.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="o">.</span><span class="n">add_axes</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_axis_off</span><span class="p">()</span></span></span></code></pre>
</div>
<p>Finally, we create bars for each year, assign the
data, colormap and color limits and add it to the axes.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="c1"># create a collection with a rectangle for each year</span>
</span></span><span class="line"><span class="cl"><span class="n">col</span> <span class="o">=</span> <span class="n">PatchCollection</span><span class="p">([</span><span class="n">Rectangle</span><span class="p">((</span><span class="n">y</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">FIRST</span><span class="p">,</span> <span class="n">LAST</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># set data, colormap and color limits</span>
</span></span><span class="line"><span class="cl"><span class="n">col</span><span class="o">.</span><span class="n">set_array</span><span class="p">(</span><span class="n">anomaly</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">col</span><span class="o">.</span><span class="n">set_cmap</span><span class="p">(</span><span class="n">cmap</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">col</span><span class="o">.</span><span class="n">set_clim</span><span class="p">(</span><span class="n">reference</span> <span class="o">-</span> <span class="n">LIM</span><span class="p">,</span> <span class="n">reference</span> <span class="o">+</span> <span class="n">LIM</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">add_collection</span><span class="p">(</span><span class="n">col</span><span class="p">)</span></span></span></code></pre>
</div>
<p>Make sure the axes limits are correct and save the figure.</p>


<div class="highlight">
  <pre class="chroma"><code><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ax</span><span class="o">.</span><span class="n">set_xlim</span><span class="p">(</span><span class="n">FIRST</span><span class="p">,</span> <span class="n">LAST</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fig</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s2">&#34;warming-stripes.png&#34;</span><span class="p">)</span></span></span></code></pre>
</div>
<p><img src="/matplotlib/warming-stripes/warming-stripes.png" alt="Warming Stripes"></p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="tutorials" label="tutorials" />
                             
                                <category scheme="taxonomy:Tags" term="academia" label="academia" />
                             
                                <category scheme="taxonomy:Tags" term="matplotlib" label="matplotlib" />
                            
                        
                    
                
            
        </entry>
    
</feed>
